Docker Compose实战指南
Docker Compose实战指南
概述与背景
Docker Compose是Docker官方推出的多容器编排工具,它让你能够通过一个YAML配置文件定义、运行和管理多个Docker容器。对于开发环境搭建、微服务应用部署等场景,Docker Compose是不可或缺的利器。
graph TB
subgraph Docker Compose架構
A[docker-compose.yml] --> B[Docker Compose]
B --> C[服務編排]
C --> D[Web服務<br/>nginx:alpine]
C --> E[應用服務<br/>backend:node]
C --> F[數據庫服務<br/>postgres:15]
C --> G[緩存服務<br/>redis:7]
D --> H[Docker Network<br/>app_network]
E --> H
F --> H
G --> H
F --> I[Volume<br/>db_data]
G --> J[Volume<br/>redis_data]
end
style A fill:#fff9c4
style B fill:#e1f5fe
style C fill:#f3e5f5
style H fill:#c8e6c9
graph LR
subgraph 手動Docker vs Compose對比
A[手動Docker] --> A1[多個docker run命令]
A --> A2[命令冗長易錯]
A --> A3[配置分散]
A --> A4[難以版本控制]
B[Docker Compose] --> B1[單個YAML文件]
B --> B2[聲明式配置]
B --> B3[一鍵部署]
B --> B4[Git友好]
end
style A fill:#ffcdd2
style B fill:#c8e6c9
为什么需要Docker Compose?
传统Docker命令的局限:
# 手动启动多个容器(繁琐且易错)
docker run -d --name db -e POSTGRES_PASSWORD=pass postgres:15
docker run -d --name redis redis:7
docker run -d --name backend --link db:db --link redis:redis -p 3000:3000 myapp
docker run -d --name nginx --link backend:backend -p 80:80 nginx
# 问题:
# 1. 命令冗长,难以维护
# 2. 容器间通信配置复杂
# 3. 启动顺序难以控制
# 4. 环境变量分散管理
# 5. 无法一键重建整个环境
Docker Compose解决方案:
# docker-compose.yml - 声明式配置
services:
db:
image: postgres:15
environment:
POSTGRES_PASSWORD: pass
redis:
image: redis:7
backend:
build: ./backend
ports:
- "3000:3000"
nginx:
image: nginx:alpine
ports:
- "80:80"
# 一键启动所有服务
# docker compose up -d
核心优势对比
| 维度 | 手动Docker命令 | Docker Compose |
|---|---|---|
| 配置管理 | 分散在脚本中 | 集中在YAML文件 |
| 一键部署 | ❌ 需要多个命令 | ✅ docker compose up |
| 版本控制 | ❌ 困难 | ✅ Git友好 |
| 环境一致性 | ❌ 易出错 | ✅ 声明式配置 |
| 服务依赖 | ❌ 手动控制 | ✅ 自动管理 |
| 多环境支持 | ❌ 复杂 | ✅ override文件 |
| 团队协作 | ❌ 文档说明 | ✅ 配置即文档 |
核心概念
graph TD
subgraph Compose核心概念
A[Services<br/>服務] --> A1[容器定義]
A1 --> A2[映像來源]
A1 --> A3[端口映射]
A1 --> A4[環境變量]
B[Networks<br/>網絡] --> B1[服務間通信]
B --> B2[網絡隔離]
C[Volumes<br/>卷] --> C1[數據持久化]
C --> C2[配置文件掛載]
D[Configs<br/>配置] --> D1[敏感配置]
D --> D2[環境特定配置]
E[Secrets<br/>密鑰] --> E1[密碼/證書]
E --> E2[API密鑰]
end
style A fill:#e1f5fe
style B fill:#fff3e0
style C fill:#c8e6c9
style D fill:#f3e5f5
style E fill:#ffcdd2
sequenceDiagram
participant D as 開發者
participant C as Docker Compose
participant N as Docker Network
participant S as 服務容器
Note over D,S: 服務啟動流程
D->>C: docker compose up -d
C->>C: 解析docker-compose.yml
C->>N: 創建網絡
C->>S: 按依賴順序啟動服務
loop 健康檢查
C->>S: 檢查服務狀態
S-->>C: 返回健康狀態
end
C-->>D: 所有服務就緒
Note over D,S: 服務擴縮容
D->>C: docker compose up -d --scale backend=3
C->>S: 啟動多個backend實例
S-->>C: 註冊到負載均衡
C-->>D: 擴容完成
Note over D,S: 服務更新
D->>C: docker compose up -d --build
C->>S: 重建映像
C->>S: 滾動更新服務
S-->>C: 更新完成
C-->>D: 服務已更新
服务(Service)
服务是Compose的基本单元,对应一个应用容器。
services:
# 单实例服务
web:
image: nginx:alpine
# 多实例服务(可扩展)
api:
image: myapi:latest
deploy:
replicas: 3 # 运行3个实例
项目(Project)
项目是一组相关服务的集合,默认使用目录名作为项目名。
# 项目名规则
# 默认:目录名(如 myapp)
# 自定义:COMPOSE_PROJECT_NAME=myproject docker compose up
# 或在.env中设置:COMPOSE_PROJECT_NAME=myproject
网络(Network)
服务之间通过服务名通信,Compose自动创建默认网络。
services:
backend:
# 可以通过 "db" 或 "redis" 访问其他服务
environment:
- DB_HOST=db
- REDIS_HOST=redis
db:
image: postgres:15
redis:
image: redis:7
# Compose自动创建:myapp_default 网络
# 所有服务默认加入该网络
卷(Volume)
卷用于持久化数据,即使容器删除数据也不会丢失。
services:
db:
image: postgres:15
volumes:
- postgres_data:/var/lib/postgresql/data # 命名卷
- ./init.sql:/docker-entrypoint-initdb.d/ # 主机挂载
volumes:
postgres_data: # 定义命名卷
实战步骤
第一步:安装与验证
# Docker Desktop 已内置 Compose
# 检查版本
docker compose version
# Docker Compose version v2.24.0
# Linux 单独安装(如果未内置)
sudo curl -L "https://github.com/docker/compose/releases/download/v2.24.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
# 验证安装
docker compose version
版本说明:
- Docker Compose V2:使用
docker compose命令(推荐) - Docker Compose V1:使用
docker-compose命令(已废弃)
第二步:第一个Compose项目
2.1 项目结构
my-nginx/
├── docker-compose.yml
├── html/
│ └── index.html
└── nginx.conf
2.2 创建基础文件
index.html:
<!DOCTYPE html>
<html>
<head>
<title>My Docker App</title>
</head>
<body>
<h1>Hello from Docker Compose!</h1>
</body>
</html>
nginx.conf:
events {
worker_connections 1024;
}
http {
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html;
}
}
}
docker-compose.yml:
version: '3.8'
services:
web:
image: nginx:alpine
ports:
- "8080:80"
volumes:
- ./html:/usr/share/nginx/html
- ./nginx.conf:/etc/nginx/nginx.conf:ro
restart: unless-stopped
2.3 启动服务
# 前台运行(看到日志)
docker compose up
# 后台运行(推荐)
docker compose up -d
# 输出
[+] Running 2/2
✔ Network my-nginx_default Created
✔ Container my-nginx-web-1 Started
# 查看运行状态
docker compose ps
# NAME IMAGE STATUS PORTS
# my-nginx-web-1 nginx:alpine Up 2 minutes 0.0.0.0:8080->80/tcp
# 访问应用
curl http://localhost:8080
# <h1>Hello from Docker Compose!</h1>
# 停止服务
docker compose down
第三步:多服务编排
3.1 完整的Web应用栈
构建一个典型的三层架构:Nginx → Node.js → PostgreSQL + Redis
项目结构:
fullstack-app/
├── docker-compose.yml
├── .env
├── nginx/
│ └── nginx.conf
├── backend/
│ ├── Dockerfile
│ ├── package.json
│ └── src/
│ └── server.js
└── init/
└── init.sql
docker-compose.yml:
version: '3.8'
services:
# ==================== 前端 - Nginx ====================
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./nginx/ssl:/etc/nginx/ssl:ro
depends_on:
backend:
condition: service_healthy
networks:
- frontend
- backend
restart: unless-stopped
healthcheck:
test: ["CMD", "nginx", "-t"]
interval: 30s
timeout: 10s
retries: 3
# ==================== 后端 - Node.js ====================
backend:
build:
context: ./backend
dockerfile: Dockerfile
environment:
- NODE_ENV=production
- DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}
- REDIS_URL=redis://redis:6379
- JWT_SECRET=${JWT_SECRET}
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
networks:
- backend
restart: unless-stopped
healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
deploy:
resources:
limits:
cpus: '1'
memory: 512M
# ==================== 数据库 - PostgreSQL ====================
db:
image: postgres:15-alpine
environment:
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: ${POSTGRES_DB}
volumes:
- postgres_data:/var/lib/postgresql/data
- ./init/init.sql:/docker-entrypoint-initdb.d/init.sql:ro
networks:
- backend
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
interval: 10s
timeout: 5s
retries: 5
# ==================== 缓存 - Redis ====================
redis:
image: redis:7-alpine
command: redis-server --appendonly yes --maxmemory 256mb --maxmemory-policy allkeys-lru
volumes:
- redis_data:/data
networks:
- backend
restart: unless-stopped
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 3
networks:
frontend:
driver: bridge
backend:
driver: bridge
internal: true # 内部网络,不暴露到外部
volumes:
postgres_data:
redis_data:
3.2 服务间通信示例
backend/src/server.js:
const express = require('express');
const { Pool } = require('pg');
const Redis = require('ioredis');
const app = express();
// 使用服务名作为主机名
const pool = new Pool({
host: 'db', // Docker Compose服务名
port: 5432,
user: process.env.POSTGRES_USER,
password: process.env.POSTGRES_PASSWORD,
database: process.env.POSTGRES_DB,
});
const redis = new Redis({
host: 'redis', // Docker Compose服务名
port: 6379,
});
// 健康检查端点
app.get('/health', (req, res) => {
res.json({ status: 'ok', timestamp: new Date().toISOString() });
});
// 缓存示例
app.get('/api/users/:id', async (req, res) => {
const cacheKey = `user:${req.params.id}`;
// 先查缓存
const cached = await redis.get(cacheKey);
if (cached) {
return res.json(JSON.parse(cached));
}
// 查数据库
const result = await pool.query('SELECT * FROM users WHERE id = $1', [req.params.id]);
const user = result.rows[0];
if (user) {
// 写入缓存,过期10分钟
await redis.setex(cacheKey, 600, JSON.stringify(user));
}
res.json(user);
});
app.listen(3000, () => {
console.log('Server running on port 3000');
});
第四步:构建自定义镜像
4.1 多阶段构建Dockerfile
backend/Dockerfile:
# ==================== 构建阶段 ====================
FROM node:20-alpine AS builder
WORKDIR /app
# 复制依赖文件
COPY package*.json ./
# 安装所有依赖(包括devDependencies)
RUN npm ci
# 复制源代码
COPY . .
# 构建应用
RUN npm run build
# ==================== 生产阶段 ====================
FROM node:20-alpine
WORKDIR /app
# 安全:创建非root用户
RUN addgroup -g 1001 -S nodejs && \
adduser -S nodeapp -u 1001
# 复制生产依赖
COPY package*.json ./
RUN npm ci --only=production && npm cache clean --force
# 从构建阶段复制构建产物
COPY --from=builder /app/dist ./dist
# 设置权限
RUN chown -R nodeapp:nodejs /app
# 切换用户
USER nodeapp
# 健康检查
HEALTHCHECK --interval=30s --timeout=10s --retries=3 \
CMD wget -q --spider http://localhost:3000/health || exit 1
# 暴露端口
EXPOSE 3000
# 启动命令
CMD ["node", "dist/server.js"]
4.2 在Compose中使用构建
services:
backend:
build:
context: ./backend
dockerfile: Dockerfile
args:
- NODE_ENV=production
- BUILD_VERSION=1.0.0
# 或直接使用镜像(生产环境)
# image: myregistry/backend:1.0.0
4.3 构建最佳实践
services:
app:
build:
context: ./app
dockerfile: Dockerfile
args:
- NODE_ENV=production
# 多平台构建
platforms:
- linux/amd64
- linux/arm64
# 缓存配置
cache_from:
- myapp:latest
# 标签
tags:
- myapp:latest
- myapp:${VERSION}
第五步:环境配置管理
5.1 环境变量文件
.env(开发环境):
# 项目配置
COMPOSE_PROJECT_NAME=myapp-dev
# 数据库配置
POSTGRES_USER=myuser
POSTGRES_PASSWORD=mypassword
POSTGRES_DB=myapp_dev
# Redis配置
REDIS_PASSWORD=redispassword
# 应用配置
NODE_ENV=development
JWT_SECRET=dev-secret-key-change-in-production
API_PORT=3000
# 外部服务
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USER=noreply@example.com
SMTP_PASSWORD=smtp-password
.env.production(生产环境):
# 项目配置
COMPOSE_PROJECT_NAME=myapp-prod
# 数据库配置(生产环境使用强密码)
POSTGRES_USER=${DB_USER}
POSTGRES_PASSWORD=${DB_PASSWORD}
POSTGRES_DB=myapp
# 应用配置
NODE_ENV=production
JWT_SECRET=${JWT_SECRET}
# 日志配置
LOG_LEVEL=info
5.2 在Compose中使用环境变量
services:
db:
image: postgres:15
environment:
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: ${POSTGRES_DB}
# 或使用env_file
env_file:
- .env
- .env.local # 本地覆盖(不提交到Git)
backend:
environment:
- DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}
- NODE_ENV=${NODE_ENV:-production} # 默认值
5.3 多环境配置策略
方式1:使用多个env文件
# 开发环境
docker compose --env-file .env.development up -d
# 生产环境
docker compose --env-file .env.production up -d
# 测试环境
docker compose --env-file .env.test up -d
方式2:使用Override文件
docker-compose.yml(基础配置):
version: '3.8'
services:
backend:
build: ./backend
environment:
- NODE_ENV=development
volumes:
- ./backend:/app
- /app/node_modules
ports:
- "3000:3000"
docker-compose.override.yml(开发覆盖,自动加载):
version: '3.8'
services:
backend:
environment:
- DEBUG=true
volumes:
- ./backend:/app
# 开发环境启用了热重载
docker-compose.prod.yml(生产配置):
version: '3.8'
services:
backend:
image: myregistry/backend:${VERSION}
environment:
- NODE_ENV=production
restart: always
deploy:
resources:
limits:
memory: 512M
# 不挂载源码
# 开发环境(自动加载override)
docker compose up -d
# 生产环境(显式指定)
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
第六步:常用命令速查
启动和停止
# 启动所有服务(后台)
docker compose up -d
# 启动特定服务
docker compose up -d backend redis
# 停止所有服务
docker compose down
# 停止并删除卷(数据清空)
docker compose down -v
# 停止并删除镜像
docker compose down --rmi all
# 优雅停止(等待任务完成)
docker compose stop
# 强制停止
docker compose kill
查看状态
# 查看运行状态
docker compose ps
# 查看所有容器(包括停止的)
docker compose ps -a
# 查看资源使用
docker compose top
# 查看服务日志
docker compose logs
docker compose logs -f # 实时跟踪
docker compose logs -f backend # 特定服务
docker compose logs --tail=100 # 最后100行
docker compose logs --since=1h # 最近1小时
管理操作
# 重启服务
docker compose restart
docker compose restart nginx # 重启特定服务
# 重新构建
docker compose build
docker compose build --no-cache # 不使用缓存
docker compose up --build # 构建并启动
# 进入容器
docker compose exec backend sh
docker compose exec -u root backend sh # 以root用户
docker compose exec db psql -U user -d myapp # 执行命令
# 运行一次性命令
docker compose run --rm backend npm test
docker compose run --rm db pg_dump -U user myapp > backup.sql
# 扩展服务
docker compose up -d --scale backend=3
# 查看网络
docker compose network ls
docker network inspect myapp_default
# 查看卷
docker compose volume ls
docker volume inspect myapp_postgres_data
调试命令
# 查看配置(解析后的结果)
docker compose config
# 验证配置文件
docker compose config --quiet
# 查看服务依赖关系
docker compose config --services
# 查看环境变量
docker compose config | grep -A 20 environment
# 拉取所有镜像
docker compose pull
# 推送镜像
docker compose push
高级配置
健康检查配置
services:
web:
image: nginx:alpine
healthcheck:
# 检查命令
test: ["CMD", "curl", "-f", "http://localhost/"]
# 或使用shell命令
# test: ["CMD-SHELL", "curl -f http://localhost/ || exit 1"]
# 检查间隔
interval: 30s
# 超时时间
timeout: 10s
# 重试次数
retries: 3
# 启动等待时间
start_period: 10s
健康检查状态:
starting:启动期间healthy:健康unhealthy:不健康(超过重试次数)none:未配置健康检查
资源限制
services:
app:
image: myapp:latest
deploy:
resources:
# 资源限制(硬限制)
limits:
cpus: '2' # 最多使用2个CPU
memory: 1G # 最多使用1GB内存
# 资源预留(软限制)
reservations:
cpus: '0.5' # 预留0.5个CPU
memory: 256M # 预留256MB内存
安全配置
services:
app:
image: myapp:latest
# 只读文件系统
read_only: true
# 安全选项
security_opt:
- no-new-privileges:true
# 能力控制
cap_drop:
- ALL
cap_add:
- CHOWN
- SETGID
- SETUID
# 临时文件系统(只读文件系统需要)
tmpfs:
- /tmp:size=100M,mode=1777
- /var/cache:size=50M
- /var/run:size=10M
# 用户和组
user: "1000:1000"
# 禁止特权
privileged: false
日志配置
services:
app:
image: myapp:latest
logging:
# 日志驱动
driver: "json-file"
options:
# 单个日志文件最大10MB
max-size: "10m"
# 保留3个日志文件
max-file: "3"
# 日志标签
labels: "service,environment"
# 标签值
tag: "{{.Name}}/{{.ID}}"
# 或使用syslog驱动
# logging:
# driver: "syslog"
# options:
# syslog-address: "tcp://logs.example.com:514"
# tag: "myapp"
网络高级配置
networks:
# 前端网络(可从外部访问)
frontend:
driver: bridge
ipam:
driver: default
config:
- subnet: 172.20.0.0/16
gateway: 172.20.0.1
driver_opts:
com.docker.network.bridge.enable_icc: "true"
com.docker.network.bridge.enable_ip_masquerade: "true"
# 后端网络(内部网络,隔离外部访问)
backend:
driver: bridge
internal: true # 无法访问外部网络
ipam:
config:
- subnet: 172.21.0.0/16
# 数据库网络(最严格隔离)
database:
driver: bridge
internal: true
attachable: false # 不允许手动连接容器
services:
nginx:
networks:
- frontend
- backend
backend:
networks:
- backend
- database
db:
networks:
- database
实战案例:微服务架构
完整微服务配置
version: '3.8'
services:
# ==================== 网关服务 ====================
gateway:
image: traefik:v2.10
command:
- "--api.insecure=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
ports:
- "80:80"
- "8080:8080" # Dashboard
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
networks:
- frontend
restart: unless-stopped
# ==================== 用户服务 ====================
user-service:
build:
context: ./services/user
labels:
- "traefik.enable=true"
- "traefik.http.routers.user.rule=PathPrefix(`/api/users`)"
- "traefik.http.routers.user.middlewares=auth"
environment:
- DATABASE_URL=postgresql://user:pass@user-db:5432/users
- JWT_SECRET=${JWT_SECRET}
- REDIS_URL=redis://redis:6379
depends_on:
- user-db
- redis
networks:
- frontend
- backend
restart: unless-stopped
deploy:
replicas: 2
resources:
limits:
memory: 256M
user-db:
image: postgres:15-alpine
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
POSTGRES_DB: users
volumes:
- user_db_data:/var/lib/postgresql/data
networks:
- backend
restart: unless-stopped
# ==================== 订单服务 ====================
order-service:
build:
context: ./services/order
labels:
- "traefik.enable=true"
- "traefik.http.routers.order.rule=PathPrefix(`/api/orders`)"
environment:
- DATABASE_URL=mongodb://order-db:27017/orders
- USER_SERVICE_URL=http://user-service:3000
- RABBITMQ_URL=amqp://rabbitmq:5672
depends_on:
- order-db
- rabbitmq
networks:
- frontend
- backend
restart: unless-stopped
order-db:
image: mongo:6
volumes:
- order_db_data:/data/db
networks:
- backend
restart: unless-stopped
# ==================== 消息队列 ====================
rabbitmq:
image: rabbitmq:3-management-alpine
ports:
- "15672:15672" # Management UI
volumes:
- rabbitmq_data:/var/lib/rabbitmq
networks:
- backend
restart: unless-stopped
healthcheck:
test: ["CMD", "rabbitmqctl", "status"]
interval: 30s
timeout: 10s
retries: 5
# ==================== 缓存 ====================
redis:
image: redis:7-alpine
command: redis-server --maxmemory 512mb --maxmemory-policy allkeys-lru
volumes:
- redis_data:/data
networks:
- backend
restart: unless-stopped
networks:
frontend:
driver: bridge
backend:
driver: bridge
internal: true
volumes:
user_db_data:
order_db_data:
rabbitmq_data:
redis_data:
常见问题解决
Q1: 网络连接问题
症状:服务间无法通信
# 诊断步骤
# 1. 检查网络
docker network ls
docker network inspect myapp_default
# 2. 检查容器是否在同一网络
docker inspect myapp-backend-1 | grep Networks -A 10
# 3. 测试连接
docker compose exec backend ping db
docker compose exec backend nc -zv db 5432
# 4. 检查DNS解析
docker compose exec backend nslookup db
解决方案:
# 确保服务在同一网络
services:
backend:
networks:
- app-network
db:
networks:
- app-network
networks:
app-network:
driver: bridge
Q2: 数据持久化问题
症状:重启后数据丢失
# 正确的卷配置
services:
db:
image: postgres:15
volumes:
# 命名卷(推荐)
- postgres_data:/var/lib/postgresql/data
# 主机挂载(用于初始化脚本)
- ./init.sql:/docker-entrypoint-initdb.d/init.sql:ro
volumes:
postgres_data: # 必须在顶层声明
查看卷位置:
docker volume inspect myapp_postgres_data
# Mountpoint: /var/lib/docker/volumes/myapp_postgres_data/_data
Q3: 服务启动顺序
问题:后端在数据库就绪前启动导致连接失败
解决方案:
services:
backend:
depends_on:
db:
condition: service_healthy # 等待健康检查通过
redis:
condition: service_started # 只等待启动
db:
image: postgres:15
healthcheck:
test: ["CMD-SHELL", "pg_isready -U user -d myapp"]
interval: 5s
timeout: 5s
retries: 5
start_period: 10s
Q4: 端口冲突
症状:端口被占用
# 查看端口占用
lsof -i :3000
# 或
netstat -tulpn | grep :3000
# 解决方案1:修改端口
ports:
- "3001:3000"
# 解决方案2:动态分配
ports:
- "3000" # 宿主机随机分配端口
# 查看分配的端口
docker compose port backend 3000
# 0.0.0.0:32768
Q5: 权限问题
症状:无法写入挂载目录
# 方案1:修改容器用户
services:
app:
user: "${UID:-1000}:${GID:-1000}"
volumes:
- ./data:/app/data
# 方案2:使用命名卷(避免主机权限问题)
services:
app:
volumes:
- app_data:/app/data
volumes:
app_data:
# 主机上修复权限
sudo chown -R 1000:1000 ./data
最佳实践总结
1. 配置文件组织
project/
├── docker-compose.yml # 基础配置
├── docker-compose.override.yml # 开发覆盖(自动加载)
├── docker-compose.prod.yml # 生产配置
├── .env # 环境变量(不提交)
├── .env.example # 环境变量示例(提交)
└── .gitignore
.env
.env.local
2. 安全检查清单
- 使用
.env管理敏感信息 - 不使用
privileged: true - 限制资源使用(CPU、内存)
- 配置只读文件系统
- 使用非root用户运行
- 限制网络访问(internal网络)
- 定期更新基础镜像
3. 性能优化
- 使用
.dockerignore排除不必要文件 - 多阶段构建减小镜像体积
- 使用
depends_on.condition避免启动竞争 - 配置健康检查
- 合理设置日志轮转
4. 运维建议
- 定期备份数据卷
- 监控资源使用
- 配置日志收集
- 使用健康检查
- 准备回滚方案
💬 評論區