上一篇 下一篇 分享链接 返回 返回顶部

Docker 生产环境落地实战:从服务器初始化到一键上线

发布人:慈云数据-客服中心 发布时间:8小时前 阅读量:3

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 的主要优势包括:

  1. 环境一致性高
    镜像中包含应用运行所需依赖,减少环境差异。

  2. 部署速度快
    通过 Docker Compose 或脚本可以快速启动完整服务栈。

  3. 回滚简单
    镜像具有版本标签,可以快速回退到历史版本。

  4. 资源隔离清晰
    每个服务运行在独立容器中,互不污染。

  5. 扩展能力强
    可结合 Docker Compose、Swarm、Kubernetes 等实现扩容。

  6. 适合自动化运维
    能与 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

几个生产环境关键点:

  1. restart: always
    容器异常退出后自动重启。

  2. 数据库端口绑定 127.0.0.1
    避免 MySQL、Redis 直接暴露到公网。

  3. 使用 env_file 管理环境变量
    避免敏感配置写死在 Compose 文件中。

  4. 使用 volume 持久化数据
    数据库、上传文件、日志必须持久化。

  5. 服务之间通过内部网络通信
    应用连接数据库时使用服务名,例如 mysql:3306redis: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 完全可以支撑稳定的生产环境部署。

目录结构
全文