Docker利器之Compose项目


主要参考来自《Docker 从入门到实践》文章,侵权必删!

Docker Compose 是官方编排项目之一,负责快速的部署分布式应用,定义和运行多个容器的应用。从功能上看,跟 OpenStack 中的 Heat 十分类似。如果不使用的话,我们部署或者搭建一个环境可能需要启动 5~9 容器才能够满足我们的需要,而且更新和维护都不是很方便。

Docker利器之Compose项目


1. 简介说明

分布式系统中常常会使用到,可以极大地方便部署和环境搭建。

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

Compose 中有两个重要的概念:

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

默认管理对象是项目,通过子命令对项目中的一组容器进行便捷地生命周期管理。该项目由 Python编写,实现上调用了 Docker 服务提供的 API 来对容器进行管理。因此,只要所操作的平台支持 Docker API,就可以在其上利用 Compose 来进行编排管理。

Docker利器之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. 命令使用

使用当中最核心的知识点集中在,基础命令的使用和排版文件的编写。

Docker三剑客之Compose项目

  • [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. 实战演示

实际使用才能够真正用法和使用技巧,哈哈哈。

Docker三剑客之Compose项目

  • [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

文章作者: Escape
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Escape !
  目录