1. 程式人生 > 其它 >docker容器配置與資源限制

docker容器配置與資源限制

一、Docker容器配置進階

1、容器的自動重啟

Docker提供重啟策略控制容器退出時或Docker重啟時是否自動啟動該容器。

容器預設不支援自動重啟,要使用 --restart 選項指定重啟策略。

[root@localhost ~]# docker run --help
      --restart string                 Restart policy to apply when a container exits (default "no")  

容器重啟策略選項值:

選項值 功能
no 容器退出時不重啟,預設設定
on-failure[:max-retries] 容器以非0狀態退出時重啟,max-retries指定重啟的次數
always 不管退出狀態始終重啟,無限次
unless-stopped 不管退出狀態始終重啟,(Docker守護程序啟動時,容器處於執行狀態才生效)
# 案例1:執行一個始終重啟的redis容器,容器退出時Docker重啟它
[root@localhost ~]# docker run -d --name testrs --restart=always redis
cdf90c50d38f712020f2bd75e10e20c5ba6aa980747176f7bff4b45d4844ab8a
[root@localhost ~]# docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED         STATUS         PORTS      NAMES
cdf90c50d38f   redis     "docker-entrypoint.s…"   7 seconds ago   Up 6 seconds   6379/tcp   testrs
# 停止Docker後,容器立馬重啟
[root@localhost ~]# systemctl stop docker
[root@localhost ~]# docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED         STATUS                  PORTS      NAMES
cdf90c50d38f   redis     "docker-entrypoint.s…"   2 minutes ago   Up Less than a second   6379/tcp   testrs

# 案例2:設定容器最大重啟次數
# 設定非0狀態最大重啟十次
[root@localhost ~]# docker run -dti --restart=on-failure:10 redis bash
fe8f308023cfde7a738ba5a22098dbe8d5f35697db85094a2dc7778a7293f1d5
# 另一個終端執行
[root@localhost ~]# systemctl stop docker
[root@localhost ~]# docker ps -a
CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS                      PORTS      NAMES
fe8f308023cf   redis     "docker-entrypoint.s…"   20 seconds ago   Up Less than a second       6379/tcp   serene_pascal

# 案例3:已經執行或建立的容器,用 docker update 更改重啟策略
[root@localhost ~]# docker update --restart=on-failure:3 fe8f308
fe8f308

作用:容器自動重啟;重啟策略能夠確保關聯的多個容器按照正確的順序啟動。

使用重啟策略時的注意事項:

  1. 重啟策略只在容器成功啟動後才會生效。(容器執行後生效)
  2. 如果手動停止一個容器,那麼它的重啟策略會被忽略,直到Docker守護程序重啟或容器手動重啟。(手動停止,暫停重啟策略)
  3. Docker Swarm服務的重啟策略採用不同的配置方式。(叢集採用不同的重啟策略)
  4. 重啟策略不同於dockerd命令的--live-restore選項,這個選項可使Docker升級中,即使網路和使用者輸入都終端,容器依然保持執行。
  5. Docker建議使用重啟策略,並避免使用程序管理器啟動容器:(1)同時使用兩者會產生衝突;(2)程序管理器依賴於作業系統,Docker無法監控。

2、在Docker停止時保持容器繼續執行

預設情況下,Docker守護程序終止時,正在執行的容器會關閉。

實時恢復(Live Restore):管理員配置守護程序,讓容器在守護程序不可用時依然執行。

實時恢復的作用:減少因Docker守護程序崩潰、計劃停機或升級導致的容器停機時間。

(1)啟用實時恢復功能

第一種方式是在Docker守護程序配置檔案中設定:

sighup(結束通話)訊號在控制終端或者控制程序死亡時向關聯會話中的程序發出,預設程序對SIGHUP訊號的處理時終止程式,所以我們在shell下建立的程式,在登入退出連線斷開之後,會一併退出。

nohup,故名思議就是忽略SIGHUP訊號,一般搭配& 一起使用,&表示將此程式提交為後臺作業或者說後臺程序組。

[root@localhost ~]# vi /etc/docker/daemon.json 
{
  "live-restore":true
}

# 配置生效方法一:
# 修改配置後重啟守護程序生效
[root@localhost ~]# systemctl daemon-reload
[root@localhost ~]# systemctl restart docker

# 配置生效方法二:
# 重新載入Docker守護程序,避免容器停止
[root@localhost ~]# systemctl reload docker

# 案例1:
# 1.啟動兩個容器
[root@localhost ~]# docker ps 
CONTAINER ID   IMAGE              COMMAND                  CREATED       STATUS          PORTS     NAMES
1dd65fa55b80   top                "/bin/sh -c 'exec to…"   5 weeks ago   Up 38 seconds             test_exec_entry
52a7de98ccc7   test_shell_entry   "/bin/sh -c 'top -b'"    5 weeks ago   Up 52 seconds             test:
# 2.停止docker守護程序
[root@localhost ~]# systemctl stop docker
Warning: Stopping docker.service, but it can still be activated by:
  docker.socket
[root@localhost ~]# systemctl status docker
● docker.service - Docker Application Container Engine
   Loaded: loaded (/usr/lib/systemd/system/docker.service; enabled; vendor preset: disabled)
   Active: inactive (dead) since Wed 2022-05-11 00:23:16 CST; 8s ago
     Docs: https://docs.docker.com
  Process: 1697 ExecReload=/bin/kill -s HUP $MAINPID (code=exited, status=0/SUCCESS)
  Process: 1853 ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock (code=exited, status=0/SUCCESS)
 Main PID: 1853 (code=exited, status=0/SUCCESS)
# 3.檢視容器是否依然執行
[root@localhost ~]# docker ps 
CONTAINER ID   IMAGE              COMMAND                  CREATED       STATUS              PORTS     NAMES
1dd65fa55b80   top                "/bin/sh -c 'exec to…"   5 weeks ago   Up About a minute             test_exec_entry
52a7de98ccc7   test_shell_entry   "/bin/sh -c 'top -b'"    5 weeks ago   Up 2 minutes                  test

# 案例2:apache容器測試實時恢復
# 1.修改守護程序配置檔案,啟動實時恢復
[root@localhost ~]# vi /etc/docker/daemon.json 
{
  "registry-mirrors": ["https://nxwgbmaq.mirror.aliyuncs.com"],
  "live-restore":true
}
# 2.重啟守護程序
[root@localhost ~]# systemctl restart docker
# 3.執行一個apache容器
[root@localhost ~]# docker pull httpd
[root@localhost ~]# docker run --rm -d -p 8080:80 httpd
27c266f2fbc9bb5dd67e442a99b82db440d135506b9d912d624331baae675ca9
# 4.重新載入Docker守護程序
[root@localhost ~]# systemctl reload docker
# 5.檢視當前容器
[root@localhost ~]# docker ps
CONTAINER ID   IMAGE     COMMAND              CREATED              STATUS              PORTS                                   NAMES
27c266f2fbc9   httpd     "httpd-foreground"   About a minute ago   Up About a minute   0.0.0.0:8080->80/tcp, :::8080->80/tcp   inspiring_robinson    《————容器依然執行
# 6.kill結束程序
[root@localhost ~]# ps -e | grep dockerd     
  5052 ?        00:00:01 dockerd              《————檢視獲取程序號
[root@localhost ~]# kill -SIGHUP 5052         《————向程序傳送sighup訊號
[root@localhost ~]# docker ps                  
CONTAINER ID   IMAGE     COMMAND              CREATED         STATUS         PORTS                                   NAMES
27c266f2fbc9   httpd     "httpd-foreground"   2 minutes ago   Up 2 minutes   0.0.0.0:8080->80/tcp, :::8080->80/tcp   inspiring_robinson      《————容器依然執行
# 7.訪問apache驗證服務是否正常
[root@localhost ~]# curl 127.0.0.1:8080
<html><body><h1>It works!</h1></body></html>

另一種恢復方式:在手動啟動dockerd程序時指定--live-restore選項。
不建議使用這種方式,因為不會設定systemd或其他程序管理器的環境,會導致意外發生。

(2)升級期間的實時恢復

實時恢復功能支援Docker守護程序在升級期間保持容器的執行。

存在的問題:

  1. 只支援Docker 補丁版本升級,不支援主要版本和次要版本的升級。
  2. 升級過程中跳過版本,守護程序可能無法恢復其與容器的連線。

(3)重啟時的實時恢復

限定條件:只有Docker守護程序選項未發生變化,實時恢復才能恢復容器。

(4)實時恢復功能對執行容器的影響

守護程序停止,正在執行的容器可能會填滿守護程序通常讀取的FIFO日誌,阻止容器記錄更多日誌資料。

緩衝區填滿,必須重新啟動Docker守護程序來重新整理。
可以更改/proc/sys/fs/pipe-max=size來修改核心的緩衝區大小。

[root@localhost ~]# cat /proc/sys/fs/pipe-max-size 
1048576

3、一個容器中執行多個服務

注意:一個容器可以有多個程序,但為了高效利用Docker,不要讓一個容器負責整個應用程式的多個方面,而要通過使用者定義網路和共享卷連線多個容器來實現應用程式的多個方面。

容器的主程序負責管理它啟動的所有程序。

解決子程序回收:--init選項可以將一個精簡的初始化程序作為主程序插入容器,並在容器退出時回收所有的程序。

解決多程序啟停最好方式:設定一個上層的程序統一處理這些程序的生命週期(sysinit\upstart\systemd)

在一個容器執行多個服務的方式:

  1. 將所有命令放入包裝器指令碼中,並提供測試和除錯資訊,使用CMD指令執行包裝器指令碼。
  2. 如果有一個主程序需要首先啟動並保持執行,但是臨時需要執行一些其他程序(可能與主程序互動),可以使用bash指令碼的作業控制實現。
  3. 在容器中使用supervisord等程序管理器。

Supervisor 是 Linux/UNIX系統下的一個程序管理工具,守護程序名為supervisord,可以方便地監聽、啟動、停止、重啟一個或多個程序。
該工具管理程序時,如遇到程序被意外殺死,守護程序監聽到後,會自動重啟。

# 案例:將supervisord和配置和要管理的應用程式(nginx和tomcat)打包到一個映象中,一個容器執行多個服務
# 1.建立dockerfile目錄
[root@hecs-localhost-01 ~]# mkdir web-supervisord
[root@hecs-localhost-01 web-supervisord]# cd web-supervisord/

# 2.編寫Dockerfile
[root@hecs-localhost-01 web-supervisord]#  vi Dockerfile            《————dockerfile目錄
FROM centos:7
MAINTAINER [email protected]
COPY CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo
COPY nginx_install.sh /tmp/nginx_install.sh
RUN sh /tmp/nginx_install.sh; \rm -rf /usr/local/src/*
RUN sed -i -e '/worker_processes/a daemon off;' /usr/local/nginx/conf/nginx.conf;
COPY jdk-8u162-linux-x64.tar.gz /usr/local/src/jdk-8u162-linux-x64.tar.gz
COPY tomcat_install.sh /tmp/tomcat_install.sh
RUN sh /tmp/tomcat_install.sh; \rm -rf /usr/local/src/*
COPY supervisor_install.sh /tmp/supervisor_install.sh
COPY supervisord.conf /etc/supervisord.conf
COPY start_tomcat.sh /usr/local/tomcat/bin/mystart.sh
RUN sh /tmp/supervisor_install.sh; \rm -rf /tmp/*.sh

# 3.預設源下載慢且總有問題,更換為163的yum源
[root@hecs-localhost-01 web-supervisord]# vi CentOS-Base.repo 
[base]
name=CentOS-$releasever - Base
baseurl=http://mirrors.163.com/centos/$releasever/os/$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7

#released updates
[updates]
name=CentOS-$releasever - Updates
baseurl=http://mirrors.163.com/centos/$releasever/updates/$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7

#additional packages that may be useful
[extras]
name=CentOS-$releasever - Extras
baseurl=http://mirrors.163.com/centos/$releasever/extras/$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
 
#additional packages that extend functionality of existing packages
[centosplus]
name=CentOS-$releasever - Plus
baseurl=http://mirrors.163.com/centos/$releasever/centosplus/$basearch/
gpgcheck=1
enabled=0
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7 


# 4.準備nginx安裝指令碼
[root@hecs-localhost-01 web-supervisord]# vi nginx_install.sh
yum install -y wget tar gcc gcc-c++ make pcre pcre-devel zlib zlib-devel openssl openssl-devel
cd /usr/local/src
wget 'http://nginx.org/download/nginx-1.12.2.tar.gz'
tar -zxvf nginx-1.12.2.tar.gz
cd nginx-1.12.2
./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-stream --with-stream_ssl_module
make
make install
exit 0

# 5.準備tomcat安裝指令碼
[root@hecs-localhost-01 web-supervisord]# vi tomcat_install.sh
yum install -y wget tar
cd /usr/local/src/
tar -zxvf jdk-8u162-linux-x64.tar.gz
mv jdk1.8.0_162 /usr/local/
#/usr/local/jdk1.8.0_162/bin/java -version
#配置java環境變數
echo 'JAVA_HOME=/usr/local/jdk1.8.0_162/' >>/etc/profile
echo 'PATH=$PATH:$JAVA_HOME/bin' >>/etc/profile
echo 'CLASSPATH=.:$JAVA_HOME/lib/tools.jar:$JAVA_HOME/lib/dt.jar:$CLASSPATH' >>/etc/profile
source /etc/profile
wget https://mirrors.tuna.tsinghua.edu.cn/apache/tomcat/tomcat-8/v8.5.38/bin/apache-tomcat-8.5.38.tar.gz
tar -zxvf apache-tomcat-8.5.38.tar.gz
mv apache-tomcat-8.5.38 /usr/local/tomcat


# 6.下載jdk
# 官網下載地址:https://www.oracle.com/java/technologies/javase/javase8-archive-downloads.html 需要註冊才能下載
[root@hecs-localhost-01 web-supervisord]# ls


# 7.準備supervisor安裝指令碼
[root@hecs-localhost-01 web-supervisord]# vi supervisor_install.sh 
yum -y install epel-release
yum -y install python2-pip
pip install supervisor


# 8.準備supervisor配置檔案
[root@hecs-localhost-01 web-supervisord]# vi supervisord.conf 
[unix_http_server]
file=/tmp/supervisor.sock ; the path to the socket file

[supervisord]
logfile=/tmp/supervisord.log ; # 日誌
logfile_maxbytes=50MB ; # 最大50M日誌
logfile_backups=10 ; # 輪循日誌備份10個
loglevel=info ; # 日誌等級記錄info的
pidfile=/tmp/supervisord.pid ;pid
nodaemon=true ; # 在前臺啟動
minfds=102400 ; # 檔案描述符限制
minprocs=2000 ; # 程序數
 
[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface

[supervisorctl]
serverurl=unix:///tmp/supervisor.sock ; use a unix:// URL for a unix socket

[program:nginx]
command=/usr/local/nginx/sbin/nginx ; # 前臺啟動nginx
autostart=true ; # 隨著supervisor自動啟動
startsecs=10 ; # 啟動10s後算正常啟動
autorestart=true ; # 程式退出後自動重啟
startretries=3 ; # 啟動失敗自動重試次數
stdout_logfile_maxbytes=20MB ;stdout # 日誌檔案大小最大20Mb
stdout_logfile=/usr/local/nginx/logs/out.log

[program:tomcat]
command=sh /usr/local/tomcat/bin/mystart.sh ; # 前臺啟動tomcat
autostart=true ; # 隨著supervisor自動啟動
startsecs=10 ; # 啟動10s後算正常啟動
autorestart=true ; #程式退出後自動重啟
startretries=3 ; # 啟動失敗自動重試次數
stdout_logfile_maxbytes=20MB ;stdout 日誌檔案大小最大20Mb
stdout_logfile=/usr/local/tomcat/logs/catalina.out

# 9.tomcat啟動指令碼準備
# 由於supervisor無法使用source,需要編寫個指令碼來啟動
[root@hecs-localhost-01 web-supervisord]# vi start_tomcat.sh
source /etc/profile
/usr/local/tomcat/bin/catalina.sh run


# 10.構建映象
[root@hecs-localhost-01 web-supervisord]# docker build -t web-supervisor .
[root@localhost web-supervisord]# docker images
REPOSITORY         TAG       IMAGE ID       CREATED         SIZE
web-supervisor     latest    5198c5737571   7 minutes ago   1.44GB

# 11.啟動容器測試
[root@localhost web-supervisord]# docker run -d web-supervisor /bin/bash -c 'supervisord -c /etc/supervisord.conf'
a326e2589794c4b2a19c23d177f2c418d0583c87605342fd7445694dc40e2219



# 6.基於映象啟動容器和測試web服務
docker exec -it 76782ab /bin/bash
ifconfig

curl 127.0.0.1
curl 127.0.0.1:8080

4、容器健康檢查機制

程序級的健康檢查:最簡單的,檢驗程序是否執行。重啟策略可以根據檢查情況重啟已停止的容器。這個檢查不足:無法發現應用程式問題。

Docker提供了健康檢查機制,可以通過Dockerfile檔案在映象中注入,也可以在啟動容器時通過相應選項實現。

(1)在Dockerfile中使用HEALTHCHECK指令

可以在Dockerfile中使用HEALTHCHECK指令宣告健康檢測配置,用於判斷容器主程序的服務狀態是否正常,反映容器的實際健康狀態。

Dockerfile構建映象時,加入了HEALTHCHECK指令,基於這樣映象啟動的容器,就具備了健康狀態檢查能力,能自動進行健康檢查。

Dockerfile中,只能出現一次HEALTHCHECK指令,出現多次,僅最後一次生效。

一旦有一次健康檢查成功,Docker就會確認容器為健康狀態。

HEALTHCHECK指令格式:

  1. 設定檢查容器健康狀況的命令
HEALTHCHECK [選項] CMD <命令> 

# 選項:
    --interval:設定容器執行後開始健康檢查的時間間隔,預設30s。
    --timeout:設定允許健康檢查命令允許的最長時間,預設30s。超時即失敗。
    --start-period:設定容器啟動的初始化時間。(啟動過程中的健康檢查失敗不報錯)
    --retries:設定允許連續重試的次數,預設3次。(連續檢查失敗後視為不健康)

# CMD指令後的命令:指定執行健康檢查的具體命令。可以使用shell格式或exec格式。

# 返回值:CMD指令後面的“命令” 執行完畢返回值表示容器的執行狀況。
    0:成功。容器是健康且可用的。
    1:失敗。容器不健康,不能正常工作。
    2:保留值。暫時不要使用。

# 案例:每5分鐘健康檢查一次,訪問web伺服器主頁,每次檢查3秒以內
HEALTHCHECK --interval=5m --timeout=3s CMD curl -f http://localhost/ || exit 1       # || 表示上一條命令執行失敗後,才執行下一條命令,退出返回值為1,告訴docker健康檢查失敗
  1. 表示禁止從基礎映象繼承HEALTHCHECK指令設定
HEALTHCHECK NONE 

(2)啟動容器時通過相應選項實現健康檢查

可以在執行 docker rundocker create 命令啟動建立容器時指定容器的健康檢查策略。

[root@localhost ~]# docker run --help
      --health-cmd string              Command to run to check health                                      # 指定和執行健康檢查
      --health-interval duration       Time between running the check (ms|s|m|h) (default 0s)              # 設定容器執行後開始健康檢查的時間間隔(單位:ms/s/m/h),預設是0s
      --health-retries int             Consecutive failures needed to report unhealthy                     # 設定連續失敗需要報告的次數
      --health-start-period duration   Start period for the container to initialize before starting        # 設定容器啟動的初始化時間(單位:ms/s/m/h),預設是0s
                                       health-retries countdown (ms|s|m|h) (default 0s)
      --health-timeout duration        Maximum time to allow one check to run (ms|s|m|h) (default 0s)      # 設定允許健康檢查命令允許的最長時間(單位:ms/s/m/h),預設是0s
      --no-healthcheck                 Disable any container-specified HEALTHCHECK                         # 禁用容器健康檢查指令

(3)案例:測試容器的健康檢查功能

容器啟動,開始執行健康檢查命令,並週期執行,如果返回0,容器處於健康狀態。如果返回非0值,容器不健康。

下面案例使用busybox映象來測試健康檢查功能。

# 1.下載busybox映象
[root@localhost ~]# docker pull busybox
Using default tag: latest
latest: Pulling from library/busybox
5cc84ad355aa: Pull complete 
Digest: sha256:5acba83a746c7608ed544dc1533b87c737a0b0fb730301639a0179f9344b1678
Status: Downloaded newer image for busybox:latest
docker.io/library/busybox:latest

# 2.建立容器設定健康檢查,檢查間隔20s,失敗重複1次;並立即檢視容器的健康檢查狀態
[root@localhost ~]#  docker run --rm --name test-health -d \
> --health-cmd 'stat /etc/passwd || exit 1' \
> --health-interval 20s --health-retries 1 \
> busybox sleep 1d; docker inspect  --format '{{.State.Health.Status}}' test-health
d8fa5965abc02ec8d01722f98257ba2b8f76d50af05890dc8c6e1a18573ee6a3
starting       《————容器啟動後的健康狀態為Starting

# 3.延遲20s時間,再次檢視容器的健康檢查狀態
[root@localhost ~]# sleep 20s;docker inspect  --format '{{.State.Health.Status}}' test-health
healthy        《————容器處於健康狀態

# 4.刪除容器的/etc/passwd檔案,模擬健康問題
[root@localhost ~]# docker exec test-health rm /etc/passwd

# 5.延遲20s時間,再次檢視容器的健康檢查狀態
[root@localhost ~]# sleep 20s;docker inspect  --format '{{.State.Health.Status}}' test-health
unhealthy     《————容器處於不健康狀態
# 進一步檢視容器的詳情
[root@localhost ~]# docker inspect  --format '{{json .State.Health}}' test-health
{"Status":"unhealthy","FailingStreak":6,"Log":[{"Start":"2022-05-12T04:06:13.855633253+08:00","End":"2022-05-12T04:06:13.899152317+08:00","ExitCode":1,"Output":"stat: can't stat '/etc/passwd': No such file or directory\n"},{"Start":"2022-05-12T04:06:33.910019299+08:00","End":"2022-05-12T04:06:33.953470925+08:00","ExitCode":1,"Output":"stat: can't stat '/etc/passwd': No such file or directory\n"},{"Start":"2022-05-12T04:06:53.956520997+08:00","End":"2022-05-12T04:06:53.998897439+08:00","ExitCode":1,"Output":"stat: can't stat '/etc/passwd': No such file or directory\n"},{"Start":"2022-05-12T04:07:14.002929368+08:00","End":"2022-05-12T04:07:14.045233889+08:00","ExitCode":1,"Output":"stat: can't stat '/etc/passwd': No such file or directory\n"},{"Start":"2022-05-12T04:07:34.050748795+08:00","End":"2022-05-12T04:07:34.090015044+08:00","ExitCode":1,"Output":"stat: can't stat '/etc/passwd': No such file or directory\n"}]}
# 上述資訊中報錯:stat: can't stat '/etc/passwd': No such file or directory\n,符合前面模擬的健康問題

# 6.檢視容器的當前狀態
[root@localhost ~]# docker ps
CONTAINER ID   IMAGE     COMMAND      CREATED         STATUS                     PORTS     NAMES
d8fa5965abc0   busybox   "sleep 1d"   5 minutes ago   Up 5 minutes (unhealthy)             test-health

5、執行時選項覆蓋Dockerfile指令

Dockerfile中的FROMMAINTAINERRUNADD這四個指令在執行時是不能被覆蓋的,其他的指令在執行docker run(或docker create)命令時都會被相應地覆蓋。

從映象執行一個容器時,可以指定一個新的命令來覆蓋Dockerfile的CMD指令。

如果映象的Dockerfile還聲明瞭ENTRYPOINT指令,則Dockerfile的CMD指令或容器執行時指定的命令均作為引數追加到ENTRYPOINT指令中。

(1)覆蓋CMD指令

從映象執行一個容器的時候,可以指定一個新命令來覆蓋Dockerfile中的CMD指令。

[root@localhost ~]# docker history ubuntu
IMAGE          CREATED       CREATED BY                                      SIZE      COMMENT
ff0fea8310f3   7 weeks ago   /bin/sh -c #(nop)  CMD ["bash"]                 0B           《——————預設命令
<missing>      7 weeks ago   /bin/sh -c #(nop) ADD file:1d3b09cf9e041d608…   72.8MB  

# 語法
[root@localhost ~]# docker run --help
Usage:  docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

# 不覆蓋的案例:使用CMD的預設命令
[root@localhost ~]# docker run -tid ubuntu 
d6adcb9ca10de89dcb1a1f8ab49b33a715b502e4aa4f1ec240774a7f4d2aa9f5

# 覆蓋案例
[root@localhost ~]# docker run -tid ubuntu top            《————top替換預設的bash
0485fee218e64e858ca5b2214b9349b523a3bd41d1ad86c08877240635fa0d32

如果映象的Dockerfile還聲明瞭ENTRYPOINT指令,則Dockerfile的CMD指令或容器執行時指定的命令均作為引數追加到ENTRYPOINT指令中。

(2)覆蓋ENTRYPOINT指令

使用 --entrypoint選項可以覆蓋定義映象的 Dockerfile 中的 ENTRYPOINT 指令設定。

映象的 ENTRYPOINT 指令定義容器啟動時要執行的命令,在啟動容器時不容易被覆蓋。

注意:執行時使用--entrypoint 選項將清除映象胡任何預設命令。

# 語法
[root@localhost ~]# docker run --help
      --entrypoint string              Overwrite the default ENTRYPOINT of the image

# 案例
[root@localhost ~]# docker pull redis
[root@localhost ~]# docker history redis
IMAGE          CREATED        CREATED BY                                      SIZE      COMMENT
7614ae9453d1   4 months ago   /bin/sh -c #(nop)  CMD ["redis-server"]         0B        
<missing>      4 months ago   /bin/sh -c #(nop)  EXPOSE 6379                  0B        
<missing>      4 months ago   /bin/sh -c #(nop)  ENTRYPOINT ["docker-entry…   0B        
<missing>      4 months ago   /bin/sh -c #(nop) COPY file:df205a0ef6e6df89…   374B      
<missing>      4 months ago   /bin/sh -c #(nop) WORKDIR /data                 0B        
<missing>      4 months ago   /bin/sh -c #(nop)  VOLUME [/data]               0B        
<missing>      4 months ago   /bin/sh -c mkdir /data && chown redis:redis …   0B        
...省略

# 預設自動執行redis-server的容器中,再執行一個shell
[root@localhost ~]# docker run -ti --entrypoint /bin/bash redis
root@484cb9c42858:/usr/local/bin# ls
docker-entrypoint.sh  redis-benchmark  redis-check-rdb	redis-sentinel
gosu		      redis-check-aof  redis-cli	redis-server
root@bd7640ba7206:/data# exit
exit

# 傳遞更多引數給ENTRYPOINT
# 預設傳遞--help給redis-server
[root@localhost ~]# docker run -ti  redis --help
Usage: ./redis-server [/path/to/redis.conf] [options] [-]
       ./redis-server - (read config from stdin)
       ./redis-server -v or --version
       ./redis-server -h or --help
...省略
# 傳遞--help給redis-cli
[root@localhost ~]# docker run -ti --entrypoint redis-cli redis --help
redis-cli 6.2.6
Usage: redis-cli [OPTIONS] [cmd [arg [arg ...]]]
  -h <hostname>      Server hostname (default: 127.0.0.1).
  -p <port>          Server port (default: 6379).
  -s <socket>        Server socket (overrides hostname and port).
...省略

# 傳遞空字串重置容器的入口命令
[root@localhost ~]# docker run -ti --entrypoint="" redis bash
root@5cb647f12d63:/data# exit
exit

(3)覆蓋EXPOSE傳入埠指令

EXPOSE指令定義對外提供服務的初始傳入埠,這些埠可用於容器中的程序。

[root@localhost ~]# docker run --help
      --expose list                    Expose a port or a          # 對外暴露容器的一個埠或一個埠範圍
                                       range of ports
      --link list                      Add link to another         # 新增到其他容器的連線
                                       container
  -p, --publish list                   Publish a container s       # 將容器的一個埠或埠範圍釋出到主機
                                       port(s) to the host
  -P, --publish-all                    Publish all exposed         # 將所有的埠釋出到主機隨機埠
                                       ports to random ports

(4)覆蓋ENV指令

linux中的容器,Docker自動設定瞭如下環境變數(預設值):

  • HOME(使用者主目錄):根據USER值設定
  • HOSTNAME(主機名):預設為容器名
  • PATH(執行檔案的預設路徑):常用目錄
  • TERM(終端):若容器分配了偽TTY,則為xterm。

可以使用若干 -e 選項設定任何環境變數,並可以覆蓋上述預設環境變數或Dockerfile中ENV指令定義的環境變數。

# 語法
[root@localhost ~]# docker run --help
  -e, --env list                       Set environment variables             # 設定環境變數
      --env-file list                  Read in a file of                     # 讀取檔案中環境變數
                                       environment variables

# 案例
[root@localhost ~]# export today=Sunday
[root@localhost ~]# echo $today
Sunday
[root@localhost ~]# docker run -t -e "deep=purple" \
> -e today \
> --rm alpine env
# 輸出如下資訊
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=40951973766d
TERM=xterm
deep=purple
today=Sunday
HOME=/root

(5)HEALTHCHECK和WORDDIR指令

覆蓋HEALTHCHECK的相關選項:

[root@localhost ~]# docker run --help
      --health-cmd string              Command to run to check health                                      # 指定和執行健康檢查
      --health-interval duration       Time between running the check (ms|s|m|h) (default 0s)              # 設定容器執行後,健康檢查的時間間隔(單位:ms/s/m/h),預設是0s
      --health-retries int             Consecutive failures needed to report unhealthy                     # 設定連續失敗需要報告的次數
      --health-start-period duration   Start period for the container to initialize before starting        # 設定容器啟動的初始化時間(單位:ms/s/m/h),預設是0s
                                       health-retries countdown (ms|s|m|h) (default 0s)
      --health-timeout duration        Maximum time to allow one check to run (ms|s|m|h) (default 0s)      # 設定允許健康檢查命令允許的最長時間(單位:ms/s/m/h),預設是0s
      --no-healthcheck                 Disable any container-specified HEALTHCHECK                         # 禁用容器健康檢查指令

容器中執行二進位制檔案的預設工作目錄是根目錄(/),Dockerfile中可以使用WORDDIR指令自定義工作目錄。還可以使用 -w選項覆蓋WORKDIR指令設定。

[root@localhost ~]# docker run --help
  -w, --workdir string                 Working directory              # 修改容器的工作目錄
                                       inside the container

(6)USER

容器預設使用者是root(UID=0),Dockerfile的USER指令可以指定容器執行第一個程序時的預設使用者。

啟動容器的時候,可以使用 -u(--user)選項指定新的預設使用者覆蓋映象的USER指令。

# 語法
[root@localhost ~]# docker run --help
  -u, --user string                    Username or UID            # 指定容器執行第一個程序的預設使用者,可以使用使用者名稱、UID、組名、GID引數
                                       (format:
                                       <name|uid>[:<group|gid>])

# 案例
[root@localhost home]# docker run  -t -u daemon ubuntu env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=88f322b48026
TERM=xterm
HOME=/usr/sbin

[root@localhost ~]# docker run -ti -u ftp  alpine env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=a5f4455a2407
TERM=xterm
HOME=/var/lib/ftp

(7)VOLUME指令

Dockerfile中可以使用 VOLUME 指令定義一個或多個與映象關聯的卷。

容器啟動時可以使用 -v--mount--volume-from選項來指定掛載卷。詳見:Docker儲存管理

回到頂部

二、限制容器資源使用

1、容器記憶體資源限制

容器可使用的內容包括:實體記憶體、交換空間(SWAP)。

Docker 預設沒有設定記憶體限制的,容器程序可以根據需要儘可能多地使用記憶體和交換空間。

硬限制:僅允許容器使用不超過給定值的使用者記憶體或系統記憶體。

軟限制:允許容器按需使用記憶體,但不能影響到記憶體使用或與佔用主機記憶體。

(1)使用者記憶體限制

同時設定記憶體和交換空間時,交換空間限制必須大於實體記憶體限制。

[root@localhost ~]# docker run --help
  -m, --memory bytes                   Memory limit                 # 容器可用記憶體限制,最低是4MB
      --memory-swap bytes              Swap limit equal to memory plus swap: '-1' to enable     # 容器可以使用的交換空間,-1為無限
                                       unlimited swap

# 案例1:對容器記憶體使用不限制
[root@localhost ~]# docker run -ti ubuntu /bin/bash

# 案例2:設定記憶體限制並取消交換空間的限制
[root@localhost ~]# docker run -ti -m 300M --memory-swap -1  ubuntu /bin/bash

# 案例3:只設置記憶體限制
[root@localhost ~]# docker run -ti -m 300M  ubuntu /bin/bash
[root@localhost ~]# docker inspect --format='{{.HostConfig.Memory}}' a84ca902dbab
314572800      《————314572800/1024/1024=300


# 案例4:同時設定記憶體和交換空間
[root@localhost ~]# docker run -ti -m 300M --memory-swap 1G  ubuntu /bin/bash

(2)核心記憶體限制

核心記憶體不能使用交換空間,消耗過多的核心記憶體會導致系統服務被阻塞。

核心記憶體不獨立於使用者記憶體,一般在使用者記憶體限制的基礎上限制核心記憶體。

限制核心記憶體的效果:當核心記憶體太多時,系統會阻止新程序建立。

[root@localhost ~]# docker run --help
      --kernel-memory bytes            Kernel memory limit         # 容器核心記憶體限制

# 案例1:同時設定使用者記憶體和核心記憶體
[root@localhost ~]# docker run -ti -m 200M --kernel-memory 50M ubuntu /bin/bash

# 案例2:只設置核心記憶體,記憶體不限制
[root@localhost ~]# docker run -ti --kernel-memory 50M ubuntu /bin/bash

(3)設定記憶體預留實現軟限制

作為一個軟限制功能,記憶體預留並不能保證不會超過限制。主要目的是確保當記憶體爭用嚴重時,記憶體就按預留設定進行分配。

記憶體軟限制設定效能:確保容器不會長時間消耗過多記憶體,每次記憶體回收將容器記憶體消耗縮減到軟限制之下。

軟限制設定規則:

  1. 記憶體預留值應當始終低於硬限制,否則硬限制會優先觸發。
  2. 將記憶體預留值設定為0表示不作限制。
[root@localhost ~]# docker run --help
      --memory-reservation bytes       Memory soft limit    # 設定記憶體預留。0表示無限制

# 示例1:限制記憶體為500MB,記憶體預留值(軟限制)為200MB
[root@localhost ~]# docker run -ti -m 500M --memory-reservation 200M ubuntu /bin/bash

# 示例2:設定記憶體軟限制為1GB,沒有設定記憶體硬限制
[root@localhost ~]# docker run -ti --memory-reservation 1G ubuntu /bin/bash

2、容器所用CPU資源限制

預設設定是所有容器都可以平等地使用主機CPU資源而不受限制。

(1)CPU份額限制

預設情況,所有容器得到相同比例的CPU週期。

通過設定CPU份額權重,分配容器可以使用的CPU週期。

[root@localhost ~]# docker run --help
  -c, --cpu-shares int                 CPU shares (relative weight)   # 設定CPU份額權重,預設值1024

# 案例
[root@localhost ~]# docker run -tid -c 1024 ubuntu /bin/bash
17ea3842fe624a9719817255dba50ba809f3f30c0ffbd1b50e1fd42172e032f0

[root@localhost ~]# docker run -tid -c 512 ubuntu /bin/bash
5c51e13530879ab7ed56bc42c1f71de0b6a2bff9cadbac6fb1364fa4c11c529a

(2)CPU週期限制

預設的CFS(完全公平排程器)週期為100ms(100000us)。

設定CPU週期限制容器CPU資源使用。

[root@localhost ~]# docker run --help
      --cpu-period int                 Limit CPU CFS (Completely Fair Scheduler) period    # 限制容器CPU CFS週期
      --cpu-quota int                  Limit CPU CFS (Completely Fair Scheduler) quota     # 限制容器CPU CFS配額
	  --cpus decimal                   Number of CPUs         # 指定容器可用CPU資源,浮點數,預設0.000(不受限)
	  
# 案例:
[root@localhost ~]# docker run -ti --cpu-period=50000 --cpu-quota=25000 ubuntu /bin/bash

# 案例2:
[root@localhost web-supervisord]# docker run -ti --cpus=0.5 ubuntu /bin/bash

(3)CPU放置限制

限制容器程序執行在什麼CPU上。

[root@localhost web-supervisord]# docker run --help
      --cpuset-cpus string             CPUs in which to allow execution (0-3, 0,1)
	  
# 案例:
# 容器的程序允許執行在cpu1\cpu2\cpu3
[root@localhost ~]# docker run -ti --cpuset-cpus='1-3' ubuntu /bin/bash
# 容器的程序允許執行在cpu0
[root@localhost ~]# docker run -ti --cpuset-cpus='0' ubuntu /bin/bash
# 容器的程序允許執行在cpu0\cpu4
[root@localhost ~]# docker run -ti --cpuset-cpus='0,4' ubuntu /bin/bash

(4)CPU配額限制

--cpu-quota限制容器程序的CPU配額。

預設值0 表示容器佔用一個CPU 100%的CPU資源。

設為 50000 表示容器至多使用CPU50%的資源。

3、容器所用塊I/O頻寬的限制

塊I/O頻寬(Block I/O Bandwith,Blkio):磁碟讀寫頻寬。

Docker 可設定權重,限制容器讀寫磁碟的頻寬。

(1)設定塊I/O權重

使用--blkio-weight選項設定一個容器相對於所有其他正在執行的容器的塊I/O頻寬權重。

可設定的塊I/O頻寬權重範圍是10-1000。

預設所有的容器的權重值為500。0表示被禁用。

[root@localhost ~]# docker run --help
      --blkio-weight uint16            Block IO (relative       
                                       weight), between 10
                                       and 1000, or 0 to
                                       disable (default 0)

案例:
[root@localhost ~]# docker run -tid --blkio-weight 300 ubuntu /bin/bash

[root@localhost ~]# docker run -tid --blkio-weight 0 ubuntu /bin/bash

(2)限制裝置讀寫效率

Docker 按照兩種指標限制容器的裝置讀寫速率:每秒位元組數、每秒I/O次數。

1)每秒位元組數
使用--device-read-bps選項限制指定裝置的讀取速率,即每秒讀取的位元組數。
使用--device-write-bps選項限制指定裝置的寫入速率

單位可以是kb,mb或gb中的一個。

[root@localhost ~]# docker run --help
      --device-read-bps list           Limit read rate (bytes
                                       per second) from a
                                       device (default [])
      --device-write-bps list          Limit write rate
                                       (bytes per second) to
                                       a device (default [])
# 案例:限制/dev/sda的讀取速率為1kb/s
[root@localhost ~]# docker run -ti --device-read-bps /dev/sda:1kb ubuntu   # /dev/sda1和/dev/sda2會報錯,只能控制磁碟IO不能控制分割槽IO
root@d2003fdad6bc:/# 

2)每秒I/O次數
限制指定裝置的讀取和寫入速率,用每秒I/O次數表示。

[root@localhost ~]# docker run --help
      --device-read-iops list          Limit read rate (IO
                                       per second) from a
                                       device (default [])
      --device-write-iops list         Limit write rate (IO
                                       per second) to a
                                       device (default [])

# 案例:限制/dev/sda裝置的讀取速率為每秒1000次
[root@localhost ~]# docker run -ti --device-read-iops /dev/sda:1000 ubuntu
root@8900e9904535:/# 

4、資源限制的實現機制

對容器使用的記憶體、CPU和塊I/O頻寬資源的限制具體是由控制組的相應子系統來實現的。

  1. memory子系統設定控制組中的任務所使用的記憶體限制。
  2. cpu子系統通過排程程式提供對CPU的控制組任務的訪問。
  3. blkio子系統為塊裝置(如磁碟、固態硬碟、USB等)設定輸入和輸出限制。

注意:在docker run命令中使用--cpu-shares、--memory、--device-read-bps等選項實際上就是在配置控制組,相關的配置檔案儲存在/sys/fs/cgroup目錄中。

# 1.建立容器記憶體限額300M,CPU權重512
[root@localhost docker]# docker run -tid -p 8080:80 -m 300M --cpu-shares=512 httpd
3cdbdafe0398d40daa8bf334413dc748a3a707cfac96c8ff0ee22a87e5d85e60

# 2.檢視/sys/fs/cgroup目錄中容器CPU的配置資訊
[root@localhost ~]# cd /sys/fs/cgroup/cpu/docker
# 裡面有容器ID命名的目錄,包含容器CPU相關配置
[root@localhost 3cdbdafe0398d40daa8bf334413dc748a3a707cfac96c8ff0ee22a87e5d85e60]# cat cpu.shares 
512

# 3.檢視容器記憶體限制資訊
[root@localhost ~]# cd /sys/fs/cgroup/memory/docker/3cdbdafe0398d40daa8bf334413dc748a3a707cfac96c8ff0ee22a87e5d85e60/
[root@localhost 3cdbdafe0398d40daa8bf334413dc748a3a707cfac96c8ff0ee22a87e5d85e60]# cat memory.limit_in_bytes 
314572800      《——————換算為300M

5、動態更改容器的資源限制

docker update 命令可以動態地更新容器配置,防止容器在主機上使用太多的資源。

除了kernel-memory選項,其他選項都是立即生效。

kernel-memory選項只能應用於停止的容器,在下一次重啟時生效。

[root@localhost ~]# docker update --help
Usage:  docker update [OPTIONS] CONTAINER [CONTAINER...]
Update configuration of one or more containers
Options:
      --blkio-weight uint16        Block IO (relative weight), between 10 and 1000, or 0 to disable (default 0)
      --cpu-period int             Limit CPU CFS (Completely Fair Scheduler) period
      --cpu-quota int              Limit CPU CFS (Completely Fair Scheduler) quota
      --cpu-rt-period int          Limit the CPU real-time period in microseconds
      --cpu-rt-runtime int         Limit the CPU real-time runtime in microseconds
  -c, --cpu-shares int             CPU shares (relative weight)
      --cpus decimal               Number of CPUs
      --cpuset-cpus string         CPUs in which to allow execution (0-3, 0,1)
      --cpuset-mems string         MEMs in which to allow execution (0-3, 0,1)
      --kernel-memory bytes        Kernel memory limit
  -m, --memory bytes               Memory limit
      --memory-reservation bytes   Memory soft limit
      --memory-swap bytes          Swap limit equal to memory plus swap: '-1' to enable unlimited swap
      --pids-limit int             Tune container pids limit (set -1 for unlimited)
      --restart string             Restart policy to apply when a container exits


# 案例:
[root@localhost docker]# docker run -tid -p 8080:80 -m 300M --cpu-shares=512 httpd

[root@localhost ~]# docker update -m 500M --cpu-shares=400 --memory-swap 600M 3cdbdafe0398
3cdbdafe0398