Docker 容器化实战:从 Dockerfile 到多服务编排

1133 字
6 分钟
Docker 容器化实战:从 Dockerfile 到多服务编排

为什么用 Docker#

“在我机器上能跑” 是开发者的经典痛点。Docker 把应用及其依赖打包进容器,确保在任何环境运行一致。

Docker 容器化概念图
图:Docker 让应用与环境解耦

容器 vs 虚拟机#

对比维度Docker 容器虚拟机
启动速度秒级分钟级
资源占用MB 级GB 级
隔离级别进程级硬件级
镜像大小通常 < 100MB通常 > 1GB
内核共享宿主机内核独立内核

一、编写第一个 Dockerfile#

假设我们有一个简单的 Node.js 应用:

app.js
const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000;
app.get('/', (req, res) => {
res.json({ status: 'ok', uptime: process.uptime() });
});
app.listen(PORT, () => console.log(`Server running on :${PORT}`));
{
"name": "my-app",
"dependencies": { "express": "^4.21.0" },
"scripts": { "start": "node app.js" }
}

对应的 Dockerfile:

# ---- 构建阶段 ----
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
# ---- 运行阶段 ----
FROM node:20-alpine
WORKDIR /app
# 创建非 root 用户
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
# 从构建阶段复制依赖
COPY --from=builder /app/node_modules ./node_modules
COPY app.js ./
USER appuser
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=3s \
CMD wget -qO- http://localhost:3000/ || exit 1
CMD ["node", "app.js"]

关键技巧:多阶段构建(multi-stage build)让最终镜像只包含运行时依赖,减小体积。

构建与运行#

Terminal window
# 构建镜像
docker build -t my-app:latest .
# 查看镜像大小
docker images my-app
# 运行容器
docker run -d -p 3000:3000 --name my-app my-app:latest
# 查看日志
docker logs -f my-app
# 进入容器调试
docker exec -it my-app sh

二、Docker Compose 多服务编排#

真实项目通常由多个服务组成(Web + 数据库 + 缓存)。Compose 用一个 YAML 文件描述整个技术栈。

架构图#

HTTP :3000

proxy_pass

读写

缓存

搜索

浏览器

Nginx 反向代理

Web 应用 :3000

PostgreSQL :5432

Redis :6379

Elasticsearch :9200

HTTP :3000

proxy_pass

读写

缓存

搜索

浏览器

Nginx 反向代理

Web 应用 :3000

PostgreSQL :5432

Redis :6379

Elasticsearch :9200

docker-compose.yml#

version: '3.9'
services:
web:
build: .
ports:
- '3000:3000'
environment:
DATABASE_URL: postgres://user:pass@db:5432/mydb
REDIS_URL: redis://redis:6379
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
volumes:
- ./uploads:/app/uploads
restart: unless-stopped
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
POSTGRES_DB: mydb
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ['CMD-SHELL', 'pg_isready -U user -d mydb']
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped
redis:
image: redis:7-alpine
volumes:
- redisdata:/data
restart: unless-stopped
volumes:
pgdata:
redisdata:
Terminal window
# 一键启动所有服务
docker compose up -d
# 查看服务状态
docker compose ps
# 查看日志
docker compose logs -f web
# 执行一次性命令
docker compose run --rm web npm run migrate
# 停止并清理
docker compose down -v

三、镜像优化:让镜像瘦身 90%#

06012018024030036042048054060066072078084090096010201080基础 nodealpine (150MB) 多阶段 (80MB) distroless (50MB)优化前优化后镜像优化前后体积对比
06012018024030036042048054060066072078084090096010201080基础 nodealpine (150MB) 多阶段 (80MB) distroless (50MB)优化前优化后镜像优化前后体积对比

优化技巧清单#

# ❌ 反面教材:一条命令一层,镜像臃肿
FROM node:20
RUN apt-get update
RUN apt-get install -y curl
RUN npm install -g pm2
# ✅ 优化版:合并 RUN、清理缓存
FROM node:20-alpine
RUN apk add --no-cache curl \
&& npm install -g pm2 \
&& rm -rf /root/.npm
# ✅ 使用 .dockerignore 排除不必要的文件
# node_modules
# .git
# *.md
# .env.local

四、常用命令速查#

场景命令
列出运行中的容器docker ps
列出所有容器(含停止的)docker ps -a
停止容器docker stop <name>
删除容器docker rm <name>
删除镜像docker rmi <image>
清理无用资源docker system prune -a
查看容器资源占用docker stats
查看镜像层历史docker history <image>
复制文件到容器docker cp file.txt container:/path/
导出镜像docker save -o myapp.tar myapp:latest

五、生产环境部署流程#

生产服务器镜像仓库CI/CDGitHub开发者生产服务器镜像仓库CI/CDGitHub开发者git pushWebhook 触发运行测试docker builddocker pushSSH + docker pulldocker compose up -d健康检查 OK部署成功通知
生产服务器镜像仓库CI/CDGitHub开发者生产服务器镜像仓库CI/CDGitHub开发者git pushWebhook 触发运行测试docker builddocker pushSSH + docker pulldocker compose up -d健康检查 OK部署成功通知

对应的 CI 配置片段(GitHub Actions):

# .github/workflows/deploy.yml 中的关键步骤
- name: Build and Push Docker image
run: |
docker build -t ghcr.io/${{ github.repository }}:${{ github.sha }} .
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
docker push ghcr.io/${{ github.repository }}:${{ github.sha }}
- name: Deploy to server
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.SERVER_HOST }}
username: deploy
key: ${{ secrets.SSH_KEY }}
script: |
docker pull ghcr.io/${{ github.repository }}:${{ github.sha }}
cd /opt/app && docker compose up -d --no-deps web

总结#

Docker 不是银弹,但它是现代开发的基础设施。掌握 Dockerfile + Compose 基本上覆盖了 80% 的使用场景:

  1. 多阶段构建减小镜像
  2. Docker Compose 编排多服务
  3. 健康检查确保服务可用
  4. CI/CD 集成实现自动部署

参考链接#

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

Docker 容器化实战:从 Dockerfile 到多服务编排
https://mingblog.de5.net/posts/docker-container-practice/
作者
念铭
发布于
2026-07-13
许可协议
CC BY-NC-SA 4.0
Profile Image of the Author
念铭
全栈开发者,喜欢折腾前端工程化、DevOps 与各种效率工具。
欢迎来到念铭的博客
一个分享编程、开发与效率工具的个人博客。不定期更新,欢迎交流~
标签