名称: docker-compose-production 用户可调用: false 描述: 当部署Docker Compose应用到生产环境时使用,包括安全加固、资源管理、健康检查、日志记录、监控和高可用性模式。 允许工具: [Bash, Read]
Docker Compose 生产部署
生产就绪的Docker Compose配置,包含安全、可靠性和可扩展性的最佳实践。
生产就绪基础模板
一个全面的生产模板,包含基本配置:
版本: '3.8'
服务:
nginx:
图像: nginx:1.25-alpine
容器名称: production-nginx
重启: unless-stopped
端口:
- "80:80"
- "443:443"
卷:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./nginx/ssl:/etc/nginx/ssl:ro
- nginx-cache:/var/cache/nginx
- nginx-logs:/var/log/nginx
网络:
- frontend
健康检查:
测试: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost/health"]
间隔: 30s
超时: 10s
重试: 3
启动期: 40s
日志:
驱动: "json-file"
选项:
最大大小: "10m"
最大文件: "3"
部署:
资源:
限制:
cpus: '1.0'
内存: 512M
保留:
cpus: '0.5'
内存: 256M
api:
图像: mycompany/api:${API_VERSION:-latest}
容器名称: production-api
重启: unless-stopped
网络:
- frontend
- backend
环境:
NODE_ENV: production
DATABASE_URL: postgresql://postgres:5432/production_db
REDIS_URL: redis://cache:6379
LOG_LEVEL: ${LOG_LEVEL:-info}
PORT: 3000
环境文件:
- .env.production
秘密:
- db_password
- jwt_secret
健康检查:
测试: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:3000/health"]
间隔: 30s
超时: 10s
重试: 3
启动期: 60s
依赖:
数据库:
条件: service_healthy
缓存:
条件: service_healthy
日志:
驱动: "json-file"
选项:
最大大小: "10m"
最大文件: "5"
部署:
资源:
限制:
cpus: '2.0'
内存: 2G
保留:
cpus: '1.0'
内存: 1G
worker:
图像: mycompany/worker:${WORKER_VERSION:-latest}
容器名称: production-worker
重启: unless-stopped
网络:
- backend
环境:
NODE_ENV: production
DATABASE_URL: postgresql://postgres:5432/production_db
REDIS_URL: redis://cache:6379
QUEUE_NAME: ${QUEUE_NAME:-default}
环境文件:
- .env.production
秘密:
- db_password
依赖:
数据库:
条件: service_healthy
缓存:
条件: service_healthy
日志:
驱动: "json-file"
选项:
最大大小: "10m"
最大文件: "5"
部署:
副本: 3
资源:
限制:
cpus: '1.0'
内存: 1G
保留:
cpus: '0.5'
内存: 512M
数据库:
图像: postgres:15-alpine
容器名称: production-db
重启: unless-stopped
网络:
- backend
环境:
POSTGRES_DB: production_db
POSTGRES_USER: postgres
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
POSTGRES_INITDB_ARGS: "-E UTF8 --locale=en_US.UTF-8"
秘密:
- db_password
卷:
- postgres-data:/var/lib/postgresql/data
- ./db/init:/docker-entrypoint-initdb.d:ro
- postgres-logs:/var/log/postgresql
健康检查:
测试: ["CMD-SHELL", "pg_isready -U postgres -d production_db"]
间隔: 10s
超时: 5s
重试: 5
启动期: 30s
命令:
- "postgres"
- "-c"
- "max_connections=200"
- "-c"
- "shared_buffers=256MB"
- "-c"
- "effective_cache_size=1GB"
- "-c"
- "maintenance_work_mem=64MB"
- "-c"
- "checkpoint_completion_target=0.9"
- "-c"
- "wal_buffers=16MB"
- "-c"
- "default_statistics_target=100"
- "-c"
- "random_page_cost=1.1"
- "-c"
- "effective_io_concurrency=200"
- "-c"
- "work_mem=1MB"
- "-c"
- "min_wal_size=1GB"
- "-c"
- "max_wal_size=4GB"
日志:
驱动: "json-file"
选项:
最大大小: "10m"
最大文件: "5"
部署:
资源:
限制:
cpus: '2.0'
内存: 2G
保留:
cpus: '1.0'
内存: 1G
缓存:
图像: redis:7-alpine
容器名称: production-cache
重启: unless-stopped
网络:
- backend
命令: >
redis-server
--appendonly yes
--appendfsync everysec
--maxmemory 512mb
--maxmemory-policy allkeys-lru
--requirepass ${REDIS_PASSWORD}
卷:
- redis-data:/data
健康检查:
测试: ["CMD", "redis-cli", "--raw", "incr", "ping"]
间隔: 10s
超时: 5s
重试: 5
启动期: 20s
日志:
驱动: "json-file"
选项:
最大大小: "10m"
最大文件: "3"
部署:
资源:
限制:
cpus: '1.0'
内存: 768M
保留:
cpus: '0.5'
内存: 512M
备份:
图像: prodrigestivill/postgres-backup-local:15-alpine
容器名称: production-backup
重启: unless-stopped
网络:
- backend
环境:
POSTGRES_HOST: 数据库
POSTGRES_DB: production_db
POSTGRES_USER: postgres
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
SCHEDULE: "@daily"
BACKUP_KEEP_DAYS: 7
BACKUP_KEEP_WEEKS: 4
BACKUP_KEEP_MONTHS: 6
HEALTHCHECK_PORT: 8080
秘密:
- db_password
卷:
- ./backups:/backups
依赖:
数据库:
条件: service_healthy
网络:
frontend:
驱动: bridge
backend:
驱动: bridge
内部: true
卷:
postgres-data:
驱动: local
驱动选项:
类型: none
o: bind
设备: /data/postgres
redis-data:
驱动: local
nginx-cache:
驱动: local
nginx-logs:
驱动: local
postgres-logs:
驱动: local
秘密:
db_password:
文件: ./secrets/db_password.txt
jwt_secret:
文件: ./secrets/jwt_secret.txt
安全加固
生产安全配置:
版本: '3.8'
服务:
web:
图像: nginx:1.25-alpine
重启: unless-stopped
只读: true
tmpfs:
- /var/cache/nginx
- /var/run
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE
security_opt:
- no-new-privileges:true
- seccomp:./security/seccomp-profile.json
用户: "nginx:nginx"
网络:
- frontend
端口:
- "80:80"
- "443:443"
卷:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./nginx/ssl:/etc/nginx/ssl:ro
api:
图像: mycompany/api:${VERSION}
重启: unless-stopped
只读: true
tmpfs:
- /tmp
cap_drop:
- ALL
security_opt:
- no-new-privileges:true
- seccomp:./security/seccomp-profile.json
用户: "1000:1000"
网络:
- frontend
- backend
环境:
NODE_ENV: production
环境文件:
- .env.production
秘密:
- 源: db_password
目标: /run/secrets/db_password
模式: 0400
- 源: api_key
目标: /run/secrets/api_key
模式: 0400
数据库:
图像: postgres:15-alpine
重启: unless-stopped
只读: true
tmpfs:
- /tmp
- /run/postgresql
cap_drop:
- ALL
cap_add:
- CHOWN
- DAC_OVERRIDE
- FOWNER
- SETGID
- SETUID
security_opt:
- no-new-privileges:true
用户: "postgres:postgres"
网络:
- backend
环境:
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
秘密:
- 源: db_password
模式: 0400
卷:
- postgres-data:/var/lib/postgresql/data
网络:
frontend:
驱动: bridge
驱动选项:
com.docker.network.bridge.enable_icc: "false"
backend:
驱动: bridge
内部: true
卷:
postgres-data:
秘密:
db_password:
文件: ./secrets/db_password.txt
api_key:
文件: ./secrets/api_key.txt
资源限制和保留
全面资源管理:
版本: '3.8'
服务:
web:
图像: nginx:alpine
重启: unless-stopped
部署:
资源:
限制:
cpus: '0.50'
内存: 256M
pids: 100
保留:
cpus: '0.25'
内存: 128M
ulimits:
nofile:
软: 1024
硬: 2048
nproc:
软: 64
硬: 128
api:
图像: node:18-alpine
重启: unless-stopped
部署:
资源:
限制:
cpus: '2.0'
内存: 2G
pids: 200
保留:
cpus: '1.0'
内存: 1G
ulimits:
nofile:
软: 4096
硬: 8192
nproc:
软: 256
硬: 512
数据库:
图像: postgres:15-alpine
重启: unless-stopped
部署:
资源:
限制:
cpus: '4.0'
内存: 4G
pids: 500
保留:
cpus: '2.0'
内存: 2G
ulimits:
nofile:
软: 8192
硬: 16384
shm_size: '256mb'
卷:
- postgres-data:/var/lib/postgresql/data
缓存:
图像: redis:7-alpine
重启: unless-stopped
部署:
资源:
限制:
cpus: '1.0'
内存: 1G
保留:
cpus: '0.5'
内存: 512M
sysctls:
net.core.somaxconn: 1024
卷:
- redis-data:/data
卷:
postgres-data:
redis-data:
高可用性配置
多个副本与负载均衡:
版本: '3.8'
服务:
负载均衡器:
图像: nginx:alpine
重启: unless-stopped
端口:
- "80:80"
- "443:443"
卷:
- ./nginx/nginx-lb.conf:/etc/nginx/nginx.conf:ro
- ./nginx/ssl:/etc/nginx/ssl:ro
网络:
- frontend
健康检查:
测试: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost/health"]
间隔: 10s
超时: 5s
重试: 3
部署:
资源:
限制:
cpus: '1.0'
内存: 512M
api:
图像: mycompany/api:${VERSION}
重启: unless-stopped
网络:
- frontend
- backend
环境:
NODE_ENV: production
DATABASE_URL: postgresql://postgres:5432/app
INSTANCE_ID: "{{.Task.Slot}}"
部署:
副本: 5
更新配置:
并行度: 2
延迟: 10s
顺序: start-first
失败操作: rollback
回滚配置:
并行度: 2
延迟: 10s
重启策略:
条件: on-failure
延迟: 5s
最大尝试: 3
窗口: 120s
资源:
限制:
cpus: '1.0'
内存: 1G
保留:
cpus: '0.5'
内存: 512M
健康检查:
测试: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:3000/health"]
间隔: 30s
超时: 10s
重试: 3
启动期: 60s
数据库:
图像: postgres:15-alpine
重启: unless-stopped
网络:
- backend
环境:
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
秘密:
- db_password
卷:
- postgres-data:/var/lib/postgresql/data
健康检查:
测试: ["CMD-SHELL", "pg_isready"]
间隔: 10s
超时: 5s
重试: 5
部署:
资源:
限制:
cpus: '4.0'
内存: 4G
数据库副本:
图像: postgres:15-alpine
重启: unless-stopped
网络:
- backend
环境:
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
POSTGRES_PRIMARY_HOST: 数据库
POSTGRES_PRIMARY_PORT: 5432
秘密:
- db_password
卷:
- postgres-replica-data:/var/lib/postgresql/data
- ./db/replica-setup.sh:/docker-entrypoint-initdb.d/replica-setup.sh:ro
依赖:
数据库:
条件: service_healthy
部署:
资源:
限制:
cpus: '2.0'
内存: 2G
网络:
frontend:
驱动: bridge
backend:
驱动: bridge
内部: true
卷:
postgres-data:
postgres-replica-data:
秘密:
db_password:
文件: ./secrets/db_password.txt
监控和可观察性
生产监控堆栈:
版本: '3.8'
服务:
prometheus:
图像: prom/prometheus:latest
容器名称: prometheus
重启: unless-stopped
命令:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
- '--storage.tsdb.retention.time=30d'
- '--web.console.libraries=/usr/share/prometheus/console_libraries'
- '--web.console.templates=/usr/share/prometheus/consoles'
- '--web.enable-lifecycle'
卷:
- ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml:ro
- ./monitoring/alerts:/etc/prometheus/alerts:ro
- prometheus-data:/prometheus
网络:
- monitoring
端口:
- "9090:9090"
健康检查:
测试: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:9090/-/healthy"]
间隔: 30s
超时: 10s
重试: 3
部署:
资源:
限制:
cpus: '1.0'
内存: 2G
grafana:
图像: grafana/grafana:latest
容器名称: grafana
重启: unless-stopped
环境:
GF_SECURITY_ADMIN_PASSWORD__FILE: /run/secrets/grafana_password
GF_INSTALL_PLUGINS: grafana-clock-panel,grafana-simple-json-datasource
GF_SERVER_ROOT_URL: https://monitoring.example.com
秘密:
- grafana_password
卷:
- ./monitoring/grafana/provisioning:/etc/grafana/provisioning:ro
- ./monitoring/grafana/dashboards:/var/lib/grafana/dashboards:ro
- grafana-data:/var/lib/grafana
网络:
- monitoring
- frontend
端口:
- "3001:3000"
依赖:
- prometheus
健康检查:
测试: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:3000/api/health"]
间隔: 30s
超时: 10s
重试: 3
部署:
资源:
限制:
cpus: '0.5'
内存: 512M
node-exporter:
图像: prom/node-exporter:latest
容器名称: node-exporter
重启: unless-stopped
命令:
- '--path.rootfs=/host'
- '--path.procfs=/host/proc'
- '--path.sysfs=/host/sys'
- '--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)'
卷:
- /:/host:ro,rslave
网络:
- monitoring
端口:
- "9100:9100"
部署:
资源:
限制:
cpus: '0.2'
内存: 128M
cadvisor:
图像: gcr.io/cadvisor/cadvisor:latest
容器名称: cadvisor
重启: unless-stopped
特权: true
设备:
- /dev/kmsg
卷:
- /:/rootfs:ro
- /var/run:/var/run:ro
- /sys:/sys:ro
- /var/lib/docker:/var/lib/docker:ro
- /dev/disk:/dev/disk:ro
网络:
- monitoring
端口:
- "8080:8080"
部署:
资源:
限制:
cpus: '0.3'
内存: 256M
loki:
图像: grafana/loki:latest
容器名称: loki
重启: unless-stopped
命令: -config.file=/etc/loki/local-config.yaml
卷:
- ./monitoring/loki-config.yml:/etc/loki/local-config.yaml:ro
- loki-data:/loki
网络:
- monitoring
端口:
- "3100:3100"
部署:
资源:
限制:
cpus: '1.0'
内存: 1G
promtail:
图像: grafana/promtail:latest
容器名称: promtail
重启: unless-stopped
命令: -config.file=/etc/promtail/config.yml
卷:
- ./monitoring/promtail-config.yml:/etc/promtail/config.yml:ro
- /var/log:/var/log:ro
- /var/lib/docker/containers:/var/lib/docker/containers:ro
网络:
- monitoring
依赖:
- loki
部署:
资源:
限制:
cpus: '0.2'
内存: 256M
网络:
monitoring:
驱动: bridge
frontend:
驱动: bridge
卷:
prometheus-data:
grafana-data:
loki-data:
秘密:
grafana_password:
文件: ./secrets/grafana_password.txt
日志配置
集中式日志设置:
版本: '3.8'
服务:
应用:
图像: myapp:latest
重启: unless-stopped
日志:
驱动: "json-file"
选项:
最大大小: "10m"
最大文件: "5"
标签: "app,environment,version"
标签: "{{.Name}}/{{.ID}}"
标签:
app: "myapp"
environment: "production"
version: "${VERSION}"
nginx:
图像: nginx:alpine
重启: unless-stopped
日志:
驱动: "syslog"
选项:
syslog地址: "tcp://logserver:514"
标签: "nginx"
syslog格式: "rfc5424micro"
api:
图像: api:latest
重启: unless-stopped
日志:
驱动: "fluentd"
选项:
fluentd地址: "localhost:24224"
标签: "docker.{{.Name}}"
fluentd异步连接: "true"
fluentd重试等待: "1s"
fluentd最大重试: "30"
数据库:
图像: postgres:15-alpine
重启: unless-stopped
日志:
驱动: "json-file"
选项:
最大大小: "50m"
最大文件: "10"
压缩: "true"
卷:
- postgres-data:/var/lib/postgresql/data
卷:
postgres-data:
环境配置管理
多环境设置:
版本: '3.8'
服务:
应用:
图像: myapp:${VERSION:-latest}
重启: unless-stopped
环境:
NODE_ENV: ${NODE_ENV:-production}
LOG_LEVEL: ${LOG_LEVEL:-info}
PORT: ${APP_PORT:-3000}
DATABASE_URL: postgresql://${DB_USER}:${DB_PASSWORD}@database:5432/${DB_NAME}
REDIS_URL: redis://:${REDIS_PASSWORD}@cache:6379
JWT_SECRET: ${JWT_SECRET}
API_TIMEOUT: ${API_TIMEOUT:-30000}
MAX_CONNECTIONS: ${MAX_CONNECTIONS:-100}
环境文件:
- .env.${ENVIRONMENT:-production}
- .env.secrets
网络:
- app-network
数据库:
图像: postgres:${POSTGRES_VERSION:-15}-alpine
重启: unless-stopped
环境:
POSTGRES_DB: ${DB_NAME}
POSTGRES_USER: ${DB_USER}
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_INITDB_ARGS: ${POSTGRES_INITDB_ARGS:--E UTF8}
卷:
- postgres-data:/var/lib/postgresql/data
网络:
- app-network
缓存:
图像: redis:${REDIS_VERSION:-7}-alpine
重启: unless-stopped
命令: redis-server --requirepass ${REDIS_PASSWORD} --maxmemory ${REDIS_MAX_MEMORY:-256mb}
卷:
- redis-data:/data
网络:
- app-network
网络:
app-network:
驱动: bridge
卷:
postgres-data:
redis-data:
健康检查和就绪
全面健康监控:
版本: '3.8'
服务:
web:
图像: nginx:alpine
重启: unless-stopped
健康检查:
测试: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost/health"]
间隔: 30s
超时: 10s
重试: 3
启动期: 40s
api:
图像: node:18-alpine
重启: unless-stopped
健康检查:
测试: ["CMD", "node", "healthcheck.js"]
间隔: 30s
超时: 10s
重试: 3
启动期: 60s
依赖:
数据库:
条件: service_healthy
缓存:
条件: service_healthy
数据库:
图像: postgres:15-alpine
重启: unless-stopped
健康检查:
测试: ["CMD-SHELL", "pg_isready -U postgres -d production_db || exit 1"]
间隔: 10s
超时: 5s
重试: 5
启动期: 30s
卷:
- postgres-data:/var/lib/postgresql/data
缓存:
图像: redis:7-alpine
重启: unless-stopped
健康检查:
测试: ["CMD", "redis-cli", "ping"]
间隔: 10s
超时: 5s
重试: 5
启动期: 20s
卷:
- redis-data:/data
队列:
图像: rabbitmq:3-management-alpine
重启: unless-stopped
健康检查:
测试: ["CMD", "rabbitmq-diagnostics", "ping"]
间隔: 30s
超时: 10s
重试: 5
启动期: 60s
卷:
- rabbitmq-data:/var/lib/rabbitmq
卷:
postgres-data:
redis-data:
rabbitmq-data:
备份和恢复
自动备份配置:
版本: '3.8'
服务:
数据库:
图像: postgres:15-alpine
重启: unless-stopped
环境:
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
秘密:
- db_password
卷:
- postgres-data:/var/lib/postgresql/data
网络:
- backend
数据库备份:
图像: prodrigestivill/postgres-backup-local:15-alpine
重启: unless-stopped
环境:
POSTGRES_HOST: 数据库
POSTGRES_DB: ${DB_NAME}
POSTGRES_USER: ${DB_USER}
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
SCHEDULE: "@daily"
BACKUP_KEEP_DAYS: 7
BACKUP_KEEP_WEEKS: 4
BACKUP_KEEP_MONTHS: 6
BACKUP_DIR: /backups
HEALTHCHECK_PORT: 8080
秘密:
- db_password
卷:
- ./backups:/backups
- ./backup-scripts:/scripts:ro
网络:
- backend
依赖:
数据库:
条件: service_healthy
卷备份:
图像: futurice/docker-volume-backup:2.6.0
重启: unless-stopped
环境:
BACKUP_CRON_EXPRESSION: "0 2 * * *"
BACKUP_FILENAME: "backup-%Y-%m-%d_%H-%M-%S.tar.gz"
BACKUP_RETENTION_DAYS: 30
AWS_S3_BUCKET_NAME: ${S3_BACKUP_BUCKET}
AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID}
AWS_SECRET_ACCESS_KEY_FILE: /run/secrets/aws_secret
秘密:
- aws_secret
卷:
- postgres-data:/backup/postgres-data:ro
- redis-data:/backup/redis-data:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./backup-archive:/archive
网络:
backend:
驱动: bridge
卷:
postgres-data:
redis-data:
秘密:
db_password:
文件: ./secrets/db_password.txt
aws_secret:
文件: ./secrets/aws_secret.txt
何时使用此技能
使用docker-compose-production当您需要:
- 将Docker Compose应用程序部署到生产环境
- 实施安全加固和最佳实践
- 配置资源限制和保留
- 设置健康检查和就绪探针
- 实现具有多个副本的高可用性
- 配置生产级日志记录和监控
- 设置自动备份和灾难恢复
- 管理秘密和敏感配置
- 实施零停机部署
- 配置多环境部署策略
- 设置容器编排以处理生产工作负载
- 优化性能和资源利用率
最佳实践
-
始终使用版本固定:固定特定镜像版本,而不是使用
latest,以确保可重复部署。 -
实施健康检查:为所有服务配置健康检查,以启用自动恢复和适当的依赖管理。
-
设置资源限制:始终定义CPU和内存限制,以防止资源耗尽并确保可预测性能。
-
使用秘密管理:永远不要将秘密存储在环境变量或compose文件中;使用Docker秘密或外部秘密管理器。
-
配置重启策略:对生产服务使用
restart: unless-stopped,以确保从故障中自动恢复。 -
实施适当日志记录:配置结构化日志记录与轮换和保留策略,以管理磁盘空间。
-
使用只读文件系统:尽可能设置
read_only: true,并对临时数据使用tmpfs以提高安全性。 -
删除不必要能力:使用
cap_drop: ALL并仅添加所需能力,以遵循最小特权原则。 -
启用监控:部署监控和可观察性工具,以跟踪应用程序健康和性能指标。
-
实施自动备份:配置定期自动备份与保留策略,并测试恢复程序。
-
使用内部网络:将后端网络标记为内部,以防止直接外部访问数据库和缓存。
-
配置更新策略:定义更新和回滚配置以实现零停机部署。
-
实施资源保留:设置资源保留以保障关键服务的最低资源。
-
使用多阶段依赖:配置
depends_on与健康检查条件,以确保适当的启动顺序。 -
文档配置:维护生产配置和部署程序的全面文档。
常见陷阱
-
使用最新标签:使用
latest或未版本化镜像可能在镜像更新时导致意外行为;始终固定版本。 -
忽略资源限制:未设置资源限制可能允许一个服务消耗所有可用资源并导致其他服务崩溃。
-
缺失健康检查:没有健康检查,Docker无法确定服务是否实际就绪或需要重启。
-
以纯文本存储秘密:将秘密提交到版本控制或存储在环境变量中会暴露敏感数据。
-
不测试备份:创建备份而无需定期测试恢复程序会导致实际事件中的数据丢失。
-
暴露不必要端口:将所有服务端口发布到主机增加攻击面;仅暴露所需内容。
-
以根用户运行:未指定非根用户会使容器容易受到特权升级攻击。
-
忽略日志轮换:没有日志轮换,日志可能填满磁盘空间并导致服务或主机崩溃。
-
缺失监控:部署没有监控使得在影响用户之前检测和诊断问题变得不可能。
-
不使用网络:在默认网络上运行所有服务阻止适当分段并增加安全风险。
-
忘记就绪检查:在依赖项就绪之前启动依赖服务会导致连接故障和重启。
-
硬编码配置:在compose文件中嵌入环境特定值使得部署到多个环境变得困难。
-
忽视安全更新:不定期更新基础镜像会使服务易受已知安全问题影响。
-
启动期不足:设置健康检查启动期过短导致在慢速应用程序启动期间出现误报。
-
未计划扩展:设计服务时未考虑水平扩展使得处理增加负载变得困难。