本篇介绍 docker 官方三剑客之一的 docker-compose。
注:环境为 CentOS7,docker 19.03。
docker-compose
docker-compose 的前身是开源的 docker 容器集群编排工具 Fig,2014年7月,Fig 被 Docker 收购并更名成为 docker-compose。
之前我们已经学习了关于 docker 的 dockerfile,使用它可以让用户快速生成一个需要的镜像,进而生成容器,快速配置一个应用。但是云计算的使用更多是面对庞大的用户群体,这样一来所发布的容器数量必然不少。而单机的 dockerfile 相比起来就相形见绌了。因此,像 Fig 这样的工具就孕育而生了。如果说 dockerfile 重现一个容器,那 docker-componse 就是重现容器的配置和集群了。
在 docker 中,“编排”和“部署”这两个词是时常出现的,那么它们具体指什么呢?
- 编排(orchestration):它根据被部署的对象之间的耦合关系,以及被部署对象对环境的依赖,制定部署流程中各个动作的执行顺序,部署过程中所需要的依赖文件和被部署文件的存储位置和获取方式,以及如何验证部署成功。这些信息都会在编排工具中以指定的格式(比如配置文件或者特定的代码)来要求运维人员定义并保存起来,从而保证这个流程能够随时在全新的环境中可靠有序地重现出来。
- 部署(deployment),它是指按照编排所指定地内容和流程,在目标机器上执行编排指定环境初始化,存放指定地依赖和文件,运行指定地部署动作,最终按照编排中地规则来确定部署成功。
总地来说,编排制定流程,部署执行流程,协同完成容器云的创建。
安装 docker-compose
dcoekr-componse 的安装方式如下:
# curl -L "https://github.com/docker/compose/releases/download/1.24.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose # chomd +x /usr/local/bin/docker-compose
docker-compose 简单实例
下面我们来用一个简单实例来说明 docker-compose 的用法:
1.创建一个 docker-compose 的目录
# mkdir composetest # cd composetest
2.在目录中创建 app.py 并添加以下代码:
import time import redis from flask import Flask app = Flask(__name__) cache = redis.Redis(host='redis', port=6379) def get_hit_count(): retries = 5 while True: try: return cache.incr('hits') except redis.exceptions.ConnectionError as exc: if retries == 0: raise exc retries -= 1 time.sleep(0.5) @app.route('/') def hello(): count = get_hit_count() return 'Hello World! I have been seen {} times.\n'.format(count)
3.在目录下创建 python 代码的依赖文件 requirements.txt 并添加依赖项:
redis flask
4.创建 Dockerfile 文件
# 以 python:3.7-alpine 为基础镜像,创建镜像 FROM python:3.7-alpine # 设置工作目录为 /code WORKDIR /code # 设置环境变量 ENV FLASK_APP app.py ENV FLASK_RUN_HOST 0.0.0.0 # alpine 安装软件包 RUN apk add --no-cache gcc musl-dev linux-headers # 从主机上复制 python 的依赖文件 COPY requirements.txt requirements.txt # 安装依赖 RUN pip install -r requirements.txt # 复制 composetest 目录中的所有文件到工作目录中 COPY . . # 运行 python 应用 CMD ["flask", "run"]
5.定义 docker-compose.yml 文件
version: '3' services: web: build: . ports: - "5000:5000" redis: image: "redis:alpine"
6.从 docker-compose 构建并启动应用
# docker-compose up
执行成功后,服务会启动并绑定端口 5000。
docker-compose 模板语法
目前 docker-compose 模板已经更新到 v3 版本,支持众多指令:
1.build
指定 Dockerfile 所在⽂件夹的路径(可以是绝对路径, 或者相对dockercompose.yml⽂件的路径) 。 Compose将会利⽤它⾃动构建应⽤镜像, 然后使⽤这个镜像, 例如:
version: '3' services: app: build: /path/to/build/dirbuild
指令还可以指定创建镜像的上下⽂、 Dockerfile路径、 标签、 Shm⼤⼩、 参数和缓存来源等, 例如:
version: '3' services: app: build: context: /path/to/build/dir dockerfile: Dockerfile-app labels: version: "2.0" released: "true" shm_size: '2gb' args: key: value name: myApp cache_from: - myApp:1.0
2.cap_add, cap_drop
指定容器的内核能⼒(capacity) 分配。 例如, 让容器拥有所有能⼒可以指定为:
cap_add: - ALL
去掉NET_ADMIN能⼒可以指定为:
cap_drop: - NET_ADMIN
3.command
覆盖容器启动后默认执⾏的命令, 可以为字符串格式或JSON数组格式。 例如:
command: echo "hello world"
或者:
command: ["bash", "-c", "echo", "hello world"]
4.configs
在Docker Swarm模式下, 可以通过configs来管理和访问⾮敏感的配置信息。 ⽀持从⽂件读取或外部读取。 例如:
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
5.cgroup_parent
指定⽗cgroup组, 意味着将继承该组的资源限制。 ⽬前不⽀持在Swarm模式中使⽤。 例如, 创建了⼀个cgroup组名称为cgroups_1:
cgroup_parent: cgroups_1
6.container_name
指定容器名称。 默认将会使⽤“项⽬名称_服务名称_序号”这样的格式。 ⽬前不⽀持在Swarm模式中使⽤。 例如:
container_name: docker-web-container
注意, 指定容器名称后, 该服务将⽆法进⾏扩展, 因为Docker不允许多个容器实例重名。
7.devices指定设备映射关系, 不⽀持Swarm模式。 例如:
devices: - "/dev/ttyUSB1:/dev/ttyUSB0"
8.depends_on
指定多个服务之间的依赖关系。 启动时, 会先启动被依赖服务。 例
如, 可以指定依赖于db服务:
depends_on: db
9.dns
⾃定义DNS服务器。 可以是⼀个值, 也可以是⼀个列表。 例如:
dns: 8.8.8.8 dns: - 8.8.8.8 - 9.9.9.9
10.dns_search
配置DNS搜索域。 可以是⼀个值, 也可以是⼀个列表。 例如:
dns_search: example.com dns_search: - domain1.example.com - domain2.example.com
11.dockerfile
如果需要, 指定额外的编译镜像的Dockefile⽂件, 可以通过该指令来指定。 例如:
dockerfile: Dockerfile-alternate
注意:该指令不能跟image同时使⽤, 否则Compose将不知道根据哪个指令来⽣成最终的服务镜像。
12.entrypoint
覆盖容器中默认的⼊⼜命令。 注意, 也会取消掉镜像中指定的⼊⼜命令和默认启动命令。 例如, 覆盖为新的⼊⼜命令:
entrypoint: python app.py
13.env_file
从⽂件中获取环境变量, 可以为单独的⽂件路径或列表。 如果通过 docker-compose-f FILE⽅式来指定Compose模板⽂件, 则env_file中变量的路径会基于模板⽂件路径。 如果有变量名称与environment指令冲突, 则按照惯例, 以后者为准。 例如:
env_file: .env env_file: - ./common.env - ./apps/web.env - /opt/secrets.env
环境变量⽂件中每⼀⾏必须符合格式, ⽀持#开头的注释⾏, 例如:
# common.env: Set development environment PROG_ENV=development
14.environment
设置环境变量, 可以使⽤数组或字典两种格式。 只给定名称的变量会⾃动获取运⾏Compose主机上对应变量的值, 可以⽤来防⽌泄露不必要的数据。 例如:
environment: RACK_ENV: developmentSESSION_SECRET:
或者:
environment: - RACK_ENV=development - SESSION_SECRET
注意:如果变量名称或者值中⽤到 true | false, yes | no 等表达布尔含义的词汇, 最好放到引号⾥, 避免YAML⾃动解析某些内容为对应的布尔语义:http://yaml.org/type/bool.html中给出了这些特定词汇, 包括
y|Y|yes|Yes|YES|n|N|no|No|NO |true|True|TRUE|false|False|FALSE |on|On|ON|off|Off|OFF
15.expose
暴露端口, 但不映射到宿主机, 只被连接的服务访问。 仅可以指定内部端口为参数, 如下所⽰:
expose: - "3000" - "8000"
16.extends
基于其他模板⽂件进⾏扩展。 例如, 我们已经有了⼀个webapp服务,定义⼀个基础模板⽂件为 common.yml, 如下所⽰:
# common.yml webapp: build: ./webapp environment: - DEBUG=false - SEND_EMAILS=false
再编写⼀个新的development.yml⽂件, 使⽤common.yml中的webapp服务进⾏扩展:
# 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 中定义的容器和数据卷资源。⼀般情况下, 推荐在基础模板中只定义⼀些可以共享的镜像和环境变量, 在扩展模板中具体指定应⽤变量、 链接、 数据卷等信息。
17.external_links
链接到docker-compose.yml外部的容器, 甚⾄并⾮Compose管理的外部容器。 参数格式跟links类似。
external_links: - redis_1 - project_db_1:mysql - project_db_1:postgresql
18.extra_hosts
类似Docker中的--add-host参数, 指定额外的host名称映射信息。
例如:extra_hosts:
- "googledns:8.8.8.8"
- "dockerhub:52.1.157.61"
会在启动后的服务容器中/etc/hosts⽂件中添加如下两条条⽬。
8.8.8.8 googledns
52.1.157.61 dockerhub
19.healthcheck
指定检测应⽤健康状态的机制, 包括检测⽅法(test) 、 间隔
(interval) 、 超时(timeout) 、 重试次数(retries) 、 启动等待时间
(start_period) 等。
例如, 指定检测⽅法为访问8080端⼜, 间隔为30秒, 超时为15秒, 重
试3次, 启动后等待30秒再做检查。
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080"]
interval: 30s
timeout: 15s
retries: 3
start_period: 30s
20.image
指定为镜像名称或镜像ID。 如果镜像在本地不存在, Compose将会尝
试拉去这个镜像。
例如:
image: ubuntu
image: orchardup/postgresql
image: a4bc65fd
21.isolation
配置容器隔离的机制, 包括default、 process和hyperv。22.labels
为容器添加Docker元数据(metadata) 信息。 例如可以为容器添加辅
助说明信息。
labels:
com.startupteam.description: "webapp for a startup team"
com.startupteam.department: "devops department"
com.startupteam.release: "rc3 for v1.0"
23.links
注意: links命令属于旧的⽤法, 可能在后续版本中被移除。
链接到其他服务中的容器。 使⽤服务名称(同时作为别名) 或服务名
称: 服务别名(SERVICE: ALIAS) 格式都可以。
links: - db
- db:database
- redis
使⽤的别名将会⾃动在服务容器中的/etc/hosts⾥创建。 例如:
172.17.2.186 db
172.17.2.186 database
172.17.2.187 redis
被链接容器中相应的环境变量也将被创建。
24.logging
跟⽇志相关的配置, 包括⼀系列⼦配置。
logging.driver: 类似于Docker中的--log-driver参数, 指定⽇志驱动类
型。 ⽬前⽀持三种⽇志驱动类型:
driver: "json-file"
driver: "syslog"
driver: "none"logging.options: ⽇志驱动的相关参数。 例如:
logging:
driver: "syslog"
options:
syslog-address: "tcp://192.168.0.42:123"
或:
logging:
driver: "json-file"
options:
max-size: "1000k"
max-file: "20"
25.network_mode
设置⽹络模式。 使⽤和docker client的--net参数⼀样的值。
network_mode: "none"
network_mode: "bridge"
network_mode: "host"
network_mode: "service:[service name]"
network_mode: "container:[name or id]"
26.networks
所加⼊的⽹络。 需要在顶级的networks字段中定义具体的⽹络信息。
例如, 指定web服务的⽹络为web_net, 并添加服务在⽹络中别名为
web_app。
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/2427.pid
跟主机系统共享进程命名空间。 打开该选项的容器之间, 以及容器和
宿主机系统之间可以通过进程ID来相互访问和操作。
pid: "host"
28.ports
暴露端⼜信息。
使⽤宿主: 容器(HOST: CONTAINER) 格式, 或者仅仅指定容器的
端⼜(宿主将会随机选择端⼜) 都可以。
ports: - "3000"
- "8000:8000"
- "49100:22"
- "127.0.0.1:8001:8001"
或者:
ports: - target: 80
published: 8080
protocol: tcp
mode: ingress
注意
当使⽤HOST: CONTAINER格式来映射端⼜时, 如果你使⽤的容器端
⼜⼩于60并且没放到引号⾥, 可能会得到错误结果, 因为YAML会⾃动解
析xx: yy这种数字格式为60进制。 为避免出现这种问题, 建议数字串都采
⽤引号包括起来的字符串格式。
29.secrets
配置应⽤的秘密数据。可以指定来源秘密、 挂载后名称、 权限等。
例如:
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_secret:
file: ./web_secret.txt
30.security_opt
指定容器模板标签(label) 机制的默认属性(⽤户、 ⾓⾊、 类型、 级
别等) 。
例如, 配置标签的⽤户名和⾓⾊名:
security_opt: - label:user:USER
- label:role:ROLE
31.stop_grace_period
指定应⽤停⽌时, 容器的优雅停⽌期限。 过期后则通过SIGKILL强制
退出。
默认值为10s。
32.stop_signal
指定停⽌容器的信号, 默认为SIGTERM。
33.sysctls配置容器内的内核参数。 Swarm模式中不⽀持。
例如, 指定连接数为4096和开启TCP的syncookies:
sysctls:
net.core.somaxconn: 4096
net.ipv4.tcp_syncookies: 1
34.ulimits
指定容器的ulimits限制值。
例如, 指定最⼤进程数为65535, 指定⽂件句柄数为20000(软限制,
应⽤可以随时修改, 不能超过硬限制) 和40000(系统硬限制, 只能root⽤
户提⾼) 。
ulimits:
nproc: 65535
nofile:
soft: 20000
hard: 40000
35.userns_mode
指定⽤户命名空间模式。 Swarm模式中不⽀持。 例如, 使⽤主机上的
⽤户命名空间:
userns_mode: "host"
36.volumes
数据卷所挂载路径设置。 可以设置宿主机路径(HOST:
CONTAINER) 或加上访问模式(HOST: CONTAINER: ro) 。
⽀持driver、 driver_opts、 external、 labels、 name等⼦配置。
该指令中路径⽀持相对路径。 例如
volumes:- /var/lib/mysql - cache/:/tmp/cache
- ~/configs:/etc/configs/:ro
或者可以使⽤更详细的语法格式:
volumes: - type: volume
source: mydata
target: /data
volume:
nocopy: true
volumes:
mydata:
37.restart
指定重启策略, 可以为no(不重启) 、 always(总是) 、 onfailure(失败时) 、 unless-stopped(除⾮停⽌) 。
注意Swarm模式下要使⽤restart_policy。 在⽣产环境中推荐配置为
always或者unless-stopped。
例如, 配置除⾮停⽌:
restart: unless-stopped
38.deploy
指定部署和运⾏时的容器相关配置。 该命令只在Swarm模式下⽣效,
且只⽀持docker stack deploy命令部署。
例如:
version: '3'
services:
redis:
image: web:stable
deploy:
replicas: 3
update_config:
parallelism: 2
delay: 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分配⼀个域名给服务, ⽤户访问域名时候回按照轮流顺
序返回容器地址。
例如:
version: '3'
services:
redis:
image: web:stable
deploy:
mode: replicated
replicas: 3
endpoint_mode: vip
(2) labels
指定服务的标签。 注意标签信息不会影响到服务内的容器。
例如:
version: "3"
services:
web:
image: web:stable
deploy:
labels:
description: "This is a web application service."
(3) mode
定义容器副本模式, 可以为:global: 每个Swarm节点上只有⼀个该应⽤容器;
replicated: 整个集群中存在指定份数的应⽤容器副本, 默认值。
例如, 指定集群中web应⽤保持3个副本:
version: "3"
services:
web:
image: web:stable
deploy:
mode: replicated
replicas: 3
(4) placement
定义容器放置的限制(constraints) 和配置(preferences) 。 限制可以
指定只有符合要求的节点上才能运⾏该应⽤容器; 配置可以指定容器的分
配策略。 例如, 指定集群中web应⽤容器只存在于⾼安全的节点上, 并且
在带有zone标签的节点上均匀分配。 :
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。
version: '3'
services:redis:
image: web:stable
deploy:
resources:
limits:
cpus: '0.25'
memory: 500M
reservations:
cpus: '0.10'
memory: 200M
(7) restart_policy
指定容器重启的策略。 例如, 指定重启策略为失败时重启, 等待2s,
重启最多尝试3次, 检测状态的等待时间为10s。
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、 先停⽌旧容器
再升级。
version: "3.4"
services:
redis:
image: web:stable
deploy:
replicas: 2
update_config:
parallelism: 2
delay: 10s
order: stop-first39.其他指令
此外, 还有包括domainname、 hostname、 ipc、 mac_address、
privileged、 read_only、 shm_size、 stdin_open、 tty、 user、 working_dir等指
令, 基本跟docker-run中对应参数的功能⼀致。 例如, 指定容器中⼯作⽬
录:
working_dir: /code
指定容器中搜索域名、 主机名、 mac地址等:
domainname: your_website.com
hostname: test
mac_address: 08-00-27-00-0C-0A
允许容器中运⾏⼀些特权命令:
privileged: true
40.读取环境变量
从1.5.0版本开始, Compose模板⽂件⽀持动态读取主机的系统环境变
量。 例如, 下⾯的Compose⽂件将从运⾏它的环境中读取变量
\({MONGO_VERSION}的值(不指定时则采⽤默认值3.2) , 并写⼊执⾏的 指令中。 db: image: "mongo:\){MONGO_VERSION-3.2}"
如果直接执⾏docker-compose up则会启动⼀个mongo: 3.2镜像的容
器; 如果执⾏MONGO_VERSION=2.8 docker-compose up则会启动⼀个
mongo: 2.8镜像的容器。
41.扩展特性
从3.4开始, Compose还⽀持⽤户⾃定义的扩展字段。 利⽤YAML语法
⾥的锚点引⽤功能来引⽤⾃定义字段内容。 例如: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