Skip to content

Docker 容器化

前言

"在我机器上能跑"是开发者最经典的借口,Docker 让这个借口彻底消失。 容器化技术将应用及其所有依赖打包成一个标准化的单元,确保在任何环境中都能一致运行。它是现代软件交付的基石。

这篇文章会带你学什么?

学完这章后,你将获得:

  • 核心概念:理解镜像、容器、仓库三大核心概念
  • 架构对比:明白容器和虚拟机的本质区别
  • 实操能力:掌握 Dockerfile 编写和常用命令
  • 编排基础:学会用 Docker Compose 管理多服务应用
  • 最佳实践:了解镜像优化、安全加固等生产级实践
章节内容核心概念
第 1 章为什么需要容器环境一致性、资源效率、标准化交付
第 2 章核心概念镜像、容器、仓库、Dockerfile
第 3 章Docker 生命周期编写、构建、推送、运行、管理
第 4 章Docker Compose多服务编排、网络、数据卷
第 5 章最佳实践镜像优化、安全、多阶段构建

1. 为什么需要容器?

在容器出现之前,部署一个应用需要在服务器上手动安装运行时、配置环境变量、处理依赖冲突。不同环境(开发、测试、生产)之间的差异是 bug 的温床。

虚拟机 vs 容器
点击切换查看两种虚拟化方式的架构差异
应用 A / 应用 B / 应用 C
App A + Bins/Libs
App B + Bins/Libs
App C + Bins/Libs
Docker Engine
宿主操作系统(Host OS)
物理硬件
启动速度秒级
资源占用共享宿主 OS 内核(MB 级)
隔离性较强(进程级隔离)
密度单机可运行数百个容器
镜像大小MB 级

容器解决了什么问题?

问题传统方式容器方式
环境不一致"我本地能跑"打包所有依赖,到处一致
依赖冲突App A 要 Node 14,App B 要 Node 18每个容器独立环境
资源浪费每个 VM 一个完整 OS共享内核,MB 级开销
部署慢手动安装配置docker run 一条命令
扩容难新建 VM、装环境、部署秒级启动新容器

容器的本质

容器不是轻量级虚拟机。它的本质是被隔离的进程。Linux 内核通过两个机制实现容器:

  • Namespace:隔离进程的视野(PID、网络、文件系统等)
  • Cgroups:限制进程的资源使用(CPU、内存、IO)

容器里的进程和宿主机上的普通进程没有本质区别,只是被"关在了一个看不到外面的房间里"。


2. 核心概念

Docker 的世界围绕三个核心概念:镜像(Image)、容器(Container)、仓库(Registry)。

概念类比说明
镜像(Image)类 / 模板只读的应用模板,包含代码、运行时、库、配置
容器(Container)实例 / 对象镜像的运行实例,可读写,有独立的生命周期
仓库(Registry)应用商店存储和分发镜像的服务(Docker Hub、ACR、ECR)
Dockerfile配方 / 蓝图定义如何构建镜像的文本文件
数据卷(Volume)外接硬盘持久化数据,容器删除后数据不丢失

镜像的分层结构

Docker 镜像由多个只读层(Layer)叠加而成,每条 Dockerfile 指令创建一层:

┌─────────────────────────┐
│  CMD ["node", "app.js"] │  ← 启动命令层
├─────────────────────────┤
│  COPY . /app            │  ← 应用代码层(经常变)
├─────────────────────────┤
│  RUN npm install        │  ← 依赖安装层(偶尔变)
├─────────────────────────┤
│  FROM node:18-alpine    │  ← 基础镜像层(很少变)
└─────────────────────────┘

为什么分层很重要?

Docker 会缓存每一层。如果某一层没有变化,构建时会直接复用缓存。所以 Dockerfile 中应该把变化频率低的指令放在前面(如安装依赖),变化频率高的放在后面(如复制代码)。这样大部分构建都能命中缓存,速度快很多。


3. Docker 生命周期

从编写 Dockerfile 到容器运行,Docker 的工作流程是一条清晰的流水线。

Docker 生命周期
点击每个阶段查看详细说明
📝
编写 Dockerfile
🔨
构建镜像
☁️
推送仓库
▶️
运行容器
⚙️
管理容器
编写 Dockerfile
Dockerfile 是构建镜像的"配方",定义了从基础镜像开始,如何一步步构建出你的应用环境。每条指令创建一个镜像层(Layer),Docker 会缓存这些层以加速后续构建。
常用命令
FROM node:18-alpine指定基础镜像
WORKDIR /app设置工作目录
COPY package*.json ./复制依赖文件(利用缓存)
RUN npm install安装依赖
COPY . .复制应用代码
EXPOSE 3000声明端口
CMD ["node", "server.js"]启动命令

Dockerfile 常用指令速查

指令作用示例
FROM指定基础镜像FROM node:18-alpine
WORKDIR设置工作目录WORKDIR /app
COPY复制文件到镜像COPY package.json ./
RUN构建时执行命令RUN npm install
ENV设置环境变量ENV NODE_ENV=production
EXPOSE声明端口(仅文档作用)EXPOSE 3000
CMD容器启动命令CMD ["node", "app.js"]
ENTRYPOINT容器入口点(不易被覆盖)ENTRYPOINT ["nginx"]

4. Docker Compose:多服务编排

真实项目通常不止一个容器。一个 Web 应用可能需要:应用服务器 + 数据库 + Redis + Nginx。Docker Compose 用一个 YAML 文件定义和管理多个容器。

docker-compose.yml 示例

yaml
version: '3.8'
services:
  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      - DB_HOST=db
      - REDIS_HOST=redis
    depends_on:
      - db
      - redis

  db:
    image: postgres:15-alpine
    volumes:
      - db-data:/var/lib/postgresql/data
    environment:
      - POSTGRES_PASSWORD=secret

  redis:
    image: redis:7-alpine

volumes:
  db-data:

Compose 核心概念

概念说明示例
services定义各个容器服务app、db、redis
volumes持久化数据卷db-data 保存数据库文件
networks自定义网络(默认自动创建)服务间通过服务名互相访问
depends_on启动顺序依赖app 依赖 db 和 redis
environment环境变量数据库密码、连接地址

服务发现

在 Docker Compose 中,服务名就是主机名。app 容器可以直接用 db:5432 访问数据库,用 redis:6379 访问 Redis,不需要知道 IP 地址。这是 Docker 内置 DNS 的功劳。


5. 最佳实践

5.1 多阶段构建(Multi-stage Build)

多阶段构建是优化镜像大小的利器。构建阶段安装所有工具和依赖,最终阶段只保留运行时需要的文件。

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/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
EXPOSE 3000
CMD ["node", "dist/server.js"]

5.2 镜像优化清单

优化项做法效果
选择小基础镜像alpine 而非 ubuntu镜像从 ~200MB 降到 ~50MB
合并 RUN 指令多个命令用 && 连接减少镜像层数
使用 .dockerignore排除 node_modules、.git 等加速构建,减小上下文
多阶段构建分离构建和运行环境最终镜像不含构建工具
固定版本号node:18.17-alpine 而非 node:latest构建可重复

5.3 安全实践

实践说明
不用 root 运行USER node 指定非 root 用户
扫描漏洞docker scout 或 Trivy 扫描镜像
最小权限只安装必要的包,不装调试工具
不硬编码密钥用环境变量或 Docker Secrets
定期更新基础镜像及时修复安全漏洞

总结

Docker 容器化是现代软件交付的基础设施,理解它对于任何开发者都至关重要。

回顾本章的关键要点:

  1. 容器 vs 虚拟机:容器共享宿主内核,更轻量、更快,但隔离性略弱于 VM
  2. 核心三件套:镜像(模板)、容器(实例)、仓库(分发)
  3. Dockerfile:分层构建,利用缓存,变化少的指令放前面
  4. Docker Compose:用 YAML 定义多服务应用,服务名即主机名
  5. 生产实践:多阶段构建减小镜像、alpine 基础镜像、非 root 运行

延伸阅读