Docker三剑客:DockerEngine、DockerCompose、DockerMachine
Compose的英文含义为组成、创作、构成,在隔离环境中运行应用程序并与之交互,这个就是Compose的主要目标
1. Docker Compose概述
1.1. Docker Compose 介绍
Docker Compose是一个用于定义和运行多容器Docker应用程序的工具,在隔离环境中运行应用程序并与之交互,这个就是Compose的主要目标
使用Compose,可以使用YAML文件(docker-compose.yml)来配置应用程序的服务,然后,使用单个命令docker-compose up
,可以从配置中创建并启动所有(依赖)服务,比如数据库,队列,高速缓存,Web服务的API,等等。
使用Compose命令行工具,您可以使用单个命令(docker-compose up)为每个依赖项创建和启动一个或多个容器,Compose可以将多页“开发人员入门指南”,简化为单个机器可读的Compose配置文件和一些命令。
- 使用场景:
- 多应用开发环境
- 自动化测试环境
- 单机部署
1.1.1. Compose特性
- 单主机上的多环境隔离:基于使用项目名称将环境彼此隔离(单个环境的多个副本、避免CI环境相互干扰、共享主机上面防止同名服务)
- 应用存储方面,创建容器保留卷数据:容器未删除的话(仅停止),主机卷不会被删除;若容器被删除,在
docker volume prune
时候,会被移除! - 仅重建有变更的容器:缓存用于创建容器的配置,加速容器启动
- 变量在多环境之间组合:支持环境变量设置和传递变更到容器(
extends字段
)
1.1.2. Compose功能 - 管理应用程序整个生命周期的命令
- 服务启动,停止和创建/重建/重新编排
- 服务运行状态查看
- 服务的日志流式输出
- 服务上运行一次性命令
1.1.3. Compose安装
参考:https://docs.docker.com/compose/install/
Mac下的Docker Desktop for Mac已经附带安装了Docker Compose,另外Docker Compose支持远程Docker主机操作
1.2. Compose构建应用流程概述
- 基于
Dockerfile
定义应用运行环境 - 基于
docker-compose.yml
构建应用程序的服务,以便它们可以在隔离的环境中一起运行。 - 运行
docker-compose up
或者compose start
运行整个应用
|
|
1.2.1. 准备应用
可以是Go、PHP、Python、JAVA、NodeJS应用
1.2.2. 准备应用环境(Dockerfile)
- FROM:镜像
- WORKDIR:工作目录
- ENV:指定构建过程中使用到的环境变量,注意与
docker run
的ARG的区别 - RUN:执行指定命令,
- COPY:复制内容,注意与ADD支持解压区别(COPY语义性更好)
- CMD:容器默认命令,可以与ENTRYPOINT配合使用(CMD转为参数了)
参考:https://docs.docker.com/engine/reference/builder/
|
|
1.2.3. 准备服务组装(docker-compose.yml)
此Compose文件定义了两个服务:web和redis。
- version:配置版本
- services:服务组成
- web:服务名称
- redis
- 卷定义
- 单个服务支持:
- 镜像如何build
- 端口映射
- 数据绑定
- 环境变量配置
- 服务依赖
|
|
1.2.4. 创建并启动应用(docker-compose up)
首次运行会基于拉取Docker镜像或者基于本地Dockerfile构建容器,来创建应用服务:
- 创建基础网络
- 拉取两个基础服务的镜像(python、redis)以及创建一个应用镜像(一共3个)
- 运行应用服务(启动python以及redis容器)
- 创建数据卷,与web日志中的/var/log绑定(其他方式有文件夹共享、卷、绑定卷)
- 环境变量设置,将FLASK设定在开发模式下
1.3. Compose命令概述
容器扩容,可以在配置中deploy下的replicas下指定,基于Swarm Mode
不要使用
docker-compose scale web=2 worker=3
或者docker-compose up --scale web=2 worker=3
1.3.1. 构建、移除、重启、停掉等
|
|
1.3.2. 容器命令执行
|
|
1.3.3. 镜像推、拉
|
|
1.3.4. 信息查看
|
|
2. docker-compose.yml配置使用
参见:https://docs.docker.com/compose/compose-file/
Tips,使用版本3的Compose堆栈文件来实现多容器应用程序,服务定义和swarm模式,文件扩展名.yml
或.yaml
扩展名都支持。
docker-compose.yml
文件是定义了应用软件的相关服务组成,以及每个组成的服务的各自的容器构建、端口映射、网络、存储卷、部署、服务依赖的YAML文件,等同于:
- docker container create
- docker network create
- docker volume create
由于一些CMD, EXPOSE,VOLUME,ENV指令都已经在Dockerfile中已指定,故无需再在docker-compose.yml
再次指定
2.1. 镜像构建上下文、参数设定 - (build)
- 最直接的,直接使用某个镜像构建服务:
|
|
- 基于目录下的Dockerfile以及相关上下文以及参数构建服务,相关布尔值可以使用true、false、yes、no、off、on来设定(需加括号):
- 支持上下文
- 支持参数设定
- 支持lables标签设定
|
|
- 资源设定:
- 支持
/dev/shm
(共享内存)
- 支持
|
|
- 多阶段构建,指定target阶段名称
|
|
2.2. 按服务依赖顺序启停 - (depends_on)
|
|
更多服务启停依赖,参考:https://docs.docker.com/compose/startup-order/
2.3. 部署和运行服务 - (deploy)
注意:Compose does not support ‘deploy’ configuration - use
docker stack deploy
to deploy to a swarm
2.3.1. 部署模式、部署更新回滚策略
- endpoint_mode:服务发现方式,为客户端连接到群集的外部指定服务发现方法。
- vip: 默认设置,Docker为服务设定VIP,而无需客户端知道有多少节点(dockerd主机)参与服务,这是是默认设置
- dnsrr: 基于DNS服务发现,基于DNS查询到的DNS条目IP,客户端随后挑选其中一个进行连接
- labels:针对服务设定的标签(web>deploy>labels);在容器上设定标签,需要提升至服务下级(web>lables)
- mode: 设定集群节点的容器部署模式
- global:每个节点一个容器
- replicated: 每个节点指定数量(replicas指定)的多个容器(默认模式)
- replicas: replicated模式下(默认)应运行的容器数
- update_config:配置服务应如何更新,用于配置滚动更新
- delay:一组容器更新等待时间
- failure_action:失败措施(continue|rollback|pause(默认))
- monitor: 更新后监视时间以检测失败(ns|us|ms|s|m|h)
- max_failure_ratio: 失败率
- order:更新期间的操作顺序(start-first|stop-first(默认))
- rollback_config:配置在更新失败的情况下应如何回滚服务
|
|
2.3.2. 部署和运行服务资源限定 - (deploy > resources)
示例中,redis服务被限制为使用不超过50M的内存和0.50(单核的50%)可用处理时间(CPU),并且保留20M了内存和0.25CPU时间(始终可用)。
- limits:资源使用限制
- cpus
- memory
- reservations:保留资源
|
|
2.4. 记录容器运行的服务日志 - (logging)
通常可以基于docker run --log-opt
指定容器的日志选项。基于docker-compose.yml配置中,可以单独指定相关日志驱动和其选项(比如日志旋转大小,保留日志数量等)
- driver驱动类型支持:
- json-file(默认)
- syslog
- none
- journald
- options日志选项类型支持
json-file
和journald
驱动支持docker-compose logs
或者docker-compose up
|
|
2.5. 设置服务网络 - (network)
通常可以基于docker client --network
指定容器的网络选项。基于docker-compose.yml配置中,可以单独指定服务的网络
- networks - 网络模式:服务的顶层
- bridge
- host
- none
- service:[service name]
- container:[container name/id]
- aliases - 网络别名:
- 同网络上面的其他容器或服务,可以基于该网络别名,与别名的容器通信
- Tips:网络范围的别名可以由多个容器共享(无法保证名称解析为确定的哪个容器),甚至可以由多个服务共享(比如共享的代理服务)
- app_net - 指定服务的应用网络,包含每个静态地址的子网
2.5.1. 为容器服务指定静态的IP地址
如果需要IPv6寻址,则enable_ipv6
必须设置该选项
|
|
2.5.2. 顶级networks键允许您指定要创建的网络
- driver:
- overlay:Swarm集群
- bridge:单主机
- host
- none
- attachable:仅在driver设置为时使用overlay,如果设置为true,则除了服务之外,独立容器可以附加到此网络。
- 它可以与也从其他Docker守护程序连接到覆盖网络的服务和独立容器进行通信。
- driver_opts
- external:如果设置为true,则指定此网络已在Compose之外创建(否则直接报错)。
2.6. 设置容器通信端口 - (expose、ports)
- expose: 端口暴露,暴露给被链接的服务访问,不将它们发布到主机
- ports:
- 短语法:指定ports(HOST:CONTAINER)或仅指定容器端口(选择短暂的主机端口),使用低于60的容器端口时可能会遇到错误的结果
- 长语法:target - 容器内的端口、published - 公开端口、prtotocl - udp|tcp、mode - host|ingress
|
|
2.7. 容器重启策略 - (restart)
|
|
2.8. 容器卷 - (volumes)
- 默认情况下,在容器内创建的所有文件都存储在可写容器层中。这意味着:
- 容器不存在,数据会丢失
- 无法轻松移动或者管控容器数据
- 写入容器的可写层需要存储驱动程序来管理文件系统
- 主机和容器存储文件的交互方式:
- volume,卷:卷存储在主机上的文件系统中,非Docker进程不应修改文件系统的这一部分,卷是在Docker中保留数据的最佳方式。
- bind,绑定挂载:主机的文件系统和容器中文件系统绑定,可以在主机和容器中同步修改
- tmpfs,tmpfs挂载,仅存储在主机的内存中,npipe命令管道(windows)
- 卷指令设置
- 短语法(示例db):HOST:CONTAINER
- 若是相对路径,则主机上面路径相对于Compose配置文件的目录
- 长语法
- 短语法(示例db):HOST:CONTAINER
2.8.1. Volumes示例
|
|
2.8.2. Volumes语法说明
- 短语法:
|
|
- 长语法:
- type:安装类型,支持
volume
、bind
、tmpfs
、npipe
- source:挂载源,卷名或者主机路径
- target:容器安装卷或映射的路径
- bind:配置其他绑定选项(propagation)
- volume:nocopy,禁止从容器复制数据
- tmpfs:size(配置tmpfs大小)
- consistency:
consistent
(容器与主机读写一致)、cached
(容器读的是缓存)、delegated
(容器的实体是权威的)
- type:安装类型,支持
参考:https://docs.docker.com/compose/compose-file/#volumes-for-services-swarms-and-stack-files
2.8.3. 服务、Swarm和Stack以及卷
使用服务,Swarm群组(多个Dockerd主机组合在一起)和docker-stack.yml
文件时,请记住,支持服务的任务(容器)可以部署在群中的任何节点上,每次更新服务时,容器可能是在不同的节点上。
如果没有具有指定源的命名卷,Docker会为支持服务(Services)的每个任务创建一个匿名卷,删除关联的容器后,匿名卷不会保留。
如果希望数据保持不变,请使用可识别多主机的命名卷和卷驱动程序,以便可以从任何节点访问数据。或者,对服务设置约束,以便将其任务部署在具有卷的节点上。
2.8.4. 跨服务重用命名卷 - (volumes_from)
- 双服务作为共享卷设置,顶级volumes键下的条目可以为空,在这种情况下,它使用引擎配置的默认驱动程序(在大多数情况下,这是local驱动程序),(可选)您可以使用以下键进行配置:
- driver:卷驱动程序(默认是local)
- driver_opts:卷驱动相关设置,比如驱动类型、选项、驱动
- external:
- name:为卷命名
|
|
2.9. 基础设施杂项相关
- sysctls:设置容器内核参数
- ulimits:设置容器的默认ulimits
- userns_mode
- dns相关
- dns:dns服务IP
- dns_search:dns搜寻域
- entrypoint:覆盖Dockerfile中默认进入点以及CMD命令
- 构建变量相关
- env_file:从文件添加环境变量,可以是单个值或列表,env文件每行都基于
VAR=VAL
模式,#
为注释;另外文件的顺序很重要(尤其是存在重名变量) - environment:环境变量,没有指定则从构建机器上的环境变量
- env_file:从文件添加环境变量,可以是单个值或列表,env文件每行都基于
- external_links:外部链接(推荐使用
network
网络链接),公共共享服务容器,外部docker-compose.yml,指定容器名称 - extra_hosts:为容器添加host映射
- devices:设备映射
- healthcheck:容器状态转变(starting=>健康监测通过=>healthy=>连续失败=>unhealthy)
- 通过在容器内运行命令、禁用从基础映像继承的任何运行状况检查
- interval:间隔多久监测一次
- timeout:超时算失败一次
- retries:最大重试次数,重试连续的健康检查失败才能考虑容器unhealthy
- start-period:提供引导的容器提供初始化时间(容器启动期间,监测失败不算重试失败)
- pid:将PID模式设置为主机PID模式。这打开了容器和主机操作系统之间的PID地址空间共享。
- 容器停止信号
- stop_grace_period
- stop_signal
- 其他相关配置
- domainname
- hostname
- ipc
- mac_address
- privileged
- read_only
- shm_size
- stdin_open
- tty
- user
- working_dir
- 持续时间格式:us,ms,s,m和h,比如
5h34m56s
- 指定字节值:b,k/kb,m/mb,g/gb
container_name
:指定自定义容器名称init
:容器内运行init
|
|
2.10. 配置、秘钥 - (configs、secrets)
顶级configs声明指定每个服务为基础授予对配置的访问权限,配置文件等信息统一管控,类似于顶级的volumes以及networkds
顶级secrets声明定义或引用 可以授予此堆栈中的服务的机密,使用服务secrets可以配置基于每个服务授予对秘密的访问权限。秘密的来源是file或external
|
|
2.11. 变量替换 - (支持.env文件)
若环境变量包含POSTGRES_VERSION=9.3
,则以下镜像会选择postgres:9.3
,如果未设置环境变量,则使用空字符串Compose替换。
可以使用Compose自动查找的.env文件
为环境变量设置默认值,shell环境中设置的值将覆盖.env文件中设置的值(.env仅针对docker-compose up
有效,不对docker stack deploy
有效)。
另外变量支持默认语法,类似于shell中变量的默认值使用:
- ${VARIABLE:-default}:环境变量没设置或设置为空,则为默认的default
- ${VARIABLE-default}
- ${VARIABLE:?err}
- ${VARIABLE?err}
|
|
3. 调试
3.1. 针对应用内容器网络连通调试
以下测试为了方便,均以nginx:alpine
镜像启动,模拟代理层<=>服务层<=>数据存储层通信。
代理层:仅可与服务层(websrv-a、websrv-b)正常网络通信 服务层:websrv可以与代理层、数据存储层通信 数据层:仅可与服务层通信
- 网络连通性应用模拟 - docker-compose.yml
|
|
- proxy容器路由情况
|
|
- websrv容器路由情况(以websrv-a为例)
|
|
- db、mq容器路由情况(以db为例)
|
|
- 网络查看
|
|
针对容器网络互通,可以查看另外一篇文章
3.2. 其他相关错误
3.2.1. docker-compose.yml版本问题
|
|
4. 小结
文章对docker compose进行了简要概览,docker compose主要目的是对服务进行编排(即组合多个服务成一个应用),docker-compose.yml就是一份应用服务的配置清单,标注清楚了服务的依赖服务以及其配置!
通过docker-compose.yml配置文件,docker引擎可以指定应用的每个服务的镜像如何构建,容器如何部署(部署模式、部署份数),容器之间网络是如何互通的,容器内进程对存储卷的读写以及存储设置(支持volume、bind等类型),并且还支持运行容器的资源大小设置(比如打开文件数、服务内存使用大小等),更进一步的配置详情需要参考对应的官方文档。