Skip to content

Docker Compose 的编写

Docker Compose 是一个用于定义和运行多容器 Docker 应用程序的强大工具。在现代软件开发中,应用程序往往由多个互相关联的服务组成,例如数据库、Web 服务器和后端服务等。Docker Compose 通过一个简单的 YAML 文件来描述这些服务,并提供了一键式启动、停止和管理整个应用的能力,使得开发、测试和部署变得更加简便和高效。

让我们开始这段 Docker Compose 的探索之旅,了解如何利用这一工具简化多容器应用的管理,提升效率和协作能力。🚀

常用内容

yaml
name: syncthing # 堆栈的名称

services: # 要使用的软件。固定格式。
  Syncthing: # 服务的名称。没什么用,可以随便填。
    image: lscr.io/linuxserver/syncthing # 镜像。指定了作者与软件
    container_name: syncthing # 容器的名称
    network_mode: host # 网络模式。
    environment: # 环境变量。一种设定配置的方式。
      - PUID=3000
      - PGID=950
      - TZ=Asia/Shanghai
    volumes: # 卷的映射。将宿主机的文件或目录映射到容器中。
      # 格式:外部卷:容器内路径
      - /app/syncthing/config:/config
      - mynfs:/mnt/nfs

    ports: # 端口映射
      # 格式 宿主机端口:容器端口/协议
      - 8384:8384

    restart: always # 重启策略

volumes: # 卷的另一种定义方式。可以实现更多功能。
  mynfs:
    external: true

多容器堆栈

示例

yaml
name: brother
services:
  web:
    image: nginx:latest
    ports:
      - "80:80"

  db:
    image: mysql:5.7
    volumes:
      - db_data:/var/lib/mysql

volumes:
  db_data:

软件

yaml
services:
  my-service:
    image: lscr.io/linuxserver/syncthing:latest # 镜像

image 用于确定要使用的软件和来源。
格式:仓库/作者/软件:版本。其中,软件是必要的,其它都是可选项目。要指定镜像仓库,则需要指定作者。

yaml
image: redis # 镜像名
image: ubuntu:14.04 # 镜像名:版本
image: estrellaxd/auto_bangumi # 作者/镜像名
image: my-registry.com:4000/postgresql # 仓库/作者/镜像名
image: a4bc65fd # 镜像id

支持的格式。

环境变量

它是一种存储配置的方式。

yaml
services:
  my-service:
    environment: # 环境变量
      - PUID=3000 # 用户ID
      - PGID=950 # 组ID
      - TZ=Asia/Shanghai # 时区

另一种写法

yaml
services:
  my-service:
    environment:
      PUID: 3000 # 用户ID
      PGID: 950 # 组ID
      TZ: Asia/Shanghai # 时区

存储

Docker 的卷(Volume)是用于在容器之间共享和持久化数据的一种机制。它们提供了一种独立于容器生命周期的数据管理方式,使得数据在容器停止或删除后仍然能够保留。

背景

默认情况下,容器的数据不会被保存。这使得,在这些情况下,数据丢失:容器停止、重启系统、软件升级

为什么使用卷?

  • 持久化数据:卷允许你持久化数据,即使容器被删除,数据也不会丢失。
  • 共享数据:不同的容器可以共享同一个卷,方便实现数据共享和协作。
  • 数据隔离:卷可以隔离数据,使得不同的应用和环境可以使用独立的数据存储。
yaml
services:
  my-service:
    volumes: # 卷的映射。将宿主机的文件或目录映射到容器中。
      - /path/to/host:/config # 宿主机路径:容器内路径
      - mynfs:/mnt/nfs # 卷的名称:容器内路径

      - web_data:/usr/share/nginx/html
      - db_data:/var/lib/mysql

      - /path2:/config:ro # 只允许容器读取数据,不能写入
      - /path3:/config:rw # 允许容器读取、写入数据


volumes: # 卷的另一种定义方式。可以实现更多功能。
  web_data: # 简单定义
  
  # 更多可选项
  db_data: 
    name: custom_db_data # 卷的名称

  volumes_3: 
    driver: local
    driver_opts:
      o: bind
      device: /path/on/host
  
  # 网络卷
  mynfs:
    driver_opts:
      type: "nfs"
      o: "addr=192.168.5.25,vers=4,nolock,soft,rw"
      device: ":/mnt/pool_1/Main/"

  my_smb:
    driver_opts:
      type: "cifs"
      o: "addr=192.168.5.25,username=用户,password=密码,vers=3.0"
      device: "//192.168.5.25/pool_1"

  wai_bu: # 外部卷
    external: true

端口映射

功能:映射容器内的端口,到宿主机的端口
在网络模式模式为bridge时,外部不能主动访问容器内。这个功能可以解决此问题。通过此功能,还能使用自定义的端口,而不是软件默认监听的的端口。

yaml
services:
  my-service:
    network_mode: bridge # 网络模式
    ports: # 端口映射
      # 格式 宿主机端口:容器端口/协议
      - 8384:8384
      - 22000:22000/tcp
      - 22000:22000/udp

网络模式

yaml
services:
  my-service:
    network_mode: host # 网络模式

区别

  • bridge : Docker 的默认网络模式,每个容器在启动时都会连接到一个桥接网络。容器之间可以通过容器名相互通信,但默认情况下,外部不能直接访问容器。它的本质是NAT,就像小区内的快递柜。
  • host: 容器与宿主机共享网络栈。网络方面,效果和直接在宿主机运行相同。适用于需要高性能网络的场景,但会减少网络隔离。
  • none : 容器不配置任何网络。容器内没有网络接口,只适用于不需要网络通信的场景。

网络相关

yaml
services:
  my-service:
    hostname: my-service # 主机名。没什么用。

重启策略

yaml
services:
  my-service:
    restart: always
  • no:默认值,表示不会自动重启容器。如果容器停止或退出,它将保持停止状态。
  • always:无论容器如何停止,都会自动重启。这意味着即使容器崩溃或手动停止,Compose 也会尝试重新启动它。
  • on-failure:仅在容器以非零退出码退出时重启。你可以指定最大重启次数,例如 on-failure:5 表示容器最多重启五次。
  • unless-stopped:除非容器被手动停止,否则会自动重启。这意味着如果容器崩溃,Compose 会尝试重新启动它,但如果你手动停止了容器,它将保持停止状态。

参数与入口点

yaml
services:
  Watchtower:
    command: --schedule "0 5 * * *"    aria2 AriaNg yacd-meta Peer-Ban-Helper Home_Assistant AutoBangumi DDNS-Go

command 的功能是传递参数

yaml
services:
  web:
    entrypoint: ["sh", "-c", 'apk add openssh && exec /app/ddns-go && "$@"']

entrypoint 指容器开启时,启动软件的命令。它被指定时,效果是覆盖原有的entrypoint,而不是追加。

yaml
services:
  jellyfin:
    image: jellyfin/jellyfin
    entrypoint: ["sh", "-c", 'apt update && apt install -y fonts-noto-cjk-extra && exec /jellyfin/jellyfin && "$@"']

覆盖entrypoint,可以在启动软件前,安装其他的依赖,或做一些定制。
在这个示例中,先安装代号为fonts-noto-cjk-extra的字体,再启动软件。解决了问题:Jellyfin没有中文字体,导致中文显示为方框

交互式的终端环境

yaml
services:
    web:
      stdin_open: true # 开启标准输入
      tty: true # 分配为伪终端
shell
docker exec -it 容器名称 sh # 连接容器的 shell

这两个选项通常一起使用,以确保容器能够提供一个交互式的终端环境,适合调试或运行需要用户输入的应用程序。通常使用场景:需要在容器启动后,立刻在其中执行命令。

资源限制

Docker 允许用户对容器,限制、预留CPU、内存。因此,可以更容易地管理资源。

yaml
services:
  web:
    deploy:
      resources:
        limits: # 资源限制
          cpus: "0.50"      # 多可以使用 0.5 个CPU核心
          memory: "512M"    # 最多可以使用 512MB 的内存。
        reservations: # 资源保留
          cpus: "0.25"      # 保留 0.25 个CPU核心
          memory: "256M"    # 保留 256MB 的内存。

cpus单位:1 CPU核心。例子:宿主的 CPU 有 6 核,要使用全部资源的50%,则值应为3;它的最大值为6。

拉取策略

此策略告诉Compose如何处理镜像拉取:

yaml
services:
  my-service:
    pull_policy: always

pull_policy的选项:

  • always: 每次启动服务时都会拉取镜像。
  • missing: 如果服务启动时本地没有该镜像,则会拉取镜像。
  • never: 强制使用本地存在的镜像,不会进行任何拉取操作。
  • if_not_present: 如果镜像本地不存在则会拉取,但如果本地已经有这个镜像,即使不是最新的也不会进行更新。

注意事项

  • 使用--pull alwayspull_policy: always可能会导致更新时由于镜像变化过大而产生兼容性问题或服务中断,所以生产环境中要慎用,确保更新的镜像与现有应用兼容。
  • 使用pull_policy是一种更细粒度的控制,可以为每个服务独立设置更新策略。
  • 确保你的环境变量以及其它依赖的配置是与新的镜像更新兼容的。

扩展功能

secrets

定义可以被服务使用的全局机密(仅适用于Compose v3.1+):

yaml
secrets:
  my-secret:
    file: ./my_secret.txt

configs

定义可以在服务之间共享的配置(仅适用于Compose v3.1+):

yaml
configs:
  my-config:
    file: ./my_config.txt

扩展标签

docker-compose.yml可以包含一些全局设置,允许你为整个文件应用某些配置:

  • x-default-env-file: 指定一个环境文件,所有的服务都将默认读取这个文件中的环境变量
yaml
x-default-env-file:
  - .env
  • x-default-pull_policy: 拉取策略
yaml
x-default-pull_policy: always
  • x-default-logging: 设置一个全局的日志记录配置,这是被所有服务继承,除非单个服务有自己的特殊设置:
yaml
x-default-logging: &global-logging
  driver: syslog
  options:
    syslog-address: "udp://127.0.0.1:123"
    tag: 'something'
services:
  web:
    image: myimage
    logging: *global-logging
  • x-default-ports: 在某些版本中,你可以定义一个默认的端口映射策略,它将自动应用于所有适用的服务:
yaml
x-default-ports:
  - 'target: 80, published: 8080'
  • x-default-networks: 为所有服务添加默认网络:
yaml
x-default-networks:
  - default
  • x-default-volumes: 定义可以在服务中使用的全局卷:
yaml
x-default-volumes:
  - data:/data
volumes:
  data:
...

WARNING

需要注意的是,像x-*这样的用户定义的扩展字段都是非标准的,所以它们在不同的Docker Compose版本中可能有不同的支持方式或被忽略。在使用这些扩展功能时,请检查你的Docker Compose版本和官方支持的功能,确保你使用的标签是有效的。