Docker 容器化部署实践:从开发环境到生产上线
前言
在大三这一年里,我参与了多个项目的开发与部署。从最初的"在我电脑上能跑啊"到后来的"一键部署",Docker 在其中扮演了关键角色。这篇文章记录我在实际项目中使用 Docker 进行容器化部署的经验和踩过的坑。
为什么需要 Docker
在团队协作中,环境不一致是最常见的问题之一。Node.js 版本不同、数据库版本差异、系统依赖缺失……这些问题在传统部署方式下层出不穷。
Docker 解决了这个痛点:
- 环境一致性:开发、测试、生产环境完全一致
- 快速部署:一条命令启动整个应用栈
- 资源隔离:每个容器独立运行,互不干扰
- 易于扩展:配合 Docker Compose 和 Kubernetes 实现弹性伸缩
Docker 核心概念速览
在动手之前,先理清三个核心概念:
| 概念 | 类比 | 说明 |
|---|---|---|
| 镜像(Image) | 类(Class) | 应用程序的只读模板 |
| 容器(Container) | 实例(Instance) | 镜像的运行实例 |
| 仓库(Registry) | Maven/NPM 仓库 | 存储和分发镜像的地方 |
一句话概括:用 Dockerfile 构建镜像,用镜像创建容器,从 Registry 拉取或推送镜像。
实战:容器化一个 Node.js 应用
1. 编写 Dockerfile
以一个典型的 Express + MySQL 项目为例:
# 使用官方 Node.js 18 镜像作为基础
FROM node:18-alpine
# 设置工作目录
WORKDIR /app
# 复制 package.json 和 package-lock.json
COPY package*.json ./
# 安装依赖
RUN npm ci --production
# 复制源代码
COPY . .
# 暴露端口
EXPOSE 3000
# 启动应用
CMD ["node", "src/index.js"]
几个关键点:
- 使用
alpine版本减小镜像体积(约 5 倍差距) - 先复制
package.json再npm install,利用 Docker 的层缓存机制 - 生产环境使用
npm ci而非npm install,确保依赖版本严格一致
2. 构建镜像
docker build -t my-app:1.0.0 .
3. 运行容器
docker run -d \
--name my-app \
-p 3000:3000 \
-e DB_HOST=mysql \
-e DB_PASSWORD=secret123 \
my-app:1.0.0
Docker Compose:编排多容器应用
现实中的项目很少只有一个服务。一个典型的 Web 应用至少包含:应用服务 + 数据库 + 缓存。Docker Compose 可以统一管理这些服务。
# docker-compose.yml
version: '3.8'
services:
app:
build: .
ports:
- "3000:3000"
environment:
- DB_HOST=mysql
- DB_PASSWORD=${DB_PASSWORD}
- REDIS_HOST=redis
depends_on:
mysql:
condition: service_healthy
redis:
condition: service_started
restart: unless-stopped
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
MYSQL_DATABASE: myapp
volumes:
- mysql_data:/var/lib/mysql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped
redis:
image: redis:7-alpine
volumes:
- redis_data:/data
restart: unless-stopped
nginx:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf
depends_on:
- app
restart: unless-stopped
volumes:
mysql_data:
redis_data:
关键设计:
depends_on+healthcheck确保数据库就绪后才启动应用volumes持久化数据,容器重启数据不丢失restart: unless-stopped实现自动重启.env文件管理敏感配置,不提交到 Git
Dockerfile 优化实践
多阶段构建(Multi-stage Build)
# 原始镜像:800MB+
# 优化后:120MB
# ====== 构建阶段 ======
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# ====== 运行阶段 ======
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/package*.json ./
RUN npm ci --production && npm cache clean --force
EXPOSE 3000
CMD ["node", "dist/index.js"]
多阶段构建的好处:
- 构建依赖(如 TypeScript、Webpack)不进入最终镜像
- 最终镜像只包含运行时所需文件
- 镜像体积大幅减小,部署和拉取更快
.dockerignore
node_modules
npm-debug.log
.git
.env
.vscode
dist
coverage
善用 .dockerignore 可以避免将不必要的文件打入镜像,减小体积、加快构建。
实际项目中的踩坑记录
坑1:时区问题
容器默认是 UTC 时区,日志时间差了 8 小时:
# 解决方案
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
坑2:MySQL 连接拒绝
应用启动比 MySQL 快,导致连接失败。单纯 depends_on 不够,必须加 healthcheck:
depends_on:
mysql:
condition: service_healthy # 等 MySQL 真正可用
坑3:文件权限
在 Linux 容器中运行 Node.js 时,挂载的卷可能出现权限问题:
RUN chown -R node:node /app
USER node
坑4:环境变量注入
不要在 Dockerfile 中硬编码敏感信息:
# ❌ 错误
ENV DB_PASSWORD=123456
# ✅ 正确:运行时注入
# docker run -e DB_PASSWORD=xxx
部署流程最佳实践
我所在项目的最终部署流程:
本地开发 → Git Push → CI/CD 构建镜像 → 推送镜像仓库 → 服务器拉取部署
对应的 CI/CD 配置(GitLab CI 示例):
stages:
- build
- deploy
build:
stage: build
script:
- docker build -t registry.example.com/my-app:$CI_COMMIT_SHA .
- docker push registry.example.com/my-app:$CI_COMMIT_SHA
only:
- main
deploy:
stage: deploy
script:
- docker pull registry.example.com/my-app:$CI_COMMIT_SHA
- docker-compose down
- docker-compose up -d
only:
- main
Docker 常用命令速查
| 命令 | 用途 |
|---|---|
docker ps |
查看运行中的容器 |
docker images |
查看本地镜像 |
docker logs -f 容器名 |
实时查看容器日志 |
docker exec -it 容器名 sh |
进入容器 Shell |
docker-compose up -d |
后台启动所有服务 |
docker-compose logs -f |
查看所有服务日志 |
docker system prune -a |
清理未使用的镜像和容器 |
docker stats |
查看容器资源使用情况 |
总结
Docker 不是一个"可选项",而是现代软件工程的"必修课"。从我个人的项目经验来看,引入 Docker 后:
- 新成员入职从"配一天环境"变成"一条命令跑起来"
- 部署从手动传文件变成自动化流水线
- "我电脑上没问题"这句话从团队的字典里消失了
如果你还没有在项目中使用 Docker,强烈建议现在就动手试试。从写第一个 Dockerfile 开始,到用 Docker Compose 编排多服务,再到接入 CI/CD 流水线——每一步都能感受到开发体验的质变。
本文基于大三期间多个项目(ERP 系统、灵山胜境等)的实际部署经验总结。

浙公网安备 33010602011771号