跳转至

compose.yaml

compose V2 版本变化

V2-compose

Compose 文件是一个YAML文件,为 Docker 应用程序定义服务、网络和卷。Compose 文件格式的最新推荐版本由Compose Specification定义。Compose 规范合并了旧版 2.x 和 3.x 版本,聚合了这些格式的属性,并由Compose 1.27.0+实现。

compose.yaml 编写

规范

Compose 文件是一个定义 版本(弃用)、 服务(必需)、 网络、 卷、 配置和 机密的YAML文件。Compose 文件的默认路径是(首选)或在工作目录中。Compose 实现还应该支持和以实现向后兼容性。如果两个文件都存在,Compose 实现必须优先选择规范文件。

V2-优先级

compose.yaml → compose.yml → docker-compose.yaml → docker-compose.yml

规划

顶级元素:

  • 版本顶级元素 verison(弃用):

  • 服务顶级元素 ( services ): 组成文件必须将services根元素声明为映射,其键是服务名称的字符串表示形式,其值是服务定义。服务定义包含应用于该服务启动的每个容器的配置。

services:
  foo:
    image: foo
  bar:
    image: bar
    profiles:
      - test
  baz:
    image: baz
    depends_on:
      - bar
    profiles:
      - test
  zot:
    image: zot
    depends_on:
      - bar
    profiles:
      - debug

docker compose build

服务除了可以基于指定的镜像,还可以基于一份Dockerfile,在使用up启动时执行构建任务,构建标签是build,可以指定Dockerfile所在文件夹的路径。也可以是相对路径,只要上下文确定就可以读取Dockerfile。Compose将会利用Dockerfile自动构建镜像,然后使用镜像启动服务容器

build 可以指定为包含构建上下文路径的字符串:

services:
  web:
    build: 
      # context选项可以是Dockerfile的文件路径,也可以是到链接到git仓库的url,当提供的值是相对路径时,被解析为相对于撰写文件的路径,此目录也是发送到Docker守护进程的context
      context: /path/to/build/dir 
      dockerfile: Dockerfile-alternate # 使用dockerfile文件来构建,必须指定构建路径
      args:
        buildno:1

如果同时指定image和build两个标签,那么Compose会构建镜像并且把镜像命名为image值指定的名字。

args: 添加构建参数,这些参数是仅在构建过程中可访问的环境变量。 首先,在Dockerfile中指定参数:

ARG buildno
ARG gitcommithash
RUN echo "Build number: $buildno"
RUN echo "Based on commit: $gitcommithash"

之后在build键下指定参数,可以传递映射或列表:

build:
  context:.
  args:
    buildno:1
    gitcommithash: cdc3b19
  build:
  context:.
  args:
    - buildno=1
    - gitcommithash=cdc3b19

注意:在Dockerfile中,如果ARG在FROM指令之前指定, ARG则在构建说明中不可用FROM。如果您需要在两个位置都可以使用参数,请在FROM指令下指定它

您可以在指定构建参数时省略该值,在这种情况下,它在构建时的值是运行Compose的环境中的值

args:
  - buildno
  - gitcommithash

注意:YAML布尔值(true,false,yes,no,on,off)必须用引号括起来,这样分析器会将它们解释为字符串。

cache_from

编写缓存解析镜像列表,此选项是v3.2中的新选项。

build:
  context:.
  cache_from:
    - alpine:latest
    - corp/web_app:3.14

target

根据对应的 Dockerfile 构建指定 Stage

build:
  context:.
  target: prod

configs 配置文件

使用服务 configs 配置为每个服务赋予相应的访问权限,支持两种不同的语法

SHORT 语法只能指定配置名称,这允许容器访问配置并将其安装在 / 容器内,源名称和目标装入点都设为配置名称。

services:
redis:
  image:redis:latest
  deploy:
    replicas:1
  configs:
    -my_config
    -my_other_config
configs:
my_config:
  file:./my_config.txt
my_other_config:
  external:true

以上实例使用 SHORT 语法将 redis 服务访问授予 my_config 和 my_other_config ,并被 my_other_config 定义为外部资源,这意味着它已经在 Docker 中定义。可以通过 docker config create 命令或通过另一个堆栈部署。如果外部部署配置都不存在,则堆栈部署会失败并出现 config not found 错误。

注意: config 定义仅在 3.3 版本或在更高版本的撰写文件格式中受支持,YAML 的布尔值(true, false, yes, no, on, off)必须要使用引号引起来(单引号、双引号均可),否则会当成字符串解析。

  • source:Docker 中存在的配置的名称

  • target:要在服务的任务中装载的文件的路径或名称。如果未指定则默认为 /

  • uid 和 gid:在服务的任务容器中拥有安装的配置文件的数字 UID 或 GID。如果未指定,则默认为在Linux上。Windows不支持。

  • mode:在服务的任务容器中安装的文件的权限,以八进制表示法。例如,0444 代表文件可读的。默认是 0444。如果配置文件无法写入,是因为它们安装在临时文件系统中,所以如果设置了可写位,它将被忽略。可执行位可以设置。如果您不熟悉 UNIX 文件权限模式,Unix Permissions Calculator

下面示例在容器中将 my_config 名称设置为 redis_config,将模式设置为 0440(group-readable)并将用户和组设置为 103。该redis服务无法访问 my_other_config 配置。

services:
redis:
  image:redis:latest
  deploy:
    replicas:1
  configs:
    -source:my_config
      target:/redis_config
      uid:'103'
      gid:'103'
      mode:0440
configs:
my_config:
  file:./my_config.txt
my_other_config:
  external:true
可以同时授予多个配置的服务相应的访问权限,也可以混合使用 LONG 和 SHORT 语法。定义配置并不意味着授予服务访问权限。

示例:

image

image是指定服务的镜像名称或镜像ID。如果镜像在本地不存在,Compose将会尝试拉取镜像。以下格式都可以

services:
  web:
    image: redis
    image: ubuntu:22.04
    image: a4bc65fdad # 镜像id
    image: "${URL}"

command

使用command可以覆盖容器启动后默认执行的命令。

# /bin/bash -c 字符串方式
# command: cmd1 && cmd2 && cmd3 ...
command: /bin/bash -c sleep 1 && python /path/hello.py
command: ["bash", "-c", "sleep 1 && python /path/hello.py"]
可以使用多行字符串和管道符号(|)来实现串行执行和并行执行的命令。
  • 串行执行:

    command:
      - sh
      - -c 
      - |
        cmd1
        cmd2
        cmd3
    
    在这个示例中,命令被传递给sh -c,并使用管道符号(|)表示多行字符串。在多行字符串中,每行都是一个要执行的命令。这些命令将按顺序依次执行。

    具体解释如下:

    • sh -c:在Linux系统中,sh -c是一个常用的方式,用于在Shell中执行命令。
    • cmd1cmd2cmd3:这些是要执行的具体命令。您可以根据需要替换它们为实际的命令。这些命令将按顺序依次执行,即等待前一个命令完成后再执行下一个命令。

    串行执行适用于需要确保命令按照特定顺序执行的场景。每个命令都会等待前一个命令完成后才会执行。例如,您可能需要在容器启动时按顺序执行初始化脚本或设置多个环境变量。

  • 并行执行:

    command:
      - sh
      - -c 
      - |
        cmd1 &
        cmd2 &
        cmd3
    
    在这个示例中,每个命令后面都有一个&符号,表示并行执行。这意味着每个命令将在后台同时运行,而不需要等待前一个命令完成。

    具体解释如下:

    • cmd1 &cmd2 &cmd3:这些命令之间使用&符号分隔,表示它们将在后台同时运行,不会相互阻塞。

    并行执行适用于需要同时执行多个独立命令的场景。这可以提高运行多个命令的效率,特别是当这些命令之间没有依赖关系时。

container_name

Compose的容器名称格式是:<项目名称><服务名称><序号>,自定义项目名称、服务名称,但如果想完全控制容器的命名,可以使用标签指定

container_name: my-web-container

depends_on

设置依赖关系。

  • docker-compose up :以依赖性顺序启动服务。在以下示例中,先启动 db 和 redis ,才会启动 web。
  • docker-compose up SERVICE :自动包含 SERVICE 的依赖项。在以下示例中,docker-compose up web 还将创建并启动 db 和 redis。
  • docker-compose stop :按依赖关系顺序停止服务。在以下示例中,web 在 db 和 redis 之前停止。

version: "3.7"
services:
  web:
    build: .
    depends_on:
      - db
      - redis
  redis:
    image: redis
  db:
    image: postgres
注意:web 服务不会等待 redis db 完全启动 之后才启动。

PID

将PID模式设置为主机PID模式,跟主机系统共享进程命名空间。容器使用pid标签将能够访问和操纵其他容器和宿主机的名称空间。

pid: "host"

ports

ports用于映射端口的标签。使用HOST:CONTAINER格式或者只是指定容器的端口,宿主机会随机映射端口。

ports:
 - "3000"
 - "8000:8000"
 - "49100:22"
 - "127.0.0.1:8001:8001"

extra_hosts

添加主机名映射。类似 docker client --add-host。

extra_hosts:
 - "somehost:1.1.1.1"
 - "otherhost:2.2.2.2"

以上会在此服务的内部容器中 /etc/hosts 创建一个具有 ip 地址和主机名的映射关系:

1.1.1.1 somehost
2.2.2.2 otherhost

volumes

!!! note "挂载一个目录或者一个已存在的数据卷容器,可以直接使用 [HOST:CONTAINER]格式,或者使用[HOST:CONTAINER:ro]格式,后者对于容器来说,数据卷是只读的,可以有效保护宿主机的文件系统。 Compose的数据卷指定路径可以是相对路径,使用.或者..来指定相对目录。"

services:
  db:
    image: postgres:latest
    volumes: # 数据卷的格式可以是下面多种形式
      - "/localhost/postgres.sock:/var/run/postgres/postgres.sock"
      - "/localhost/data:/var/lib/postgresql/data"
      - /var/lib/mysql # 只是指定一个路径,Docker 会自动在创建一个数据卷(这个路径是容器内部的)。
      - /opt/data:/var/lib/mysql # 使用绝对路径挂载数据卷
      - ./cache:/tmp/cache # 以 Compose 配置文件为中心的相对路径作为数据卷挂载到容器。
      - ~/configs:/etc/configs/:ro # 使用用户的相对路径(~/ 表示的目录是 /home/<用户目录>/ 或者 /root/)。
      - datavolume:/var/lib/mysql # 已经存在的命名的数据卷。

如果不使用宿主机的路径,可以指定一个volume_driver

volume_driver: mydriver

volumes_from

从另一个服务或容器挂载其数据卷:

volumes_from:
   - service_name   
     - container_name

dns

自定义 DNS 服务器,可以是单个值或列表的多个值。

dns: 8.8.8.8

dns:
  - 8.8.8.8
  - 9.9.9.9

自定义 DNS 搜索域。可以是单个值或列表。

dns_search: example.com

dns_search:
  - dc1.example.com
  - dc2.example.com

expose

暴露端口,但不映射到宿主机,只被连接的服务访问。

仅可以指定内部端口为参数:

expose:
 - "3000"
 - "8000"

entrypoint

覆盖容器默认的 entrypoint。

entrypoint: /code/entrypoint.sh

env_file

从文件添加环境变量。可以是单个值或列表的多个值。

env_file: .env

env_file:
  - ./common.env
  - ./apps/web.env
  - /opt/secrets.env

environment

添加环境变量。您可以使用数组或字典、任何布尔值,布尔值需要用引号引起来,以确保 YML 解析器不会将其转换为 True 或 False。

environment:
  RACK_ENV: development
  SHOW: 'true'

restart

  • no:是默认的重启策略,在任何情况下都不会重启容器。
  • always:容器总是重新启动。
  • on-failure:在容器非正常退出时(退出状态非0),才会重启容器。
  • unless-stopped:在容器退出时总是重启容器,但是不考虑在Docker守护进程启动时就已经停止了的容器

restart: "no"
restart: always
restart: on-failure
restart: unless-stopped
注:swarm 集群模式,请改用 restart_policy。

healthcheck

用于检测 docker 服务是否健康运行。

healthcheck:
  test: ["CMD", "curl", "-f", "http://localhost"] # 设置检测程序
  interval: 1m30s # 设置检测间隔
  timeout: 10s # 设置检测超时时间
  retries: 3 # 设置重试次数
  start_period: 40s # 启动后,多少秒开始启动检测程序

network_mode

设置网络模式。

network_mode: "bridge"
network_mode: "host"
network_mode: "none"
network_mode: "service:[service name]"
network_mode: "container:[container name/id]"

networks

配置容器连接的网络,引用顶级 networks 下的条目。

services:
  some-service:
    networks:
      some-network:
        aliases:
         - alias1
      other-network:
        aliases:
         - alias2
networks:
  some-network:
    # Use a custom driver
    driver: custom-driver-1
  other-network:
    # Use a custom driver which takes special options
    driver: custom-driver-2
aliases :同一网络上的其他容器可以使用服务名称或此别名来连接到对应容器的服务。

secrets

存储敏感数据,例如密码:

services:

mysql:
  image: mysql
  environment:
    MYSQL_ROOT_PASSWORD_FILE: /run/secrets/my_secret
  secrets:
    - my_secret

secrets:
  my_secret:
    file: ./my_secret.txt

ulimits

覆盖容器默认的 ulimit。

ulimits:
  nproc: 65535
  nofile:
    soft: 20000
    hard: 40000

devices

指定设备映射列表。

devices:
  - "/dev/ttyUSB0:/dev/ttyUSB0"

准备基础环境

定义应用程序依赖项

(1. 为项目创建目录

mkdir -p /opt/v2-compose && cd /opt/v2-compose

(2. 在您的项目目录中创建一个名为 app.py 的文件

import time

import redis
from flask import Flask

app = Flask(__name__)
cache = redis.Redis(host='redis', port=6379)

def get_hit_count():
    retries = 5
    while True:
        try:
            return cache.incr('hits')
        except redis.exceptions.ConnectionError as exc:
            if retries == 0:
                raise exc
            retries -= 1
            time.sleep(0.5)

@app.route('/')
def hello():
    count = get_hit_count()
    return 'Hello World! I have been seen {} times.\n'.format(count)
在此示例中,redis是应用程序网络上的redis容器的主机名。我们为Redis使用默认端口6379

(3. 在项目目录中创建另一个名为 requirements.txt 的文件:

flask
redis

编写 Dockerfile

  • 您将编写一个构建Docker映像的Dockerfile。该图像包含Python应用程序所需的所有依赖关系,包括Python本身。
  • 在您的项目目录中,创建一个名为的文件Dockerfile并粘贴以下内容:
# syntax=docker/dockerfile:1
FROM python:3.7-alpine # 从Python 3.7 Alpine基础映像开始构建镜像。
WORKDIR /code # 将工作目录设置为 /code。
ENV FLASK_APP=app.py # 设置环境变量,供 flask 命令使用,指定为 app.py。
ENV FLASK_RUN_HOST=0.0.0.0 # 设置环境变量,让 Flask 在所有可用网络接口上运行。
RUN apk add --no-cache gcc musl-dev linux-headers # 安装 gcc 和其他依赖项,并禁用包索引的缓存。
COPY requirements.txt requirements.txt #  requirements.txt 文件复制到镜像中。
RUN pip install -r requirements.txt # 安装 requirements.txt 文件中指定的 Python 依赖项。
EXPOSE 5000 # 暴露端口 5000,以允许外部访问 Flask 应用程序。
COPY . . # 将当前目录(所有文件和文件夹)复制到镜像中。
CMD ["flask", "run"] # 设置默认命令为使用 "flask run" 命令运行 Flask 应用程序。

编写 compose.yaml

在您的项目目录中创建一个名为的文件 compose.yaml 的文件

services:
  web:
    build: .
    ports:
      - "5000:5000"
  redis:
    image: "redis:alpine"

Note

  • 网络服务: 该web服务使用从Dockerfile当前目录中构建的映像。然后,它将容器和主机绑定到暴露的端口5000。此示例服务使用Flask Web服务器的默认端口5000。

  • Redis服务: 该redis服务使用 从Docker Hub注册表中提取的公共Redis映像。

使用 compose 构建并运行应用

(1. 在项目目录中,运行来启动应用程序

docker compose up
image-20231101155901739

Compose提取一个Redis映像,为您的代码构建一个映像,然后启动您定义的服务。在这种情况下,代码会在构建时静态复制到映像中。

(2. curl http://localhost:5000 可以查看该应用程序正在运行。 image-20231101160127169

(3. 每执行一次 curl http://localhost:5000 , 该数字应递增。 image-20231101160108801

(4. 切换到另一个终端窗口,然后键入 docker image ls以列出本地图像。

(5. 通过 docker compose down 从第二个终端的项目目录中运行,或在启动该应用的原始终端中按CTRL + C来停止该应用。

编辑Compose文件以添加绑定挂载

(1. 编辑 compose.yaml 在项目目录添加绑定安装的web服务:

services:
  web:
    build: .
    ports:
      - "5000:5000"
    volumes:
      - .:/code
    environment:
      FLASK_ENV: development
  redis:
    image: "redis:alpine"

volumes 将主机上的项目目录(当前目录)安装到容器内部的 /code,使您可以即时修改代码,而不必重建映像。 该environment键设置了 FLASK_ENV 环境变量,该变量指示flask run要在开发模式下运行并在更改时重新加载代码。此模式只能在开发中使用。

使用 Compose 重建并运行应用程序

(1. 键入docker compose up以使用更新的Compose文件构建应用程序,然后运行它。

更新应用程序

现在应用程序代码是使用卷安装到容器中的,所以您可以对其代码进行更改并立即查看更改,而无需重建映像。问候语应更新,并且计数器应仍在增加。

image-20231101161323457

尝试其他命令

(1. 如果要在后台运行服务,则可以将-d标志(用于“分离”模式)传递给docker compose up 使用 docker compose ps查看当前正在运行的内容:

image-20231101161939636

(2. 该docker-compose run命令允许您为服务运行一次性命令。例如,查看哪些环境变量可用于 web服务:

docker-compose run web env

(3. 使用 docker-compose up -d ,请在完成服务后停止它们:

docker compose stop