Skip to content

Compose

编排功能,是复杂系统是否具有灵活可操作性的关键。
特别在 Docker 应用场景中,编排意味着用户可以灵活地对各种容器资源实现定义和管理。

Compose 作为 Docker 官方编排工具,其重要性不言而喻,它可以让用户通过编写一个简单的模板文件,快速地创建和管理基于 Docker 容器的应用集群。

https://github.com/docker/compose/

https://docs.docker.com/compose/

https://github.com/docker/awesome-compose

安装

依赖 python3

1
2
pip install docker-compose
docker-compose --version

Compose 简介

Compose 项目是 Docker 官方的开源项目,负责实现对基于 Docker 容器的多应用服务的快速编排。

Compose 定位是“定义和运行多个 Docker 容器的应用”,其前身是开源项目 Fig,目前仍然兼容 Fig 格式的模板文件

我们已经知道使用一个 Dockerfile 模板文件,可以让用户很方便地定义一个单独的应用容器。
然而,在日常工作中,经常会碰到需要多个容器相互配合来完成某项任务的情况。
例如要实现一个 Web 项目,除了 Web 服务容器本身,往往还需要再加上后端的数据库服务容器,甚至还包括前端的负载均衡容器等。

Compose 恰好满足了这样的需求。
它允许用户通过一个单独的docker-compose.yml模板文件(YAML 格式)来定义一组相关联的应用容器为一个服务栈。

Compose 中有几个重要的概念:

  • 任务(task): 一个容器被称为一个任务。任务拥有独一无二的 ID,在同一个服务中的多个任务序号依次递增。
  • 服务(service): 某个相同应用镜像的容器副本集合,一个服务可以横向扩展为多个容器实例
  • 服务栈(stack): 由多个服务组成,相互配合完成特定业务,如 Web 应用服务、数据库服务共同构成 Web 服务栈,一般由一个docker-compose.yml文件定义

Compose 的默认管理对象是服务栈,通过子命令对栈中的多个服务进行便捷的生命周期管理。

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

Compose 模板文件

模板文件是使用 Compose 的核心,涉及的指令关键字也比较多。
但是不用担心,这里的大部分指令与 docker [container] create | run 相关参数的含义都是类似的

默认的模板文件名称为docker-compose.yml,格式为 YAML 格式

版本 1 的 Compose 文件结构十分简单,每个顶级元素为服务名称,次级元素为服务容器的配置信息,例如:

1
2
3
4
5
6
webapp:
    image: examples/web
    ports:
        - "80:80"
    volumes:
        - "/data"

版本 2 和 3 扩展了 Compose 的语法,同时尽量保持跟旧版本的兼容,除了可以声明网络和存储信息外,最大的不同一是添加了版本信息,另一个是需要将所有的服务放到 services 根下面

例如,上面例子改写为版本 3,并启动资源限制,内容如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
version: "3"
services:
    webapp:
        image: examples/web
        deploy:
            replicas: 2
            resources:
                limits:
                    cpus: "0.1"
                    memory: 100M
                restart_policy:
                    condition: on-failure
        ports:
            - "80:80"
        networks:
            - mynet
        volumes:
            - "/data"

注意每个服务都必须通过 image 指令指定镜像或 build 指令(需要 Dockerfile)等来自动构建生成镜像

如果使用 build 指令,在 Dockerfile 中设置的选项(例如:CMD、EXPOSE、VOLUME、ENV 等)将会自动被获取,无须在docker-compose.yml中再次设置

Compose 模板文件主要命令

命令 功能
build 指定 Dockerfile 所在文件夹的路径
cap_add, cap_drop 指定容器的内核能力(capacity)分配
command 覆盖容器启动后默认执行的命令
cgroup_parent 指定父 cgroup 组,意味着将继承该组的资源限制。目前不支持 Swarm 模式
container_name 指定容器名称。目前不支持 Swarm 模式
devices 指定设备映射关系。不支持 Swarm 模式
depends_on 指定多个服务之间的依赖关系
dns 自定义 DNS 服务器
dns_search 配置 DNS 搜索域
dockerfile 指定格外的编译镜像的 Dockerfile 文件
entrypoint 覆盖容器中默认的入口命令
env_file 从文件中获取环境变量
enviroment 设置环境变量
expose 暴露端口,但不映射到宿主机,只被连接的服务访问
extends 基于其他模板文件进行扩展
external_links 链接到 docker-compose.yml 外部的容器
extra_hosts 指定额外的 host 名称映射信息
healthcheck 指定检测应用健康状态的机制
image 指定为镜像名称或镜像 ID
isolation 配置容器隔离的机制v
labels 为容器添加 Docker 元数据信息
links 链接到其他服务中的容器
logging 根日志相关的配置
network_mode 设置网络模式
networks 所加入的网络
pid 根主机系统共享进程命名空间
ports 暴露端口信息
secrets 配置应用的秘密数据
security_opt 指定容器模板标签(label)机制的默认属性(用户、角色、类型、级别等)
stop_grace_period 指定应用停止时,容器的优雅停止期限。过期后则通过 SIGKILL 强制退出。默认为 10s
stop_signal 指定停止容器的信号
sysctls 配置容器内的内核参数。目前不支持 Swarm 模式
ulimits 指定容器的 ulimits 限制值
userns_mode 指定用户命名空间模式。目前不支持 Swarm 模式
volumes 数据卷所挂载路径设置
restart 指定重启策略
deploy 指定部署和运行时的容器相关配置。该命令只在 Swarm 模式下生效,且只支持 dokcer stack deploy 命令部署

下面介绍部分指令的用法。

build

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

1
2
3
4
version: "3"
services:
    app:
        build: /paht/to/build/dir

build 指令还可以指定创建镜像的上下文、Dockerfile 路径、标签、Shm 大小、参数和缓存来源等,例如:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
version: "3"
services:
    app:
        build:
            context: /path/to/build/dir
            dockerfile: Dockerfile-app
            labels:
                versin: "2.0"
                released: "true"
            shm_size: '2gb'
            args:
                key: value
                name: myApp
            cache_from:
                - myApp: 1.0

cap_add, cap_drop

指定容器的内核能力(capacity)分配。
例如,让容器拥有所有能力可以指定为:

1
2
cap_add:
    - ALL

去掉 NET_ADMIN 能力可以指定为:

1
2
cap_drop:
    - NET_ADMIN

command

覆盖容器启动后默认执行的命令,可以为字符串格式或 JSON 数组格式。例如:

1
command: echo "hello world"

或者:

1
command: ["bash", "-c", "echo", "hello world"]

configs

在 Docker Swarm 模式下,可以通过 configs 来管理和访问非敏感的配置信息。支持从文件读取或外部读取。例如:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
version: "3.3"
services:
    app:
        image: myApp:1.0
        deploy:
            replicas: 1
        configs:
            - file_config
            - external_config
configs:
    file_config:
        file: ./config_file.cfg
    external_config:
        external: true

cgroup_parent

指定父 cgroup 组,意味着将继承该组的资源限制。目前不支持 Swarm 模式中使用。
例如,创建了一个 cgroup 组名称为 cgroups_1:

1
cgroup_parent: cgroups_1

container_name

指定容器名称。默认将会使用“项目名称_服务名称_序号”这样的格式。
目前不支持在 Swarm 模式中使用。例如:

1
container_name: docker-web-container

需要注意,指定容器名称后,该服务将无法进行扩展,因为 Docker 不允许多个容器实例重名

devices

指定设备映射关系,不支持 Swarm 模式,例如:

1
2
devices:
    - "/dev/ttyUSB1:/dev/ttyUSB0"

depends_on

指定多个服务之间的依赖关系。启动时,会先启动被依赖服务。例如,可以指定依赖于 db 服务

1
depends_on: db

dns

自定义 DNS 服务器。可以是一个值,也可以是一个列表。例如:

1
2
3
4
dns: 8.8.8.8
dns:
    - 8.8.8.8
    - 9.9.9.9

dns_search

配置 DNS 搜索域。可以是一个值,可以是一个列表。例如:

1
2
3
4
dns_search: example.com
dns_search:
    - domain1.example.com
    - domain2.example.com

dockerfile

如果需要,指定额外的编译镜像的 Dockerfile 文件,可以通过该指令来指定。例如:

1
dockerfile: Dockerfile-alternate

注意:该指令不能跟 image 同时使用,否则 Compose 将不知道根据哪个指令来生成最终的服务镜像。

entrypoint

覆盖容器中默认的入口命令。注意,也会取消掉镜像中指定的入口命令和默认启动命令。
例如,覆盖为新的入口明林:

1
entrypoint: python app.py

env_file

从文件中获取环境变量,可以为单独的文件路径或列表。
如果通过 docker-compose -f FILE 方式来指定 Compose 模板文件,则 env_file 中变量的路径会基于模板文件路径。
如果有变量名称与 environment 指令冲突,则按照惯例,以后者为准。例如:

1
2
3
4
5
env_file: .env
env_file:
    - ./common.env
    - ./apps/web.env
    - /opt/secrets.env

环境变量文件中每一行必须符合格式,支持#开头的注释行,例如:

1
2
# common.env: Set development environment
PROG_ENV=development

enviroment

设置环境变量,可以使用数组或字典两种格式。
只给定名称的变量会自动获取运行 Compose 主机上对应变量的值,可以用来防止泄漏不必要的数据。例如:

1
2
3
environment:
    RACK_ENV: development
    SESSION_SECRET:

或者:

1
2
3
environment:
    - RACK_ENV=development
    - SESSION_SECRET

注意,如果变量名称或者值中用到 true|false,yes|no 等表达布尔含义的词汇,最好放到引号里,避免 YAML 自动解析某些内容为对应的布尔语义

expose

暴露端口,但不映射宿主机,只被连接的服务访问。
仅可以指定内部端口为参数,如下所示:

1
2
3
expose:
    - "3000"
    - "8000"

extends

基于其他模板文件进行扩展。
例如,我们已经有了一个 webapp 服务,定义一个基础模板文件为 common.yml,如下所示:

1
2
3
4
5
6
# common.yml
webapp:
    build: ./webapp
    environment:
        - DEBUG=false
        - SEND_EMAILS=false

再编写一个新的 development.yml 文件,使用 common.yml 中的 webapp 服务进行扩展:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# development.yml
web:
    extends:
        file: common.yml
        service: webapp
    ports:
        - "8000:8000"
    links:
        - db
    environment:
        - DEBUG=true
db:
    image: postgres

后者会自动继承 common.yml 中的 webapp 服务及环境变量定义。使用 extends 需要注意以下两点:

  • 要避免出现循环依赖,例如 A 依赖 B,B 依赖 C,C 反过来依赖 A 的 情况。
  • extends 不会继承 links 和 volumes_from 中定义的容器和数据卷资源

一般情况下,推荐在基础模板中只定义一些可以共享的镜像和环境变量,在扩展模板中具体指定应用变量、链接、数据卷等信息。

external_links

链接到 docker-compose.yml 外部的容器,甚至并非 Compose 管理的外部容器。参数格式跟 links 类似

1
2
3
4
external_links:
    - redis_1
    - project_db_1: mysql
    - project_db_1: postgresql

extra_hosts

类似 Docker 中的 --add-host 参数,指定额外的 host 名称映射信息。

例如:

1
2
3
extra_hosts:
    - "googledns: 8.8.8.8"
    - "dockerhub: 52.1.157.61"

会在启动后的服务容器中/etc/hosts文件中添加如下两条条目。

1
2
8.8.8.8 googledns
52.1.157.61 dockerhub

healthcheck

指定检测应用健康状态的机制,包括检测方法(test)、间隔(interval)、超时(timeout)、重试次数(retries)、启动等待时间(start_period)等。

例如,指定检测方法为访问 8080 端口,间隔为 30 秒,超时为 15 秒,重试 3 次,启动后等待 30 秒再做检查

1
2
3
4
5
healthcheck:
    test: ["CMD", "curl", "-f", "http://localhost:8080"]
    interva: 30s
    timeout: 30s
    start_period: 30s

image

指定为镜像名称或镜像 ID。如果镜像在本地不存在,Compose 将会尝试去拉取这个镜像。

例如:

1
2
3
image: ubuntu
image: orchardup/postgresql
image: a4bc65fd

isolation

配置容器隔离的机制,包括 default、process 和 hyperv

labels

为容器添加 Docker 元数据(metadata)信息。例如可以为容器添加辅助说明信息

1
2
3
4
labels:
    com.startupteam.description: "web for a startup team"
    com.startupteam.department: "devops department"
    com.startupteam.release: "rc3 for v1.0"

links

注意:links 命令属于旧的用法,可能在后续版本中被移除

链接到其他服务中的容器。使用服务名称(同时作为别名)或服务名称:服务别名(SERVICE:ALIAS)格式都可以

1
2
3
4
links:
    - db
- db:database
- redis

使用的别名将会自动在服务容器中的/etc/hosts里创建。例如:

1
2
3
172.17.2.186 db
172.17.2.186 database
172.17.2.186 reids

被链接容器中相应的环境变量也将被创建

logging

跟日志相关的配置,包括一些列子配置

logging.driver: 类似于 Docker 中的 --log--driver 参数,指定日志驱动类型。
目前支持三种日志驱动类型:

1
2
3
driver: "json-file"
driver: "syslog"
driver: "none"

logging.options: 日志驱动的相关参数,例如:

1
2
3
4
logging:
    driver: "syslog"
    options:
        syslog-address: "tcp://192.168.0.42:123"

或:

1
2
3
4
5
logging:
    driver: "json-file"
    options:
        max-size: "1000k"
        max-file: "20"

network_mode

设置网络模式。使用和 docker client 的 --net 参数一样的值。

1
2
3
4
5
netowrk_mode: "none"
netowrk_mode: "bridge"
netowrk_mode: "host"
netowrk_mode: "service:[service name]"
netowrk_mode: "container:[name or id]"

networks

所加入的网络。需要在顶级的 networks 字段中定义具体的网络信息。

例如,指定 web 服务的网络为 web_net,并添加服务在网络中别名为 web_app

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
services:
    web:
        networks:
            web_net:
                aliases: web_app
            ipv4_address: 172.16.0.10
networks:
    web_net:
        driver: bridge
        enable_ipv6: true
        ipam:
            driver: default
            config:
                subnet: 172.16.0.0/24

pid

跟主机系统共享进程命名空间。
打开该选项的容器之间,以及容器和宿主系统之间可以通过进程 ID 来相互访问和操作。

1
pid: "host"

ports

暴露端口信息。

使用宿主:容器(HOST:CONTAINER)格式,或者仅仅指定容器的端口(宿主将会随机选择端口)都可以

1
2
3
4
5
ports:
    - "3000"
    - "8000:8000"
    - "49100:22"
    - "127.0.0.1:8001:8001"

或者:

1
2
3
4
5
ports:
    - target: 80
      published: 8080
      protocol: tcp
      mode: ingress

注意:
当使用 HOST:CONTAINER 格式来映射端口时,如果你使用的容器端口小于 60 并且没放到引号里,可能会得到错误结果,因为 YAML 会自动解析 xx:yy 这种数字格式为 60 进制。
为避免出现这种问题,建议数字串都采用引号包括起来的字符串格式

secrets

配置应用的秘密数据。
可以指定来源秘密、挂载后名称、权限等。
例如:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
version: "3.1"
services:
    web:
        image: webapp:stable
        deploy:
            replicas: 2
        secrets:
            - source: web_secret
              target: web_secret
              uid: '103'
              gid: '103'
              mode: 0444
secrets:
    web_scret:
        file: ./web_secret.txt

security_opt

指定容器模板标签(label)机制的默认属性(用户、角色、类型、级别等)

例如,配置标签的用户名和角色名

1
2
3
security_opt:
    - label:user:USER
    - label:role:ROLE

stop_grace_period

指定应用停止时,容器的优雅停止期限。过期后则通过 SIGKILL 强制退出。
默认值为 10s

stop_signal

指定停止容器的信号,默认为 SIGTERM

sysctls

配置容器内的内核参数。Swarm 模式中不支持

例如,指定连接数为 4096 和开启 TCP 的 syncookies:

1
2
3
sysctls:
    net.core.somaxconn: 4096
    net.ipv4.tcp_syncookies: 1

ulimits

指定容器的 ulimits 限制值

例如,指定最大进程数为 65535,指定文件句柄数为 20000(软限制,应用可以随时修改,不能超过硬限制)和 40000(系统硬限制,只能 root 用户提高)

1
2
3
4
5
ulimits:
    nproc: 65535
    nofile:
        soft: 20000
        hard: 40000

userns_mode

指定用户命名空间模式。Swarm 模式不支持。例如,使用主机上的用户命名空间:

1
userns_mode: "host"

volumes

数据卷所挂载路径设置。
可以设置宿主机路径(HOST:CONTAINER)或加上访问模式(HOST:CONTAINER:ro)

支持 driver、derver_opts、external、labels、name 等子配置

该指令中路径支持相对路径。例如

1
2
3
4
volumes:
    - /var/lib/mysql
    - cache/:/tmp/cache
    - ~/configs:/etc/configs/:ro

或者可以使用更详细的语法格式:

1
2
3
4
5
6
7
8
volumes:
    - type: volume
        source: mydata
        target: /data
        volume:
            nocopy: true
volumes:
    mydata:

restart

指定重启策略,可以为 no(不重启)、always(总是)、on-failure(失败时)、unless-stopped(除非停止)

注意 Swarm 模式下要使用 restart_policy。在生产环境中推荐配置为 always 或者 unless-stopped

例如,配置除非停止:

1
restart: unless-stopped

deploy

指定部署和运行时的容器相关配置。该命令只在 Swarm 模式下生效,且只支持 docker stack deploy 命令部署

例如:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
version: '3'
services:
    redis:
        image: web:stable
        deploy:
            replicas: 3
            update_config:
                parallelism: 2
                dealy: 10s
            restart_policy:
                condition: on-failure

deploy 命令中包括 endpoint_mode、labels、mode、placement、replicas、resources、restart_policy、update_config 等配置项

(1) endpoint_mode

指定服务端点模式。包括两种类型:

  • vip:Swarm 分配一个前段的虚拟地址,客户端通过给地址访问服务,而无须关心后端的应用容器个数
  • dnsrr:Swarm 分配一个域名给服务,用户访问域名时候会按照轮流顺序返回容器地址

例如:

1
2
3
4
5
6
7
8
version: '3'
services:
    redis:
        image: web:stable
        deploy:
            mode: replicated
            replicas: 3
            endpoint_mode: vip

(2) labels

指定服务的标签。注意标签信息不会影响到服务内的容器

例如:

1
2
3
4
5
6
7
version: "3"
services:
    web:
        image: web:stable
        deploy:
            labels:
                description: "This is a web application service."

(3) mode

定义容器副本模式,可以为

  • global: 每个 Swarm 节点上只有一个该应用容器
  • replicated: 整个集群中存在指定份数的应用容器副本,默认值

例如,指定集群中 web 应用保持 3 个副本:

1
2
3
4
5
6
7
version: "3"
services:
    web:
        image: web:stable
        deploy:
            mode: replicated
            replicas: 3

(4) placement

定义容器放置的限制(constraints)和配置(preferences)。
限制可以指定只有符合要求的节点上才能运行该应用容器;配置可以指定容器的分配策略。
例如,指定集群中 web 应用容器只存在于高安全的节点上,并且在带有 zone 标签的节点上均匀分配

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
version: '3'
services:
    db:
        image: web:stable
        deploy:
            placement:
                constraints:
                    - node.labels.security==high
                preferences:
                    - spread: node.labels.zone

(5) replicas

容器副本模式为默认的 replicated 时,指定副本的个数

(6) resources

指定使用资源的限制,包括 CPU、内存资源等。
例如,指定应用使用的 CPU 份额为 10% 到 25%,内存为 200 MB 到 500 MB

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
version: '3'
services:
    redis:
        image: web:stable
        deploy:
            resources:
                limits:
                    cpus: '0.25'
                    memory: 500M
                reservatrions:
                    cpus: '0.10'
                    memory: 200M

(7) restart_policy

指定容器重启的策略。例如,指定重启策略为失败时重启,等待 2s,重启最多尝试 3 次,检测状态的等待时间为 10s

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
version: "3"
services:
    redis:
        image: web:stable
        deploy:
            restart_policy:
                condition: on-failure
                delay: 2s
                max_attempts: 3
                window: 10s

(8) update_config

有些时候需要对容器内容进行更新,可以使用该配置指定升级的行为。
包括每次升级多少个容器(parallelism)、升级的延迟(delay)、升级失败后的行动(failure_action)、检测升级后状态的等待时间(monitor)、升级后容忍的最大失败比例(max_failure_ratio)、升级顺序(order)等。
例如,指定每次更新两个容器、更新等待 10s、先停止就容器再升级

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
version: "3.4"
services:
    redis:
        image: web: stable
        deploy:
            replicas: 2
            update_config:
                parallelism: 2
                delay: 10s
                order: stop-first

其他指令

此外,还有包括 domainname、hostname、ipc、mac_address、privileged、read_only、shm_size、stdin_open、tty、user、working_dir 等指令,基本跟 docker-run 中对应参数的功能一致。
例如,指定容器中工作目录:

1
working_dir: /code

指定容器中搜索域名、主机名、mac 地址等:

1
2
3
domainname: your_website.com
hostname: test
mac_address: 08-00-27-00-0c-0A

允许容器中运行一些特权命令:

1
privileged: true

读取环境变量

从 1.5.0 版本开始,Compose 模板文件支持动态读取主机的系统环境变量。
例如,下面的 Compose 文件将从运行它的环境中读取变量 ${MONGO_VERSION}的值(不指定时则采用默认值 3.2),并写入执行的指令中。

1
2
db:
    image: "mongo:${MONGO_VERSION-3.2}"

如果直接执行 docker-compose up 则会启动一个 mongo:3.2 镜像的容器;
如果执行 MONGO_VERSION=2.8 docker-compose up 则会启动一个 mongo:2.8 镜像的容器

扩展特性

从 3.4 开始,Compose 还支持用户自定义的扩展字段。
利用 YAML 语法里的锚点引用功能来引用自定义字段内容。例如:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
version: '3.4'
x-logging:
    &default-logging
    options:
        max-size: '10m'
        max-file: '10'
    driver: json-file
services:
    web:
        image: webapp:stable
        logging: *default-logging

Compose 命令说明

对于 Compose 来说,大部分命令的对象既可以是项目本身,也可以指定为项目中的服务或容器。

网络

https://docs.docker.com/compose/networking/

Links allow you to define extra aliases by which a service is reachable from another service.
They are not required to enable services to communicate - by default, any service can reach any other service at that service’s name.
In the following example, db is reachable from web at the hostnames db and database:

1
2
3
4
5
6
7
8
9
version: "3.9"
services:

  web:
    build: .
    links:
      - "db:database"
  db:
    image: postgres