当前位置:首页 > 学习笔记 > 正文内容

Docker 容器化部署实战完全指南

Docker 是现代软件开发和运维的核心技术,它通过容器化技术实现了"一次构建,到处运行"的理念。本文将从 Docker 基础概念讲起,深入讲解镜像管理、容器操作、网络配置、数据持久化、Docker Compose 多容器编排等核心技术,并通过实战案例演示如何将一个完整的 Web 应用容器化部署。

一、Docker 核心概念

在深入学习 Docker 之前,我们需要理解几个核心概念:

1.1 镜像(Image)

镜像是容器的蓝图,包含了运行应用所需的所有内容:代码、运行时、库、环境变量和配置文件。镜像是只读的,可以看作是一个轻量级的虚拟机快照。

1.2 容器(Container)

容器是镜像的运行实例。如果说镜像是"类",那容器就是"对象"。容器之间相互隔离,每个容器都有自己独立的文件系统、网络配置和进程空间。

1.3 仓库(Registry)

仓库是存储和分发镜像的地方。Docker Hub 是最大的公共仓库,企业也可以搭建私有仓库来存储自己的镜像。

1.4 Dockerfile

Dockerfile 是一个文本文件,包含了构建镜像的所有指令。通过 Dockerfile,我们可以将应用的运行环境标准化,实现环境的一致性。

二、Docker 安装与基础操作

2.1 安装 Docker

以 Ubuntu 为例,安装 Docker 的步骤如下:

# 更新软件包索引
sudo apt-get update

# 安装必要的依赖
sudo apt-get install apt-transport-https ca-certificates curl gnupg lsb-release

# 添加 Docker 官方 GPG 密钥
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

# 添加 Docker 仓库
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# 安装 Docker Engine
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io

# 验证安装
sudo docker run hello-world

# 将当前用户加入 docker 组(避免每次使用 sudo)
sudo usermod -aG docker $USER

2.2 镜像管理命令

# 搜索镜像
docker search nginx

# 拉取镜像(默认 latest 版本)
docker pull nginx

# 拉取指定版本镜像
docker pull nginx:1.21-alpine

# 查看本地镜像列表
docker images

# 查看镜像详细信息
docker inspect nginx:latest

# 删除镜像
docker rmi nginx:latest

# 清理悬空镜像(没有标签的镜像)
docker image prune

# 导出镜像为 tar 文件
docker save -o nginx.tar nginx:latest

# 从 tar 文件导入镜像
docker load -i nginx.tar

2.3 容器生命周期管理

# 运行容器(交互模式)
docker run -it ubuntu:latest /bin/bash

# 后台运行容器
docker run -d --name my-nginx -p 8080:80 nginx:latest

# 查看运行中的容器
docker ps

# 查看所有容器(包括停止的)
docker ps -a

# 停止容器
docker stop my-nginx

# 启动已停止的容器
docker start my-nginx

# 重启容器
docker restart my-nginx

# 进入运行中的容器
docker exec -it my-nginx /bin/bash

# 查看容器日志
docker logs my-nginx

# 实时查看日志
docker logs -f my-nginx

# 删除容器
docker rm my-nginx

# 强制删除运行中的容器
docker rm -f my-nginx

# 清理所有停止的容器
docker container prune

三、Dockerfile 编写最佳实践

3.1 基础指令详解

# 指定基础镜像
FROM python:3.9-slim

# 设置工作目录
WORKDIR /app

# 设置环境变量
ENV PYTHONUNBUFFERED=1
ENV APP_ENV=production

# 复制依赖文件(利用 Docker 缓存层)
COPY requirements.txt .

# 安装依赖
RUN pip install --no-cache-dir -r requirements.txt

# 复制应用代码
COPY . .

# 暴露端口
EXPOSE 8000

# 设置启动命令
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]

3.2 多阶段构建优化镜像大小

多阶段构建可以显著减小最终镜像的体积,只保留运行时必需的文件:

# 构建阶段
FROM golang:1.19-alpine AS builder

WORKDIR /build

# 复制 go.mod 和 go.sum 以利用缓存
COPY go.mod go.sum ./
RUN go mod download

# 复制源代码并编译
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main .

# 运行阶段
FROM alpine:latest

# 安装 ca-certificates(HTTPS 请求需要)
RUN apk --no-cache add ca-certificates

WORKDIR /root/

# 从构建阶段复制二进制文件
COPY --from=builder /build/main .

# 暴露端口
EXPOSE 8080

# 运行应用
CMD ["./main"]

3.3 Dockerfile 最佳实践总结

  • 使用官方基础镜像:优先选择官方维护的镜像,如 python、nginx、alpine
  • 指定镜像版本:避免使用 latest 标签,明确指定版本号保证可重复性
  • 使用 .dockerignore:排除不需要的文件,加快构建速度
  • 合并 RUN 指令:减少镜像层数,减小镜像体积
  • 利用构建缓存:将不常变化的指令放在前面
  • 最小化镜像层数:每个指令都会创建一个新层
  • 不要在镜像中存储敏感信息:使用环境变量或 secrets 管理

四、数据持久化与网络配置

4.1 数据卷管理

容器删除后,容器内的数据也会丢失。数据卷可以持久化存储数据,实现容器间的数据共享:

# 创建数据卷
docker volume create my-data

# 查看数据卷列表
docker volume ls

# 查看数据卷详情
docker volume inspect my-data

# 使用数据卷运行容器
docker run -d --name mysql \
  -v my-data:/var/lib/mysql \
  -e MYSQL_ROOT_PASSWORD=root123 \
  mysql:8.0

# 挂载主机目录到容器
docker run -d --name nginx \
  -v /host/path:/usr/share/nginx/html:ro \
  nginx:latest

# 删除数据卷
docker volume rm my-data

# 清理未使用的数据卷
docker volume prune

4.2 网络配置

Docker 提供了多种网络模式,满足不同的应用场景:

# 查看网络列表
docker network ls

# 创建自定义网络
docker network create my-network

# 创建指定子网的网络
docker network create --subnet=172.20.0.0/16 my-network

# 运行容器并连接到网络
docker run -d --name web --network my-network nginx

# 将运行中的容器连接到网络
docker network connect my-network existing-container

# 断开容器网络连接
docker network disconnect my-network web

# 查看网络详情
docker network inspect my-network

# 删除网络
docker network rm my-network

4.3 网络模式详解

  • bridge(桥接模式):默认模式,容器通过网桥连接到宿主机网络
  • host(主机模式):容器直接使用宿主机网络,性能最佳但隔离性最差
  • none(无网络):容器没有网络接口,适合完全隔离的场景
  • overlay(覆盖网络):用于跨主机的容器通信,需要 Swarm 模式

五、Docker Compose 多容器编排

5.1 docker-compose.yml 编写

Docker Compose 可以定义和运行多容器应用,非常适合开发和测试环境:

version: '3.8'

services:
  # Web 应用服务
  web:
    build: .
    container_name: django-app
    command: python manage.py runserver 0.0.0.0:8000
    volumes:
      - .:/app
    ports:
      - "8000:8000"
    environment:
      - DEBUG=1
      - DATABASE_URL=postgres://user:password@db:5432/mydb
    depends_on:
      - db
      - redis
    networks:
      - app-network

  # PostgreSQL 数据库服务
  db:
    image: postgres:14-alpine
    container_name: postgres-db
    environment:
      - POSTGRES_USER=user
      - POSTGRES_PASSWORD=password
      - POSTGRES_DB=mydb
    volumes:
      - postgres-data:/var/lib/postgresql/data
    networks:
      - app-network

  # Redis 缓存服务
  redis:
    image: redis:7-alpine
    container_name: redis-cache
    volumes:
      - redis-data:/data
    networks:
      - app-network

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

networks:
  app-network:
    driver: bridge

volumes:
  postgres-data:
  redis-data:

5.2 Docker Compose 常用命令

# 启动所有服务
docker-compose up -d

# 查看服务状态
docker-compose ps

# 查看服务日志
docker-compose logs

# 实时查看特定服务日志
docker-compose logs -f web

# 进入服务容器
docker-compose exec web /bin/bash

# 停止所有服务
docker-compose stop

# 启动已停止的服务
docker-compose start

# 重启所有服务
docker-compose restart

# 停止并删除所有服务
docker-compose down

# 停止并删除所有服务和数据卷
docker-compose down -v

# 重新构建服务镜像
docker-compose build --no-cache

# 扩展服务(运行多个实例)
docker-compose up -d --scale web=3

六、实战案例:部署完整的 Web 应用

6.1 项目结构

myproject/
├── app/
│   ├── main.py
│   ├── requirements.txt
│   └── Dockerfile
├── nginx/
│   ├── nginx.conf
│   └── Dockerfile
├── docker-compose.yml
└── .env

6.2 应用 Dockerfile

# app/Dockerfile
FROM python:3.9-slim

WORKDIR /app

# 安装系统依赖
RUN apt-get update && apt-get install -y \
    gcc \
    && rm -rf /var/lib/apt/lists/*

# 安装 Python 依赖
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# 复制应用代码
COPY . .

# 创建非 root 用户
RUN useradd -m appuser && chown -R appuser:appuser /app
USER appuser

EXPOSE 8000

CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

6.3 应用主程序

# app/main.py
from fastapi import FastAPI
from pydantic import BaseModel
import redis
import os

# 创建 FastAPI 应用实例
app = FastAPI(title="Docker Demo API", version="1.0.0")

# 连接 Redis
redis_host = os.getenv("REDIS_HOST", "localhost")
redis_client = redis.Redis(host=redis_host, port=6379, db=0)

class Item(BaseModel):
    """数据模型定义"""
    name: str
    price: float
    description: str = None

@app.get("/")
async def root():
    """根路径欢迎信息"""
    return {"message": "Hello Docker!", "status": "running"}

@app.get("/health")
async def health_check():
    """健康检查接口"""
    return {"status": "healthy"}

@app.post("/items/")
async def create_item(item: Item):
    """创建物品并存入 Redis"""
    import json
    item_key = f"item:{item.name}"
    redis_client.set(item_key, json.dumps(item.dict()))
    return {"message": "Item created", "item": item}

@app.get("/items/{item_name}")
async def get_item(item_name: str):
    """从 Redis 获取物品"""
    import json
    item_key = f"item:{item_name}"
    item_data = redis_client.get(item_key)
    if item_data:
        return json.loads(item_data)
    return {"error": "Item not found"}

@app.get("/counter")
async def counter():
    """访问计数器示例"""
    count = redis_client.incr("visit_counter")
    return {"visits": count}

6.4 Nginx 配置

# nginx/nginx.conf
events {
    worker_connections 1024;
}

http {
    upstream app {
        server web:8000;
    }

    server {
        listen 80;
        server_name localhost;

        # 静态文件缓存
        location /static/ {
            alias /app/static/;
            expires 30d;
        }

        # 反向代理到应用
        location / {
            proxy_pass http://app;
            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;
        }

        # 健康检查
        location /health {
            proxy_pass http://app/health;
            access_log off;
        }
    }
}

6.5 完整的 docker-compose.yml

version: '3.8'

services:
  web:
    build: ./app
    container_name: fastapi-app
    environment:
      - REDIS_HOST=redis
    depends_on:
      - redis
    networks:
      - backend
    restart: unless-stopped

  nginx:
    image: nginx:alpine
    container_name: nginx-lb
    ports:
      - "80:80"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
    depends_on:
      - web
    networks:
      - backend
    restart: unless-stopped

  redis:
    image: redis:7-alpine
    container_name: redis-cache
    volumes:
      - redis-data:/data
    networks:
      - backend
    restart: unless-stopped

networks:
  backend:
    driver: bridge

volumes:
  redis-data:

6.6 部署流程

# 1. 克隆项目
git clone 
cd myproject

# 2. 创建环境变量文件
cat > .env << EOF
REDIS_HOST=redis
EOF

# 3. 构建并启动所有服务
docker-compose up -d --build

# 4. 查看服务状态
docker-compose ps

# 5. 查看日志
docker-compose logs -f

# 6. 测试 API
curl http://localhost/health
curl http://localhost/counter

# 7. 扩展 Web 服务
docker-compose up -d --scale web=3

七、Docker 性能优化技巧

7.1 镜像优化

  • 使用 alpine 基础镜像,大幅减小镜像体积
  • 多阶段构建,只保留运行时必需的文件
  • 合并 RUN 指令,减少镜像层数
  • 清理缓存和临时文件

7.2 运行时优化

# 限制容器资源使用
docker run -d \
  --name app \
  --memory="512m" \
  --cpus="1.0" \
  --cpu-shares=512 \
  --pids-limit=100 \
  my-app:latest

# 设置重启策略
docker run -d --restart=unless-stopped my-app

# 使用健康检查
docker run -d \
  --health-cmd="curl -f http://localhost/health || exit 1" \
  --health-interval=30s \
  --health-timeout=5s \
  --health-retries=3 \
  my-app

7.3 日志管理

# 限制日志文件大小
docker run -d \
  --log-driver json-file \
  --log-opt max-size=10m \
  --log-opt max-file=3 \
  my-app

# 使用 syslog 驱动
docker run -d \
  --log-driver syslog \
  --log-opt syslog-address=tcp://192.168.0.42:514 \
  my-app

八、常见问题与解决方案

8.1 容器无法访问宿主机服务

在 Linux 上,容器可以通过 host.docker.internal 访问宿主机(需要添加 --add-host 参数):

docker run -d --add-host=host.docker.internal:host-gateway my-app

8.2 权限问题

在容器中挂载的目录可能遇到权限问题,可以通过设置正确的用户 ID 解决:

# 在 Dockerfile 中设置用户
RUN useradd -u 1000 -m myuser
USER myuser

8.3 时区设置

# 方法1:挂载时区文件
docker run -v /etc/localtime:/etc/localtime:ro my-app

# 方法2:设置环境变量
docker run -e TZ=Asia/Shanghai my-app

总结

Docker 容器化技术已经彻底改变了软件开发和部署的方式。通过本文的学习,你应该掌握了:

  1. Docker 核心概念:镜像、容器、仓库的关系和区别
  2. 基础操作:镜像拉取、容器运行、日志查看等日常命令
  3. Dockerfile 编写:如何编写高效、可维护的镜像构建脚本
  4. 数据持久化:数据卷的使用和数据备份策略
  5. 网络配置:不同网络模式的适用场景
  6. Docker Compose:多容器应用的编排和管理
  7. 性能优化:镜像瘦身、资源限制、日志管理
  8. 实战部署:从零构建完整的容器化 Web 应用

Docker 的学习曲线相对平缓,但要真正用好它,需要在实践中不断积累经验。建议从简单的单容器应用开始,逐步过渡到复杂的多服务架构。掌握 Docker 后,你将能更高效地进行开发、测试和部署,为后续学习 Kubernetes 等容器编排工具打下坚实基础。

本文链接:https://www.kkkliao.cn/?id=919 转载需授权!

分享到:

版权声明:本文由廖万里的博客发布,如需转载请注明出处。


发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。