第9章 Docker-compose

摘要: 本章详细介绍了 Docker Compose 这一多容器编排管理工具。首先解释了 Compose 的核心概念(服务与项目)及其工作原理,然后展示了完整的命令说明和版本信息。重点讲解了 Compose 模板文件的结构和语法,最后通过 WordPress 博客系统的实战案例,对比了传统 docker run 方式与 Compose 方式的部署差异,演示了如何使用 docker-compose.yml 文件一键启动和管理多个关联容器。

续上篇博客 容器日志全解:Docker 日志输出原理与 logs 命令实战

我们知道使用一个 Dockerfile 模板文件,可以让用户很方便的定义一个单独的应用容器。然而,在日 常工作中,经常会碰到需要多个容器相互配合来完成某项任务的情况。例如要实现一个 Web 项目,除了 Web 服务容器本身,往往还需要再加上后端的数据库服务容器,甚至还包括负载均衡容器等。如果每个 容器都要按顺序手动启停,那么维护工作量将会很大,而且工作效率也很低。

Docker Compose 可以轻松、高效地管理容器,它是一个用于定义和运行多容器的管理工具。

它通过一个单独的 docker-compose.yml 模板文件(YAML 格式)定义一组相关联资源集。

Compose 中有两个重要的概念:

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

Compose 的默认管理对象是项目,通过子命令对项目中的一组容器进行便捷地生命周期管理。

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

在这里插入图片描述

命令说明

[root@docker ~]# docker compose -h
Flag shorthand -h has been deprecated, please use --help

Usage:  docker compose [OPTIONS] COMMAND

Define and run multi-container applications with Docker

Options:
      --all-resources              Include all resources, even those not used by services
      --ansi string                Control when to print ANSI control characters 
("never"|"always"|"auto") (default "auto")
      --compatibility              Run compose in backward compatibility mode
      --dry-run                    Execute command in dry run mode
      --env-file stringArray       Specify an alternate environment file
      -f, --file stringArray       Compose configuration files    
      --parallel int               Control max parallelism, -1 for unlimited
(default -1)
      --profile stringArray        Specify a profile to enable
      --progress string            Set type of progress output (auto, tty, plain, quiet) (default "auto")
      --project-directory string   Specify an alternate working directory
                                   (default: the path of the, first specified, Compose file)
  -p, --project-name string        Project name
Commands:
  attach      Attach local standard input, output, and error streams to a service's running container
  build       Build or rebuild services
  config      Parse, resolve and render compose file in canonical format
  cp          Copy files/folders between a service container and the local
filesystem
  create      Creates containers for a service
  down        Stop and remove containers, networks
  events      Receive real time events from containers
  exec        Execute a command in a running container
  images      List images used by the created containers
  kill        Force stop service containers
  logs        View output from containers
  ls          List running compose projects
  pause       Pause services
  port        Print the public port for a port binding
  ps          List containers
  pull        Pull service images
  push        Push service images
  restart     Restart service containers
  rm          Removes stopped service containers
  run         Run a one-off command on a service
  scale       Scale services
  start       Start services
  stats       Display a live stream of container(s) resource usage statistics
  stop        Stop services
  top         Display the running processes
  unpause     Unpause services
  up          Create and start containers
  version     Show the Docker Compose version information
  wait        Block until the first service container stops
  watch       Watch build context for service and rebuild/refresh containers when files are updated

Run 'docker compose COMMAND --help' for more information on a command.

version

[root@docker ~]# docker compose version
Docker Compose version v2.27.0

Compose 模板

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

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

模板文件结构

  • version:用来定义模板文件的版本,不同版本的模板,格式也不一样。
  • 资源列表:用来定义资源清单,包括service、secret、network、volume等。
  • 注释行:#开头的注释行。

示例:使用版本2模板,定义一个使用httpd镜像的services。

version: "2"

services:
  webapp:
    image: httpd

详细结构参考官方 https://docs.docker.com

实战-Wordpress

回顾一下如果用docker run改如何操作:

[root@docker ~]# docker run -tid --name db --restart always -v /db:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=huawei -e MYSQL_DATABASE=wordpress mysql
d3fa1d9e6ecc285427b38bca95130cade90ca69ee9487825db92b3bc8af4c995
[root@docker ~]# docker run -tid --name blog -v /web:/var/www/html -p 80:80 --link db -e WORDPRESS_DB_HOST=db -e WORDPRESS_DB_USER=root -e WORDPRESS_DB_PASSWORD=huawei -e WORDPRESS_DB_NAME=wordpress wordpress
b5b80bd69f57bff576415f2e449a23fe6cb37be353f9b4b69d24d60a2fb9a6e1
[root@docker ~]#
[root@docker ~]# docker ps -a
CONTAINER ID   IMAGE       COMMAND                  CREATED          STATUS       
   PORTS                               NAMES
b5b80bd69f57   wordpress   "docker-entrypoint.s…"   13 seconds ago   Up 12 seconds   0.0.0.0:80->80/tcp, :::80->80/tcp   blog
d3fa1d9e6ecc   mysql       "docker-entrypoint.s…"   26 seconds ago   Up 25 seconds   3306/tcp, 33060/tcp                 db

MYSQL_DATABASE=wordpress

测试效果:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

通过docker compose来统一管理这两个容器呢?

假设新建一个名为 wordpress 的文件夹,然后进入这个文件夹,创建 docker-compose.yml文件

# 删除之前的环境
[root@docker ~]# docker rm -f $(docker ps -aq)

# 通过docker compose实现多个容器一起启动
[root@docker ~]# mkdir wordpress
[root@docker ~]# cd wordpress/
[root@docker wordpress]# vim docker-compose.yml
services:
  blog:                           #服务名字,相当于docker run的时候指定的一个名称
    image: wordpress:latest            #必选,镜像的名字
    restart: always
    links:
      - db
    ports:                        #可选,等价于 docker run 里的 -p 选项指定端口映射
      - "80:80"    
    environment:           #可选,等价于 docker run 里的 --env 选项设置环境变量
      - WORDPRESS_DB_HOST=db
      - WORDPRESS_DB_USER=root
      - WORDPRESS_DB_PASSWORD=huawei
      - WORDPRESS_DB_NAME=wordpress
  db:
    image: mysql:latest
    restart: always
    environment:
      - MYSQL_ROOT_PASSWORD=huawei
      - MYSQL_DATABASE=wordpress
            
[root@docker wordpress]# docker compose config -q    #检测语法

后端运行

[root@docker wordpress]# docker compose up -d
[+] Running 3/3
 ✔ Network wordpress_default   Created     0.0s                                   
                                              
 ✔ Container wordpress-db-1    Started     0.3s                                   
                                              
 ✔ Container wordpress-blog-1  Started     0.6s    

查看现象

[root@docker ~]# docker ps
CONTAINER ID   IMAGE              COMMAND                  CREATED              STATUS   
           PORTS                               NAMES
85b438b2ff89   wordpress:latest   "docker-entrypoint.s…"   About a minute ago   Up About a minute   0.0.0.0:80->80/tcp, :::80->80/tcp   wordpress-blog-1
d3fa1d9e6ecc   mysql:latest       "docker-entrypoint.s…"   About a minute ago   Up About a minute   3306/tcp, 33060/tcp                 wordpress-db-1

在这里插入图片描述
docker compose 实战

[root@docker ~]# mkdir porject
[root@docker ~]# cd project/
[root@docker project]# vim docker-compose.yml
# 自定义网络,所有服务同网段
networks:
  web-net:
    driver: bridge
# 数据卷持久化
volumes:
  mysql-data:
  nginx-conf:
  
services:
# MySQL 数据库
  mysql:
    image: mysql:5.7
    container_name: mysql-db
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: 123456
      MYSQL_DATABASE: webdb
      MYSQL_USER: webuser
      MYSQL_PASSWORD: web123456
    volumes:
      - mysql-data:/var/lib/mysql
    ports:
      - "3306:3306"
    networks:
      - web-net
    command: --default-authentication plugin=mysql_native_password
    
# 后端网站1
  web1:
    image: nginx:alpine
    container_name: web-site1
    restart: always
    networks:
      - web-net
    environment:
      DB_HOST: mysql-db
      DB_PORT: 3306
      DB_NAME: webdb
    volumes:
      - ./site1:/usr/share/nginx/html
      
# 后端网站2
  web2:
    image: nginx:alpine
    container_name: web-site2
    restart: always
    networks:
      - web-net
    environment:
      DB_HOST: mysql-db
      DB_PORT: 3306
      DB_NAME: webdb
    volumes:
      - ./site2:/usr/share/nginx/html
      
# 后端网站3
  web3:
    image: nginx:alpine
    container_name: web-site3
    restart: always
    networks:
      - web-net
    environment:
      DB_HOST: mysql-db
      DB_PORT: 3306
      DB_NAME: webdb
    volumes:
    - ./site3:/usr/share/nginx/html
    
# 前端Nginx负载均衡
  nginx-lb:
    image: nginx:alpine
    container_name: nginx-loadbalance
    restart: always
    ports:
      - "80:80"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
      - nginx-conf:/etc/nginx/conf.d
    networks:
      - web-net
    depends_on:
      - web1
      - web2
      - web3
      - mysql

新建 Nginx 负载均衡配置

[root@docker project]# mkdir nginx
[root@docker project]# vim nginx/nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;

events {
    worker_connections 1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    # 定义后端服务器集群
    upstream web_server_pool {
        server web-site1:80 weight=1;
        server web-site2:80 weight=2;
        server web-site3:80 weight=3;
    }
    
    server {
        listen 80;
        server_name localhost;

        location / {
            proxy_pass http://web_server_pool;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
         }
    }
}

准备网站首页内容

[root@docker project]# mkdir site1 site2 site3
[root@docker project]# echo site1 > site1/index.html
[root@docker project]# echo site2 > site2/index.html
[root@docker project]# echo site3 > site3/index.html

检查

[root@docker project]# tree
.
├── docker-compose.yml
├── nginx
│   └── nginx.conf
├── site1
│   └── index.html
├── site2
│   └── index.html
└── site3
    └── index.html
    
4 directories, 5 files
[root@docker project]# docker compose up -d

测试

[root@docker project]# for n in {1..6}; do curl http://192.168.108.30 -s; done | sort |uniq -c
      1 site1
      2 site2
      3 site3

更多推荐