Docker 容器化部署实战:从零搭建你的第一个生产级环境


前言

“在我机器上明明能跑啊!”

这句话大概是每个开发者都说过(或听过)的经典台词。而 Docker 的出现,正是为了彻底终结这个世纪难题。

本文将从核心概念出发,带你一步步完成一个真实项目的容器化部署,涵盖 Dockerfile 编写、镜像构建、多容器编排(Docker Compose),以及生产环境中的最佳实践。


一、Docker 到底是什么?

一句话理解

Docker 是一个轻量级的虚拟化平台,它把你的应用程序和所有依赖(运行环境、系统库、配置文件)打包成一个标准化的单元——容器(Container),保证在任何机器上都能一致运行。

容器 vs 虚拟机

对比维度虚拟机(VM)容器(Container)
启动速度分钟级秒级甚至毫秒级
资源占用GB 级别MB 级别
隔离程度完全隔离(含 OS)进程级隔离(共享内核)
镜像体积数 GB数十 ~ 数百 MB
运行密度一台机器跑十几个一台机器跑上百个

💡 简单类比:虚拟机像独栋别墅(自带地基和水电),容器像集装箱公寓(共享大楼基础设施,但各自独立)。


二、核心概念速览

在动手之前,先搞懂三个核心概念:

  • 镜像(Image):只读的应用模板,包含代码 + 运行时 + 依赖,相当于"安装包"
  • 容器(Container):镜像的运行实例,相当于"正在运行的程序"
  • 仓库(Registry):存放和分发镜像的地方,Docker Hub 是最大的公共仓库

它们的关系:仓库 → 拉取镜像 → 运行容器

# 从仓库拉取镜像并运行容器(一条命令搞定)
docker run -d -p 8080:80 nginx

这条命令做了什么?

  1. 检查本地是否有 nginx 镜像 → 没有则从 Docker Hub 拉取
  2. 以后台模式(-d)启动容器
  3. 将宿主机的 8080 端口映射到容器的 80 端口

三、实战:容器化一个 Python Flask 应用

我们从一个真实场景出发:将一个 Flask API 服务容器化部署。

3.1 项目结构

flask-app/
├── app.py              # Flask 应用代码
├── requirements.txt    # Python 依赖
├── Dockerfile          # Docker 构建文件
└── docker-compose.yml  # 多容器编排文件

3.2 应用代码

app.py

from flask import Flask, jsonify
import datetime
import os

app = Flask(__name__)

@app.route("/")
def home():
    return jsonify({
        "message": "Hello from Docker! 🐳",
        "hostname": os.uname().nodename,
        "time": datetime.datetime.now().isoformat()
    })

@app.route("/health")
def health():
    return jsonify({"status": "healthy"}), 200

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000)

requirements.txt

flask==3.0.0
gunicorn==21.2.0

3.3 编写 Dockerfile

Dockerfile 是构建镜像的"配方",告诉 Docker 如何一步步打包你的应用:

# 1. 选择基础镜像(Python 官方镜像,slim 版本更小)
FROM python:3.11-slim

# 2. 设置工作目录
WORKDIR /app

# 3. 先复制依赖文件,利用 Docker 缓存层加速构建
COPY requirements.txt .

# 4. 安装依赖
RUN pip install --no-cache-dir -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple

# 5. 复制应用代码
COPY . .

# 6. 暴露端口(仅声明,实际映射靠 docker run -p)
EXPOSE 5000

# 7. 启动命令(使用 gunicorn 作为生产级 WSGI 服务器)
CMD ["gunicorn", "-w", "4", "-b", "0.0.0.0:5000", "app:app"]
Dockerfile 最佳实践要点
实践说明
使用 slim/alpine 基础镜像体积更小,攻击面更少
先 COPY 依赖再 COPY 代码依赖不变时命中缓存,加速构建
--no-cache-dir不缓存 pip 下载包,减小镜像体积
使用 .dockerignore排除 .git、__pycache__、venv 等无用文件
非 root 用户运行提升安全性(下面会讲)

创建 .dockerignore 文件:

.git
__pycache__
*.pyc
venv/
.env

3.4 构建与运行

# 构建镜像(注意最后的 . 表示构建上下文)
docker build -t flask-app:1.0 .

# 运行容器
docker run -d \
  --name my-flask-app \
  -p 8080:5000 \
  --restart unless-stopped \
  flask-app:1.0

# 验证
curl http://localhost:8080/
# 输出: {"hostname":"abc123def","message":"Hello from Docker! 🐳","time":"2026-08-15T13:25:00"}

常用参数说明:

  • -d:后台运行
  • --name:给容器起个名字,方便管理
  • -p 宿主机端口:容器端口:端口映射
  • --restart unless-stopped:异常退出时自动重启

四、进阶:Docker Compose 多容器编排

真实项目中,你的应用通常不止一个容器——还需要数据库、缓存、消息队列等。手动管理多个 docker run 命令既不优雅也不可持续。

Docker Compose 让你用一个 YAML 文件定义和运行多容器应用。

4.1 场景:Flask + Redis + Nginx

我们用 Compose 编排三个服务:

  • Flask API:业务逻辑
  • Redis:缓存层
  • Nginx:反向代理 + 静态资源服务

4.2 docker-compose.yml

version: "3.8"

services:
  # Flask API 服务
  web:
    build: .
    container_name: flask-app
    ports:
      - "5000:5000"
    environment:
      - REDIS_HOST=redis
      - FLASK_ENV=production
    depends_on:
      redis:
        condition: service_healthy
    restart: unless-stopped
    networks:
      - app-network

  # Redis 缓存服务
  redis:
    image: redis:7-alpine
    container_name: redis-cache
    ports:
      - "6379:6379"
    volumes:
      - redis-data:/data
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 5s
      retries: 3
    restart: unless-stopped
    networks:
      - app-network

  # Nginx 反向代理
  nginx:
    image: nginx:alpine
    container_name: nginx-proxy
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
    depends_on:
      - web
    restart: unless-stopped
    networks:
      - app-network

# 数据卷(持久化 Redis 数据)
volumes:
  redis-data:

# 自定义网络
networks:
  app-network:
    driver: bridge

4.3 Nginx 配置

nginx.conf

upstream flask_backend {
    server web:5000;
}

server {
    listen 80;
    server_name localhost;

    location / {
        proxy_pass http://flask_backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

4.4 一键启动

# 启动所有服务(后台运行)
docker compose up -d

# 查看运行状态
docker compose ps

# 输出示例:
# NAME          IMAGE           STATUS        PORTS
# flask-app     flask-app:1.0   Up 5 seconds  0.0.0.0:5000->5000/tcp
# redis-cache   redis:7-alpine  Up 6 seconds  0.0.0.0:6379->6379/tcp
# nginx-proxy   nginx:alpine    Up 5 seconds  0.0.0.0:80->80/tcp

# 查看日志
docker compose logs -f web

# 停止所有服务
docker compose down

# 停止并清除数据卷
docker compose down -v

🎯 只需要一个命令 docker compose up -d,三个服务全部启动,网络互通,依赖自动排序。


五、生产环境最佳实践

5.1 镜像瘦身

# ❌ 不推荐:完整 Python 镜像,约 900MB
FROM python:3.11

# ✅ 推荐:slim 版本,约 150MB
FROM python:3.11-slim

# ✅✅ 进阶:多阶段构建,最终镜像可压缩到 50MB 以下
FROM python:3.11-slim AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir --prefix=/install -r requirements.txt

FROM python:3.11-alpine
WORKDIR /app
COPY --from=builder /install /usr/local
COPY . .
CMD ["gunicorn", "-w", "4", "-b", "0.0.0.0:5000", "app:app"]

5.2 安全性加固

# 创建非 root 用户运行应用
RUN adduser --disabled-password --gecos '' appuser
USER appuser

5.3 健康检查

# docker-compose.yml 中添加健康检查
services:
  web:
    build: .
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:5000/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 10s

5.4 环境变量管理

# .env 文件(不要提交到 Git!)
FLASK_ENV=production
DATABASE_URL=postgresql://user:pass@db:5432/mydb
REDIS_URL=redis://redis:6379/0
SECRET_KEY=your-super-secret-key
# docker-compose.yml 中引用
services:
  web:
    env_file:
      - .env

六、常用命令速查表

# ========== 镜像操作 ==========
docker build -t myapp:1.0 .        # 构建镜像
docker images                       # 列出本地镜像
docker rmi <image_id>               # 删除镜像
docker tag myapp:1.0 user/myapp:1.0 # 打标签
docker push user/myapp:1.0          # 推送到仓库
docker pull nginx:latest            # 拉取镜像

# ========== 容器操作 ==========
docker run -d -p 8080:80 nginx      # 运行容器
docker ps                            # 查看运行中的容器
docker ps -a                         # 查看所有容器(含已停止)
docker logs -f <container>           # 查看日志
docker exec -it <container> /bin/sh  # 进入容器
docker stop <container>              # 停止容器
docker rm <container>                # 删除容器
docker stats                         # 查看资源使用情况

# ========== 清理 ==========
docker system prune -a               # 清理所有未使用的资源(慎用!)
docker volume prune                  # 清理未使用的数据卷

七、总结

阶段关键动作
理解概念镜像 = 模板,容器 = 实例,仓库 = 商店
编写 Dockerfile选小基础镜像、利用缓存层、.dockerignore
构建与运行docker build → docker run
多容器编排Docker Compose 一键管理
生产部署镜像瘦身 + 安全加固 + 健康检查 + 环境变量管理

Docker 的价值不仅仅是"解决环境一致性问题",它更是现代云原生架构的基石——CI/CD 流水线、微服务部署、弹性伸缩,都离不开它。

更多推荐