运维部署

Docker 与容器化完全指南:从开发到部署

深入学习 Docker 的核心概念、容器构建、镜像管理、容器编排和生产部署,掌握现代应用部署的必备技能

17 分钟阅读
#Docker #容器化 #DevOps #微服务部署

📖 文章概述

Docker 是现代应用部署的事实标准。本文深入讲解 Docker 的核心概念、镜像构建、容器运行、编排部署和最佳实践。


🎯 Docker 核心概念

什么是 Docker?

Docker 是一个开源的容器化平台,可以打包应用及其依赖到一个标准单元(容器)中。

虚拟机                      Docker 容器
┌──────────────┐           ┌─────────────────┐
│ 操作系统      │           │ 应用程序        │
├──────────────┤           ├─────────────────┤
│ 应用程序      │    vs     │ 依赖库          │
├──────────────┤           ├─────────────────┤
│ 依赖库       │           │ Docker 引擎     │
├──────────────┤           └─────────────────┘
│ Hypervisor   │           └─────────────────┘
├──────────────┤           ┌─────────────────┐
│ 硬件         │           │ 操作系统        │
└──────────────┘           │ Docker          │
体积:GB       │           │ 硬件            │
启动:分钟     │           └─────────────────┘
              │           体积:MB
              │           启动:秒

Docker 核心概念

概念描述类比
镜像应用的模板/蓝图类 (Class)
容器运行的镜像实例对象 (Instance)
仓库镜像的存储库包管理器
Dockerfile镜像构建脚本构建配置
Volume持久化存储硬盘
Network容器网络网络接口

🚀 快速开始

1. Docker 安装和基础命令

# 安装 Docker
# macOS: brew install docker
# Linux: curl -fsSL https://get.docker.com | sh
# Windows: 下载 Docker Desktop

# 验证安装
docker --version

# 基础命令
docker pull ubuntu                 # 拉取镜像
docker run -it ubuntu /bin/bash    # 运行容器
docker ps                          # 查看运行中的容器
docker ps -a                       # 查看所有容器
docker images                      # 查看镜像
docker stop container_id           # 停止容器
docker rm container_id             # 删除容器
docker rmi image_id               # 删除镜像

2. 构建第一个镜像

# Dockerfile - 构建 Node.js 应用镜像
FROM node:18-alpine

# 设置工作目录
WORKDIR /app

# 复制 package 文件
COPY package*.json ./

# 安装依赖
RUN npm ci --only=production

# 复制应用代码
COPY . .

# 暴露端口
EXPOSE 3000

# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=40s --retries=3 \
  CMD node healthcheck.js

# 启动应用
CMD ["node", "server.js"]

构建和运行

# 构建镜像
docker build -t my-app:1.0 .

# 运行容器
docker run -d -p 3000:3000 --name my-app-container my-app:1.0

# 查看日志
docker logs -f my-app-container

# 进入容器
docker exec -it my-app-container /bin/bash

🏗️ Dockerfile 详解

3. 优化的 Dockerfile

# 多阶段构建 - 减少最终镜像大小
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/node_modules ./node_modules
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/package.json ./

# 非 root 用户
RUN addgroup -g 1001 -S nodejs && \
    adduser -S nodejs -u 1001

USER nodejs

EXPOSE 3000

# 使用 exec 形式确保信号正确传递
ENTRYPOINT ["node"]
CMD ["dist/server.js"]

4. Dockerfile 最佳实践

# ✅ 好的实践

# 1. 使用具体的标签,而不是 latest
FROM node:18.12.1-alpine

# 2. 使用 .dockerignore
# .dockerignore 内容:
# node_modules
# npm-debug.log
# .git

# 3. 最小化层数
RUN apt-get update && \
    apt-get install -y --no-install-recommends \
    curl \
    && rm -rf /var/lib/apt/lists/*

# 4. 按构建顺序排列命令(经常变化的放最后)
COPY package.json .
RUN npm install
COPY . .

# 5. 使用非 root 用户
USER nodejs

# 6. 定义元数据
LABEL maintainer="your@email.com"
LABEL version="1.0"

# ❌ 避免的做法
# FROM ubuntu:latest        # 过于宽泛
# RUN apt-get install *     # 安装不必要的包
# COPY . /app               # 复制整个项目,包括 node_modules

🗂️ 镜像管理

5. Docker 镜像操作

# 构建镜像
docker build -t app:1.0 .
docker build -t app:latest -t app:v1.0 .  # 多标签

# 查看镜像详情
docker inspect image_id

# 标签(重新命名)
docker tag app:1.0 myregistry/app:1.0

# 推送到仓库
docker push myregistry/app:1.0

# 拉取镜像
docker pull ubuntu:20.04

# 查看镜像历史
docker history app:1.0

# 保存镜像
docker save app:1.0 > app.tar

# 加载镜像
docker load < app.tar

# 删除镜像
docker rmi app:1.0
docker rmi -f app:1.0        # 强制删除

# 清理未使用的镜像
docker image prune
docker image prune -a        # 删除所有未使用的

🎯 容器运行和管理

6. 容器操作详解

# 运行容器的各种方式
docker run -d -p 8080:3000 --name web app:1.0

# 参数说明:
# -d: 后台运行
# -p: 端口映射 (主机:容器)
# --name: 容器名称
# -e: 环境变量
# -v: 挂载卷
# --network: 网络
# --restart: 重启策略
# -m: 内存限制
# --cpus: CPU 限制

# 完整示例
docker run -d \
  --name web-app \
  -p 8080:3000 \
  -e NODE_ENV=production \
  -e DATABASE_URL=postgresql://db:5432/myapp \
  -v /data/uploads:/app/uploads \
  --restart unless-stopped \
  -m 512m \
  --cpus 1 \
  myapp:1.0

# 容器通信
docker network create app-network
docker run --network app-network --name web app:1.0
docker run --network app-network --name db postgres:13

# 容器间通信(使用容器名)
# curl http://web:3000

# 查看容器详情
docker ps
docker ps -a
docker inspect container_id

# 查看容器日志
docker logs container_id
docker logs -f container_id        # 实时日志
docker logs --tail 100 container_id

# 进入容器
docker exec -it container_id /bin/bash
docker exec -it container_id sh

# 暂停和恢复
docker pause container_id
docker unpause container_id

# 停止和启动
docker stop container_id
docker start container_id

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

# 容器资源统计
docker stats                       # 实时监控
docker stats --no-stream          # 一次输出

🎛️ Docker Compose 编排

7. Docker Compose 完整示例

# docker-compose.yml - 多容器应用编排
version: '3.9'

services:
  # 前端应用
  frontend:
    build:
      context: ./frontend
      dockerfile: Dockerfile
    ports:
      - "3000:3000"
    environment:
      - REACT_APP_API_URL=http://backend:3001
    depends_on:
      - backend
    networks:
      - app-network
    restart: unless-stopped

  # 后端应用
  backend:
    build:
      context: ./backend
      dockerfile: Dockerfile
    ports:
      - "3001:3001"
    environment:
      - NODE_ENV=production
      - DATABASE_URL=postgresql://postgres:password@db:5432/myapp
      - REDIS_URL=redis://redis:6379
    depends_on:
      - db
      - redis
    volumes:
      - ./backend/src:/app/src
    networks:
      - app-network
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3001/health"]
      interval: 30s
      timeout: 10s
      retries: 3

  # 数据库
  db:
    image: postgres:13-alpine
    environment:
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=password
      - POSTGRES_DB=myapp
    volumes:
      - postgres_data:/var/lib/postgresql/data
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql
    networks:
      - app-network
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 10s
      timeout: 5s
      retries: 5

  # 缓存
  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    volumes:
      - redis_data:/data
    networks:
      - app-network
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5

volumes:
  postgres_data:
  redis_data:

networks:
  app-network:
    driver: bridge

Compose 命令

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

# 停止所有服务
docker-compose down

# 查看服务状态
docker-compose ps

# 查看日志
docker-compose logs -f backend

# 进入容器
docker-compose exec backend /bin/bash

# 重启服务
docker-compose restart backend

# 扩展服务
docker-compose up -d --scale worker=3

# 删除所有数据
docker-compose down -v

🚀 生产部署

8. Docker 生产部署检查清单

# 生产级 Dockerfile 示例
FROM node:18-alpine

# 设置工作目录
WORKDIR /app

# 复制锁文件优先(缓存优化)
COPY package-lock.json .

# 安装依赖
RUN npm ci --only=production && \
    npm cache clean --force

# 复制源代码
COPY --chown=node:node . .

# 非 root 用户
USER node

# 暴露端口
EXPOSE 3000

# 环境变量
ENV NODE_ENV=production

# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=40s --retries=3 \
  CMD node -e "require('http').get('http://localhost:3000/health', (r) => {if (r.statusCode !== 200) throw new Error(r.statusCode)})"

# 启动应用
CMD ["node", "server.js"]

部署脚本

#!/bin/bash
# deploy.sh

set -e

# 构建镜像
echo "Building Docker image..."
docker build -t myapp:$VERSION .

# 标记镜像
docker tag myapp:$VERSION myregistry/myapp:$VERSION
docker tag myapp:$VERSION myregistry/myapp:latest

# 推送到仓库
echo "Pushing image to registry..."
docker push myregistry/myapp:$VERSION
docker push myregistry/myapp:latest

# 在生产环境上更新
echo "Deploying to production..."
ssh user@production-server "cd /apps/myapp && \
  docker pull myregistry/myapp:$VERSION && \
  docker-compose down && \
  docker-compose up -d"

echo "Deployment complete!"

📊 Docker 性能优化

9. 镜像大小优化

优化方案镜像大小启动时间
标准 Node 镜像908MB5s
Alpine 镜像123MB1s
多阶段构建98MB0.8s
压缩优化45MB0.3s

优化技巧

# 1. 使用 Alpine 镜像
FROM node:18-alpine

# 2. 多阶段构建
FROM node:18-alpine AS builder
# 构建阶段
FROM node:18-alpine
COPY --from=builder /app/dist ./dist

# 3. 移除不必要的文件
RUN npm ci --only=production && \
    npm cache clean --force && \
    rm -rf /var/lib/apt/lists/*

# 4. 使用 .dockerignore
# .dockerignore 文件:
# node_modules
# npm-debug.log
# .git
# .env
# coverage

🔒 Docker 安全最佳实践

10. 安全配置

# ✅ 安全的 Dockerfile
# 1. 不要以 root 运行
RUN addgroup -g 1001 -S nodejs && \
    adduser -S nodejs -u 1001
USER nodejs

# 2. 使用只读文件系统(可能)
# docker run --read-only app:1.0

# 3. 限制容器权限
# docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE app:1.0

# 4. 不要在镜像中存储密钥
# ❌ RUN echo "SECRET=xxx" >> .env
# ✅ 使用环境变量或密钥管理系统

# 5. 定期更新基础镜像
FROM alpine:3.18  # 使用最新的安全版本

安全扫描

# 扫描漏洞
docker scan myapp:1.0

# 使用 Trivy
trivy image myapp:1.0

# 检查镜像历史
docker history myapp:1.0

🐛 常见问题解决

问题 1:容器文件权限问题

# ❌ 问题:挂载卷权限不匹配
docker run -v /data:/app/data app:1.0

# ✅ 解决方案
docker run -v /data:/app/data --user $(id -u):$(id -g) app:1.0

# 或在 Dockerfile 中指定用户
RUN addgroup -g 1001 -S nodejs && \
    adduser -S nodejs -u 1001
USER nodejs

问题 2:Docker 容器占用空间

# 查看 Docker 磁盘占用
docker system df

# 清理未使用的资源
docker system prune          # 清理容器和镜像
docker system prune -a       # 清理所有未使用的
docker volume prune          # 清理卷

问题 3:容器之间网络通信

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

# 在同一网络中运行容器
docker run --network app-net --name web app:1.0
docker run --network app-net --name db postgres:13

# 容器内可以通过名称通信
# curl http://web:3000

🎓 最佳实践总结

DO ✅

# 1. 使用 Alpine 基础镜像
FROM alpine:3.18

# 2. 多阶段构建
FROM node:18 AS builder
COPY . .
RUN npm run build

FROM node:18-alpine
COPY --from=builder /app/dist ./dist

# 3. 非 root 用户
USER nodejs

# 4. 健康检查
HEALTHCHECK CMD curl localhost:3000/health

# 5. 环境变量管理
ENV NODE_ENV=production

# 6. 定期更新依赖
RUN npm update

DON'T ❌

# 1. 不要使用 latest 标签
# FROM ubuntu:latest

# 2. 不要在镜像中存储密钥
# RUN echo "PASSWORD=secret" >> .env

# 3. 不要以 root 运行
# USER root

# 4. 不要安装不必要的包
# RUN apt-get install *

# 5. 不要忽视安全更新
# 定期扫描和更新基础镜像

📚 扩展资源


总结

Docker 容器化的核心要素:

  1. 镜像构建:优化 Dockerfile,使用多阶段构建
  2. 容器运行:正确配置环保变量、卷、网络
  3. 编排管理:使用 Docker Compose 管理多个容器
  4. 生产部署:健康检查、监控、自动化部署
  5. 安全保障:非 root 用户、安全扫描、权限管理
  6. 性能优化:镜像大小、启动时间、资源限制

掌握 Docker,成为现代 DevOps 工程师!