Docker 生产级单机部署指南
适用场景服务器资源有限、需要精细化控制每个容器启动参数、或希望深入理解 Docker 底层命令的生产环境。本指南完全基于docker run和原生 Docker 命令构建。1. 核心架构与设计理念在不使用 Docker Compose 的情况下我们需要手动管理容器的生命周期、网络互联和数据卷挂载。1.1 架构拓扑[客户端] -- [Nginx 容器 (Port 80/443)] -- [App 容器 (Port 8000)] | | [Backend Network] | -------------------------- | | | [Postgres] [Redis] [MinIO] (Port 5432) (Port 6379) (Port 9000)1.2 关键设计原则网络隔离创建独立的 Bridge 网络后端服务不暴露端口到宿主机仅通过容器名通信。数据持久化所有状态数据数据库、日志、配置必须挂载到宿主机目录。资源限制为每个容器设置 CPU 和内存上限防止单个服务耗尽资源。自动重启配置--restart unless-stopped确保服务异常退出后自动恢复。2. 基础设施准备2.1 系统优化脚本在生产环境部署前执行以下优化以提升稳定性#!/bin/bash # system-prep.sh 1. 增加文件描述符限制 echo * soft nofile 65536 /etc/security/limits.conf echo * hard nofile 65536 /etc/security/limits.conf 2. 内核参数调优 cat /etc/sysctl.d/99-docker-prod.conf net.ipv4.ip_forward 1 net.core.somaxconn 65535 vm.max_map_count 262144 fs.file-max 65536 EOF sysctl -p /etc/sysctl.d/99-docker-prod.conf 3. 创建项目目录结构 mkdir -p /opt/myapp/{logs,config,data,backups,ssl} mkdir -p /opt/myapp/logs/{app,nginx,postgres,redis} mkdir -p /opt/myapp/data/{postgres,redis,minio}2.2 Docker Daemon 配置编辑/etc/docker/daemon.json以优化全局日志和存储{ storage-driver: overlay2, log-driver: json-file, log-opts: { max-size: 100m, max-file: 5 }, live-restore: true }执行systemctl restart docker生效。3. 网络与存储初始化在启动任何容器之前先创建基础架构资源。3.1 创建专用网络# 创建后端内部网络外部无法直接访问 docker network create --driver bridge backend-net 创建前端网络可选如果 Nginx 需要与其他外部服务通信 docker network create --driver bridge frontend-net3.2 准备数据卷目录确保宿主机目录权限正确避免容器内写入权限问题# 创建数据目录 mkdir -p /opt/myapp/data/postgres mkdir -p /opt/myapp/data/redis mkdir -p /opt/myapp/data/minio 设置权限根据具体用户 ID 调整通常 postgres 用户 ID 为 999 chown -R 999:999 /opt/myapp/data/postgres4. 服务部署详解我们将按照依赖顺序启动服务数据库/缓存 → 应用 → 反向代理。4.1 部署 PostgreSQL 数据库docker run -d \ --name myapp-postgres \ --network backend-net \ --restart unless-stopped \ -e POSTGRES_DBmyapp_db \ -e POSTGRES_USERmyapp_user \ -e POSTGRES_PASSWORDSecurePassword123! \ -v /opt/myapp/data/postgres:/var/lib/postgresql/data \ -v /opt/myapp/logs/postgres:/var/log/postgresql \ -p 127.0.0.1:5432:5432 \ --memory4g \ --cpus2.0 \ postgres:15-alpine \ -c max_connections200注意-p 127.0.0.1:5432:5432仅允许宿主机本地访问增强安全性。4.2 部署 Redis 缓存docker run -d \ --name myapp-redis \ --network backend-net \ --restart unless-stopped \ -v /opt/myapp/data/redis:/data \ -v /opt/myapp/logs/redis:/var/log/redis \ -p 127.0.0.1:6379:6379 \ --memory1g \ --cpus1.0 \ redis:7-alpine \ redis-server --requirepass SecureRedisPass! --maxmemory 512mb --appendonly yes4.3 部署应用服务 (App)假设你已经构建了镜像myapp:latest。docker run -d \ --name myapp-app \ --network backend-net \ --restart unless-stopped \ -e APP_ENVproduction \ -e LOG_LEVELINFO \ -e DATABASE_URLpostgresql://myapp_user:SecurePassword123!myapp-postgres:5432/myapp_db \ -e REDIS_URLredis://:SecureRedisPass!myapp-redis:6379/0 \ -v /opt/myapp/logs/app:/app/logs \ -v /opt/myapp/config:/app/config:ro \ --memory2g \ --cpus2.0 \ --health-cmdcurl -f http://localhost:8000/health || exit 1 \ --health-interval30s \ --health-timeout10s \ --health-retries3 \ myapp:latest关键点使用--network backend-net后应用可以通过容器名myapp-postgres和myapp-redis直接解析 IP。4.4 部署 Nginx 反向代理docker run -d \ --name myapp-nginx \ --network frontend-net \ --restart unless-stopped \ -p 80:80 \ -p 443:443 \ -v /opt/myapp/config/nginx.conf:/etc/nginx/nginx.conf:ro \ -v /opt/myapp/logs/nginx:/var/log/nginx \ -v /opt/myapp/ssl:/etc/nginx/ssl:ro \ --memory512m \ --cpus0.5 \ nginx:alpine注意Nginx 需要能访问 App 容器。如果 App 在backend-netNginx 在frontend-net它们默认不通。解决方案将 Nginx 也加入backend-net或者创建一个共享网络。# 将 Nginx 连接到后端网络使其能解析 app 容器名 docker network connect backend-net myapp-nginx5. 日志管理深度实践在没有 Compose 的情况下日志管理更依赖于宿主机文件和 Docker 驱动配置。5.1 策略一Docker JSON File 驱动推荐这是最简单且性能较好的方式。我们在daemon.json中已经配置了全局限制也可以针对特定容器覆盖# 示例为高日志量应用单独配置 docker run -d \ --name myapp-app \ --log-driver json-file \ --log-opt max-size200m \ --log-opt max-file10 \ ...其他参数...查看日志# 实时查看 docker logs -f --tail 100 myapp-app 查看特定时间段 docker logs --since 2026-07-23T10:00:00 myapp-app5.2 策略二应用层文件日志 宿主机挂载对于生产环境建议应用在容器内将日志写入文件并挂载到宿主机。这样即使容器崩溃日志依然保留。应用代码配置 (logger.py)import logging from logging.handlers import RotatingFileHandler def setup_logger(): logger logging.getLogger(app) logger.setLevel(logging.INFO) # 写入容器内的 /app/logs/app.log该目录已挂载到宿主机 handler RotatingFileHandler( /app/logs/app.log, maxBytes10010241024, backupCount10 ) formatter logging.Formatter(%(asctime)s - %(levelname)s - %(message)s) handler.setFormatter(formatter) logger.addHandler(handler) return logger宿主机日志清理由于是普通文件可以使用 Linux 原生的 logrotate 进行管理。创建/etc/logrotate.d/myapp/opt/myapp/logs/app/*.log { daily rotate 30 compress delaycompress missingok notifempty create 0644 root root postrotate # 如果应用支持信号重载日志句柄在此处发送信号 # docker kill -s HUP myapp-app endscript }5.3 策略三集中式日志收集 (Syslog/Fluentd)如果有多台服务器建议将 Docker 日志驱动改为 syslog 或 fluentd发送到中央日志服务器。docker run -d \ --name myapp-app \ --log-driver syslog \ --log-opt syslog-addresstcp://192.168.1.100:514 \ --log-opt tagmyapp-production \ ...6. 运维与维护脚本由于没有 docker-compose.yml我们需要编写 Shell 脚本来管理集群。6.1 启动脚本 (start.sh)#!/bin/bash set -e echo 启动生产环境服务... 确保网络存在 docker network inspect backend-net /dev/null 21 || docker network create backend-net 启动基础服务 echo Starting Database... docker start myapp-postgres || docker run -d --name myapp-postgres --network backend-net ... (参考上文完整命令) echo Starting Redis... docker start myapp-redis || docker run -d --name myapp-redis --network backend-net ... 等待数据库就绪 echo Waiting for DB... sleep 5 启动应用 echo Starting App... docker start myapp-app || docker run -d --name myapp-app --network backend-net ... 启动 Nginx echo Starting Nginx... docker start myapp-nginx || docker run -d --name myapp-nginx --network frontend-net ... docker network connect backend-net myapp-nginx echo ✅ 所有服务已启动 docker ps --filter namemyapp6.2 停止与清理脚本 (stop.sh)#!/bin/bash echo 停止服务... docker stop myapp-nginx myapp-app myapp-redis myapp-postgres echo 清理未使用的资源... docker system prune -f6.3 备份脚本 (backup.sh)#!/bin/bash DATE$(date %Y%m%d_%H%M%S) BACKUP_DIR/opt/myapp/backups mkdir -p $BACKUP_DIR echo 备份 PostgreSQL... docker exec myapp-postgres pg_dump -U myapp_user myapp_db $BACKUP_DIR/db_$DATE.sql echo 备份 Redis... docker exec myapp-redis redis-cli -a SecureRedisPass! SAVE cp /opt/myapp/data/redis/dump.rdb $BACKUP_DIR/redis_$DATE.rdb echo ✅ 备份完成: $BACKUP_DIR 可选删除 7 天前的备份 find $BACKUP_DIR -type f -mtime 7 -delete7. 监控与健康检查7.1 原生健康检查在 docker run 中使用--health-cmd参数Docker 引擎会自动监控容器状态。docker inspect --format{{.State.Health.Status}} myapp-app7.2 资源监控使用 docker stats 实时监控docker stats --format table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.NetIO}} myapp-postgres myapp-app myapp-nginx7.3 简单告警脚本结合 Crontab 每 5 分钟检查一次#!/bin/bash # check_health.sh SERVICES(myapp-postgres myapp-app myapp-nginx) for svc in ${SERVICES[]}; do if [ $(docker inspect -f {{.State.Running}} $svc 2/dev/null) ! true ]; then echo CRITICAL: Service $svc is down! | mail -s Alert: $svc Down adminexample.com # 尝试自动重启 docker start $svc fi done8. 安全加固清单最小权限原则不要以 root 运行应用容器在 Dockerfile 中使用 USER appuser。挂载配置文件时使用:ro(Read-Only)。网络隔离数据库和 Redis 绝不绑定 0.0.0.0仅绑定 127.0.0.1 或通过内部 Docker 网络通信。秘密管理避免在 docker run 命令历史中留下密码。建议使用 Docker Secrets 或环境变量文件 (--env-file .env)。镜像安全定期扫描镜像漏洞docker scan myapp:latest