一文搞懂Docker Compose

什么是Docker Compose

Docker Compose 是 Docker 的一个编排管理工具,它允许你使用一个 YAML 文件来配置应用程序的服务。通过这个文件,你可以定义多个容器如何通过网络相互连接,以及如何配置它们的环境变量、卷挂载、端口映射等。这使得在单个主机上运行复杂的多容器应用程序变得非常简单和直观。
Docker Compose主要解决了docker run指令以及docker build后需要手动运行docker run的问题。

Docker Compose主要概念

  • 服务(Services):在 Docker Compose 文件中,一个服务通常指的是一个容器。你可以定义多个服务,每个服务都运行一个或多个容器实例。例如,你的应用程序可能包含一个 Web 服务和一个数据库服务。

  • 网络(Networks):Docker Compose 可以创建和管理 Docker 网络,以便服务之间可以相互通信。默认情况下,Docker Compose 会为每个服务创建一个网络,但你也可以定义跨多个服务的自定义网络。

  • 卷(Volumes):卷是 Docker 中用于持久化数据的一种机制。在 Docker Compose 中,你可以定义卷,并将卷挂载到容器内的特定路径上,这样即使容器被删除,数据也不会丢失。

  • 环境变量(Environment Variables):你可以为服务定义环境变量,这些变量可以在容器内部被读取和使用。这对于配置应用程序的设置非常有用。

  • 依赖(Dependencies):你可以在 Docker Compose 文件中定义服务的依赖关系,确保在启动服务时按照正确的顺序进行。例如,你可能希望先启动数据库服务,然后再启动依赖于数据库的服务。

安装Docker Compose

Docker Compose项目地址:https://github.com/docker/compose
安装环境信息

IP 系统 规格
10.0.0.10 Ubuntu22.04 2c4g

安装前置准备:需要安装Docker

安装步骤:

# 下载Docker Compose
[root@lb ~]# wget https://github.com/docker/compose/releases/download/v2.35.0/docker-compose-linux-x86_64
[root@lb ~]# ll docker-compose-linux-x86_64
-rw-r--r-- 1 root root 73664588 Apr 19 14:42 docker-compose-linux-x86_64

# 移动至/usr/bin/docker-compose
[root@lb ~]# mv docker-compose-linux-x86_64 /usr/bin/docker-compose

# 授予权限
[root@lb ~]# chmod +x /usr/bin/docker-compose
[root@lb ~]# ll /usr/bin/docker-compose
-rwxr-xr-x 1 root root 73664588 Apr 19 14:42 /usr/bin/docker-compose*

# 检查
[root@lb ~]# docker-compose version
Docker Compose version v2.35.0

Docker Compose常用命令

Docker Compose的命令非常多,下面列举几个常用的,后文遇到新的命令继续讲解

容器相关

  • docker-compose up -d:相当于docker run -d,创建并后台运行容器
  • docker-compose ps:查看容器运行情况,只有-q选项
  • docker-compose down:删除容器,删除所有容器的所有内容(网络、数据卷)
  • docker-compose start:启动容器
  • docker-compose stop:容器关闭
  • docker-compose restart:重启容器
  • docker-compose top:查看容器进程信息
  • docker-compose logs:查看容器日志
  • docker-compose rm:删除容器
  • docker-compose exec:进入容器

镜像相关

  • docker-compose pull:拉取服务的镜像
  • docker-compose push:推送服务的镜像
  • docker-compose build:构建服务镜像

Docker Compose文件中常用指令

官网文章:https://docs.docker.com/reference/compose-file/services/
Docker Compose文件是一个yaml文件,且运行docker-compose命令时,所在的目录下必须有一个docker-compose.yaml或者compose.yaml文件。

services

Compose 文件必须将services设置为顶级元素,services指定运行容器的相关信息,可以理解成docker run指令的集合
示例:

# docker-compose文件
[root@lb ~/services]# cat docker-compose.yaml
services:
  # 服务名称
  web:
    image: nginx:latest
    ports:
      - "8080:80"

# 运行容器
[root@lb ~/services]# docker-compose up -d
[+] Running 1/1
 ✔ Container services-web-1  Started

# 查看运行的容器
[root@lb ~/services]# docker-compose ps
NAME             IMAGE          COMMAND                  SERVICE   CREATED              STATUS              PORTS
services-web-1   nginx:latest   "/docker-entrypoint.…"   web       About a minute ago   Up About a minute   0.0.0.0:8080->80/tcp, [::]:8080->80/tcp

image

指定容器运行时的基础镜像

ports

指定容器运行时的端口号,可以写多个

container_name

指定容器的名字,没有container_name标签时,会以services-[services_name]-[services_num]为容器名称
示例:

[root@lb ~/container_name]# cat docker-compose.yaml
services:
  web:
    image: nginx:latest
    # 指定容器名称
    container_name: nginx_1
    ports:
      - "8081:80"
   
[root@lb ~/container_name]# docker-compose up -d
[+] Running 2/2
 ✔ Network container_name_default  Created                                                                                                                                                                0.1s
 ✔ Container nginx_1               Started                                                                                                                                                                0.2s
[root@lb ~/container_name]# docker-compose ps -a
NAME      IMAGE          COMMAND                  SERVICE   CREATED         STATUS         PORTS
nginx_1   nginx:latest   "/docker-entrypoint.…"   web       5 seconds ago   Up 5 seconds   0.0.0.0:8081->80/tcp, [::]:8081->80/tcp

build

运行Dockerfile,构建镜像使用,有几个子标签

context

指定Dockerfile所在的目录

dockerfile

指定Dockerfile的文件名,同docker build -f指令,该指令可以不写,默认是Dockerfile

示例:

[root@lb ~/build]# cat compose.yaml
services:
  zrlog:
    container_name: zrlog
    # build指令使用
    build:
      context: ./zrlog
      dockerfile: Dockerfile
    ports:
      - "8082:8080"
   
# 构建镜像
[root@lb ~/build]# docker-compose build
Compose can now delegate builds to bake for better performance.
 To do so, set COMPOSE_BAKE=true.
[+] Building 6.5s (9/9) FINISHED                                                                                                                                                                docker:default
 => [zrlog internal] load build definition from Dockerfile                                                                                                                                                0.0s
 => => transferring dockerfile: 409B                                                                                                                                                                      0.0s
 => [zrlog internal] load metadata for docker.io/library/tomcat:9.0.87-jdk8-corretto                                                                                                                      6.3s
 => [zrlog internal] load .dockerignore                                                                                                                                                                   0.0s
 => => transferring context: 2B                                                                                                                                                                           0.0s
 => [zrlog internal] load build context                                                                                                                                                                   0.1s
 => => transferring context: 10.80MB                                                                                                                                                                      0.1s
 => [zrlog 1/3] FROM docker.io/library/tomcat:9.0.87-jdk8-corretto@sha256:6928733a4f4c15d61c45a14b0197fe9a160f49f6f13b1b0b06310561cb320ef0                             
 => => writing image sha256:0d6bbaa1db8bf9d30e976c17f2991aca20e6b6e070be646b85240e1ec0ffdc71                                                                                                              0.0s
 => => naming to docker.io/library/build-zrlog                                                                                                                                                            0.0s
 => [zrlog] resolving provenance for metadata file                                                                                                                                                        0.0s
[+] Building 1/1
 ✔ zrlog  Built                                                                                                                                                                                           0.0s
# 启动镜像
[root@lb ~/build]# docker-compose up -d
[+] Running 2/2
 ✔ Network build_default    Created                                                                                                                                                                       0.1s
 ✔ Container build-zrlog-1  Started                              

[root@lb ~/build]# docker-compose ps
NAME      IMAGE         COMMAND             SERVICE   CREATED              STATUS                        PORTS
zrlog     build-zrlog   "catalina.sh run"   zrlog     About a minute ago   Up About a minute (healthy)   0.0.0.0:8082->8080/tcp, [::]:8082->8080/tcp

environment

docker run -e选项,指定容器运行后的环境变量

示例:

[root@lb ~/environment]# cat compose.yaml
services:
  db:
    image: mysql:5.7
    container_name: mysql_db
    ports:
      - "3306:3306"
    environment:
      # 指定MySQL root的密码
      - "MYSQL_ROOT_PASSWORD=root123"
      # 指定创建一个zrlog的数据库
      - "MYSQL_DATABASE=zrlog"
# 运行
[root@lb ~/environment]# docker-compose up -d
[+] Running 2/2
 ✔ Network environment_default  Created                                                                                                                                                                   0.1s
 ✔ Container mysql_db           Started                                                                       

# check
[root@lb ~/environment]# docker-compose ps -a
NAME       IMAGE       COMMAND                  SERVICE   CREATED          STATUS          PORTS
mysql_db   mysql:5.7   "docker-entrypoint.s…"   db        14 seconds ago   Up 14 seconds   0.0.0.0:3306->3306/tcp, [::]:3306->3306/tcp, 33060/tcp

restart

指定容器的重启方式,和docker run --restart选项一致
重启方式:

  • always:自动重启
  • unless-stopped:只在容器关闭,停止的时候重启
  • on-failure:只在失败的时候重启

示例:

services:
  db:
    # 指定重启策略
    restart: always
    image: mysql:5.7
    container_name: mysql_db
    ports:
      - "3306:3306"
    environment:
      # 指定MySQL root的密码
      - "MYSQL_ROOT_PASSWORD=root123"
      # 指定创建一个zrlog的数据库
      - "MYSQL_DATABASE=zrlog"

volumes

官网文章:https://docs.docker.com/reference/compose-file/volumes/
volumes指令在Compose文件中有两个作用,作为顶级元素时,volume会创建一个数据卷,作为子级元素时,会为容器挂载数据卷。

示例:

[root@lb ~/volumes]# cat compose.yaml
services:
  db:
    # 指定重启策略
    restart: always
    image: mysql:5.7
    container_name: mysql_db_1
    ports:
      - "3307:3306"
    environment:
      # 指定MySQL root的密码
      - "MYSQL_ROOT_PASSWORD=root123"
      # 指定创建一个zrlog的数据库
      - "MYSQL_DATABASE=zrlog"
    volumes:
      - mysql_data:/var/lib/mysql
   
# 创建mysql_data的数据卷
volumes:
  mysql_data:
# 启动容器  
[root@lb ~/volumes]# docker-compose up -d
[+] Running 1/1
 ✔ Container mysql_db_1  Started                                                                             # 检查                                                                                             0.3s
[root@lb ~/volumes]# docker-compose ps -a
NAME         IMAGE       COMMAND                  SERVICE   CREATED         STATUS         PORTS
mysql_db_1   mysql:5.7   "docker-entrypoint.s…"   db        4 seconds ago   Up 4 seconds   33060/tcp, 0.0.0.0:3307->3306/tcp, [::]:3307->3306/tcp

# 检查数据卷
[root@lb ~/volumes]# docker inspect mysql_data
[
    {
        "CreatedAt": "2025-04-12T15:42:17+08:00",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/mysql_data/_data",
        "Name": "mysql_data",
        "Options": null,
        "Scope": "local"
    }
]

当需要挂载到本机宿主机时,仅使用次级元素的volumes即可

示例:

services:
  web:
    image: nginx:latest
    volumes:
      - ./html:/usr/share/nginx/html

可以使用外部存储卷

示例:

services:
  web:
    image: nginx:latest
    volumes:
      - web_data:/usr/share/nginx/html
volumes:
  web_data:
  #external指定此卷已存在于平台上,并且其生命周期由应用程序之外的生命周期管理。如果卷不存在,Compose 将不会创建该卷并返回错误。
    external: true

healthcheck

healthcheck用于定义服务的健康检查机制。通过健康检查,可以确保容器在启动后能够正常运行,并且在容器不可用时自动重启或重新调度.

其子元素有:

  • test:定义健康检查的命令。可以是一个命令或一个脚本。
  • interval:两次健康检查之间的间隔时间(默认单位为秒)。
  • timeout:单次健康检查的超时时间。
  • retries:健康检查失败后重试的次数。
  • start_period:容器启动后开始健康检查的延迟时间。
    示例:
services:
  web:
    image: nginx:latest
    ports:
      - "80:80"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 5s

depends_on

depends_on用于控制服务之间的启动顺序。它确保在启动某个服务之前,其依赖的服务已经启动。例如web服务依赖数据库服务,需要数据库服务先启动时可以使用depends_on。

虽然depends_on确保了服务的启动顺序,但它不会等待服务完全启动后再启动依赖的服务,例如,数据库服务可能还在初始化过程中,而web服务已经启动了,这可能会导致web应用程序无法连接到数据库服务,这个时候需要使用healthcheck

depends_on只会影响容器的启动顺序,不会影响容器的停止顺序
示例:

services:
  web:
    image: nginx:latest
    ports:
      - "80:80"
    # 指定依赖db服务
    depends_on:
      db:
        condition: service_healthy
  db:
    image: mysql:latest
    environment:
      - "MYSQL_ROOT_PASSWORD=root123"
    # 健康检查
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s
      timeout: 5s
      retries: 5

links(在Docker Compose版本3以上已被废弃)

links 是一个用于定义服务之间网络连接的指令。它允许一个服务访问另一个服务的容器,并通过服务名称进行通信。虽然 links 在 Docker Compose 的早期版本中非常常用,但在 Docker Compose 版本 3 及以上中,links 已被废弃,推荐使用默认的网络功能来实现服务之间的通信。

links的作用:

  • 建立网络连接:links 用于在服务之间建立网络连接,允许一个服务访问另一个服务的容器。
  • 环境变量和 /etc/hosts:当使用 links 时,Docker 会自动设置环境变量和 /etc/hosts 条目,使得服务之间可以通过服务名称进行通信。

示例:

[root@lb ~/links]# cat compose.yaml
services:
  web1:
    container_name: nginx1
    image: nginx:latest
    links:
      - web2:nginx
    ports:
      - "81:80"
  web2:
    container_name: nginx2
    image: nginx:latest
    ports:
      - "82:80"

# 运行容器
[root@lb ~/links]# docker-compose up -d
[+] Running 3/3
 ✔ Network links_default  Created                                                                                                                                                                         0.1s
 ✔ Container nginx2       Started                                                                                                                                                                         0.4s
 ✔ Container nginx1       Started                                                                                                                                                                         0.6s
# 检查
[root@lb ~/links]# docker-compose ps -a
NAME      IMAGE          COMMAND                  SERVICE   CREATED          STATUS          PORTS
nginx1    nginx:latest   "/docker-entrypoint.…"   web1      13 seconds ago   Up 11 seconds   0.0.0.0:81->80/tcp, [::]:81->80/tcp
nginx2    nginx:latest   "/docker-entrypoint.…"   web2      13 seconds ago   Up 12 seconds   0.0.0.0:82->80/tcp, [::]:82->80/tcp


###### 测试,进入nginx1的容器内部
[root@lb ~/links]# docker exec -it nginx1 bash
# 查看hosts解析
root@12b2517e712e:/# cat /etc/hosts
127.0.0.1       localhost
...
# web2的hosts解析
172.24.0.3      12b2517e712e

root@12b2517e712e:/# curl
curl: try 'curl --help' or 'curl --manual' for more information
root@12b2517e712e:/# curl http://nginx
<!DOCTYPE html>
<html>
# 网页内容
</body>
</html>

在 Docker Compose 版本 3 及以上中,推荐使用默认网络功能来实现服务之间的通信。

示例:

services:
  web1:
    container_name: nginx1
    image: nginx:latest
    ports:
      - "81:80"
  web2:
    container_name: nginx2
    image: nginx:latest
    ports:
      - "82:80"

在这个示例中,web1和web2默认连接到同一个网络中,web1可以通过web2服务名称直接访问web2服务

networks

networks用于定义和管理服务之间的网络通信,通过networks可以创建自定义网络,将服务连接到这些网络中,从而实现灵活的网络结构。

在 Docker Compose 中,如果没有显式定义网络,Docker Compose 会自动为每个项目创建一个默认网络,并将所有服务连接到该网络。默认网络是桥接网络(bridge network),服务之间可以通过服务名称直接通信。

也可以自定义网络,并将服务连接到这些网络中,自定义网络可以是桥接网络(bridge)、主机网络(host)或覆盖网(overlay)。

示例:

services:
  web:
    image: nginx:latest
    ports:
      - "80:80"
    networks:
      - my_network
  db:
    image: mysql:latest
    environment:
      MYSQL_ROOT_PASSWORD: my-secret-pw
    networks:
      - my_network

networks:
  my_network:
    driver: bridge

deploy

deploy 配置项用于定义服务在部署时的行为,包括资源限制、副本数量、更新策略、重启策略等
这里以资源限制为例

services:
  web:
    image: nginx:latest
    ports:
      - "80:80"
    deploy:
      resources:
        limits:
          cpus: '0.5'  # 限制 CPU 使用量为 0.5 个核心
          memory: 50M  # 限制内存使用量为 50MB
        reservations:
          cpus: '0.2'  # 保留 0.2 个核心
          memory: 20M  # 保留 20MB 内存

limits:定义容器可以使用的最大资源量。

  • cpus:浮点数,表示 CPU 核心数。例如,0.5 表示限制为 0.5 个核心。
  • memory:字符串,表示内存限制,单位可以是 B(字节)、K(千字节)、M(兆字节)、G(吉字节)。

reservations:定义容器启动时保留的资源量。

  • cpus:浮点数,表示 CPU 核心数。
  • memory:字符串,表示内存大小。

Docker Compose变量文件

Compose变量文件是在compose.yaml同级目录中创建.env文件,在.env文件中写入key=value的形式,然后在compose.yaml文件中以${key}的形式进行使用

示例:

[root@lb ~/var]# ll
total 16
## .env是变量文件
-rw-r--r--  1 root root    8 Apr 19 21:25 .env
-rw-r--r--  1 root root   73 Apr 19 21:26 compose.yaml
[root@lb ~/var]# cat .env
PORT=83
[root@lb ~/var]# cat compose.yaml
services:
  web:
    image: nginx:latest
    ports:
      ## ${PORT}取值
      - "${PORT}:80"
[root@lb ~/var]# docker-compose up -d
[+] Running 2/2
 ✔ Network var_default  Created                                                                                                                                                                           0.1s
 ✔ Container var-web-1  Started                                                                                                                                                                           0.4s
[root@lb ~/var]# docker-compose ps
NAME        IMAGE          COMMAND                  SERVICE   CREATED         STATUS         PORTS
var-web-1   nginx:latest   "/docker-entrypoint.…"   web       7 seconds ago   Up 6 seconds   0.0.0.0:83->80/tcp, [::]:83->80/tcp

使用多个compose文件

当我们具有多个compose文件时,我们应该怎么运行呢?

方式一:使用-f选项进行合并构建

当有多个 Docker Compose 文件时,可以使用 docker-compose 命令的 -f选项来指定多个 Compose 文件,并一起构建和管理服务。这种方式允许你将配置拆分到多个文件中,然后组合使用它们。

例如我们有以下两个compose文件:

docker-compose.yaml

services:
  web:
    image: nginx:latest
    ports:
      - "80:80"

docker-compose.admin.yaml

version: '3.8'
services:
  web:
    environment:
      - NGINX_ENV=prod
  db:
    image: mysql:latest
    environment:
      MYSQL_ROOT_PASSWORD: my-secret-pw

我们可以使用下面的命令来进行构建

docker-compose -f docker-compose.yml -f docker-compose.override.yml up -d

文件合并规则:
Docker Compose 会按顺序加载指定的文件,并将它们的内容合并。合并规则如下:

  • 服务(Services):如果多个文件中定义了相同的服务,后者的配置会覆盖前者的配置。
  • 网络(Networks):如果多个文件中定义了相同的网络,后者的配置会覆盖前者的配置。
  • 卷(Volumes):如果多个文件中定义了相同的卷,后者的配置会覆盖前者的配置。

我们可以使用使用可以使用 docker-compose config 命令查看合并后的配置。这个命令会输出最终的配置内容,帮助你确认配置是否正确。

docker-compose -f docker-compose.yml -f docker-compose.override.yml config

方式二:使用include元素来引用其它的compose文件

include 指令可以在主 Compose 文件中引用其他 Compose 文件,从而实现配置的模块化和重用。被引用的文件可以定义服务、网络、卷等,主文件会将这些内容合并到最终的配置中。

示例:

include:
  - my-compose-include.yaml 
services:
  serviceA:
    build: .
    depends_on:
      - serviceB

也支持从远程URL加载Compose文件

include:
  - https://example.com/services/web.yml
  - https://example.com/services/db.yml
services:
  serviceA:
    build: .
    depends_on:
      - serviceB

文件合并规则

  • Docker Compose 会按顺序加载 include 中指定的文件,并将它们的内容合并到主文件中。合并规则如下:
  • 服务(Services):如果多个文件中定义了相同的服务,后者的配置会覆盖前者的配置。
  • 网络(Networks):如果多个文件中定义了相同的网络,后者的配置会覆盖前者的配置。
  • 卷(Volumes):如果多个文件中定义了相同的卷,后者的配置会覆盖前者的配置。

注意事项

  • 文件顺序:include 中文件的加载顺序很重要,后加载的文件会覆盖前加载的文件中的配置。
  • 本地优先:如果本地和远程文件有相同的路径或 URL,Docker Compose 会优先使用本地文件。
From:https://www.cnblogs.com/huangSir-devops/p/18835671
huangSir-devops
100+评论
captcha