Docker 生产环境运维指南(持续更新)
前言
Docker 是什么?
想象一下:你要开一家餐厅。传统方式:
- 买地皮、盖房子(买服务器)
- 装修、买厨房设备(装系统、配环境)
- 请厨师(部署应用)
Docker 方式:
- 直接租一个标准化集装箱厨房(容器)
- 里面已经配好了灶台、烤箱等设备(系统+环境)
- 厨师进去就能开工(应用直接运行)
这就是 Docker 的魔力:一次打包,到处运行!
Docker 是现代云原生的基石,被无数公司用于:
- 应用的打包和部署
- 微服务架构
- 持续集成/持续部署(CI/CD)
- 开发环境标准化
作为运维工程师,我们的职责是:让容器稳如磐石、快如闪电。
本文档会告诉你:
- Docker 核心概念和命令
- docker info 所有信息的含义
- 怎么部署 Docker Swarm 集群
- Docker 底层原理(namespace、cgroups、内核态)
目录
- 快速入门
- docker info 详解
- Dockerfile 构建镜像
- docker-compose 编排服务
- 镜像层详解
- daemon.json 配置
- 常用命令
- Docker Swarm 集群
- Docker 底层原理
- 运维监控
- 常见问题排查
快速入门
Docker 基本概念
| 概念 | 通俗解释 |
|---|---|
| 镜像(Image) | 就像"菜谱",定义了怎么制作这道菜 |
| 容器(Container) | 就像"做好的菜",按照菜谱做出来的成品 |
| 仓库(Registry) | 就像"菜市场",存放和分发菜谱的地方 |
| Dockerfile | 就像"烹饪配方",告诉 Docker 怎么制作镜像 |
安装 Docker
# Ubuntu/Debian
sudo apt update
sudo apt install docker.io
# 启动 Docker
sudo systemctl start docker
sudo systemctl enable docker
# 把当前用户加入 docker 组(免 sudo)
sudo usermod -aG docker $USER
# 需要重新登录生效
第一个容器
# 👀 运行一个 Nginx 容器
docker run -d --name my-nginx -p 80:80 nginx
# 查看运行中的容器
docker ps
# 停止容器
docker stop my-nginx
# 启动容器
docker start my-nginx
# 删除容器
docker rm my-nginx
docker info 详解
docker info 是最重要的诊断命令!
就像汽车的"仪表盘",docker info 显示 Docker 的所有配置信息和运行状态。
Client(客户端)
Client:
Version: 29.1.3
Context: default
Debug Mode: false
Plugins:
compose: Docker Compose (Docker Inc.)
Version: 2.40.3+ds1-0ubuntu1~24.04.1
Path: /usr/libexec/docker/cli-plugins/docker-compose
trust: Manage trust on Docker images (Docker Inc.)
Version: 29.1.3
Path: /usr/libexec/docker/cli-plugins/docker-trust
通俗解释:
| 字段 | 通俗解释 |
|---|---|
| Version | Docker 客户端版本(你正在使用的版本) |
| Context | 当前使用的上下文环境(default = 默认) |
| Debug Mode | 调试模式(false = 关闭) |
| Plugins | 安装的插件(compose、trust 等) |
Server / Engine(服务端)
Server:
Containers: 5
Running: 4
Paused: 0
Stopped: 1
Images: 4
通俗解释:
| 字段 | 通俗解释 |
|---|---|
| Containers | 容器总数(5个) |
| Running | 正在运行的(4个) |
| Paused | 暂停的(0个) |
| Stopped | 已停止的(1个) |
| Images | 镜像数量(4个) |
Server Version(服务端版本)
Server Version: 29.1.3
通俗解释:
Docker 服务端(daemon)版本。客户端和服务端版本最好保持一致!
Storage Driver(存储驱动)
Storage Driver: overlayfs
driver-type: io.containerd.snapshotter.v1
通俗解释:
| 字段 | 通俗解释 |
|---|---|
| Storage Driver | 存储驱动(overlayfs) |
| driver-type | 容器镜像存储类型 |
常见的存储驱动:
| 驱动 | 通俗解释 | 适用场景 |
|---|---|---|
| overlayfs | 叠加文件系统,快照方式 | 推荐,性能好 |
| devicemapper | 设备映射 | 早期版本 |
| btrfs | B树文件系统 | 完整支持快照 |
| zfs | Z文件系统 | 功能强大,占用高 |
Logging Driver(日志驱动)
Logging Driver: json-file
通俗解释:
容器日志的存储方式。json-file 把日志存成 JSON 文件。
常见的日志驱动:
| 驱动 | 通俗解释 |
|---|---|
| json-file | JSON 格式文件(默认) |
| syslog | 系统日志 |
| journald | systemd 日志 |
| fluentd | Fluentd 日志收集 |
| awslogs | AWS CloudWatch |
Cgroup(控制组)
Cgroup Driver: systemd
Cgroup Version: 2
通俗解释:
| 字段 | 通俗解释 |
|---|---|
| Cgroup Driver | Cgroup 驱动(systemd) |
| Cgroup Version | Cgroup 版本(2) |
什么是 Cgroup?
就像公司的"部门预算管理"。每个部门(容器)只能用分配给它的资源(CPU、内存),不能多用。Cgroup 就是 Linux 内核用来限制资源的功能。
Plugins(插件)
Plugins:
Volume: local
Network: bridge host ipvlan macvlan null overlay
Log: awslogs fluentd gcplogs gelf journald json-file local splunk syslog
通俗解释:
| 插件类型 | 支持的插件 | 通俗解释 |
|---|---|---|
| Volume | local | 存储卷插件 |
| Network | bridge, host, overlay 等 | 网络插件 |
| Log | json-file, syslog 等 | 日志插件 |
Runtimes(运行时)
Runtimes: io.containerd.runc.v2 runc
Default Runtime: runc
通俗解释:
| 字段 | 通俗解释 |
|---|---|
| Runtimes | 支持的容器运行时 |
| Default Runtime | 默认使用的运行时(runc) |
什么是容器运行时?
就像"厨房设备"。真正执行容器的是 runc,它负责和内核交互,启动容器。
Security Options(安全选项)
Security Options:
apparmor
seccomp
Profile: builtin
cgroupns
通俗解释:
| 安全选项 | 通俗解释 |
|---|---|
| apparmor | AppArmor 安全模块(应用程序安全策略) |
| seccomp | 安全计算模式(限制系统调用) |
| Profile: builtin | 使用内置的安全配置文件 |
| cgroupns | Cgroup 命名空间(隔离资源控制组) |
Kernel(内核)信息
Kernel Version: 6.8.0-124-generic
Operating System: Ubuntu 24.04.4 LTS
OSType: linux
Architecture: x86_64
CPUs: 4
Total Memory: 7.709GiB
通俗解释:
| 字段 | 通俗解释 |
|---|---|
| Kernel Version | Linux 内核版本(6.8.0) |
| Operating System | 操作系统(Ubuntu 24.04) |
| OSType | 操作系统类型(linux) |
| Architecture | CPU 架构(x86_64 = 64位) |
| CPUs | CPU 核心数(4核) |
| Total Memory | 总内存(7.7GB) |
Docker 信息
Name: test
ID: cd89be2d-6031-4168-a755-e03d5d0ec052
Docker Root Dir: /var/lib/docker
通俗解释:
| 字段 | 通俗解释 |
|---|---|
| Name | Docker 主机名称(test) |
| ID | 主机唯一标识 |
| Docker Root Dir | Docker 数据存储目录 |
Registry(镜像仓库)
Registry Mirrors:
https://registry.cn-shanghai.aliyuncs.com/
通俗解释:
镜像加速器地址。中国大陆使用阿里云加速器可以提高下载速度。
其他信息
Debug Mode: false
Experimental: false
Insecure Registries:
::1/128
127.0.0.0/8
Live Restore Enabled: false
Firewall Backend: iptables
| 字段 | 通俗解释 |
|---|---|
| Debug Mode | 调试模式(关闭) |
| Experimental | 实验性功能(关闭) |
| Insecure Registries | 不安全的仓库(本地测试用) |
| Live Restore | 守护进程重启时保持容器运行 |
| Firewall Backend | 防火墙后端(iptables) |
Dockerfile 构建镜像
什么是 Dockerfile?
想象一下:你去餐厅吃饭,厨房是封闭的,你看不到厨师怎么做菜。
Dockerfile 就是"开放式厨房的菜谱"! 它清清楚楚写明了:
- 用什么食材(基础镜像)
- 先放什么后放什么(指令顺序)
- 火候多大(环境变量)
- 做完了怎么装盘(端口映射)
有了这个菜谱,任何人都能做出一样的菜!
Dockerfile 常用指令
| 指令 | 通俗解释 | 示例 |
|---|---|---|
| FROM | 基础镜像(用哪种面粉) | FROM ubuntu:24.04 |
| RUN | 执行命令(和面、揉面) | RUN apt update && apt install nginx |
| COPY | 复制文件(把食材放进厨房) | COPY ./app /app |
| ADD | 复制文件(支持 URL 和 tar) | ADD https://example.com/file.tar.gz /tmp/ |
| WORKDIR | 设置工作目录(切换到哪个操作台) | WORKDIR /app |
| ENV | 设置环境变量(厨房温度、湿度) | ENV NODE_ENV=production |
| EXPOSE | 声明端口(告诉别人从哪个门取餐) | EXPOSE 80 |
| CMD | 容器启动命令(按下烹饪按钮) | CMD ["npm", "start"] |
| ENTRYPOINT | 入口点(和 CMD 类似,但不会被覆盖) | ENTRYPOINT ["python"] |
| ARG | 构建参数(临时变量) | ARG VERSION=1.0 |
| VOLUME | 声明卷(外部存储) | VOLUME ["/data"] |
| LABEL | 元数据标签 | LABEL version="1.0" |
Dockerfile 示例
# 使用官方 Node.js 基础镜像
FROM node:18-alpine
# 设置工作目录
WORKDIR /app
# 复制 package.json
COPY package*.json ./
# 安装依赖(利用缓存加速构建)
RUN npm ci --only=production
# 复制应用代码
COPY . .
# 设置环境变量
ENV NODE_ENV=production
ENV PORT=3000
# 暴露端口
EXPOSE 3000
# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:3000/health || exit 1
# 启动命令
CMD ["node", "server.js"]
多阶段构建
什么是多阶段构建?
想象一下:做蛋糕需要烤箱,但最终送到客户手里的只需要蛋糕,不需要烤箱。
多阶段构建就是:在厨房里用烤箱(构建阶段),最后只打包蛋糕(运行阶段)。
# 阶段1:构建
FROM node:18 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# 阶段2:运行(只复制构建产物)
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
CMD ["node", "dist/server.js"]
构建缓存机制
# ❌ 不推荐的写法(每次都重新安装依赖)
COPY . /app
RUN npm install
# ✅ 推荐的写法(利用缓存,只有 package.json 变化才重新安装)
COPY package*.json /app/
RUN npm install
COPY . /app/
.dockerignore 文件
什么是 .dockerignore?
就像装修时不让工人带某些工具进场,
.dockerignore告诉 Docker 哪些文件不要打包进镜像。
# .dockerignore
node_modules
npm-debug.log
.git
.gitignore
.env
*.md
构建镜像命令
# ⚙️ 构建镜像
docker build -t myapp:1.0 .
# ⚙️ 带构建参数
docker build --build-arg VERSION=1.0 -t myapp:1.0 .
# ⚙️ 使用指定 Dockerfile
docker build -f Dockerfile.dev -t myapp:dev .
# ⚙️ 构建时不使用缓存
docker build --no-cache -t myapp:latest .
最佳实践
-
使用官方基础镜像
# ✅ 推荐 FROM python:3.11-slim # ❌ 不推荐 FROM ubuntu RUN apt-get install python3.11 -
减少镜像层数
# ✅ 合并命令减少层数 RUN apt-get update && \ apt-get install -y nginx && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* -
使用多用户(安全)
RUN addgroup -S appgroup && adduser -S appuser -G appgroup USER appuser
docker-compose 编排服务
什么是 docker-compose?
想象一下:你开的不是一家餐厅,而是一整条美食街!
- 川菜馆(Web 服务)
- 粤菜馆(数据库)
- 火锅店(Redis 缓存)
- 奶茶店(消息队列)
docker-compose 就是同时管理整条美食街的配置手册!
docker-compose.yml 结构
version: '3.8' # compose 文件版本
services: # 服务列表
web: # 服务名
image: nginx:latest # 使用的镜像
ports: # 端口映射
- "80:80"
environment: # 环境变量
- NODE_ENV=production
volumes: # 挂载卷
- ./html:/usr/share/nginx/html
networks: # 所属网络
- frontend
depends_on: # 依赖的服务
- redis
restart: always # 重启策略
redis: # 另一个服务
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
- redis-data:/data
networks:
- frontend
restart: always
networks: # 网络定义
frontend:
driver: bridge
volumes: # 卷定义
redis-data:
docker-compose 常用命令
# 👀 启动所有服务(后台运行)
docker-compose up -d
# 👀 启动指定服务
docker-compose up -d web
# 👀 停止所有服务
docker-compose down
# 👀 停止并删除卷和网络
docker-compose down -v
# 🔄 重启所有服务
docker-compose restart
# 🔄 重新构建并启动
docker-compose up -d --build
# 👀 查看服务状态
docker-compose ps
# 👀 查看日志
docker-compose logs -f web
# ⚙️ 扩展服务(增加副本)
docker-compose up -d --scale web=3
depends_on vs healthcheck
# depends_on:只保证启动顺序,不保证服务就绪
services:
web:
depends_on:
- db
- redis
# healthcheck:保证服务真正就绪
services:
web:
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
db:
image: postgres:16
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5
环境变量文件
# .env 文件
POSTGRES_DB=myapp
POSTGRES_USER=admin
POSTGRES_PASSWORD=secret123
# docker-compose.yml
services:
db:
image: postgres:16
env_file:
- .env
# 或者直接在环境变量中引用
environment:
POSTGRES_DB: ${POSTGRES_DB}
多环境配置
# docker-compose.yml(基础配置)
services:
web:
image: myapp
# docker-compose.prod.yml(生产环境覆盖)
services:
web:
image: myapp:latest
environment:
- NODE_ENV=production
deploy:
replicas: 5
restart: always
# 使用生产配置
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d
完整示例:Web 应用 + 数据库 + Redis
version: '3.8'
services:
web:
build:
context: .
dockerfile: Dockerfile
image: myapp:latest
ports:
- "80:3000"
environment:
- NODE_ENV=production
- DB_HOST=db
- REDIS_HOST=redis
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
networks:
- backend
restart: always
volumes:
- ./logs:/app/logs
db:
image: postgres:16-alpine
environment:
POSTGRES_DB: myapp
POSTGRES_USER: admin
POSTGRES_PASSWORD: ${DB_PASSWORD:-secret123}
volumes:
- postgres-data:/var/lib/postgresql/data
networks:
- backend
healthcheck:
test: ["CMD-SHELL", "pg_isready -U admin -d myapp"]
interval: 10s
timeout: 5s
retries: 5
restart: always
redis:
image: redis:7-alpine
command: redis-server --requirepass ${REDIS_PASSWORD:-redis123}
volumes:
- redis-data:/data
networks:
- backend
restart: always
networks:
backend:
driver: bridge
volumes:
postgres-data:
redis-data:
镜像层详解
什么是镜像层?
想象一下:你学做菜,先买一本菜谱基础书(基础镜像),然后:
- 在书的第一页贴了个便签(层1)
- 在第二页折了个角(层2)
- 在第三页夹了一片树叶(层3)
镜像层就是这样的"叠加"结构! 每一层都是只读的,叠加在一起形成完整的文件系统。
镜像层结构
┌─────────────────────────────────────────┐
│ 容器层 (Container Layer) │
│ (writable, 可写层) │
│ 新增文件、修改文件、删除文件 │
└─────────────────┬───────────────────────┘
│
┌─────────────────┴───────────────────────┐
│ 镜像层 (Image Layers) │
│ (read-only, 只读层) │
├─────────────────────────────────────────┤
│ Layer 4: CMD, EXPOSE (元数据层) │
├─────────────────────────────────────────┤
│ Layer 3: RUN apt-get install (安装层) │
├─────────────────────────────────────────┤
│ Layer 2: COPY package.json (复制层) │
├─────────────────────────────────────────┤
│ Layer 1: WORKDIR /app (工作目录层) │
├─────────────────────────────────────────┤
│ Layer 0: FROM ubuntu (基础镜像层) │
└─────────────────────────────────────────┘
层的作用
| 层类型 | 是否可写 | 通俗解释 |
|---|---|---|
| 只读层 (Image Layer) | ❌ | 菜谱的每一页(不可撕毁、不可涂改) |
| 容器层 (Container Layer) | ✅ | 操作台上的临时操作(可以随时擦掉重做) |
查看镜像层
# 👀 查看镜像的所有层
docker history myapp:1.0
# 输出示例:
# IMAGE CREATED SIZE
# a1b2c3d4 2 hours ago 0B
# <missing> 2 hours ago 123MB # Layer 3
# <missing> 2 hours ago 45MB # Layer 2
# <missing> 2 hours ago 78MB # Layer 1
# ubuntu:24.04 3 weeks ago 78MB # Layer 0
查看镜像详细信息
# 👀 查看镜像的完整信息
docker inspect myapp:1.0
# 查看 RootFS(只读层)
docker inspect myapp:1.0 | grep -A 20 "RootFS"
分层缓存原理
为什么 Docker 构建这么快?
想象一下:你已经做了一道红烧肉,第二次再做同样的菜,只需要把新加的调料(层)加上,之前的步骤(层)不用重复。
Docker 的分层缓存就是这样工作的! 如果某一层没变化,直接用缓存,不用重新构建。
构建过程:
Step 1: FROM ubuntu → 没有缓存,从头开始
Step 2: RUN apt update → 没有缓存,重新执行
Step 3: COPY package.json → 文件没变,用缓存!
Step 4: RUN npm install → package.json 变了,重新执行
Step 5: COPY . → 文件变了,重新执行
共享层原理
为什么不同镜像可以共享层?
想象一下:你和邻居都买了同一本菜谱书(基础镜像),你们各自在书上加了自己的便签(不同的层)。
虽然你们的便签不同,但菜谱书本身是共享的!
Docker 也是这样! 不同镜像共享相同的基础层,节省磁盘空间。
# 👀 查看层被哪些镜像共享
docker images --format "{{.Repository}}:{{.Tag}} -> {{.ID}}"
UnionFS(联合文件系统)
什么是 UnionFS?
就像把多张透明塑料纸叠加在一起,每张纸上画不同的内容,叠加后能看到完整图案。
Docker 用 UnionFS 实现层的叠加!
| 文件系统 | 通俗解释 | Docker 使用情况 |
|---|---|---|
| overlayfs | 叠加文件系统 | ✅ 推荐 |
| aufs | 高级多层统一文件系统 | 早期 Docker 使用 |
| btrfs | B树文件系统 | 部分使用 |
| devicemapper | 设备映射 | 早期版本 |
容器的读写机制
读取文件:
容器层没有 → 镜像层有 → 读取成功
修改文件(Copy-On-Write):
容器层没有 → 复制到容器层 → 修改容器层
删除文件:
在容器层添加"删除标记" → 文件在容器层不可见
(实际文件仍在镜像层,只是被遮盖了)
daemon.json 配置
什么是 daemon.json?
想象一下:你开了一家餐厅,需要在开业前配置好各种事项:
- 食材从哪进货(镜像仓库)
- 厨房多大(存储驱动)
- 垃圾怎么处理(日志)
daemon.json 就是 Docker 的"开业前配置手册"! 告诉 Docker 守护进程怎么工作。
daemon.json 位置
# 默认位置
/etc/docker/daemon.json
常用配置项
{
"registry-mirrors": [
"https://registry.docker-cn.com",
"https://mirror.ccs.tencentyun.com"
],
"insecure-registries": [
"192.168.1.100:5000"
],
"storage-driver": "overlayfs",
"log-driver": "json-file",
"log-opts": {
"max-size": "100m",
"max-file": "3"
},
"data-root": "/data/docker",
"live-restore": true,
"default-ulimits": {
"nofile": {
"Name": "nofile",
"Hard": 64000,
"Soft": 64000
}
},
"dns": ["8.8.8.8", "8.8.4.4"],
"mtu": 1500
}
配置项详解
1. registry-mirrors(镜像加速器)
通俗解释:
就像你从国外进口食材太慢了,在中国设立"中转仓库",从国内拿货就快了!
{
"registry-mirrors": [
"https://registry.docker-cn.com"
]
}
常用加速器:
- 阿里云:需要登录获取专属地址
- 腾讯云:需要登录获取专属地址
- Docker 中国:
https://registry.docker-cn.com
2. insecure-registries(不安全仓库)
通俗解释:
有些仓库没有"正规营业执照"(没有 HTTPS),需要单独声明才能使用。
{
"insecure-registries": [
"192.168.1.100:5000",
"registry.mycompany.com:5000"
]
}
3. storage-driver(存储驱动)
通俗解释:
就像餐厅用不同的货架管理系统,Docker 用不同的存储驱动管理文件。
{
"storage-driver": "overlayfs"
}
推荐选择:
- overlayfs:性能好,推荐使用
- btrfs:支持完整快照功能
- zfs:功能强大,占用资源多
4. log-driver(日志驱动)
通俗解释:
就像餐厅的"收银记录系统",记录每个顾客的点单。
{
"log-driver": "json-file",
"log-opts": {
"max-size": "100m", // 单个日志文件最大 100MB
"max-file": "3" // 最多保留 3 个日志文件
}
}
日志总大小 = 100MB × 3 = 300MB
5. data-root(数据存储路径)
通俗解释:
餐厅的"仓库"在哪,默认是 /var/lib/docker。
{
"data-root": "/data/docker"
}
适合场景:
- 系统盘空间不足
- 需要挂载更大的数据盘
6. live-restore(热恢复)
通俗解释:
餐厅的"值班经理"。即使老板(Docker daemon)暂时离开去开会,餐厅(容器)也能继续营业。
{
"live-restore": true
}
| 值 | 行为 |
|---|---|
| true | daemon 重启时,容器继续运行 |
| false | daemon 重启时,容器也重启 |
7. default-ulimits(默认资源限制)
通俗解释:
给每个厨师(容器)分配固定的工作台面积(文件描述符数量)。
{
"default-ulimits": {
"nofile": {
"Name": "nofile",
"Hard": 64000,
"Soft": 64000
}
}
}
8. dns(DNS 服务器)
{
"dns": ["8.8.8.8", "114.114.114.114"]
}
配置生效
# 1. 编辑配置文件
sudo vim /etc/docker/daemon.json
# 2. 重启 Docker
sudo systemctl restart docker
# 3. 验证配置
docker info | grep -A 5 "Registry Mirrors"
完整配置示例
{
"registry-mirrors": [
"https://registry.docker-cn.com"
],
"insecure-registries": [],
"storage-driver": "overlayfs",
"log-driver": "json-file",
"log-opts": {
"max-size": "100m",
"max-file": "3"
},
"live-restore": true,
"default-ulimits": {
"nofile": {
"Name": "nofile",
"Hard": 65535,
"Soft": 65535
}
},
"dns": ["8.8.8.8", "114.114.114.114"],
"experimental": false,
"features": {
"buildkit": true
}
}
Docker 配置验证
# 👀 查看当前 daemon 配置
docker info 2>&1 | head -50
# 👀 验证 daemon.json 语法
python3 -m json.tool /etc/docker/daemon.json
# 👀 查看 Docker 数据目录
docker info | grep "Docker Root Dir"
常用命令
镜像操作
# 👀 查看本地镜像
docker images
# 👀 搜索镜像
docker search nginx
# ➕ 拉取镜像
docker pull nginx:latest
# 🗑️ 删除镜像
docker rmi nginx:latest
# ➕ 构建镜像
docker build -t myapp:1.0 .
容器操作
# 👀 查看容器
docker ps # 运行中的
docker ps -a # 所有容器
# ➕ 运行容器
docker run -d --name myapp -p 8080:80 nginx
# ✏️ 停止/启动容器
docker stop myapp
docker start myapp
# 🗑️ 删除容器
docker rm myapp
docker rm -f myapp # 强制删除(运行中)
# 👀 查看容器日志
docker logs myapp
docker logs -f myapp # 实时跟踪
# 👀 进入容器
docker exec -it myapp bash
# 👀 查看容器信息
docker inspect myapp
# 👀 查看容器资源使用
docker stats myapp
docker-compose 操作
# ➕ 启动服务
docker-compose up -d
# 🗑️ 停止服务
docker-compose down
# 🔄 重启服务
docker-compose restart
# 👀 查看服务状态
docker-compose ps
# 📊 查看日志
docker-compose logs -f
网络操作
# 👀 查看网络
docker network ls
# ➕ 创建网络
docker network create mynetwork
# ➕ 连接容器到网络
docker network connect mynetwork myapp
# 🗑️ 删除网络
docker network rm mynetwork
清理操作
# 🗑️ 删除未使用的镜像
docker image prune -a
# 🗑️ 删除停止的容器
docker container prune
# 🗑️ 删除未使用的网络
docker network prune
# 🗑️ 删除未使用的卷
docker volume prune
# 🗑️ 清理所有未使用资源
docker system prune
Docker Swarm 集群
什么是 Docker Swarm?
通俗解释:
想象一下:一家餐厅太忙了,一个厨师忙不过来怎么办?
答案是:组建厨师团队!
- 一个主厨(Manager)负责分配任务
- 其他厨师(Worker)负责做菜
- 主厨挂了?没关系,选举新的主厨
Docker Swarm 就是这个"厨师团队"! 它让多个 Docker 主机协同工作,自动分配任务,自动故障切换。
Swarm 架构
┌─────────────────────────────────────────────────────────┐
│ Docker Swarm Cluster │
│ │
│ ┌─────────────────────────────────┐ │
│ │ Manager Nodes (主节点) │ │
│ │ (负责: 调度、API、故障切换) │ │
│ └─────────────────────────────────┘ │
│ │ │
│ ┌──────────────────────┼──────────────────────┐ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌────────┐ ┌────────┐ ┌────────┐ │
│ │ Worker │ │ Worker │ │ Worker │ │
│ │ 节点1 │ │ 节点2 │ │ 节点3 │ │
│ │(执行任务)│ │(执行任务)│ │(执行任务)│ │
│ └────────┘ └────────┘ └────────┘ │
└─────────────────────────────────────────────────────────┘
Swarm 核心概念
| 概念 | 通俗解释 |
|---|---|
| Node(节点) | 餐厅里的一个厨师 |
| Manager(管理器) | 主厨,负责分配任务 |
| Worker(工作者) | 普通厨师,负责执行任务 |
| Service(服务) | 就像"菜谱",定义怎么制作这道菜 |
| Task(任务) | 分配给厨师的具体工作 |
| Stack(堆栈) | 一整套菜谱(多个服务) |
初始化 Swarm
# 👀 初始化 Swarm(成为主节点)
docker swarm init
# 👀 查看 Swarm 状态
docker info | grep Swarm
# 👀 查看节点列表
docker node ls
添加节点到 Swarm
# 👀 在主节点生成加入令牌
docker swarm join-token worker
# 输出示例:
# docker swarm join --token SWMTKN-xxxxx 192.168.1.10:2377
# 👀 在其他服务器执行上面的命令加入集群
部署服务
# ➕ 部署服务(就像派一个厨师去做一道菜)
docker service create --name myapp --replicas 3 -p 8080:80 nginx
# 👀 查看服务列表
docker service ls
# 👀 查看服务详情
docker service ps myapp
# 👀 查看服务日志
docker service logs myapp
# ✏️ 更新服务(滚动更新)
docker service update --image nginx:1.19 myapp
# 🗑️ 删除服务
docker service rm myapp
服务扩缩容
# ⚙️ 扩容(增加厨师数量)
docker service scale myapp=5
# ⚙️ 缩容(减少厨师数量)
docker service scale myapp=2
Docker Stack(多服务部署)
使用 docker-compose.yml 部署多服务:
# docker-compose.yml
version: '3.8'
services:
web:
image: nginx
ports:
- "80:80"
deploy:
replicas: 3
placement:
constraints:
- node.role == worker
api:
image: myapi:latest
ports:
- "8080:8080"
deploy:
replicas: 2
networks:
frontend:
volumes:
data:
# ➕ 部署 Stack
docker stack deploy -c docker-compose.yml myapp
# 👀 查看 Stack 列表
docker stack ls
# 👀 查看 Stack 中的服务
docker stack ps myapp
# 🗑️ 删除 Stack
docker stack rm myapp
Swarm 常用命令
# 👀 查看节点
docker node ls
# 👀 查看服务
docker service ls
# 👀 查看 Stack
docker stack ls
# 👀 查看密钥
docker secret ls
# 👀 查看配置
docker config ls
# ⚙️ 创建密钥
echo "mypassword" | docker secret create db_password -
# ⚙️ 创建配置
docker config create nginx_config nginx.conf
Swarm 高可用
# 👀 查看主节点信息
docker node inspect self
# ⚙️ 提升节点为主节点
docker node promote node2
# ⚙️ 降级节点为工作节点
docker node demote node2
Docker 底层原理
Docker 架构
┌─────────────────────────────────────────────────────────┐
│ Docker Client │
│ (命令行工具 docker) │
└─────────────────────────┬───────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ Docker Daemon │
│ (Docker 守护进程) │
│ ┌───────────────┬───────────────┬───────────────┐ │
│ │ containerd │ Builder │ Network │ │
│ │ (容器运行时) │ (镜像构建) │ (网络管理) │ │
│ └───────────────┴───────────────┴───────────────┘ │
└─────────────────────────┬───────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ runc │
│ (容器运行时) │
└─────────────────────────┬───────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ Linux Kernel │
│ (Linux 内核) │
└─────────────────────────────────────────────────────────┘
组件详解
| 组件 | 通俗解释 | 类比 |
|---|---|---|
| Docker Client | 命令行工具 | 餐厅的"前台接待" |
| Docker Daemon | 后台守护进程 | 餐厅的"经理" |
| containerd | 容器运行时 | 厨房的"调度员" |
| runc | 容器启动器 | 厨房的"灶台" |
| Docker Registry | 镜像仓库 | 餐厅的"食材库" |
用户态 vs 内核态
什么是用户态和内核态?
想象一家医院:
- 内核态 = 院长办公室,掌握医院所有资源(CPU、内存、磁盘)
- 用户态 = 普通医生的诊室,不能直接访问手术室、药房
用户态的程序想用资源,必须通过系统调用请求内核帮忙。
┌─────────────────────────────────────────┐
│ 用户空间 (User Space) │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Docker │ │ App │ │ Shell │ │
│ │ Client │ │ Process │ │ Process │ │
│ └────┬────┘ └────┬────┘ └────┬────┘ │
│ │ │ │ │
└───────┼────────────┼────────────┼───────┘
│ │ │
▼ ▼ ▼
┌─────────────────────────────────────────┐
│ 系统调用接口 │
│ (System Call Interface) │
└─────────────────────┬───────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ 内核空间 (Kernel Space) │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Process │ │ Memory │ │ File │ │
│ │Manager │ │Manager │ │ System │ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Network │ │ I/O │ │ Device │ │
│ │ Stack │ │Manager │ │ Drivers │ │
│ └─────────┘ └─────────┘ └─────────┘ │
└─────────────────────────────────────────┘
用户态的特点:
- 普通应用程序运行在这里
- 不能直接访问硬件
- 不能访问其他程序的内存
- 必须通过系统调用请求内核帮忙
内核态的特点:
- 操作系统内核运行在这里
- 可以直接访问所有硬件
- 可以访问所有内存
- 拥有最高权限
Docker 的位置:
┌─────────────────────────────────────────┐
│ 用户空间 │
│ ┌─────────────────────────────────┐ │
│ │ Docker Client + Daemon │ │
│ └─────────────────────────────────┘ │
└─────────────────────────────────────────┘
│ (通过系统调用和内核交互)
▼
┌─────────────────────────────────────────┐
│ 内核空间 │
│ ┌─────────────────────────────────┐ │
│ │ Namespaces | Cgroups | Overlay │ │
│ └─────────────────────────────────┘ │
└─────────────────────────────────────────┘
Namespace(命名空间)
什么是 Namespace?
想象一下:一家酒店有很多房间(Namespace)。
- 每个房间的人以为自己住的是"整栋楼"
- 房间 A 的"301号"和房间 B 的"301号"是不同的人
- 每个房间有独立的电视、空调、电话
Namespace 就是 Docker 的"隔离房间"! 每个容器以为自己是"整台服务器"。
六种 Namespace
| Namespace | 作用 | 通俗解释 |
|---|---|---|
| PID | 进程隔离 | 每个容器从 PID 1 开始 |
| NET | 网络隔离 | 每个容器有自己的 IP 地址 |
| IPC | 进程通信隔离 | 容器间不能互相通信 |
| MNT | 挂载隔离 | 每个容器有自己的文件系统 |
| UTS | 主机名隔离 | 每个容器有自己的 hostname |
| USER | 用户隔离 | 容器内的 root 相当于宿主机的普通用户 |
查看容器的 Namespace
# 👀 查看运行中容器的 PID
docker inspect --format '{{.State.Pid}}' myapp
# 👀 查看该进程的所有 Namespace
ls -la /proc/$(docker inspect --format '{{.State.Pid}}' myapp)/ns/
输出示例:
total 0
lrwxrwxrwx 1 root root 0 Jun 2 12:00 cgroup -> /proc/12345/ns/cgroup
lrwxrwxrwx 1 root root 0 Jun 2 12:00 ipc -> /proc/12345/ns/ipc
lrwxrwxrwx 1 root root 0 Jun 2 12:00 mnt -> /proc/12345/ns/mnt
lrwxrwxrwx 1 root root 0 Jun 2 12:00 net -> /proc/12345/ns/net
lrwxrwxrwx 1 root root 0 Jun 2 12:00 pid -> /proc/12345/ns/pid
lrwxrwxrwx 1 root root 0 Jun 2 12:00 user -> /proc/12345/ns/user
lrwxrwxrwx 1 root root 0 Jun 2 12:00 uts -> /proc/12345/ns/uts
Cgroups(控制组)
什么是 Cgroups?
想象一下:公司财务给每个部门分配预算:
- 研发部:最多用 100 万
- 销售部:最多用 50 万
- 市场部:最多用 30 万
每个部门只能在自己的预算内花钱,不能多用!
Cgroups 就是 Docker 的"预算管理"! 它限制每个容器使用的资源(CPU、内存、磁盘 I/O)。
Cgroups 版本
Cgroup Driver: systemd
Cgroup Version: 2
| 版本 | 通俗解释 |
|---|---|
| v1 | 早期版本,每个资源类型独立 hierarchy |
| v2 | 统一 hierarchy,性能更好 |
Cgroups 资源限制
# 👀 查看容器的 Cgroup 信息
docker inspect myapp | grep -i cgroup
# 查看 CPU Cgroup
cat /sys/fs/cgroup/cpu/docker/<container-id>/cpu.cfs_quota_us
# 查看内存 Cgroup
cat /sys/fs/cgroup/memory/docker/<container-id>/memory.limit_in_bytes
常用资源限制
# ⚙️ 限制内存
docker run -d --name myapp --memory=512m nginx
# ⚙️ 限制 CPU
docker run -d --name myapp --cpus=1.5 nginx
# ⚙️ 限制 CPU 核数
docker run -d --name myapp --cpuset-cpus=0,1 nginx
# ⚙️ 限制 IO
docker run -d --name myapp --device-write-iops=/dev/sda:100 nginx
OverlayFS(叠加文件系统)
什么是 OverlayFS?
想象一下:你有两张透明塑料纸:
- 底层纸:画了一个完整的圆
- 顶层纸:画了一个三角形
叠加在一起,你看到的就是:圆上有个三角形!
OverlayFS 就是 Docker 的"叠加魔法"! 它把多个目录叠加成一个。
OverlayFS 结构
┌─────────────────────────────────────────┐
│ 容器层 (Container Layer) │
│ (writable, 写入的文件) │
└─────────────────┬───────────────────────┘
│
┌─────────────────┴───────────────────────┐
│ 镜像层 (Image Layer) │
│ (lowerdir, 只读的镜像层) │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Layer 3 │ │ Layer 2 │ │ Layer 1 │ │
│ └─────────┘ └─────────┘ └─────────┘ │
└─────────────────────────────────────────┘
查看 OverlayFS 信息
# 👀 查看容器使用的文件系统
docker inspect myapp | grep -A 10 "GraphDriver"
# 输出示例:
# "GraphDriver": {
# "Name": "overlayfs",
# "Data": {
# "LowerDir": "/var/lib/docker/overlay2/xxx/diff",
# "UpperDir": "/var/lib/docker/overlay2/xxx/diff",
# "MergedDir": "/var/lib/docker/overlay2/xxx/merged"
# }
# }
systemd 与 Docker
什么是 systemd?
systemd 是 Linux 系统的"总管家",负责:
- 启动/停止服务
- 管理进程
- 记录日志
Docker 作为系统服务,由 systemd 管理。
systemd 管理 Docker
# 👀 查看 Docker 服务状态
sudo systemctl status docker
# ⚙️ 启动 Docker
sudo systemctl start docker
# ⚙️ 停止 Docker
sudo systemctl stop docker
# ⚙️ 重启 Docker
sudo systemctl restart docker
# ⚙️ 设置开机启动
sudo systemctl enable docker
# ⚙️ 禁止开机启动
sudo systemctl disable docker
# 👀 查看 Docker 日志
sudo journalctl -u docker -f
Docker 服务文件
# 👀 查看 Docker 服务文件
cat /lib/systemd/system/docker.service
服务文件示例:
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network-online.target firewalld.service containerd.service
Wants=network-online.target
[Service]
Type=notify
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
ExecReload=/bin/kill -s HUP $MAINPID
TimeoutSec=0
RestartSec=2
Restart=on-failure
[Install]
WantedBy=multi-user.target
字段解释:
| 字段 | 通俗解释 |
|---|---|
| Description | 服务描述 |
| After | 依赖的其他服务 |
| ExecStart | 启动命令 |
| Restart | 失败重启策略 |
| WantedBy | 开机启动级别 |
容器启动流程
用户输入命令
│
▼
┌─────────────────┐
│ docker run │
│ (Docker Client) │
└────────┬────────┘
│
│ API 调用
▼
┌─────────────────┐
│ dockerd │
│ (Docker Daemon) │
└────────┬────────┘
│
│ 创建容器
▼
┌─────────────────┐
│ containerd │
│ (容器运行时) │
└────────┬────────┘
│
│ 创建容器
▼
┌─────────────────┐
│ runc │
│ (启动容器) │
└────────┬────────┘
│
│ 系统调用
▼
┌─────────────────┐
│ Linux Kernel │
│ 创建 Namespace │
│ 设置 Cgroups │
│ 启动进程 │
└─────────────────┘
运维监控
监控命令
# 👀 查看容器资源使用
docker stats
# 👀 查看所有容器(包含停止的)
docker ps -a
# 👀 查看镜像
docker images
# 👀 查看磁盘使用
docker system df
# 👀 查看 Docker 磁盘使用详情
docker system df -v
监控脚本
#!/bin/bash
echo "=========================================="
echo " Docker 监控报告"
echo "=========================================="
echo "时间: $(date)"
echo ""
echo "📊 【容器状态】"
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
echo ""
echo "💾 【资源使用】"
docker stats --no-stream --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}"
echo ""
echo "💾 【磁盘使用】"
docker system df
echo "=========================================="
常见问题排查
问题 1:容器无法启动
现象: docker run 失败
排查步骤:
# 👀 查看 Docker 服务状态
sudo systemctl status docker
# 👀 查看 Docker 日志
sudo journalctl -u docker -f
# 👀 检查磁盘空间
df -h
# 👀 检查容器日志
docker logs myapp
解决方案:
- 重启 Docker
sudo systemctl restart docker
- 清理未使用的资源
docker system prune -a
问题 2:容器网络不通
现象: 容器无法访问外部网络
排查步骤:
# 👀 查看网络
docker network ls
# 👀 查看容器网络详情
docker inspect myapp | grep -A 20 "Networks"
# 👀 测试网络连通性
docker exec myapp ping google.com
解决方案:
- 创建新的网络
docker network create mynetwork
docker network connect mynetwork myapp
- 重启容器
docker restart myapp
问题 3:磁盘空间不足
现象: 无法创建容器或拉取镜像
排查步骤:
# 👀 查看磁盘使用
df -h
# 👀 查看 Docker 磁盘使用
docker system df
解决方案:
- 清理未使用的资源
docker system prune -a
- 清理镜像
docker image prune -a
- 清理卷
docker volume prune
问题 4:Swarm 节点不可用
现象: docker node ls 显示节点为 Down
排查步骤:
# 👀 查看节点状态
docker node ls
# 👀 查看节点详情
docker node inspect node2
解决方案:
- 检查节点网络
- 重启 Docker 服务
- 重新加入集群
# 在故障节点执行
docker swarm leave --force
docker swarm join --token xxx manager-ip:2377
总结
核心概念
| 概念 | 通俗解释 |
|---|---|
| 镜像 | 菜谱 |
| 容器 | 做好的菜 |
| Namespace | 隔离房间 |
| Cgroups | 资源预算 |
| OverlayFS | 叠加魔法 |
| Swarm | 厨师团队 |
运维黄金法则
- 监控资源使用 - 别让容器撑爆了
- 设置资源限制 - 给容器分配合理的预算
- 定期清理 - 删除不需要的镜像和容器
- 使用 Swarm - 生产环境必须用集群
- 查看日志 - 出问题先看日志
最后一句话总结:
Docker 就是"集装箱标准化",让应用部署变得简单。但背后是复杂的内核机制(Namespace、Cgroups、OverlayFS),理解这些才能更好地运维!
持续更新中… 如有问题或建议,欢迎交流讨论!