Docker 生产环境落地实战:从服务器初始化到一键上线
Docker 生产环境部署指南|一键部署
在现代软件交付体系中,Docker 已经成为生产环境部署的基础设施之一。相比传统部署方式,Docker 能够将应用、运行时、依赖库、系统工具和配置统一打包成镜像,从而实现“一次构建,到处运行”。对于企业项目、SaaS 平台、内部管理系统、微服务架构以及中小型 Web 应用而言,Docker 可以显著降低环境差异带来的部署风险,提高上线效率和运维可控性。
本文将围绕 Docker 生产环境部署 展开,介绍生产环境部署原则、服务器初始化、Docker 安装、镜像构建、Docker Compose 编排、数据持久化、日志管理、安全加固、自动化部署以及一键部署脚本示例,帮助你快速搭建一套可落地、可维护、可扩展的 Docker 生产部署方案。
一、为什么生产环境推荐使用 Docker?
在没有容器化之前,应用部署往往需要手动安装运行环境。例如 Java 项目需要安装 JDK、配置 Maven 或 Gradle,Node.js 项目需要安装指定版本的 Node,Python 项目需要管理虚拟环境,PHP 项目还需要配置 Nginx、PHP-FPM、扩展等。随着项目越来越多,服务器环境越来越复杂,问题也随之增加:
- 本地能运行,服务器不能运行;
- 测试环境正常,生产环境异常;
- 依赖版本不一致导致兼容问题;
- 新服务器初始化时间长;
- 回滚困难,无法快速恢复;
- 多服务部署时端口、网络、配置混乱。
Docker 通过镜像和容器机制很好地解决了这些问题。应用依赖被固定在镜像中,部署过程变成拉取镜像、启动容器。生产环境中使用 Docker 的主要优势包括:
-
环境一致性高
镜像中包含应用运行所需依赖,减少环境差异。 -
部署速度快
通过 Docker Compose 或脚本可以快速启动完整服务栈。 -
回滚简单
镜像具有版本标签,可以快速回退到历史版本。 -
资源隔离清晰
每个服务运行在独立容器中,互不污染。 -
扩展能力强
可结合 Docker Compose、Swarm、Kubernetes 等实现扩容。 -
适合自动化运维
能与 CI/CD 流水线很好结合,实现自动构建、自动发布。
二、生产环境 Docker 部署基本架构
一个典型的 Docker 生产环境通常包含以下部分:
用户请求
↓
负载均衡 / Nginx / 网关
↓
应用服务容器
↓
数据库 / Redis / 消息队列 / 对象存储
↓
持久化数据卷 / 日志系统 / 监控系统
常见组件包括:
- Nginx:反向代理、HTTPS 证书、静态资源服务;
- 应用容器:Java、Node.js、Go、Python、PHP 等业务服务;
- 数据库容器或外部数据库:MySQL、PostgreSQL、MongoDB;
- 缓存服务:Redis;
- 消息队列:RabbitMQ、Kafka;
- 数据卷:保存数据库文件、上传文件、配置文件;
- 日志目录:统一采集容器日志;
- 监控告警:Prometheus、Grafana、Node Exporter 等;
- CI/CD 工具:GitLab CI、GitHub Actions、Jenkins。
对于中小型项目,可以使用 Docker Compose 作为生产部署工具。它简单、直观、维护成本低,非常适合单机或小规模服务器部署。
三、服务器环境准备
生产服务器建议选择稳定的 Linux 发行版,例如:
- Ubuntu 22.04 LTS / 24.04 LTS
- Debian 12
- Rocky Linux 9
- AlmaLinux 9
- CentOS Stream
服务器建议配置根据业务规模决定。对于普通 Web 项目,最低建议:
| 项目 | 建议配置 |
|---|---|
| CPU | 2 核以上 |
| 内存 | 4GB 以上 |
| 磁盘 | 40GB SSD 以上 |
| 系统 | Ubuntu 22.04 LTS |
| 网络 | 公网 IP + 防火墙策略 |
如果部署数据库、Redis、应用、Nginx 都在同一台机器,建议至少 4 核 8GB 起步。数据库数据量较大时,应单独部署数据库或使用云数据库服务。
四、服务器初始化配置
1. 更新系统软件包
以 Ubuntu 为例:
sudo apt update
sudo apt upgrade -y
2. 设置服务器时区
sudo timedatectl set-timezone Asia/Shanghai
timedatectl
3. 创建普通部署用户
不建议长期使用 root 直接部署,可以创建专用用户:
sudo adduser deploy
sudo usermod -aG sudo deploy
之后切换用户:
su - deploy
4. 配置 SSH 安全策略
建议修改 SSH 默认端口、禁用 root 远程登录、使用密钥登录。
编辑配置文件:
sudo vim /etc/ssh/sshd_config
建议配置:
Port 2222
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
重启 SSH:
sudo systemctl restart ssh
注意:修改 SSH 配置前,请确保新端口已经放行,并且密钥登录正常,否则可能导致无法登录服务器。
五、安装 Docker 与 Docker Compose
1. 使用官方脚本安装 Docker
curl -fsSL https://get.docker.com | sudo bash
安装完成后查看版本:
docker version
2. 设置 Docker 开机自启
sudo systemctl enable docker
sudo systemctl start docker
3. 将当前用户加入 docker 用户组
sudo usermod -aG docker $USER
重新登录后生效,验证:
docker ps
4. 检查 Docker Compose
新版 Docker 通常内置 Compose 插件:
docker compose version
如果输出版本号,说明可直接使用:
Docker Compose version v2.x.x
六、生产环境目录规划
良好的目录规划可以显著提升可维护性。推荐结构如下:
/opt/apps/
└── myapp/
├── docker-compose.yml
├── .env
├── nginx/
│ ├── nginx.conf
│ └── conf.d/
│ └── myapp.conf
├── app/
│ └── Dockerfile
├── data/
│ ├── mysql/
│ ├── redis/
│ └── uploads/
├── logs/
│ ├── nginx/
│ └── app/
└── scripts/
├── deploy.sh
├── backup.sh
└── rollback.sh
推荐将所有项目统一放到 /opt/apps 下,每个项目一个独立目录。这样既方便备份,也方便迁移。
创建目录:
sudo mkdir -p /opt/apps/myapp
sudo chown -R deploy:deploy /opt/apps/myapp
cd /opt/apps/myapp
七、编写 Dockerfile
下面以一个 Node.js 项目为例,演示生产环境 Dockerfile。
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:20-alpine
WORKDIR /app
ENV NODE_ENV=production
COPY package*.json ./
RUN npm ci --omit=dev
COPY --from=builder /app/dist ./dist
EXPOSE 3000
CMD ["node", "dist/main.js"]
这个 Dockerfile 使用了多阶段构建:
- 第一阶段负责安装依赖并构建项目;
- 第二阶段只保留生产运行所需文件;
- 减少镜像体积;
- 降低安全风险。
如果是 Java Spring Boot 项目,可以使用类似方式:
FROM eclipse-temurin:17-jre-alpine
WORKDIR /app
COPY target/app.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
Go 项目可以进一步构建成极小镜像:
FROM golang:1.22-alpine AS builder
WORKDIR /src
COPY . .
RUN go build -o app main.go
FROM alpine:3.20
WORKDIR /app
COPY --from=builder /src/app .
EXPOSE 8080
CMD ["./app"]
八、编写 docker-compose.yml
以下是一个较完整的生产示例,包含 Nginx、应用、MySQL、Redis。
services:
nginx:
image: nginx:1.27-alpine
container_name: myapp-nginx
restart: always
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/conf.d:/etc/nginx/conf.d
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./logs/nginx:/var/log/nginx
- ./data/uploads:/data/uploads
- ./certs:/etc/nginx/certs:ro
depends_on:
- app
networks:
- myapp-net
app:
image: myapp:latest
container_name: myapp-app
restart: always
env_file:
- .env
volumes:
- ./logs/app:/app/logs
- ./data/uploads:/app/uploads
expose:
- "3000"
depends_on:
- mysql
- redis
networks:
- myapp-net
mysql:
image: mysql:8.4
container_name: myapp-mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: ${MYSQL_DATABASE}
MYSQL_USER: ${MYSQL_USER}
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
TZ: Asia/Shanghai
command:
--character-set-server=utf8mb4
--collation-server=utf8mb4_unicode_ci
--default-time-zone=+08:00
volumes:
- ./data/mysql:/var/lib/mysql
- ./logs/mysql:/var/log/mysql
ports:
- "127.0.0.1:3306:3306"
networks:
- myapp-net
redis:
image: redis:7.4-alpine
container_name: myapp-redis
restart: always
command: redis-server --requirepass ${REDIS_PASSWORD} --appendonly yes
volumes:
- ./data/redis:/data
ports:
- "127.0.0.1:6379:6379"
networks:
- myapp-net
networks:
myapp-net:
driver: bridge
几个生产环境关键点:
-
restart: always
容器异常退出后自动重启。 -
数据库端口绑定 127.0.0.1
避免 MySQL、Redis 直接暴露到公网。 -
使用 env_file 管理环境变量
避免敏感配置写死在 Compose 文件中。 -
使用 volume 持久化数据
数据库、上传文件、日志必须持久化。 -
服务之间通过内部网络通信
应用连接数据库时使用服务名,例如mysql:3306、redis:6379。
九、配置 .env 文件
.env 文件用于保存部署环境配置。
APP_ENV=production
APP_PORT=3000
MYSQL_ROOT_PASSWORD=change_root_password
MYSQL_DATABASE=myapp
MYSQL_USER=myapp_user
MYSQL_PASSWORD=change_mysql_password
REDIS_PASSWORD=change_redis_password
DB_HOST=mysql
DB_PORT=3306
DB_NAME=myapp
DB_USER=myapp_user
DB_PASSWORD=change_mysql_password
REDIS_HOST=redis
REDIS_PORT=6379
生产环境注意:
- 不要将
.env提交到公开仓库; - 密码必须使用强密码;
- 建议定期轮换密钥;
- 可以使用 Vault、云厂商 KMS 或 CI/CD Secret 管理敏感信息。
十、配置 Nginx 反向代理
创建 nginx/conf.d/myapp.conf:
server {
listen 80;
server_name example.com;
client_max_body_size 50m;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
location /uploads/ {
alias /data/uploads/;
expires 30d;
access_log off;
}
location / {
proxy_pass http://app:3000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
}
如果使用 HTTPS,可结合 Let’s Encrypt 申请证书,然后在 Nginx 中增加 443 配置。生产环境强烈建议开启 HTTPS,尤其是涉及登录、支付、用户数据等场景。
十一、一键部署脚本
为了降低部署复杂度,可以编写 scripts/deploy.sh 实现一键部署。
#!/usr/bin/env bash
set -e
APP_NAME="myapp"
APP_DIR="/opt/apps/myapp"
IMAGE_NAME="myapp"
IMAGE_TAG="${1:-latest}"
echo "======================================"
echo "开始部署 ${APP_NAME}"
echo "镜像标签:${IMAGE_TAG}"
echo "部署目录:${APP_DIR}"
echo "======================================"
cd "${APP_DIR}"
echo "1. 检查 Docker 环境"
docker version > /dev/null
docker compose version > /dev/null
echo "2. 拉取最新代码"
if [ -d ".git" ]; then
git pull
else
echo "当前目录不是 Git 仓库,跳过 git pull"
fi
echo "3. 构建镜像"
docker build -t "${IMAGE_NAME}:${IMAGE_TAG}" ./app
echo "4. 更新 docker-compose 镜像标签"
export IMAGE_TAG="${IMAGE_TAG}"
echo "5. 启动服务"
docker compose up -d
echo "6. 清理无用镜像"
docker image prune -f
echo "7. 查看容器状态"
docker compose ps
echo "======================================"
echo "部署完成"
echo "访问地址:http://your-domain.com"
echo "======================================"
赋予执行权限:
chmod +x scripts/deploy.sh
执行一键部署:
./scripts/deploy.sh latest
如果你希望支持版本发布:
./scripts/deploy.sh v1.0.0
此时建议在 docker-compose.yml 中将应用镜像改为:
app:
image: myapp:${IMAGE_TAG:-latest}
这样部署脚本就可以通过环境变量控制镜像版本。
十二、基于镜像仓库的一键部署方式
在更规范的生产流程中,通常不建议直接在生产服务器上构建镜像,而是由 CI/CD 系统构建并推送到镜像仓库,然后生产服务器只负责拉取镜像并启动。
常见流程如下:
开发提交代码
↓
CI/CD 自动测试
↓
构建 Docker 镜像
↓
推送镜像仓库
↓
生产服务器拉取镜像
↓
Docker Compose 重启服务
此时部署脚本可以写成:
#!/usr/bin/env bash
set -e
APP_DIR="/opt/apps/myapp"
IMAGE="registry.example.com/myapp/app"
TAG="${1:-latest}"
cd "${APP_DIR}"
echo "登录镜像仓库"
docker login registry.example.com
echo "拉取镜像:${IMAGE}:${TAG}"
docker pull "${IMAGE}:${TAG}"
echo "设置镜像标签"
export APP_IMAGE="${IMAGE}:${TAG}"
echo "启动服务"
docker compose up -d
echo "清理旧镜像"
docker image prune -f
echo "部署完成"
docker compose ps
对应的 docker-compose.yml:
services:
app:
image: ${APP_IMAGE}
container_name: myapp-app
restart: always
env_file:
- .env
networks:
- myapp-net
这种方式更适合团队协作,因为生产服务器无需安装构建工具,也不会因为构建过程消耗过多服务器资源。
十三、数据持久化与备份策略
生产环境最重要的是数据安全。容器可以随时删除和重建,但数据不能丢。必须将数据库、上传文件、配置文件、日志等挂载到宿主机目录或专用数据卷。
1. MySQL 备份脚本
创建 scripts/backup.sh:
#!/usr/bin/env bash
set -e
BACKUP_DIR="/opt/apps/myapp/backups"
DATE=$(date +%F_%H-%M-%S)
mkdir -p "${BACKUP_DIR}"
docker exec myapp-mysql mysqldump \
-uroot \
-p"${MYSQL_ROOT_PASSWORD}" \
--single-transaction \
--routines \
--triggers \
myapp > "${BACKUP_DIR}/myapp_${DATE}.sql"
tar -czf "${BACKUP_DIR}/uploads_${DATE}.tar.gz" -C /opt/apps/myapp/data uploads
find "${BACKUP_DIR}" -type f -mtime +15 -delete
echo "备份完成:${BACKUP_DIR}"
建议配合 crontab 定时执行:
crontab -e
添加:
0 3 * * * /opt/apps/myapp/scripts/backup.sh >> /opt/apps/myapp/logs/backup.log 2>&1
表示每天凌晨 3 点执行备份。
2. 备份建议
生产环境备份至少做到:
- 本机保留最近 7 到 15 天备份;
- 异地备份至少一份;
- 重要数据库开启每日全量备份;
- 高频业务增加 binlog 或增量备份;
- 定期演练恢复流程;
- 备份文件加密存储。
只做备份不做恢复演练是不完整的。很多系统看似有备份,但真正故障时才发现备份文件损坏、缺少权限或恢复步骤不清晰。
十四、日志管理
Docker 默认日志驱动是 json-file,如果不限制大小,日志可能持续增长并占满磁盘。生产环境必须配置日志轮转。
创建或编辑 /etc/docker/daemon.json:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "100m",
"max-file": "5"
}
}
重启 Docker:
sudo systemctl restart docker
查看容器日志:
docker logs -f myapp-app
查看 Compose 服务日志:
docker compose logs -f app
建议:
- 应用日志输出到 stdout/stderr,便于 Docker 收集;
- 关键业务日志同时写入挂载目录;
- Nginx 日志单独挂载;
- 大型项目接入 ELK、Loki、ClickHouse 或云日志服务;
- 设置日志保留周期,避免磁盘爆满。
十五、生产环境安全加固
Docker 部署方便,但不能忽视安全。生产环境建议从以下方面加固。
1. 不暴露不必要端口
MySQL、Redis、RabbitMQ 管理后台等服务不要直接暴露公网。若必须远程访问,应使用 VPN、堡垒机或安全组白名单。
错误示例:
ports:
- "3306:3306"
较安全示例:
ports:
- "127.0.0.1:3306:3306"
或者完全不映射端口,只允许容器内部网络访问。
2. 使用最小权限镜像
优先选择官方镜像、alpine 镜像或 distroless 镜像。不要在镜像中安装无关工具,例如 vim、curl、编译器等,除非确有必要。
3. 避免容器使用 privileged
生产环境一般不应使用:
privileged: true
这会让容器拥有过高权限,增加宿主机被攻击风险。
4. 敏感信息不要写入镜像
不要在 Dockerfile 中写:
ENV PASSWORD=123456
也不要把 .env、证书、私钥复制进镜像。应通过环境变量、Secret、配置中心或挂载方式注入。
5. 定期更新镜像
基础镜像可能存在漏洞,建议定期更新:
docker compose pull
docker compose up -d
同时可使用工具扫描镜像漏洞,例如 Trivy:
trivy image myapp:latest
6. 限制容器资源
避免某个容器占满 CPU 或内存。Compose 中可配置资源限制:
services:
app:
deploy:
resources:
limits:
cpus: "1.0"
memory: 1024M
需要注意,deploy 在普通 Docker Compose 场景下部分配置可能不完全生效,可结合 Docker 运行参数或系统级监控进行限制。
十六、健康检查与自动恢复
生产服务应具备健康检查能力。可以在 Compose 中加入:
services:
app:
image: myapp:latest
healthcheck:
test: ["CMD", "wget", "-qO-", "http://localhost:3000/health"]
interval: 30s
timeout: 5s
retries: 3
start_period: 30s
应用需要提供 /health 接口,返回服务状态。例如:
{
"status": "ok"
}
健康检查可以帮助运维人员快速判断容器内部服务是否正常。结合负载均衡、监控告警后,可以实现更完善的故障发现机制。
十七、灰度发布与回滚
生产环境部署不能只考虑上线,还必须考虑失败后的回滚。
1. 镜像版本化
不要所有版本都只使用 latest,建议使用明确版本:
myapp:v1.0.0
myapp:v1.0.1
myapp:v1.1.0
2. 回滚脚本
创建 scripts/rollback.sh:
#!/usr/bin/env bash
set -e
APP_DIR="/opt/apps/myapp"
ROLLBACK_TAG="$1"
if [ -z "${ROLLBACK_TAG}" ]; then
echo "请指定回滚版本,例如:./rollback.sh v1.0.0"
exit 1
fi
cd "${APP_DIR}"
export IMAGE_TAG="${ROLLBACK_TAG}"
docker compose up -d
docker compose ps
echo "已回滚到版本:${ROLLBACK_TAG}"
执行:
./scripts/rollback.sh v1.0.0
3. 回滚注意事项
- 数据库结构变更要谨慎;
- 发布前备份数据库;
- 避免不可逆迁移;
- 保留最近几个稳定镜像;
- 发布后观察日志和监控;
- 必要时先灰度一部分流量。
十八、常用运维命令
查看容器:
docker ps
查看所有容器:
docker ps -a
查看日志:
docker logs -f myapp-app
进入容器:
docker exec -it myapp-app sh
重启服务:
docker compose restart app
停止服务:
docker compose down
启动服务:
docker compose up -d
查看资源占用:
docker stats
清理无用镜像:
docker image prune -f
清理未使用资源:
docker system prune -f
注意:不要随意执行
docker volume prune,可能删除重要数据卷。
十九、生产部署检查清单
上线前建议逐项检查:
- [ ] Docker 与 Docker Compose 已正确安装;
- [ ] 服务器防火墙和安全组已配置;
- [ ] SSH 禁止 root 密码登录;
- [ ]
.env配置正确且未提交到公开仓库; - [ ] 数据目录已挂载到宿主机;
- [ ] 数据库端口未暴露公网;
- [ ] Redis 设置了密码;
- [ ] Nginx 反向代理配置正确;
- [ ] HTTPS 证书已配置;
- [ ] 日志轮转已开启;
- [ ] 数据库备份任务已配置;
- [ ] 应用健康检查接口正常;
- [ ] 镜像版本可追踪;
- [ ] 回滚脚本已验证;
- [ ] 监控告警已接入;
- [ ] 发布前已完成测试。
二十、总结
Docker 生产环境部署的核心,不只是“把应用跑起来”,而是要做到 可重复、可回滚、可监控、可备份、可扩展、可维护。对于大多数中小型项目而言,Docker Compose 已经能够满足稳定部署需求;对于大规模微服务系统,则可以进一步升级到 Kubernetes 等容器编排平台。
一套成熟的 Docker 生产部署方案通常包括:
- 使用 Dockerfile 构建标准化镜像;
- 使用 Docker Compose 管理多服务;
- 使用
.env管理环境配置; - 使用 Nginx 提供反向代理和 HTTPS;
- 使用数据卷持久化数据库和文件;
- 使用脚本实现一键部署和回滚;
- 使用日志轮转、备份、监控保障稳定性;
- 使用镜像仓库和 CI/CD 提升交付效率。
如果你是个人开发者或小团队,可以从本文的一键部署脚本和 Compose 配置开始,逐步完善备份、监控、安全和 CI/CD。只要目录规划清晰、配置管理规范、数据持久化可靠,Docker 完全可以支撑稳定的生产环境部署。