12. 容器运行策略
Docker认为任何带有非零退出代码的容器都崩溃了。默认情况下,崩溃的容器将保持停止状态。
我们已经创建了一个特殊的容器,它输出一条消息,然后使用代码1退出,以模拟崩溃。
docker run -d --name restart-default scrapbook/docker-restart-example
如果列出所有的容器,包括stopped,您将看到容器已经崩溃
$ docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 39ef0a052236 scrapbook/docker-restart-example "/bin/sh -c ./launch…" 5 seconds ago Exited (1) 2 seconds ago restart-default
而日志将输出我们的消息,这在现实生活中可能会提供帮助我们诊断问题的信息。
$ docker logs restart-default Tue Sep 28 13:41:39 UTC 2021 Booting up...
根据您的场景,重新启动失败的进程可能会纠正这个问题。Docker可以在停止尝试之前自动重试启动Docker特定次数。
他的选项--restart=on-failure
:#允许你说Docker应该重试多少次。在下面的示例中,Docker将在停止之前重新启动容器三次。
$ docker run -d --name restart-3 --restart=on-failure:3 scrapbook/docker-restart-example $ docker logs restart-3 Tue Sep 28 13:42:44 UTC 2021 Booting up... Tue Sep 28 13:42:46 UTC 2021 Booting up... Tue Sep 28 13:42:50 UTC 2021 Booting up... Tue Sep 28 13:42:53 UTC 2021 Booting up...
最后,Docker总是可以重新启动失败的容器,在这种情况下,Docker将一直尝试,直到容器被明确告知停止。
例如,当容器崩溃时,使用always标志自动重新启动容器
$ docker run -d --name restart-always --restart=always scrapbook/docker-restart-example $ docker logs restart-always
13. 容器元数据与标签
当容器通过docker运行启动时,标签可以被附加到容器上。一个容器可以在任何时候有多个标签。
注意,在这个例子中,因为我们使用的标签是用于CLI,而不是一个自动化的工具,所以我们没有使用DNS表示法格式。
要添加单个标签,可以使用l =<value>选项。下面的示例为容器分配了一个名为user的带有ID的标签。这将允许我们查询与该特定用户相关的所有正在运行的容器。
docker run -l user=12345 -d redis
如果您正在添加多个标签,那么这些标签可以来自外部文件。文件的每一行都需要有一个标签,然后这些标签将被附加到正在运行的容器上。
这一行在文件中创建了两个标签,一个用于用户,另一个用于分配角色。
echo 'user=123461' >> labels && echo 'role=cache' >> labels
The --label-file=<filename>
option will create a label for each line in the file.
docker run --label-file=labels -d redis
标签镜像的工作方式与容器相同,但在构建镜像时在Dockerfile中设置。当容器启动时,镜像的标签将应用到容器实例。
在一个Dockerfile中,你可以使用label指令分配一个标签。在标签下面创建名为“剪贴簿”的供应商。
LABEL vendor=Katacoda
如果我们想要分配多个标签,可以使用下面的格式,每行都有一个标签,使用反斜杠(“”)连接。注意,我们使用的是与第三方工具相关的DNS标记格式。
LABEL vendor=Katacoda \ com.katacoda.version=0.0.5 \ com.katacoda.build-date=2016-07-01T10:47:29Z \ com.katacoda.course=Docker
标签和元数据只有在您可以稍后查看/查询它们时才有用。查看特定容器或镜像的所有标签的第一种方法是使用docker inspect
。
环境已经为您创建了一个名为rd
的容器和一个名为katacoda-label-example
的映像。
通过提供运行容器的友好名称或哈希id,您可以查询它的所有元数据。
docker inspect rd
使用-f
选项,您可以过滤JSON响应,只针对我们感兴趣的标签部分。
$ docker inspect -f "{{json .Config.Labels }}" rd {"com.katacoda.created":"automatically","com.katacoda.private-msg":"magic","user":"scrapbook"}
这些标签将保留,即使镜像已被取消标记。当镜像未被标记时,它的名称将为<none>.
虽然检查单个容器和映像可以为您提供更多的上下文,但在运行数千个容器的生产中,限制对您感兴趣的容器的响应是很有用的。
docker ps命令允许您根据标签名称和值指定一个过滤器。例如,下面的查询将返回所有具有值katacoda的用户标签键的容器。
$ docker ps --filter "label=user=scrapbook" CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 0c0d9b5b90ed redis "docker-entrypoint.s…" 8 minutes ago Up 8 minutes 6379/tcp rd
基于构建镜像时使用的标签,可以对镜像应用相同的过滤方法。
$ docker images --filter "label=vendor=Katacoda" REPOSITORY TAG IMAGE ID CREATED SIZE katacoda-label-example latest 33a1689f8704 8 minutes ago 112MB
标签不仅适用于图像和容器,也适用于Docker Daemon
本身。当您启动守护进程的实例时,可以为它分配标签,以帮助确定应该如何使用它,例如,它是开发服务器还是生产服务器,或者它是否更适合运行数据库等特定角色。
docker -d \ -H unix:///var/run/docker.sock \ --label com.katacoda.environment="production" \ --label com.katacoda.storage="ssd"
14. 负载平衡的容器
14.1 NGINX Proxy
在这个场景中,我们希望运行一个NGINX服务,它可以在加载新容器时动态发现和更新它的负载平衡配置。我们已经创建了nginx-proxy。
Nginx-proxy接受HTTP请求,并根据请求主机名将请求代理到相应的容器。这对用户是透明的,不会产生任何额外的性能开销。
在启动代理容器时,需要配置三个键属性。
第一种方法是使用-p 80:80将容器绑定到主机上的80端口。这确保了所有HTTP请求都由代理处理。
第二步是挂载docker.sock文件。这是一个与运行在主机上的Docker守护进程的连接,允许容器通过API访问它的元数据。NGINX-proxy使用这个来监听事件,然后根据容器的IP地址更新NGINX配置。挂载文件的工作方式与使用-v /var/run/docker.sock:/tmp/docker.sock:ro的目录相同。指定:ro将访问限制为只读。
最后,我们可以设置一个可选的-e DEFAULTHOST=<domain>。如果传入的请求没有生成任何指定的主机,则该容器将处理请求。这使您能够在一台机器上运行多个具有不同域的网站,并可返回到一个已知的网站。
使用下面的命令启动nginx-proxy。
docker run -d -p 80:80 -e DEFAULT_HOST=proxy.example -v /var/run/docker.sock:/tmp/docker.sock:ro --name n
:因为我们使用的是DEFAULT_HOST
,所以任何传入的请求都将被定向到已经分配了HOST代理的容器。
您可以使用curl http://ip
向web服务器发出请求。由于我们没有容器,它将返回一个503错误。
$ curl http://ip <html> <head><title>503 Service Temporarily Unavailable</title></head> <body> <center><h1>503 Service Temporarily Unavailable</h1></center> <hr><center>nginx</center> </body> </html>
14.2 单机
Nginx-proxy现在正在监听Docker在启动/停止时引发的事件。一个名为katacoda/docker-http-server的示例网站已经创建,它将返回运行它的机器名。这允许我们测试我们的代理是否按照预期工作。它的内部是一个PHP和Apache2应用程序,侦听端口80。
为了让Nginx-proxy开始向容器发送请求,你需要指定VIRTUAL_HOST环境变量。这个变量定义了请求来自的域,并且应该由容器处理。在这个场景中,我们将把我们的HOST
设置为与DEFAULT_HOST
匹配,这样它将接受所有请求。
docker run -d -p 80 -e VIRTUAL_HOST=proxy.example katacoda/docker-http-server
有时,NGINX需要几秒钟的时间来重新加载,但如果我们使用curl http://ip
执行一个请求到我们的代理,那么请求将由我们的容器处理。
$ curl http://ip <h1>This request was processed by host: a6b180c03df3</h1>
14.3 集群
现在,我们已经成功地创建了一个容器来处理HTTP请求。如果我们用相同的VIRTUAL_HOST启动第二个容器,那么nginx-proxy将在一个循环负载平衡的场景中配置系统。这意味着第一个请求将发送到一个容器,第二个请求将发送到第二个容器,然后循环重复。您可以运行的节点数量没有限制。
使用与前面相同的命令启动第二个容器或者第三个
docker run -d -p 80 -e VIRTUAL_HOST=proxy.example katacoda/docker-http-server docker run -d -p 80 -e VIRTUAL_HOST=proxy.example katacoda/docker-http-server
如果使用curl http://ip
执行对代理的请求,则请求将由第一个容器处理。第二个HTTP请求将返回不同的机器名,这意味着它是由第二个容器处理的。
$ curl http://ip <h1>This request was processed by host: ac2c0ef08655</h1> $ curl http://ip <h1>This request was processed by host: a6b180c03df3</h1>
当NGINX -proxy为我们自动创建和配置NGINX时,如果你对最终的配置感兴趣,你可以使用docker exec输出完整的配置文件,如下所示。
docker exec nginx cat /etc/nginx/conf.d/default.conf
关于何时重新加载配置的附加信息可以在使用
docker logs nginx
15. 编排docker-compose
Docker Compose是基于docker-compose.yml
文件。该文件定义启动集群集所需的所有容器和设置。属性映射到您如何使用docker运行命令.
格式yaml:
container_name: property: value - or options
在这个场景中,我们有一个需要连接到Redis的Node.js应用程序。首先,我们需要定义docker-compose.yml文件来启动Node.js应用程序。
根据上面的格式,文件需要将容器命名为“web”,并将构建属性设置为当前目录。我们将在以后的步骤中介绍其他属性。
将下列yaml复制到编辑器中。这将定义一个名为web的容器,它基于当前目录的构建。
web: build: .
Docker Compose支持所有可以使用Docker run
定义的属性。将两个容器链接在一起以指定links属性并列出所需连接。例如,下面将链接到相同文件中定义的redis源容器,并将相同的名称分配给别名。
links: - redis
同样的格式用于端口等其他属性,有关选项的其他文档可在以下网址找到
https://docs.docker.com/compose/compose-file/
更新我们的web容器,以暴露3001端口,并创建一个链接到我们的Redis容器。
在上一步中,我们使用当前目录中的Dockerfile作为容器的基础。在此步骤中,我们希望使用来自Docker Hub的现有映像作为第二个容器。
要找到第二个容器,只需在新行上使用与前面相同的格式。YAML格式非常灵活,可以在同一个文件中定义多个容器。
定义第二个名称为redis的容器,它使用镜像redis。按照YAML格式,容器的详细信息如下:
redis: image: redis:alpine volumes: - /var/redis/data:/data
使用创建的docker-compose.yml
文件就绪后,您可以使用一个up命令启动所有应用程序。如果您想调出单个容器,那么您可以使用<name>
。
参数-d
表示在后台运行容器,类似于与docker run
一起使用。
$ ls Dockerfile Makefile docker-compose.yml node_modules package.json server.js $ cat Dockerfile FROM ocelotuproar/alpine-node:5.7.1-onbuild EXPOSE 3000 $ cat docker-compose.yml web: build: . links: - redis ports: - "3000" - "8000" redis: image: redis:alpine volumes: - /var/redis/data:/data
启动部署运行 $ docker-compose up -d $ docker-compose ps Name Command State Ports ------------------------------------------------------------------------------------------------------------ tutorial_redis_1 docker-entrypoint.sh redis ... Up 6379/tcp tutorial_web_1 npm start Up 0.0.0.0:32769->3000/tcp, 0.0.0.0:32768->8000/tcp #查看日志 $ docker-compose logs
由于Docker Compose理解如何启动应用程序容器,所以它还可以用于扩展正在运行的容器数量。scale选项允许指定服务,然后指定所需的实例数量。如果数量大于已经运行的实例,那么它将启动额外的容器。如果数量较少,那么它将停止不需要的容器。
使用该命令扩展正在运行的web容器的数量
$ docker-compose scale web=3 WARNING: The scale command is deprecated. Use the up command with the --scale flag instead. Starting tutorial_web_1 ... done Creating tutorial_web_2 ... done Creating tutorial_web_3 ... done
你可以减少使用
$ docker-compose scale web=1 WARNING: The scale command is deprecated. Use the up command with the --scale flag instead. Stopping and removing tutorial_web_2 ... done Stopping and removing tutorial_web_3 ... done
与启动应用程序时一样,要停止一组容器,可以使用该命令
$ docker-compose stop
要删除所有容器,请使用此命令
$ docker-compose rm