一、容器的自动重启

  • Docker提供重启策略选项控制容器退出时或Docker重启时是否自动启动该容器。
  • 重启策略能够确保关联的多个容器按照正确的顺序启动
  • Docker建议使用重启策略,并避免使用进程管理器启动容器。运行容器时可以使用--restart选项指定重启策略。
  • 容器的重启都是由Docker守护进程完成的因此与守护进程息息相关。

注意点

  • 重启策略只在容器成功启动后才会生效。(至少运行 10s 以上且 Docker守护进程已开始监控它,可以防止=从未启动的容器进入重启循环)
  • 如果手动停止一个容器,那么它的重启策略会被忽略,直到Docker 守护进程重启或容器手动重启。(防止重启循环)
  • 这所讲的重启策略只适用于容器。Docker Swarm服务的重启策略采用不同的配置方式
  • 重启策略不同于dockerd命令的--live-restore 选项(--live-restore选项使得在Docker升级过程中,即使网络和用户输入都中断了,容器仍然可以保持运行)

如果重启策略无法满足需求,如当 Docker 外部的进程依赖容器时,那么可以改用像upstart、systemd或supervisor这样的进程管理器来解决。要注意,不要尝试组合使用Docker重启策略与主机级进程管理器,因为这会产生冲突。

二、在Docker停止时保持容器继续运行

当 Docker 守护进程终止时,正在运行的容器会关闭(默认)。管理员配置 Docker 守护进程,使容器在Docker守护进程不可用时仍然保持运行,这个功能被称为实时恢复(Live Restore )

使用此功能有助于减少因Docker守护进程崩溃、计划停机或升级导致的容器停机时间。(运行Windows操作系统的容器不支持此功能)但对于Docker for Windows运行的Linux容器,该功能则是可用的。

实时恢复功能仅适用于独立容器,不适用于Swarm服务。Swarm服务由Swarm管理器管理。如果Swarm 管理器不可用,则Swarm服务将继续在工作节点上运行,但无法管理,直到有足够多的可用Swarm管理器,即能够保持法定的数量为止。

2.1、启用实时恢复功能

方法一、在Docker守护进程配置文件(在Linux系统上默认是/etc/docker/daemon.json)中进行设置,加入以下选项。

 {  

        "live-restore":true  

}

重启Docker守护进程。

systemctl reload docker
 或者
 kill -SIGHUP dockerd

方法二、在手动启动dockerd 进程时指定--live-restore选项。(不建议)

2.2、升级期间的实时恢复

实时恢复功能支持Docker守护进程在升级期间保持容器的运行(仅限补丁版本升级,不支持主要或次要版本升级)。

2.3、重启时的实时恢复

只有 Docker 守护进程选项(如网桥IP地址和图形驱动程序)未发生更改时,实时恢复功能才可以用于恢复容器。

如果这些守护进程的配置选项中有任意一个已更改,则实时恢复可能不起作用,管理员可能需要手动停止容器。

2.4、实时恢复功能对运行容器的影响

若Docker守护进程长时间停止,则运行中的容器可能会填满FIFO日志(守护程序所读取的)并阻止记录更多日志。(必须重启Docker刷新)

管理员可以通过更改/proc/sys/fs/pipe-max-size来修改内核的缓冲区大小。注意,不能修改 Docker Desktop for Mac 或 Docker Desktop for Windows 的缓冲区大小。

三、一个容器中运行多个服务

--init 选项可以将一个精简的初始化进程作为主进程插入容器,并在容器退出时回收所有进程。

解决这些进程启停最好的方式是设置一个上层的进程来统一处理这些进程的生命周期。比较稳定的初始化进程有sysvinit、upstart、systemd。

实现一个容器中运行多个服务方法:

  • 将所有命令放入包装器脚本中,并提供测试和调试信息,使用CMD指令运行包装器脚本。
  • 如果有一个主进程需要首先启动并保持运行,但是临时需要运行一些其他进程(可能与主进程交互),可以使用bash脚本的作业控制实现。
  • 在容器中使用supervisord等进程管理器。

四、容器健康检查机制

4.1、在Dockerfile中使用HEALTHCHECK指令

在Dockerfile 文件中使用HEALTHCHECK指令声明健康检测配置,用于判断容器主进程的服务状态是否正常,反映容器的实际健康状态。

HEALTHCHECK 选项 CMD<命令>
 或
 HEALTHCHECK NONE

第1种格式表示设置检查容器健康状况的命令;第2种格式表示禁止从基础镜像继承HEALTHCHECK指令设置。

--interval:设置容器运行之后开始健康检查的时间间隔,默认为30S。--timeout:设置允许健康检查命令运行的最长时间,默认为30s。超时则失败。 --start-period:设置需要启动的容器的初始化时间,在启动过程中的健康检查失败不会被计入,默认为0s。--retries:设置允许连续重试的次数,默认为3次。当健康检查连续失败指定的次数后,则将容器状态视为不健康状态。

返回值:

  • 0:成功。容器是健康且可用的。
  • 1:失败。容器不健康,不能正常工作。
  • 2:保留值。暂时不要使用。

在Dockerfile 中HEALTHCHECK指令只可以出现一次,如果出现多次,则只有最后一次生效。

# 每5min执行一次健康检查,通过访问Web服务器主页进行检查,每次检查限制在3s以内
 HEALTHCHECK --interval=5m --timeout=3s CMD curl -f http://localhost/ || exit 1

4.2、启动容器时通过相应选项实现健康检查

可以通过执行docker run命令时启动容器,或者执行docker create命令创建容器时通过相应选项指定容器的健康检查策略,其中--health-cmd选项用于指定健康检查命令,对应于Dockerfile中HEALTHCHECK指令的命令参数;---health-interval--health-retries--health-timeout--health-start-period分别对应 --interval--retries--timeout--start-period选项。 --no-healthcheck选项用于禁用容器的任何HEALTHCHECK指令。

五、运行时选项覆盖Dockerfile 指令

5.1、CMD(默认的命令或选项)

在命令行中重新调用可选的命令

 docker run [选项] 镜像[:标签|@摘要值][命令] [参数···]

5.2、ENTRYPOINT(运行时执行的默认命令)

使用 docker run命令的--entrypoint

镜像的ENTRYPOINT指令定义容器启动时要执行的命令,在启动容器时不容易被覆盖。

ENTRYPOINT 指令为容器给出默认的行为,基于设置该指令的镜像可以直接运行容器

示例:

# 在已设置为自动运行其他命令(如/usr/bin/redis-server)的容器中再运行一个shell命令
 docker run -it --entrypoint /bin/usr/bash example/redis
# 将更多的参数传递给ENTRYPOINT指令
 docker run -it --entrypoint /bin/bash example/redis -c ls -l
 docker run -it --entrypoint /usr/bin/redis-cli example/redis --help

还可以通过传递一个空字符串重置容器的入口命令

docker run -it --entrypoint="" mysql bash

运行时使用--entrypoint选项将清除镜像的任何默认命令(Dockerfile的任何CMD指令)。

5.3、EXPOSE(传入端口)

  • --expose=[]:对外暴露容器的一个端口或一个端口范围。
  • -P:将所有端口发布到主机接口
  • -p=[]:将容器的一个端口或一个端口范围发布到主机,使用docker port命令可以查看实际的端口映射。
  • --link="":增加到其他容器的连接

除了EXPOSE指令,镜像开发人员无法控制网络连接。

5.4、ENV(环境变量)

创建Linux容器时,Docker自动设置以下环境变量:

  • HOME(用户主目录):根据USER值设置
  • HOSTNAME(主机名):默认为容器名
  • PART(执行文件的默认路径)
  • TERM(终端):如果容器被分配了伪TTY,则为xterm。

5.5、HEALTHCHECK

5.6、VOLUME(共享的文件系统)

定义一个或多个与镜像关联的卷

5.7、USER

--user=[用户名 | 用户名:组名 | UID | UID:GID | 用户名:GID | UID:组名]

5.8、WORKDIR

该指令可以自定义工作目录。

六、示例

6.1、配置容器使用重启策略

容器默认是不支持自动重启的。要为容器配置重启策略,可以在执行docker run 或docker create命令启动或创建容器时使用--restart选项。

选项值

功能

no

容器退出时不要自动重启。这是默认设置

on-failure[:max-retrues]

只在容器以非0状态码退出时重启。这种策略还可以使用max-retries参数指定 Docker守护进程尝试重启容器的次数

always

不管是什么退出状态都始终重启容器,Docker守护进程将无限次地重启容器。容器也会在Docker守护进程启动时尝试重启,不管容器当时的状态如何

unless-stopped

不管是什么退出状态都始终重启容器,只是当Docker 守护进程启动时,如果容器之前已经为停止状态,则不会尝试启动它

容器的退出状态可用状态码表示。

  • 0:表示正常退出
  • 125:Docker守护进程本身的错误。
  • 126:容器启动后,要执行的默认命令无法调用。
  • 127:容器启动后,要执行的默认命令不存在。
  • 其他:容器启动后正常执行命令,退出命令时该命令的返回状态码作为容器的退出状态码。

运行一个始终重启的contos容器,该容器退出时Docker将重启它

[root@docker ~]# docker run -d --name c1 --restart=always centos
4fb2f8dba09e9aea194f375a494a41a594efdccd640d42334b208ba131d2306b

当容器启用重启策略时,在docker ps命令的输出结果中会显示UpRestaring状态

[root@docker ~]# docker ps
CONTAINER ID   IMAGE     COMMAND       CREATED          STATUS                        PORTS     NAMES
4fb2f8dba09e   centos    "/bin/bash"   11 seconds ago   Restarting (0) 1 second ago             c1

测试该容器是否自动重启,先停止Docker并查看当前是否有容器正在运行

[root@docker ~]# systemctl stop docker
Warning: Stopping docker.service, but it can still be activated by:
  docker.socket
[root@docker ~]# docker ps
CONTAINER ID   IMAGE     COMMAND       CREATED         STATUS                                  PORTS     NAMES
97fbf80d63c0   centos    "/bin/bash"   2 minutes ago   Restarting (0) Less than a second ago             c1

此时没有任何容器正在运行。再启动Docker并查看当前是否有容器正在运行

[root@docker ~]# systemctl start docker
[root@docker ~]# docker ps
CONTAINER ID   images   ...     STATUS                          PORTS     NAMES
97fbf80d63c0   centos   ...   Restarting (0) 23 seconds ago             c1

发现该容器随着Docker启动而启动

可以使用on-failure策略指定Docker尝试重启容器的最大次数,此命令将允许一个失败后重启、最大重启次数为10的redis容器。

docker run --restart=on-failure:10 centos

对于已经创建或运行的容器,可以通过docker update命令来更改其重启策略

docker update --restart=on-failure:3 97fbf80d63c0

6.2、测试Docker的实时恢复功能

通过重新加载Docker守护进程和结束Docker守护进程来测试实时恢复功能

编辑Docker守护进程配置文件/etc/docker/daemon.json,启用实时恢复功能

[root@docker ~]# vi /etc/docker/daemon.json
[root@docker ~]# cat /etc/docker/daemon.json 
{
	"registry-mirrors":["https://unx7713y.mirror.aliyuncs.com"],
	"insecure-registries":["10.0.0.2:5000"],
	"live-restore":true
}

重启Docker守护进程

[root@docker ~]# systemctl restart docker

基于httpd镜像创建一个运行Apache服务的容器

[root@docker ~]# docker run --rm -d -p 8080:80 httpd
f920707010871208ff9aba4e3ae1513b2ef92021320bf2539d766056bdf6fb16

重新加载Docker守护进程

[root@docker ~]# systemctl reload docker

查看该容器,可以发现该容器并没有停止,依然在运行

[root@docker ~]# docker ps
CONTAINER ID   IMAGE     ...  STATUS               PORTS              NAMES
f92070701087   httpd     ...  Up About a minute    0.0.0.0:8080->80/tcp, :::8080->80/tcp   stupefied_antonelli

使用kill命令结束进程需要获取进程号,以下操作获取dockerd的进程号

[root@docker ~]# ps -e | grep dockerd
   9530 ?        00:00:02 dockerd

向dockerd进程发送SIGHUP信号

[root@docker ~]# kill -SIGHUP 9530

再次查看该容器,发现该容器正在运行

访问该容器提供的Apache服务,结果正常

[root@docker ~]# curl 127.0.0.1:8080
<html><body><h1>It works!</h1></body></html>

实验完毕,停止该容器后自动被删除,恢复实验环境

6.3、测试容器健康检查功能

为便于快速启动镜像以检测初始状态,先下载busybox镜像

[root@docker ~]# docker pull busybox

一次执行以下两条命令

# 基于busybox镜像创建名为test-health的容器,并为该容器设置健康检查选项,检查时间间隔为20s,失败则重试1次,检查命令"stat/etc/passwd||exit 1“的含义是执行shell命令,输出/etc/passwd文件的详细信,如果找不到该文件则退出当前shell并返回状态码1。该容器启动后执行shell命令sleep 1的,休眠1天
docker run --rm --name test-health -d --health-cmd 'stat /etc/passwd || exit 1' --health-interval 20s --health-retries 1 busybox sleep 1d

# 获取该容器的健康状态信息,结果表明容器启动后的健康状态位Staring
docker inspect --format '{{.State.Health.Status}}' test-health

一次执行以下命令:

# 第一条命令延迟20秒,超过健康检查时间间隔,让Docker为该容器执行健康检查命令。
sleep 20s
docker inspect --format '{{.State.Health.Status}}' test-health
# 第二指令查看该容器的健康状态

执行以下命令查看该容器的当前信息,发现其处于不健康状态

[root@docker ~]# docker ps
CONTAINER ID   IMAGE     COMMAND      CREATED         STATUS                     PORTS     NAMES
a1fe7d7b3e59   busybox   "sleep 1d"   5 minutes ago   Up 5 minutes (unhealthy)             test-health

停止运行该容器,该容器会被自动删除