7.2.9 利用重启策略进行容器的自我修复
通常建议在运行容器时配置好重启策略。这是容器的一种自我修复能力,可以在指定事件或者错误后重启来完成自我修复。
重启策略应用于每个容器,可以作为参数被强制传入 docker-container run
命令中,或者在Compose文件中声明(在使用Docker Compose以及Docker Stacks的情况下)。
截至本书撰写时,容器支持的重启策略包括 always
、 unless-stopped
和 on-failed
。
always
策略是一种简单的方式。除非容器被明确停止,比如通过 docker container stop
命令,否则该策略会一直尝试重启处于停止状态的容器。一种简单的证明方式是启动一个新的交互式容器,并在命令后面指定 --restart always
策略,同时在命令中指定运行Shell进程。当容器启动的时候,会登录到该Shell。退出Shell时会杀死容器中PID为1的进程,并且杀死这个容器。但是因为指定了 --restart always
策略,所以容器会自动重启。如果运行 docker container ls
命令,就会看到容器的启动时间小于创建时间。下面请看示例。
$ docker container run --name neversaydie -it --restart always alpine sh
//等待几秒后输入exit
/# exit
$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS
0901afb84439 alpine "sh" 35 seconds ago Up 1 second
注意,容器于35s前被创建,但却在1s前才启动。这是因为在容器中输入退出命令的时候,容器被杀死,然后Docker又重新启动了该容器。
--restart always
策略有一个很有意思的特性,当daemon重启的时候,停止的容器也会被重启。例如,新创建一个容器并指定 --restart always
策略,然后通过 docker container stop
命令停止该容器。现在容器处于 Stopped (Exited)
状态。但是,如果重启Docker daemon,当daemon启动完成时,该容器也会重新启动。
always
和 unless-stopped
的最大区别,就是那些指定了 --restart unless-stopped
并处于 Stopped (Exited)
状态的容器,不会在Docker daemon重启的时候被重启。这个说法可能令人有点迷惑,接下来通过示例进行演示。
下面创建两个新容器,其中“always”容器指定 --restart always
策略,另一个“unless- stopped”容器指定了 --restart unless-stopped
策略。两个容器均通过 docker container stop
命令停止,接着重启Docker。结果“always”容器会重启,但是“unless-stopped”容器不会。
(1)创建两个新容器。
$ docker container run -d --name always \
--restart always \
alpine sleep 1d
$ docker container run -d --name unless-stopped \
--restart unless-stopped \
alpine sleep 1d
$ docker container ls
CONTAINER ID IMAGE COMMAND STATUS NAMES
3142bd91ecc4 alpine "sleep 1d" Up 2 secs unless-stopped
4f1b431ac729 alpine "sleep 1d" Up 17 secs always
现在有两个运行的容器了。一个叫作“always”,另一个叫作“unless-stopped”。
(2)停止两个容器。
$ docker container stop always unless-stopped
$ docker container ls -a
CONTAINER ID IMAGE STATUS NAMES
3142bd91ecc4 alpine Exited (137) 3 seconds ago unless-stopped
4f1b431ac729 alpine Exited (137) 3 seconds ago always
(3)重启Docker。
重启Docker的过程在不同的操作系统上可能不同。下面的示例中展示了如何在Linux上使用systemd重启Docker,在Windows Server 2016上可以使用restart-service重启。
$ systemlctl restart docker
(4)一旦Docker重启成功,检查两个容器的状态。
$ docker container ls -a
CONTAINER CREATED STATUS NAMES
314..cc4 2 minutes ago Exited (137) 2 minutes ago unless-stopped
4f1..729 2 minutes ago Up 9 seconds always
注意到“always”容器(启动时指定了 --restart always
策略)已经重启了,但是“unless-stopped”容器(启动时指定了 --restart unless-stopped
策略)并没有重启。
on-failure 策略会在退出容器并且返回值不是0的时候,重启容器。就算容器处于 stopped
状态,在Docker daemon重启的时候,容器也会被重启。
如果读者使用Docker Compose或者Docker Stack,可以在service对象中配置重启策略,示例如下。
version: "3.5"
services:
myservice:
<Snip>
restart_policy:
condition: always | unless-stopped | on-failure