



















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:
- db
- redis
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
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 顶级卷定义(写在文件最外层,不是服务里)。作用:提前定义好数据卷,让所有容器共用、管理更清晰。
每个字段意思:
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
# common.yml
services:
base:
image: alpine
restart: always
# docker-compose.yml
services:
web:
extends:
file: common.yml
service: base
command: /app/web
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 实现开发环境的热加载。
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.yml 和 docker-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-data、docker network rm mynet。
任务 5:水平扩展与负载均衡(结合 Nginx)
目标: 扩展 Web 服务到 3 个实例,并通过 Nginx 负载均衡访问。
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
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;
}
}
}
docker-compose up -d --scale web=3
多次访问 http://localhost:8080 ,观察返回的主机名应该在不同容器之间轮询(Nginx 默认轮询)。
查看容器状态:docker-compose ps。
清理:docker-compose down
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。