主要参考来自《Docker 从入门到实践》文章,侵权必删!
Docker Compose 是官方编排项目之一,负责快速的部署分布式应用,定义和运行多个容器的应用。从功能上看,跟 OpenStack 中的 Heat 十分类似。如果不使用的话,我们部署或者搭建一个环境可能需要启动 5~9 容器才能够满足我们的需要,而且更新和维护都不是很方便。
1. 简介说明
分布式系统中常常会使用到,可以极大地方便部署和环境搭建。
我们知道使用一个 Dockerfile 模板文件,可以让用户很方便的定义一个单独的应用容器。然而,在日常工作中,经常会碰到需要多个容器相互配合来完成某项任务的情况。例如要实现一个 Web 项目,除了 Web 服务容器本身,往往还需要再加上后端的数据库服务容器,甚至还包括负载均衡容器等,Compose 恰好满足了这样的需求。
Compose 中有两个重要的概念:
- 服务 (service)
- 一个应用的容器,实际上可以包括若干运行相同镜像的容器实例
- 项目 (project)
- 由一组关联的应用容器组成的一个完整业务单元
- 在 docker-compose.yml 文件中定义,由多个服务构建而成
- 一个项目可以由多个服务关联而成,Compose 面向项目进行管理
默认管理对象是项目,通过子命令对项目中的一组容器进行便捷地生命周期管理。该项目由 Python编写,实现上调用了 Docker 服务提供的 API 来对容器进行管理。因此,只要所操作的平台支持 Docker API,就可以在其上利用 Compose 来进行编排管理。
2. 安装卸载
Compose支持Linux/macOS/Windows三大操作系统平台。
- [1] 二进制安装 - 自带了
$ sudo apt-get update $ sudo apt-get install docker-compose-plugin
- [2] PIP 包安装
# 从pip源中安装 $ sudo pip install -U docker-compose
- [3] 自动补全命令 - 新版可能不用加了
# linux $ curl -L https://raw.githubusercontent.com/docker/compose/1.8.0/contrib/completion/bash/docker-compose > /etc/bash_completion.d/docker-compose # mac $ brew install bash-completion $ curl -L https://raw.githubusercontent.com/docker/docker/v$(docker version -f "{{.Client.Version}}")/contrib/completion/bash/docker -o /usr/local/etc/bash_completion.d/docker
- [3] 卸载方式
# 二进制包方式安装 $ sudo sudo apt-get purge docker-compose-plugin $ sudo rm -rf /var/lib/docker $ sudo rm -rf /var/lib/containerd # 通过pip安装的 $ sudo pip uninstall docker-compose
- [4] 注意事项
# 如果启动时报如下错误,则说明curl安装方式下载的包不完整 [60791] Cannot open self /usr/local/bin/docker-compose or archive /usr/local/bin/docker-compose.pkg
3. 命令使用
使用当中最核心的知识点集中在,基础命令的使用和排版文件的编写。
- 需要详细了解命令使用,请参考《官方命令使用》
- [1] 命令格式
# 命令对象与格式 # 大部分命令的对象既可以是项目也可以是服务或者容器,默认为项目 docker-compose [-f=<arg>...] [options] [COMMAND] [ARGS...]
编号 | 命令选项 | 选项说明 |
---|---|---|
1 | -f/--file FILE | 指定使用的模板文件,默认为docker-compose.yml文件 |
2 | -p/--project-name NAME | 指定项目名称,默认将使用所在子目录名称作为项目名 |
3 | --project-directory PATH | 指定另一个工作目录,默认为docker-compose.yml所在的路径 |
4 | --env-file PATH | 指定一个环境变量配置文件 |
5 | --verbose | 输出更多调试信息 |
# 指定配置文件 $ docker-compose -f ./docker-compose.yml up -d # 设置项目名称(有冲突时非常重要) $ docker-compose -p app1 up -d
- [2] 常用命令
编号 | 命令使用 | 使用说明 | 命令选项 |
---|---|---|---|
1 | build | 构建或重构项目中的容器服务 | --force-rm/--no-cache |
2 | config | 验证模板文件格式是否正确,正确或错误都有回显 | --services |
3 | up | 将自动完成构建镜像、服务创建启动并关联服务相操作 | -d/--no-deps |
4 | down | 将会停止up命令所启动的容器,并移除对应网络 | --volumes |
5 | run | 在指定服务上执行一个命令 | -d/--name NAME |
6 | exec | 进入指定的容器里面,可以直接运行对应命令 | --env KEY=VAL |
7 | start | 启动已经存在的服务容器 | - |
8 | stop | 停止已经处于运行状态的容器但不删除它 | - |
9 | restart | 重启项目中的服务 | -t TIMEOUT |
10 | pause | 暂停一个服务容器 | - |
11 | unpause | 恢复处于暂停状态中的服务 | - |
# 启动服务 docker-compose -f ./docker-compose.yml up -d docker-compose -f ./docker-compose.yml up -d eureka # 执行命令 $ docker-compose run ubuntu ping docker.com $ docker-compose run --no-deps web python manage.py shell # 起停服务 $ docker-compose start eureka $ docker-compose stop eureka $ docker-compose rm eureka # 删除进程 $ docker-compose kill eureka $ docker-compose kill -s SIGINT
- [3] 高级用法
编号 | 命令使用 | 使用说明 | 命令选项 |
---|---|---|---|
1 | top | 查看各个服务容器内运行的进程 | - |
2 | ps | 现在现在运行的容器状态,包括名称、端口等信息 | -a/--filter KEY=VAL |
3 | port | 打印端口绑定的公共端口 | --protocol=proto |
4 | logs | 显示通过该命令运行的所有容器日志(不知道容器的话) | -f/-t/--tail="all" |
5 | rm | 删除所有停止状态的服务容器 | -f/-v |
6 | kill | 发送SIGKILL信号来停止容器,支持-s参数指定信号 | -s SIGNAL |
7 | images | 列出镜像列表 | -q |
8 | pull | 下载容器镜像 | -q/--parallel |
9 | push | 推送容器镜像 | --ignore-push-failures |
10 | scale | 设置指定服务运行的容器个数 | -t |
11 | events | 从容器接收 docker 的日志监控日志 | --json |
# 查看日志 $ docker-compose logs -f -t # 查看端口 $ docker-compose port eureka 8761 # 查看进程 $ docker-compose ps $ docker-compose ps eureka $ docker-compose top $ docker-compoes top eureka # 启动副本 # 注意这里不能在配置文件中使用container_name参数来固定名称 $ docker-compose scale web=3 db=2 # 以json的形式输出nginx的docker日志 $ docker-compose events --json nginx
4. 模板编写
根据工作的实际需要来选择,排版模板的版本。
- [1] 常用命令
编号 | 命令使用 | 使用说明 | 命令选项 |
---|---|---|---|
1 | build | 自动构建镜像并使用 | context/dockerfile |
2 | image | 指定为镜像名称或镜像 | |
3 | command | 覆盖容器启动后默认执行的命令 | - |
4 | container_name | 指定容器名称,使用之后无法进行扩展 | - |
5 | volumes | 数据卷所挂载路径设置,可以设置宿主机路径或加上访问模式 | - |
6 | restart | 指定容器退出后的重启策略为始终重启 | - |
7 | depends_on | 解决容器的依赖、启动先后的问题 | - |
8 | environment | 设置环境变量,可以使用数组或字典两种格式,最好放到引号里 | - |
9 | env_file | 从文件中获取环境变量,可以为单独的文件路径或列表 | - |
10 | expose | 暴露端口,但不映射到宿主机,只被连接的服务访问 | - |
11 | ports | 暴露端口信息 | - |
12 | extra_hosts | 类似--add-host参数,指定额外的host名称映射信息 | - |
13 | networks | 配置容器连接的网络 | driver/ipam |
14 | network_mode | 设置网络模式,使用方式和docker run的 --network参数一样的值 | - |
15 | sysctls | 配置容器内核参数 | - |
16 | privileged | 允许容器中运行一些特权命令 | - |
17 | runtime | 指定容器运行时的方式,通常用户指定GPU使用 | 版本2.3特有 |
- [2] 高级用法
编号 | 命令使用 | 使用说明 | 命令选项 |
---|---|---|---|
1 | user | 指定容器中运行应用的用户名 | - |
2 | working_dir | 指定容器中工作目录 | - |
3 | entrypoint | 指定服务容器启动后执行的入口文件 | - |
4 | logging | 配置日志选项 | driver/options |
5 | devices | 指定设备映射关系 | - |
6 | healthcheck | 通过命令检查容器是否健康运行 | test |
7 | dns | 自定义DNS服务器,可以是一个值也可以是一个列表 | - |
8 | dns_search | 配置DNS搜索域,可以是一个值也可以是一个列表 | - |
9 | tmpfs | 挂载一个tmpfs文件系统到容器 | - |
10 | labels | 为容器添加额外信息,例如为容器添加辅助说明信息 | - |
11 | pid | 跟主机系统共享进程命名空间 | - |
12 | secrets | 存储敏感数据,例如mysql服务密码 | - |
13 | stop_signal | 设置另一个信号来停止容器,在默认情况下使用的是SIGTERM停止容器 | - |
14 | ulimits | 指定容器的ulimits限制值 | nproc/nofile |
15 | configs | 仅用于Swarm配置时使用 | 版本3特有 |
16 | deploy | 仅用于Swarm部署时使用 | 版本3.3特有 |
5. 实战演示
实际使用才能够真正用法和使用技巧,哈哈哈。
- [1] 搭建 Django 开发环境
version: "3" services: db: image: postgres web: build: . command: python3 manage.py runserver 0.0.0.0:8000 volumes: - .:/code ports: - "8000:8000" links: - db
- [2] 搭建 WordPress 应用程序
version: "3" services: db: image: mysql:5.7 volumes: - db_data:/var/lib/mysql restart: always environment: MYSQL_ROOT_PASSWORD: somewordpress MYSQL_DATABASE: wordpress MYSQL_USER: wordpress MYSQL_PASSWORD: wordpress wordpress: depends_on: - db image: wordpress:latest ports: - "8000:80" restart: always environment: WORDPRESS_DB_HOST: db:3306 WORDPRESS_DB_USER: wordpress WORDPRESS_DB_PASSWORD: wordpress volumes: db_data:
- [3] 控制容器启动顺序
version: "2" services: mysql: image: mysql:5.7 expose: - "3306" environment: - MYSQL_ROOT_PASSWORD=123456 wordpress: image: wordpress ports: - "80:80" volumes: - ./wait-for-it.sh:/wait-for-it.sh environment: - WORDPRESS_DB_HOST=mysql - WORDPRESS_DB_USER=root - WORDPRESS_DB_PASSWORD=123456 entrypoint: "sh /wait-for-it.sh mysql:3306 -- docker-entrypoint.sh" command: ["apache2-foreground"]
- [4] 搭建运行 ELK 环境
version: "2" services: elasticsearch: image: elasticsearch ports: - "9200:9200" # REST API端口 - "9300:9300" # RPC端口 networks: elk_network: ipv4_address: 172.30.0.10 logstash: image: logstash command: logstash -f /etc/logstash/conf.d/logstash.conf volumes: - ./config:/etc/logstash/conf.d - /opt/build:/opt/build ports: - "5000:5000" networks: elk_network: ipv4_address: 172.30.0.11 kibana: image: kibana environment: - ELASTICSEARCH_URL=http://elasticsearch:9200 ports: - "5601:5601" networks: elk_network: ipv4_address: 172.30.0.12 networks: elk_network: driver: bridge ipam: driver: default config: - subnet: 172.30.0.0/16 gateway: 172.30.0.1
# 配置logstash.conf文件的参考示例 input { file { codec => json path => "/opt/build/*.json" } } filter { grok { match => { "message" => "%{TIMESTAMP_ISO8601:timestamp}s+%{LOGLEVEL:severity}s+[%{DATA:service},%{DATA:trace},%{DATA:span},%{DATA:exportable}]s+%{DATA:pid}---s+[%{DATA:thread}]s+%{DATA:class}s+:s+%{GREEDYDATA:rest}" } } } output { elasticsearch { hosts => "elasticsearch:9200" } }
- [5] 来一个高级的实例
$ docker swarm init docker stack deploy --compose-file docker-stack.yml vote docker stack services vote
version: "3" services: redis: image: redis:alpine ports: - "6379" networks: - frontend deploy: replicas: 2 update_config: parallelism: 2 delay: 10s restart_policy: condition: on-failure db: image: postgres:9.4 volumes: - db-data:/var/lib/postgresql/data networks: - backend deploy: placement: constraints: [node.role == manager] vote: image: dockersamples/examplevotingapp_vote:before ports: - 5000:80 networks: - frontend depends_on: - redis deploy: replicas: 2 update_config: parallelism: 2 restart_policy: condition: on-failure result: image: dockersamples/examplevotingapp_result:before ports: - 5001:80 networks: - backend depends_on: - db deploy: replicas: 1 update_config: parallelism: 2 delay: 10s restart_policy: condition: on-failure worker: image: dockersamples/examplevotingapp_worker networks: - frontend - backend deploy: mode: replicated replicas: 1 labels: [APP=VOTING] restart_policy: condition: on-failure delay: 10s max_attempts: 3 window: 120s placement: constraints: [node.role == manager] visualizer: image: dockersamples/visualizer ports: - "8080:8080" stop_grace_period: 1m30s volumes: - /var/run/docker.sock:/var/run/docker.sock deploy: placement: constraints: [node.role == manager] networks: frontend: backend: volumes: db-data:
6. 注意事项
运行容器的使用是有一定的实用技巧的,比如后台启动、不依赖启动等:
# 编译运行 $ docker-compose build web $ docker-compose up --no-deps -d web