目录

学习 Docker(6)-Docker Compose

简介

Compose 项目是 Docker 官方的开源项目,负责实现对 Docker 容器集群的快速编排。Compose 可以使用 YAML 文件来配置应用程序的服务,然后可以从配置中使用单个命令,创建并启动所有服务。

Compose 中有两个重要的概念:

  • 服务 (service):一个应用的容器,实际上可以包括若干运行相同镜像的容器实例。
  • 项目 (project):由一组关联的应用容器组成的一个完整业务单元,在 docker-compose.yml 文件中定义。

Compose 项目由 Python 编写,实现上调用了 Docker 服务提供的 API 来对容器进行管理。因此,只要所操作的平台支持 Docker API,就可以在其上利用 Compose 来进行编排管理。

docker-compose.yaml

docker-compose.yamldocker-compose.yml 是 Docker Compose 的默认模版文件名称,格式为 YAML 格式。模板文件是使用 Compose 的核心。模版文件中使用的指令,与 Dockerfile 中的指令有相似之处。

docker-compose.yaml 中的配置为创建容器时的配置,Dockerfile 中的配置为创建镜像时的配置。

一般我们在第一行使用 version 声明模版文件使用的版本。

build 和 image

docker-compose 中的每个服务都必须通过 image 指令指定镜像或者 build 指令指定 Dockerfile 来自动构建生成镜像。

使用 build 指令时,要指定 Dockerfile 所在文件夹的路径(可以是绝对路径,或者相对 docker-compose.yml 文件的路径)。Compose 将会利用它自动构建这个镜像,然后使用这个镜像。

使用 image 指令时,如果本地不存在,会自动尝试拉取镜像。

1
2
3
4
5
6
7
8
version: '3'

services:
  mysql:
    image: mysql:5.7

  webapp:
    build: ./dir

上述指令含义为,mysql 服务使用 mysql:5.7 镜像,webapp 服务使用 ./dir 目录下的 Dockerfile 文件构建镜像。

depends_on

指定服务的依赖。服务启动时,必须先启动其依赖的其他服务。也就是说:

  • 被依赖的服务会先启动;
  • 启动当前服务时,也会启动其依赖的服务。

举例,celery 的服务依赖于 rabbitmq 服务和 redis 服务。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
version: '3'

services:
  celery:
    build: .
    depends_on:
      - redis
      - rabbitmq

  redis:
    image: redis:alpine

  rabbitmq:
    image: rabbitmq:alpine

environment

设置运行时的环境变量。可以使用 YAML 语法的数组格式或者字典格式。

1
2
3
4
5
environment:
  NAME: value

environment:
  - NAME=value

如果只定义环境变量名而不赋值,则从执行模版文件所在的 shell 环境变量中,或者从模版文件所在目录的 .env 文件中读取(模版文件执行时,会自动读取当前目录的 .env 环境变量文件),前者优先级较高

1
2
environment:
   NAME:

另外要注意的是,变量值中用到的表达布尔含义的词语,需要放到引号里,避免 YAML 自动解析某些内容为对应的布尔语义。这些词有:

1
y|Y|yes|Yes|YES|n|N|no|No|NO|true|True|TRUE|false|False|FALSE|on|On|ON|off|Off|OFF

env_file

从文件中获取环境变量。文件路径相对于模版文件路径。

1
2
3
env_file:
  - ./common.env
  - ./web.env

如果有变量名称与 environment 指令冲突,则以 environment 指令为准。

volumes

设置目录映射或数据卷挂载。格式可以为 HOST:CONTAINERHOST:CONTAINER:MODEDATA_VOLUME:CONTAINER,模式可以为:ro 只读,rw 读写。

宿主机路径可以指定相对路径,注意指定相对路径时,路径要写完整,否则可能被认为是数据卷。

1
2
3
4
volumes:
  - /ui:/src
  - ./ui:src
  - ui:/src

上述第一个是绝对路径映射,第二个是相对路径映射,第三个是挂载名为 ui 的数据卷。

另外如果宿主机路径指向的是一个已存在的文件,则会映射文件到容器中,而不是目录。例如映射 mysql 的配置文件。

1
2
volumes:
  - ./conf/mysql.ini:/etc/mysql/conf.d/mrchiblog.cnf:ro

networks

配置容器连接的网络。为增强安全性,我们可以给应用指定不同的网络以隔离它们。网络需要在根层级声明和配置。

举例,我们有一个 web 应用,包含 web、nginx 和 mysql 三个服务。我们可以配置两个网络:后端 back-tire 和 前端 front-tire。其中 web 和 nginx 通信使用 front-tire,web 和 mysql 通信使用 back-tire,这样就将 nginx 和 mysql 隔离开来。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
version: '3'

networks:
  back-tire:
  front-tire:

services:
  web:
    build: .
    networks:
      - back-tire
      - front-tire

  mysql:
    image: mysql:5.7
    networks:
      - back-tire

  nginx:
    image: nginx:alpine
    networks:
      - front-tire

ports 和 expose

ports 指定容器端口到宿主机的映射。expose 只暴露端口供容器间通过网络访问,不映射到宿主机(不 expose 在同一网络中也是能够互相访问的)。

expose 指定暴露的端口就可以。

ports 映射有几种格式:

  • 只指定容器端口,映射到宿主机随机端口;
  • 指定宿主机端口和容器端口 HOST:CONTAINER,则映射到指定端口并监听 0.0.0.0
  • 指定宿主机监听地址、宿主机端口和容器端口 IP:HOST:CONTAINER
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
version: '3'

services:
  web:
    expose:
      - "5000"
    ports:
      - "5000"
      - "5000:5000"
      - "127.0.0.1:5000:5000"

working_dir

指定容器中工作目录,等同于 Dockerfile 中的 WORKDIR。

1
working_dir: /dir

command

覆盖容器启动后默认执行的命令。

1
command: echo "hello"

restart

指定容器退出后的重启策略。

1
restart: on-failure

有四种取值:

  • no 默认值,退出后不重启;
  • on-failure 出错退出(exit code 不为 0)时重启。
  • unless-stoped 除非显式停止或停止或重新启动 Docker 本身,否则重新启动容器。
  • always 总是重启;

生产环境可以适当设置为 on-failure 或者 unless-stoped。对于一些特殊应用,例如 ss,可以设置为 always

注意:

  • 重启策略仅在容器成功启动后生效。在这种情况下,成功启动意味着容器启动至少 10 秒并且 Docker 已开始监视它。这可以防止根本不启动的容器进入重启循环。
  • 如果手动停止容器,则会忽略其重新启动策略,直到 Docker 守护程序重新启动或手动重新启动容器。这是防止重启循环的另一种尝试。

CLI 命令

config

验证 Compose 文件格式是否正确,若正确则显示配置,若格式错误显示错误原因。

build

构建(重新构建)项目中的服务镜像。

1
docker-compose build [options] [SERVICE...]

start

启动已经存在的服务容器。

1
docker-compose start [SERVICE...]

stop

停止已经处于运行状态的容器,但不删除它。通过 docker-compose start 可以再次启动这些容器。

1
docker-compose stop [options] [SERVICE...]

选项:

  • -t, --timeout TIMEOUT 停止容器时候的超时(默认为 10 秒)。

restart

重启项目中的服务。

1
docker-compose restart [options] [SERVICE...]

选项:

  • -t, --timeout TIMEOUT 指定重启前停止容器的超时(默认为 10 秒)。

rm

删除所有(停止状态的)服务容器。推荐先执行 docker-compose stop 命令来停止容器。

1
docker-compose rm [options] [SERVICE...]

选项:

  • -f, --force 强制直接删除,包括非停止状态的容器。一般尽量不要使用该选项。
  • -v 删除容器所挂载的数据卷。

up

该命令十分强大,它将尝试自动完成包括构建镜像,(重新)创建服务,启动服务,并关联服务相关容器的一系列操作。

1
docker-compose up [options] [SERVICE...]

选项:

  • -d 在后台运行服务容器。
  • --no-color 不使用颜色来区分不同的服务的控制台输出。
  • --no-deps 不启动服务所链接的容器。
  • --force-recreate 强制重新创建容器,不能与 --no-recreate 同时使用。
  • --no-recreate 如果容器已经存在了,则不重新创建,不能与 --force-recreate 同时使用。
  • --no-build 不自动构建缺失的服务镜像。
  • -t, --timeout TIMEOUT 停止容器时候的超时(默认为 10 秒)。

如果 docker-compose.yaml 指定的环境变量发生改变,例如 environment 发生改变,或 env_file 指向的文件内容发生改变,up 命令执行时会重新创建容器。

logs

查看服务容器的输出。

1
docker-compose logs [options][SERVICE...]

默认情况下,docker-compose 将对不同的服务输出使用不同的颜色来区分。可以通过 --no-color 来关闭颜色。

该命令在调试问题的时候十分有用。

FAQ

如何设置容器的时区

容器默认的时区为 UTC 时区,要设置为不同时区只需要在模版文件中设置 TZ 环境变量即可:

1
2
environment:
  TZ: Asia/Shanghai

参考链接