惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

H
Help Net Security
S
Secure Thoughts
I
Intezer
Project Zero
Project Zero
Stack Overflow Blog
Stack Overflow Blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
F
Full Disclosure
P
Proofpoint News Feed
T
The Exploit Database - CXSecurity.com
人人都是产品经理
人人都是产品经理
博客园_首页
J
Java Code Geeks
Recorded Future
Recorded Future
K
Kaspersky official blog
GbyAI
GbyAI
S
Schneier on Security
The Cloudflare Blog
Spread Privacy
Spread Privacy
C
Cisco Blogs
The Hacker News
The Hacker News
博客园 - 三生石上(FineUI控件)
H
Hackread – Cybersecurity News, Data Breaches, AI and More
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
爱范儿
爱范儿
Microsoft Azure Blog
Microsoft Azure Blog
Know Your Adversary
Know Your Adversary
T
Tenable Blog
A
Arctic Wolf
Blog — PlanetScale
Blog — PlanetScale
H
Hacker News: Front Page
The Last Watchdog
The Last Watchdog
O
OpenAI News
Last Week in AI
Last Week in AI
B
Blog RSS Feed
T
Troy Hunt's Blog
G
GRAHAM CLULEY
N
Netflix TechBlog - Medium
Vercel News
Vercel News
量子位
The Register - Security
The Register - Security
Google Online Security Blog
Google Online Security Blog
Apple Machine Learning Research
Apple Machine Learning Research
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
C
CERT Recently Published Vulnerability Notes
Cisco Talos Blog
Cisco Talos Blog
U
Unit 42
Security Archives - TechRepublic
Security Archives - TechRepublic
C
Cyber Attacks, Cyber Crime and Cyber Security
N
News and Events Feed by Topic

博客园 - xiashengwang

Rocky Linux 9 安装docker Rocky Linux 9 与Centos区别,以及软件安装dnf命令 《Linux 基础点滴》:(17)SSH 密钥生成与管理 – 免密登录的利器 Linux服务器安全登录:从入门到实践 putty 基础 《Linux 基础点滴》:(16)firewalld 防火墙管理命令 《Linux 基础点滴》:(15)用户管理 – 创建、删除、权限与 sudo 《Linux 基础点滴》:(14)定时任务 – 用 crontab 自动化 《Linux 基础点滴》:(13)文本编辑入门 – 使用 Vim 《Linux 基础点滴》:(12)tldr – 简化版命令手册 《Linux 基础点滴》:(11)系统信息与资源监控 – 掌握服务器状态 《Linux 基础点滴》:(10)压缩与打包 – tar 的艺术 《Linux 基础点滴》:(9)查找与过滤 – find, grep, 管道 《Linux 基础点滴》:(8)网络基础 – 查看 IP、连通性与端口 《Linux 基础点滴》:(7)进程管理 – 查看与控制运行中的程序 《Linux 基础点滴》:(6)文件权限与所有者 – 保护你的文件 《Linux 基础点滴》:(5)文件与目录操作 – 增删改查必会命令 《Linux 基础点滴》:(4)磁盘空间查看 – df 和 du 的妙用 《Linux 基础点滴》:(3)Linux 文件系统概览 – 一切皆文件 《Linux 基础点滴》:(2)SSH 连接与基础命令 – 从登录到第一次操作 《Linux 基础点滴》:(1)初识 Linux 大家族 – 发行版分类与选择 docker学习(11)- 容器的日志(log) docker学习(10)-利用Github Action 自动化部署 docker学习(9)-Docker Swarm + Nginx 跨机器负载均衡 docker学习(8)-从 Windows 开发到 Linux 部署 docker学习(6)-数据持久化与网络通信 学会 Git Tag,让版本管理不再混乱 docker学习(5)-Dockerfile docker学习(4)-Docker常用命令 docker学习(3)-一个简单的例子 docker学习(2)-安装 docker学习(1)-基本概念 Github 使用 Self-hosted Runner 实现服务器自动化部署 github创建分支 + Pull Request 合并 Git Rebase vs Git Merge:深入理解与实战选择 Git 系统学习教程:从零到团队协作 AI学习笔记(2)-OpenClaw安装 windbg分析dmp文件 docker desktop 和 Vmware冲突的解决办法
docker学习(7)-docker compose 文件
xiashengwang · 2026-04-16 · via 博客园 - xiashengwang

一、学习目标

  • 掌握 docker-compose.yml 的完整语法(版本、服务、网络、卷、环境变量、健康检查、依赖控制等)
  • 理解 Compose 中的环境管理(.env 文件、多文件覆盖、环境变量替换)
  • 学会使用 Compose 扩展(extends)和锚点(YAML 特性)复用配置
  • 能够为应用配置健康检查、资源限制、重启策略
  • 实现服务的水平扩展(scale)

二、核心知识点

1, Compose 文件版本
当前推荐使用 版本 3.8(兼容 Swarm)或 3.9(最新)。在文件开头声明:

version: '3.8'

2, 服务定义进阶
a) 构建配置

services:
  web:
    build:
      context: ./web          # 构建上下文路径
      dockerfile: Dockerfile  # 指定 Dockerfile 文件名(可选)
      args:                   # 构建参数(ARG)
        - ENV=production
    image: myapp:latest       # 构建后镜像名称

b) 环境变量注入

  • 直接定义:
environment:
  - NODE_ENV=production
  - DB_HOST=mysql
  • 从文件加载:
env_file:
  - ./config/common.env
  - ./config/prod.env
  • 使用 .env 文件(与 docker-compose.yml 同目录,自动加载):
# .env 文件内容
VERSION=1.0
PORT=8080

在 Compose 中引用:"${VERSION}""${PORT:-80}"(带默认值)

c) 依赖控制

  • depends_on:控制启动顺序(但不等待就绪)
depends_on:
  - db
  - redis
  • 条件等待(v3 已支持部分条件):可使用 condition(需要 healthcheck)

v3: Docker Compose 文件格式的第 3 代版本,如:version:3.8

depends_on:
  db:
    condition: service_healthy

d) 健康检查

healthcheck:
  test: ["CMD", "curl", "-f", "http://localhost"]
  interval: 30s
  timeout: 10s
  retries: 3
  start_period: 40s

e) 资源限制
也就是给容器限定使用cpu和内存的上限和下限。但是deploy模式只在集群模式(Swarm)才有效,单机会被忽略,但最好写,这样直接迁移到集群可以通用。

services:
  web:
    # 单机生效(资源限制)
    cpus: '0.5'     # CPU 上限
    mem_limit: 512M # 内存上限
    
    # 集群生效(兼容 Swarm)
    deploy:
      resources:
        limits: # 上限:绝对不能超过
          cpus: '0.5'
          memory: 512M
        reservations: # 保底:至少保证这么多
          cpus: '0.25'
          memory: 256M

注意:deploy 配置仅在 Swarm 模式下生效,在单机 Compose 中可使用 cpus 和 mem_limit(旧版语法)。推荐使用 deploy 保持与 Swarm 兼容。

f) 重启策略

restart: always       # always, no, on-failure, unless-stopped
  • no(默认):
    不重启。容器退出后,无论何种原因都不会自动重启。
  • on-failure:
    仅异常时重启。只有当容器以非零退出码(即程序报错/崩溃)退出时,才会重启。如果程序正常退出(exit 0),则不重启。
  • always:
    总是重启。无论容器是崩溃还是正常退出,都会自动重启。
    重点:即使你手动执行 docker stop 停止了容器,当 Docker 服务本身重启(如服务器重启)时,该容器也会跟着自动启动。
  • unless-stopped(最常用):
    除非手动停止,否则一直重启。行为与 always 类似,都会自动重启。
    核心区别:如果你手动执行了 docker stop,即使 Docker 服务重启,它也不会自动启动。这尊重了用户的主动停止操作。

g) 端口映射

ports:
  - "8080:80"           # 主机:容器
  - "8081:80"           # 简写
  - "0.0.0.0:8082:80"   # 绑定到指定主机 IP
  - "8083-8085:80-82"   # 范围映射

h) 卷挂载

volumes:
  # 1. Docker托管卷 → 存持久数据
  - type: volume
    source: mydata
    target: /data
  # 2. 挂载本机配置 → 改外面生效
  - type: bind
    source: ./config
    target: /app/config
    read_only: true
  # 3. 临时文件 → 放内存
  - type: tmpfs
    target: /tmp

3, 网络定义

networks:
  frontend:
    driver: bridge
    #ip address management
    ipam:
      config:
        - subnet: 172.20.0.0/16
  backend:
    driver: bridge

services:
  web:
    networks:
      - frontend
  db:
    networks:
      - backend
  app:
    networks:
      - frontend
      - backend

划分网络,可以做app直接的隔离,比如上面web和db是不通的,app可以访问db和web。

4, 卷定义
权限继承机制
Bind mount直接挂载宿主机目录,容器内进程访问文件时沿用宿主机的UID/GID和权限位(如0644),易因用户不一致导致权限拒绝。而named volume由Docker管理,初始化时会根据镜像设定正确属主,避免权限错配。
比如:在service下直接写:/host/data:/container/data,那么宿主机的/host/data目录属主可能是root,而/container/data的属主可能是mysql,就会出现容器无权限操作挂载目录的问题。解决方法就是用下面的这种named volume,这种方式,docker内容会自动处理权限兼容性问题,会将宿主/host/data目录改为和容器目录一致的属主(如:mysql),这样就解决了权限问题。因此,生产环境,建议都要用卷定义的方式来挂载外部数据

volumes:
  db_data:
    driver: local
    driver_opts:
      type: none
      device: /data/mysql
      o: bind
  cache:
    external: true   # 使用外部已创建的卷,不会再创建新的卷

这是 Docker 顶级卷定义(写在文件最外层,不是服务里)。作用:提前定义好数据卷,让所有容器共用、管理更清晰。
每个字段意思:

  • driver: local:本地卷(最常用)
  • type: none:我要手动绑定目录
  • device: /data/mysql:宿主机真实文件夹(不是容器里!)
  • o: bind:开启绑定模式

5, 环境管理

  • 多文件覆盖:使用 -f 指定多个 Compose 文件,后面的覆盖前面的。
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d

常见命名:

  • docker-compose.yml:基础配置
  • docker-compose.override.yml:自动覆盖(如果存在,up 时会自动加载)
  • docker-compose.prod.yml、docker-compose.test.yml:手动指定

大部分项目的结构:

你的项目/
├── docker-compose.yml          # 基础公共配置(不变)
├── docker-compose.override.yml # 开发专用(自动加载)
├── docker-compose.prod.yml     # 生产专用(手动加载)
└── .env                        # 环境变量

开发环境命令:自动加载docker-compose.yml和docker-compose.override.yml
docker-compose up -d

生产环境命令:
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d

这条命令可以查看合并后的配置,确认是否合并正确:
docker-compose -f docker-compose.yml -f docker-compose.prod.yml config

  • extends 扩展(单文件复用)
# common.yml
services:
  base:
    image: alpine
    restart: always

# docker-compose.yml
services:
  web:
    extends:
      file: common.yml
      service: base
    command: /app/web
  • YAML 锚点与别名(更灵活):
x-logging: &default-logging
  driver: json-file
  options:
    max-size: "10m"

services:
  web:
    logging: *default-logging
  db:
    logging: *default-logging
  • x-logging:只是一个名字(随便写,x- 开头是 Compose 扩展字段)

  • &default-logging:创建一个锚点,名字叫 default-logging

  • 作用:把下面这段日志配置存起来,以后随时用

  • *default-logging:调用刚才定义的锚点

  • 等于把上面那段 logging 配置原封不动复制过来

6, 常用 Compose 命令

命令 说明
docker-compose up -d 后台启动所有服务
docker-compose down 停止并删除容器、网络(保留卷)
docker-compose down -v 同时删除卷
docker-compose build 构建或重新构建服务镜像
docker-compose pull 拉取服务镜像
docker-compose push 推送镜像到仓库
docker-compose logs -f 查看日志
docker-compose ps 列出容器状态
docker-compose exec <service> <cmd> 在运行中的容器执行命令
docker-compose run <service> <cmd> 运行一次性命令(新容器)
docker-compose stop/start/restart 管理服务
docker-compose scale <service>=<num> 扩展服务实例数(需要 Swarm 或 Compose v2)
docker-compose top 显示容器内进程
docker-compose config 验证并查看解析后的配置

7, 水平扩展(Scale)
在 Compose v2 中,可以使用 scale 命令(或 --scale 选项)运行多个容器实例。需要服务无状态且可能配置负载均衡。

docker-compose up -d --scale web=3

一次运行多个实例

docker-compose up -d --scale web=3 --scale mysql=2

需要在 docker-compose.yml 中开放端口时注意端口冲突,通常结合负载均衡器(如 Nginx)或使用随机端口映射。

三、实践任务

任务 1:使用环境变量和 .env 文件
目标:创建一个 Web 应用,根据环境变量显示不同内容。

  • 创建项目目录 :\docker-compose-demo

  • 编写 app.py(Flask 示例):

import os
from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello():
    message = os.environ.get('MESSAGE', 'Hello World')
    return f'<h1>{message}</h1>'

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)
  • 编写 requirements.txt:
flask
  • 编写 Dockerfile
FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY app.py .
CMD ["python", "app.py"]
  • 编写 docker-compose.yml
version: '3.8'
services:
  web:
    build: .
    ports:
      - "5000:5000"
    environment:
      - MESSAGE=Hello from Compose
  • 启动:docker-compose up -d,访问 http://localhost:5000 看到消息。

  • 创建 .env 文件,内容:PORT=8080,并修改 Compose 文件:
    docker-compose.yml会自动读取.env里面的内容。

ports:
  - "${PORT}:5000"
  • 重新启动:docker-compose down && docker-compose up -d,访问 http://localhost:8080

  • 尝试修改 .env 中的 PORT 值,再次启动验证。

任务 2:多文件环境配置(开发 vs 生产)
目标:使用 docker-compose.override.yml 实现开发环境的热加载。

  • 沿用任务 1 的项目,创建 docker-compose.override.yml
version: '3.8'
services:
  web:
    environment:
      - MESSAGE=Development Mode
    volumes:
      - ./app.py:/app/app.py   # 挂载代码实现热加载
    command: python app.py --debug   # 开启 debug 模式
  • 执行 docker-compose up -d,此时会自动合并 docker-compose.ymldocker-compose.override.yml。访问页面看到 "Development Mode"。

  • 修改本地的 app.py 中的消息内容,保存后刷新页面,看是否立即生效(取决于 Flask 是否开启 debug 或重启)。

  • 创建生产环境文件 docker-compose.prod.yml

version: '3.8'
services:
  web:
    environment:
      - MESSAGE=Production Mode
    restart: always
  • 使用 -f 启动生产配置:
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d
  • 清理:docker-compose down

任务 3:健康检查与依赖控制
目标: 模拟一个依赖数据库的应用,确保数据库健康后才启动应用。

  • 创建 docker-compose.yml
version: '3.8'
services:
  db:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: example
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s
      timeout: 5s
      retries: 3
  app:
    image: alpine:latest
    command: sh -c "while true; do echo waiting for db... && sleep 5; done"
    depends_on:
      db:
        condition: service_healthy
  • 启动:docker-compose up -d,观察 app 容器会等待 db 健康检查通过后才启动。

  • 查看日志:docker-compose logs app,确认在 db 健康后启动。

任务 4:使用外部卷和网络
目标: 创建一个自定义网络和卷,在 Compose 中引用外部资源。

  • 预先创建卷和网络:
docker volume create shared-data
docker network create mynet
  • 编写 docker-compose.yml
version: '3.8'
services:
  writer:
    image: alpine
    command: sh -c "echo hello > /data/msg && tail -f /dev/null"
    volumes:
      - shared-data:/data
    networks:
      - mynet
  reader:
    image: alpine
    command: sh -c "sleep 10 && cat /data/msg && tail -f /dev/null"
    volumes:
      - shared-data:/data
    networks:
      - mynet
volumes:
  shared-data:
    external: true
networks:
  mynet:
    external: true
  • 启动:docker-compose up -d,查看 reader 日志应该能读取到 hello。

  • 清理:docker-compose down,手动删除卷和网络:docker volume rm shared-datadocker network rm mynet

任务 5:水平扩展与负载均衡(结合 Nginx)
目标: 扩展 Web 服务到 3 个实例,并通过 Nginx 负载均衡访问。

  • 创建简单 Web 应用(返回实例主机名)。编写 app.py:
import os
from flask import Flask
app = Flask(__name__)
hostname = os.environ.get('HOSTNAME', 'unknown')

@app.route('/')
def index():
    return f'Hello from {hostname}\n'

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

Dockerfile 同上(Flask)。

FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY app.py .
CMD ["python", "app.py"]

requirements.txt

flask

docker-compose.yml:

version: '3.8'
services:
  web:
    build: .
    # 下面的必须注释,容器启动时,会自动注入容器id到HOSTNAME
    #environment:
    # - HOSTNAME=${HOSTNAME}
    # 不暴露端口,让 Nginx 代理
  nginx:
    image: nginx:alpine
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
    ports:
      - "8080:80"
    depends_on:
      - web
  • 编写 nginx.conf(简单负载均衡):
events { worker_connections 1024; }

http {
  upstream web_servers {
    server web:5000;
  }

  server {
    listen 80;
    location / {
      proxy_pass http://web_servers;
      proxy_set_header Host $host;
    }
  }
}
  • 启动服务并扩展 web 到 3 个实例:
docker-compose up -d --scale web=3

多次访问 http://localhost:8080 ,观察返回的主机名应该在不同容器之间轮询(Nginx 默认轮询)。

  • 查看容器状态:docker-compose ps。

  • 清理:docker-compose down