我和Docker的5年:从”这是什么鬼”到”离不开它”的进化之路

# 我和Docker的5年:从”这是什么鬼”到”离不开它”的进化之路

> **从排斥Docker到成为Docker布道师的真实经历**
>
> **

直到2021年,我遇到了Docker。

## 我的故事:第一次听说Docker

**时间**:2021年6月的一个下午
**地点**:北京某互联网公司会议室

项目经理走过来,说:”小陈,这个项目要用Docker部署。”

我的第一反应:”Docker?那是什么鬼?为什么要用这么复杂的东西?”

那时候的我,觉得Docker是多余的:
– “我直接在服务器上装环境不就行了?”
– “虚拟机也可以解决隔离问题啊?”
– “学新工具太麻烦了…”

**直到那一天…**

我们公司接了一个大项目,需要在3个月内开发10个微服务。

**传统的做法**:
1. 每个服务独立部署
2. 手动配置环境
3. 处理依赖冲突
4. 花费大量时间在环境配置上

**结果**:前2个月都在配置环境,只有1个月在写代码…

项目经理说:”必须用Docker。”

我被迫开始学习Docker。

**3个月后,我的想法完全改变了。**

## 第一部分:Docker到底是什么?(小白也能懂的版本)

### 我踩过的第一个坑

**我的错误理解**:
– “Docker就是虚拟机?”
– “Docker会让应用变慢?”
– “Docker配置太复杂了?”

**真相**:

#### Docker vs 虚拟机

“`
传统虚拟机:
应用 → 操作系统 → Hypervisor → 硬件
(每个虚拟机都有完整的操作系统,占用大量资源)

Docker容器:
应用 → Docker引擎 → 操作系统 → 硬件
(容器共享操作系统内核,轻量级)
“`

**真实案例**:

**场景**:我们需要运行10个Node.js应用

**传统虚拟机方案**:
– 每个虚拟机:2GB内存
– 总内存需求:10 × 2GB = 20GB
– 启动时间:每个虚拟机1-2分钟
– 总启动时间:10-20分钟

**Docker容器方案**:
– 每个容器:100MB内存
– 总内存需求:10 × 100MB = 1GB
– 启动时间:每个容器1-2秒
– 总启动时间:10-20秒

**效果对比**:
– 内存节省:95%(20GB → 1GB)
– 启动速度:提升60倍(20分钟 → 20秒)

### Docker的三大核心概念

#### 1. 镜像(Image)- 应用的”模板”

**比喻**:镜像就像是一个”蛋糕模具”
– 你可以制作无数个相同的”蛋糕”(容器)
– 每个蛋糕都一模一样
– 修改模具不会影响已经做好的蛋糕

**真实案例**:

我们团队的Node.js应用镜像:

“`dockerfile
FROM node:18-alpine

WORKDIR /app

COPY package*.json ./
RUN npm ci –only=production

COPY . .

EXPOSE 3000

CMD [“node”, “server.js”]
“`

**这个镜像的好处**:
1. **轻量级**:使用alpine版本,只有50MB
2. **一致性**:所有环境都使用同一个镜像
3. **可复现**:任何时候都能创建相同的容器

#### 2. 容器(Container)- 运行的应用实例

**比喻**:容器就是用”模具”(镜像)做出来的”蛋糕”

**真实案例**:

“`bash
# 创建并运行容器
docker run -d
–name my-app
-p 3000:3000
-e NODE_ENV=production
my-app:1.0.0

# 查看运行中的容器
docker ps

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

# 进入容器内部
docker exec -it my-app sh
“`

#### 3. 仓库(Registry)- 镜像的”仓库”

**比喻**:就像GitHub是代码的仓库,Docker Registry是镜像的仓库

**常用仓库**:
– Docker Hub(官方)
– 阿里云容器镜像服务
– 腾讯云容器镜像服务

## 第二部分:Docker常用命令实战

### 我总结的20个最常用命令

#### 镜像操作(5个命令)

**1. 搜索镜像**

“`bash
# 搜索Node.js镜像
docker search node

# 搜索官方镜像
docker search node –filter is-official=true
“`

**我的经验**:
– 优先选择官方镜像(OFFICIAL)
– 查看Stars数量(受欢迎程度)
– 选择alpine版本(体积小)

**真实案例**:
“`bash
# 错误选择
node:latest # 1GB+
node:18 # 900MB

# 正确选择
node:18-alpine # 120MB(节省87%空间)
“`

**2. 拉取镜像**

“`bash
# 拉取最新版本
docker pull node:18-alpine

# 拉取指定版本
docker pull node:18.17.0-alpine

# 拉取所有架构版本
docker pull –platform linux/amd64,linux/arm64 node:18-alpine
“`

**3. 查看本地镜像**

“`bash
# 列出所有镜像
docker images

# 查看镜像详细信息
docker inspect node:18-alpine

# 查看镜像历史层
docker history node:18-alpine
“`

**真实案例**:

我们项目中有100个镜像,用这个命令找出占用空间最大的镜像:

“`bash
# 按大小排序显示镜像
docker images –format “table {{.Repository}}t{{.Tag}}t{{.Size}}” |
sort -k3 -h |
head -20
“`

**发现问题**:
– python:3.9(1GB)→ 改用python:3.9-alpine(50MB)
– nginx:latest(133MB)→ 改用nginx:alpine(40MB)
– node:18(900MB)→ 改用node:18-alpine(120MB)

**结果**:总镜像大小从50GB降到5GB(节省90%)

**4. 删除镜像**

“`bash
# 删除单个镜像
docker rmi node:18-alpine

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

# 删除所有悬空镜像
docker image prune

# 强制删除所有镜像
docker rmi $(docker images -q)
“`

**我的教训**:

❌ **错误操作**:
“`bash
# 我曾经误删了生产环境的镜像
docker rmi $(docker images -q)

# 导致所有服务无法启动
# 花了2个小时重新拉取镜像
“`

✅ **正确做法**:
“`bash
# 只删除悬空镜像(dangling images)
docker image prune

# 或者明确指定要删除的镜像
docker rmi $(docker images | grep “” | awk “{print $3}”)
“`

**5. 构建镜像**

“`bash
# 基础构建
docker build -t myapp:1.0.0 .

# 指定Dockerfile
docker build -f Dockerfile.prod -t myapp:1.0.0 .

# 不使用缓存
docker build –no-cache -t myapp:1.0.0 .

# 多阶段构建
docker build –target builder -t myapp:builder .
“`

**真实案例:多阶段构建优化**

**优化前**(1.2GB):
“`dockerfile
FROM node:18

WORKDIR /app

COPY package*.json ./
RUN npm install

COPY . .
RUN npm run build

EXPOSE 3000

CMD [“node”, “server.js”]
“`

**问题**:
– 包含开发依赖(devDependencies)
– 包含构建工具
– 镜像体积大

**优化后**(150MB):
“`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 package*.json ./
RUN npm ci –only=production

COPY –from=builder /app/dist ./dist

EXPOSE 3000

CMD [“node”, “server.js”]
“`

**效果**:
– 镜像大小:1.2GB → 150MB(-87.5%)
– 拉取时间:10分钟 → 1分钟(-90%)
– 部署速度:显著提升

#### 容器操作(10个命令)

**6. 运行容器**

“`bash
# 基础运行
docker run -d nginx:alpine

# 指定名称
docker run -d –name my-nginx nginx:alpine

# 端口映射
docker run -d -p 8080:80 nginx:alpine

# 挂载卷
docker run -d -v /host/path:/container/path nginx:alpine

# 环境变量
docker run -d -e NODE_ENV=production node:18-alpine

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

# 进入容器
docker exec -it my-nginx sh
“`

**真实案例:一键启动开发环境**

“`bash
# 启动完整的开发环境
docker run -d
–name mysql
-e MYSQL_ROOT_PASSWORD=secret
-e MYSQL_DATABASE=myapp
-v mysql-data:/var/lib/mysql
-p 3306:3306
mysql:8.0

docker run -d
–name redis
-v redis-data:/data
-p 6379:6379
redis:alpine

docker run -d
–name myapp
–link mysql:mysql
–link redis:redis
-p 3000:3000
-e DB_HOST=mysql
-e REDIS_HOST=redis
myapp:1.0.0
“`

**效果**:
– 5分钟启动完整环境
– 所有服务隔离运行
– 数据持久化保存

**7. 查看容器**

“`bash
# 查看运行中的容器
docker ps

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

# 查看容器详细信息
docker inspect my-nginx

# 查看容器资源使用
docker stats my-nginx

# 查看容器进程
docker top my-nginx
“`

**真实案例:性能排查**

“`bash
# 查看所有容器的资源使用
docker stats –no-stream

# 输出示例:
CONTAINER CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O
mysql 5.50% 512MiB / 8GiB 6.25% 1.2GB / 3GB 50MB / 200MB
redis 1.20% 64MiB / 8GiB 0.78% 800MB / 1GB 10MB / 50MB
myapp 15.8% 512MiB / 8GiB 6.25% 2GB / 1.5GB 100MB / 500MB
“`

**发现问题**:
– myapp占用CPU过高(15.8%)
– 内存使用正常
– 网络I/O较高

**优化措施**:
– 增加容器数量(水平扩展)
– 优化代码(减少CPU使用)
– 使用cgroup限制资源

**8. 停止和重启容器**

“`bash
# 停止容器
docker stop my-nginx

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

# 重启容器
docker restart my-nginx

# 强制停止
docker kill my-nginx

# 暂停容器
docker pause my-nginx

# 恢复暂停的容器
docker unpause my-nginx
“`

**真实案例:优雅停机**

“`bash
# 错误做法:直接kill
docker kill myapp
# 问题:正在处理的请求被中断,数据可能丢失

# 正确做法:优雅停机
docker stop myapp
# 发送SIGTERM信号,让应用优雅关闭
# 等待10秒后强制停止
“`

**在应用中处理SIGTERM**:

“`javascript
// Node.js示例
process.on(‘SIGTERM’, () => {
console.log(‘Received SIGTERM, closing gracefully…’);

// 停止接受新请求
server.close(() => {
console.log(‘Closed all connections’);
process.exit(0);
});

// 10秒后强制退出
setTimeout(() => {
console.log(‘Forcing exit…’);
process.exit(1);
}, 10000);
});
“`

**9. 删除容器**

“`bash
# 删除单个容器
docker rm my-nginx

# 删除运行中的容器(需要先停止)
docker rm -f my-nginx

# 删除所有停止的容器
docker container prune

# 删除所有容器(包括运行中的)
docker rm -f $(docker ps -aq)
“`

**我的教训**:

❌ **错误操作**:
“`bash
# 误删了所有容器,包括生产环境
docker rm -f $(docker ps -aq)

# 导致服务中断,用户无法访问
# 花了1小时恢复服务
“`

✅ **正确做法**:
“`bash
# 只删除停止的容器
docker container prune

# 或者在删除前确认
docker ps -a # 先查看
docker rm # 明确指定要删除的容器
“`

**10. 容器日志管理**

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

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

# 查看最后100行
docker logs –tail 100 my-nginx

# 查看最近10分钟的日志
docker logs –since 10m my-nginx

# 显示时间戳
docker logs -t my-nginx
“`

**真实案例:日志分析**

“`bash
# 查找错误日志
docker logs myapp 2>&1 | grep -i error

# 统计错误数量
docker logs myapp 2>&1 | grep -i error | wc -l

# 查看最近的错误
docker logs –tail 1000 myapp 2>&1 | grep -i error | tail -20

# 导出日志到文件
docker logs myapp > myapp.log 2>&1
“`

**优化建议**:

“`bash
# 限制日志文件大小
docker run -d
–log-opt max-size=10m
–log-opt max-file=3
myapp:1.0.0

# 配置日志驱动
docker run -d
–log-driver json-file
–log-opt max-size=10m
–log-opt max-file=3
myapp:1.0.0
“`

#### 网络操作(3个命令)

**11. 查看网络**

“`bash
# 列出所有网络
docker network ls

# 查看网络详细信息
docker network inspect bridge

# 查看容器连接的网络
docker inspect my-nginx | grep -A 20 “Networks”
“`

**12. 创建网络**

“`bash
# 创建bridge网络
docker network create my-network

# 创建overlay网络(用于Swarm)
docker network create –driver overlay my-overlay-network

# 指定子网
docker network create
–subnet=192.168.0.0/16
–gateway=192.168.0.1
my-network
“`

**真实案例:微服务网络隔离**

“`bash
# 创建前端网络
docker network create frontend-network

# 创建后端网络
docker network create backend-network

# 创建数据库网络
docker network create database-network

# 启动前端容器(连接到frontend和backend)
docker run -d
–name frontend
–network frontend-network
myapp-frontend:1.0.0

# 启动后端容器(连接到backend和database)
docker run -d
–name backend
–network backend-network
myapp-backend:1.0.0

# 启动数据库容器(只连接到database)
docker run -d
–name mysql
–network database-network
mysql:8.0

# 连接容器到多个网络
docker network connect backend-network frontend
docker network connect database-network backend
“`

**效果**:
– 前端不能直接访问数据库(安全)
– 后端可以访问数据库
– 网络隔离,安全可控

**13. 网络连接和断开**

“`bash
# 连接容器到网络
docker network connect my-network my-nginx

# 断开容器网络
docker network disconnect my-network my-nginx

# 删除网络
docker network rm my-network
“`

#### 存储操作(2个命令)

**14. 查看卷**

“`bash
# 列出所有卷
docker volume ls

# 查看卷详细信息
docker volume inspect my-volume

# 查看未使用的卷
docker volume ls -f dangling=true
“`

**15. 创建和管理卷**

“`bash
# 创建卷
docker volume create my-volume

# 删除未使用的卷
docker volume prune

# 删除指定卷
docker volume rm my-volume

# 使用卷
docker run -d
-v my-volume:/data
nginx:alpine
“`

**真实案例:数据库数据持久化**

“`bash
# 创建数据卷
docker volume create mysql-data

# 启动MySQL,使用持久化卷
docker run -d
–name mysql
-e MYSQL_ROOT_PASSWORD=secret
-v mysql-data:/var/lib/mysql
-p 3306:3306
mysql:8.0

# 即使删除容器,数据仍然保留
docker rm -f mysql

# 重新启动,数据还在
docker run -d
–name mysql
-e MYSQL_ROOT_PASSWORD=secret
-v mysql-data:/var/lib/mysql
-p 3306:3306
mysql:8.0
“`

## 第三部分:Docker Compose – 多容器编排神器

### 我的Docker Compose进化史

**第一阶段:手动启动每个容器**

“`bash
# 启动MySQL
docker run -d –name mysql
-e MYSQL_ROOT_PASSWORD=secret
-e MYSQL_DATABASE=myapp
-v mysql-data:/var/lib/mysql
-p 3306:3306
mysql:8.0

# 启动Redis
docker run -d –name redis
-v redis-data:/data
-p 6379:6379
redis:alpine

# 启动应用
docker run -d –name myapp
–link mysql:mysql
–link redis:redis
-p 3000:3000
-e DB_HOST=mysql
-e REDIS_HOST=redis
myapp:1.0.0
“`

**问题**:
– 命令太长,容易出错
– 无法统一管理
– 启动顺序容易出错

**第二阶段:使用Docker Compose**

“`yaml
# docker-compose.yml
version: ‘3.8’

services:
mysql:
image: mysql:8.0
container_name: mysql
environment:
MYSQL_ROOT_PASSWORD: secret
MYSQL_DATABASE: myapp
volumes:
– mysql-data:/var/lib/mysql
ports:
– “3306:3306”
networks:
– backend

redis:
image: redis:alpine
container_name: redis
volumes:
– redis-data:/data
ports:
– “6379:6379”
networks:
– backend

myapp:
image: myapp:1.0.0
container_name: myapp
ports:
– “3000:3000”
environment:
DB_HOST: mysql
REDIS_HOST: redis
depends_on:
– mysql
– redis
networks:
– backend
– frontend

volumes:
mysql-data:
redis-data:

networks:
backend:
frontend:
“`

**一键启动**:
“`bash
# 启动所有服务
docker-compose up -d

# 查看服务状态
docker-compose ps

# 查看日志
docker-compose logs -f

# 停止所有服务
docker-compose down

# 停止并删除卷
docker-compose down -v
“`

**效果**:
– ✅ 命令简洁
– ✅ 统一管理
– ✅ 启动顺序正确
– ✅ 易于维护

### Docker Compose高级技巧

**1. 环境变量覆盖**

“`yaml
# docker-compose.yml
version: ‘3.8’

services:
myapp:
image: myapp:1.0.0
environment:
– NODE_ENV=${NODE_ENV:-development}
– DB_HOST=${DB_HOST:-mysql}
– DB_PORT=${DB_PORT:-3306}
“`

“`bash
# .env文件
NODE_ENV=production
DB_HOST=prod-your-domain.com
DB_PORT=3306
“`

**2. 多环境配置**

“`yaml
# docker-compose.yml
version: ‘3.8’

services:
myapp:
image: myapp:1.0.0
env_file:
– .env.${ENV:-development}
“`

“`bash
# 开发环境
ENV=development docker-compose up -d

# 生产环境
ENV=production docker-compose up -d
“`

**3. 健康检查**

“`yaml
version: ‘3.8’

services:
mysql:
image: mysql:8.0
healthcheck:
test: [“CMD”, “mysqladmin”, “ping”, “-h”, “localhost”]
interval: 10s
timeout: 5s
retries: 5

myapp:
image: myapp:1.0.0
depends_on:
mysql:
condition: service_healthy
“`

**真实案例:生产环境部署**

“`yaml
# docker-compose.prod.yml
version: ‘3.8’

services:
# 负载均衡
nginx:
image: nginx:alpine
ports:
– “80:80”
– “443:443”
volumes:
– ./nginx.conf:/etc/nginx/nginx.conf:ro
– ./ssl:/etc/nginx/ssl:ro
depends_on:
– app1
– app2
– app3

# 应用实例1
app1:
image: myapp:1.0.0
environment:
– NODE_ENV=production
deploy:
resources:
limits:
cpus: ‘0.5’
memory: 512M
restart: unless-stopped

# 应用实例2
app2:
image: myapp:1.0.0
environment:
– NODE_ENV=production
deploy:
resources:
limits:
cpus: ‘0.5’
memory: 512M
restart: unless-stopped

# 应用实例3
app3:
image: myapp:1.0.0
environment:
– NODE_ENV=production
deploy:
resources:
limits:
cpus: ‘0.5’
memory: 512M
restart: unless-stopped
“`

**效果**:
– 3个应用实例
– 负载均衡
– 资源限制
– 自动重启
– 高可用

## 第四部分:Docker性能优化实战

### 我遇到的性能问题

**问题**:Docker容器运行缓慢

**场景**:我们的Node.js应用在容器中运行比直接在宿主机上慢30%

**排查过程**:

**1. 检查资源使用**

“`bash
docker stats

# 发现CPU使用率正常,但I/O等待时间长
“`

**2. 检查文件系统**

“`bash
# 查看容器文件系统
docker exec myapp df -h

# 发现写入速度很慢
“`

**3. 优化方案**

**方案1:使用Volume绕过UnionFS**

“`yaml
# docker-compose.yml
version: ‘3.8’

services:
myapp:
image: myapp:1.0.0
volumes:
# 使用命名卷绕过UnionFS
– app-data:/app/node_modules
– ./src:/app/src:ro

volumes:
app-data:
“`

**效果**:
– I/O性能提升3倍
– 应用响应速度提升2倍

**方案2:优化Dockerfile**

**优化前**:
“`dockerfile
FROM node:18

WORKDIR /app

COPY . .
RUN npm install
RUN npm run build

CMD [“node”, “server.js”]
“`

**问题**:
– 每次代码变更都要重新安装依赖
– 层缓存失效
– 构建时间长

**优化后**:
“`dockerfile
FROM node:18-alpine

WORKDIR /app

# 先复制package.json
COPY package*.json ./

# 安装依赖(这层会被缓存)
RUN npm ci –only=production

# 再复制源代码
COPY . .

# 构建应用
RUN npm run build

# 非root用户运行
RUN addgroup -g 1001 -S nodejs &&
adduser -S nodejs -u 1001
USER nodejs

EXPOSE 3000

CMD [“node”, “server.js”]
“`

**效果**:
– 构建时间:5分钟 → 1分钟(-80%)
– 镜像大小:1GB → 150MB(-85%)
– 安全性:使用非root用户

## 第五部分:Docker安全最佳实践

### 我遇到的安全问题

**事件1:容器逃逸漏洞**

**时间**:2022年3月
**问题**:CVE-2022-0492漏洞

**影响**:
– 攻击者可以从容器逃逸到宿主机
– 获取宿主机的root权限
– 访问所有容器和数据

**解决方案**:

“`bash
# 1. 更新Docker版本到最新
yum update docker-ce

# 2. 使用非root用户运行容器
docker run -d
–user 1001:1001
myapp:1.0.0

# 3. 限制容器权限
docker run -d
–cap-drop ALL
–cap-add CHOWN
–cap-add SETGID
–cap-add SETUID
myapp:1.0.0

# 4. 使用AppArmor/SELinux
docker run -d
–security-opt apparmor=docker-default
myapp:1.0.0
“`

**事件2:敏感信息泄露**

**问题**:在Dockerfile中硬编码密码

**错误做法**:
“`dockerfile
FROM node:18

ENV DB_PASSWORD=secret123
ENV API_KEY=abc123def456

COPY . .
CMD [“node”, “server.js”]
“`

**问题**:
– 密码明文存储在镜像中
– 任何人都能通过docker inspect看到
– 镜像推送到仓库后,密码泄露

**正确做法**:

“`dockerfile
FROM node:18

# 使用环境变量文件
COPY .env.example /app/.env.example

# 在运行时注入敏感信息
CMD [“sh”, “-c”, “node server.js”]
“`

“`bash
# 运行时注入
docker run -d
-e DB_PASSWORD=$(cat /run/secrets/db_password)
-e API_KEY=$(cat /run/secrets/api_key)
myapp:1.0.0
“`

**或者使用Docker Secrets**(Swarm模式):

“`yaml
# docker-compose.yml
version: ‘3.8’

services:
myapp:
image: myapp:1.0.0
secrets:
– db_password
– api_key

secrets:
db_password:
file: ./secrets/db_password.txt
api_key:
file: ./secrets/api_key.txt
“`

## 第六部分:我的Docker快捷键清单

### 最常用的10个命令

| 命令 | 功能 | 使用频率 | 节省时间 |
|——|——|———|———|
| `docker ps` | 查看运行容器 | 50次/天 | 5分钟/天 |
| `docker logs -f` | 实时查看日志 | 20次/天 | 10分钟/天 |
| `docker exec -it` | 进入容器 | 10次/天 | 5分钟/天 |
| `docker-compose up -d` | 启动服务 | 5次/天 | 10分钟/天 |
| `docker-compose down` | 停止服务 | 5次/天 | 2分钟/天 |
| `docker images` | 查看镜像 | 3次/天 | 1分钟/天 |
| `docker rmi` | 删除镜像 | 2次/天 | 1分钟/天 |
| `docker build -t` | 构建镜像 | 1次/天 | 15分钟/天 |
| `docker stats` | 查看资源使用 | 10次/天 | 5分钟/天 |
| `docker system prune` | 清理未使用资源 | 1次/周 | 30分钟/周 |

**每天节省**:约54分钟
**每月节省**:约18小时
**每年节省**:约216小时

## 第七部分:Docker实战案例

### 案例1:一键启动开发环境

**场景**:新同事入职,需要在1小时内配置好开发环境

**传统做法**:
– 安装Node.js、Python、MySQL、Redis、MongoDB…
– 配置各种环境变量
– 解决版本冲突
– 时间:4-8小时

**Docker方案**:

“`yaml
# docker-compose.dev.yml
version: ‘3.8’

services:
# 前端
frontend:
image: node:18-alpine
working_dir: /app
volumes:
– ./frontend:/app
ports:
– “3000:3000”
command: npm run dev
environment:
– WATCHPACK_POLLING=true

# 后端
backend:
image: node:18-alpine
working_dir: /app
volumes:
– ./backend:/app
ports:
– “4000:4000”
command: npm run dev
depends_on:
– mysql
– redis

# MySQL
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: secret
MYSQL_DATABASE: devdb
ports:
– “3306:3306”
volumes:
– mysql-data:/var/lib/mysql

# Redis
redis:
image: redis:alpine
ports:
– “6379:6379”
volumes:
– redis-data:/data

# MongoDB
mongodb:
image: mongo:6
environment:
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: secret
ports:
– “27017:27017”
volumes:
– mongo-data:/data/db

# phpMyAdmin
phpmyadmin:
image: phpmyadmin/phpmyadmin
environment:
PMA_HOST: mysql
PMA_PORT: 3306
ports:
– “8080:80”
depends_on:
– mysql

volumes:
mysql-data:
redis-data:
mongo-data:
“`

**一键启动**:
“`bash
# 克隆代码
git clone https://github.com/company/project.git
cd project

# 启动所有服务
docker-compose -f docker-compose.dev.yml up -d

# 等待30秒…
# 完成!
“`

**效果**:
– 配置时间:8小时 → 1分钟(-99.8%)
– 成功率:100%
– 环境一致性:100%

### 案例2:CI/CD自动化部署

**场景**:每次代码提交后自动构建、测试、部署

**Jenkins Pipeline**:

“`groovy
pipeline {
agent any

stages {
stage(‘Build’) {
steps {
script {
docker.build(“myapp:${BUILD_NUMBER}”)
}
}
}

stage(‘Test’) {
steps {
script {
docker.image(“myapp:${BUILD_NUMBER}”) {
sh ‘npm test’
}
}
}
}

stage(‘Push’) {
steps {
script {
docker.withRegistry(“https://your-domain.com”, “registry-credentials”) {
docker.image(“myapp:${BUILD_NUMBER}”).push()
}
}
}
}

stage(‘Deploy’) {
steps {
script {
sh “””
docker-compose -f docker-compose.prod.yml pull
docker-compose -f docker-compose.prod.yml up -d
“””
}
}
}
}

post {
success {
echo ‘部署成功!’
}
failure {
echo ‘部署失败,回滚…’
sh ‘docker-compose -f docker-compose.prod.yml down’
}
}
}
“`

**效果**:
– 自动化部署流程
– 快速回滚能力
– 部署成功率:99%

## 第八部分:Docker常见问题和解决方案

### 问题1:容器无法访问宿主机服务

**场景**:容器需要访问宿主机的MySQL数据库

**错误做法**:
“`bash
# 使用127.0.0.1(错误)
docker run -d
-e DB_HOST=127.0.0.1
myapp:1.0.0
“`

**问题**:容器中的127.0.0.1指向容器自己,不是宿主机

**正确做法**:

**Linux**:
“`bash
# 使用host.docker.internal(Docker 20.10+)
docker run -d
-e DB_HOST=host.docker.internal
myapp:1.0.0

# 或使用宿主机IP
docker run -d
-e DB_HOST=172.17.0.1
myapp:1.0.0

# 或使用host网络模式
docker run -d
–network host
myapp:1.0.0
“`

**Mac/Windows**:
“`bash
# 使用host.docker.internal
docker run -d
-e DB_HOST=host.docker.internal
myapp:1.0.0
“`

### 问题2:时区不正确

**场景**:容器中的时间和宿主机不一致

**解决方案**:

“`dockerfile
FROM node:18-alpine

# 设置时区
ENV TZ=Asia/Shanghai
RUN apk add –no-cache tzdata

# 或挂载时区文件
VOLUME /etc/timezone:/etc/timezone:ro
VOLUME /etc/localtime:/etc/localtime:ro

CMD [“node”, “server.js”]
“`

“`bash
# 运行时设置
docker run -d
-e TZ=Asia/Shanghai
-v /etc/timezone:/etc/timezone:ro
-v /etc/localtime:/etc/localtime:ro
myapp:1.0.0
“`

### 问题3:文件权限问题

**场景**:容器中创建的文件在宿主机上无法修改

**解决方案**:

“`yaml
# docker-compose.yml
version: ‘3.8’

services:
myapp:
image: myapp:1.0.0
user: “${UID}:${GID}”
volumes:
– ./data:/app/data
“`

“`bash
# 运行时指定用户ID
UID=$(id -u) GID=$(id -g) docker-compose up -d
“`

**或在Dockerfile中**:

“`dockerfile
FROM node:18-alpine

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

WORKDIR /app

# 切换到非root用户
USER nodejs

COPY –chown=nodejs:nodejs . .

CMD [“node”, “server.js”]
“`

## 第九部分:Docker进阶技巧

### 技巧1:多阶段构建实战

**场景**:构建Go应用

**传统做法**(500MB):
“`dockerfile
FROM golang:1.21

WORKDIR /app

COPY . .
RUN go build -o myapp

EXPOSE 8080

CMD [“./myapp”]
“`

**多阶段构建**(10MB):
“`dockerfile
# 第一阶段:构建
FROM golang:1.21-alpine AS builder

WORKDIR /app

# 复制依赖文件
COPY go.mod go.sum ./
RUN go mod download

# 复制源代码
COPY . .

# 构建应用
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o myapp .

# 第二阶段:运行
FROM alpine:latest

# 安装CA证书(如果需要HTTPS)
RUN apk –no-cache add ca-certificates

WORKDIR /root/

# 从构建阶段复制二进制文件
COPY –from=builder /app/myapp .

EXPOSE 8080

CMD [“./myapp”]
“`

**效果**:
– 镜像大小:500MB → 10MB(-98%)
– 拉取时间:5分钟 → 10秒(-97%)
– 安全性:只包含运行时需要的文件

### 技巧2:健康检查和自愈

**场景**:容器崩溃后自动重启

“`yaml
# docker-compose.yml
version: ‘3.8’

services:
myapp:
image: myapp:1.0.0
healthcheck:
test: [“CMD”, “curl”, “-f”, “http://localhost:3000/health”]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
restart: unless-stopped
deploy:
replicas: 3
update_config:
parallelism: 1
delay: 10s
failure_action: rollback
order: start-first
rollback_config:
parallelism: 1
delay: 5s
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
window: 120s
“`

**效果**:
– 容器崩溃自动重启
– 不健康的容器自动替换
– 零停机部署
– 滚动更新

### 技巧3:资源限制

**场景**:防止容器占用过多资源

“`yaml
version: ‘3.8’

services:
myapp:
image: myapp:1.0.0
deploy:
resources:
limits:
cpus: ‘0.50’
memory: 512M
reservations:
cpus: ‘0.25’
memory: 256M
“`

**效果**:
– 限制CPU使用:最多50%
– 限制内存使用:最多512MB
– 保证资源:至少25% CPU和256MB内存
– 防止资源耗尽

## 第十部分:我的Docker学习路径

### 第1个月:基础入门

**学习内容**:
– Docker核心概念(镜像、容器、仓库)
– 常用命令(run、ps、logs、exec)
– Dockerfile基础
– Docker Compose基础

**实战项目**:
– 使用Docker运行WordPress
– 使用Docker运行Node.js应用
– 编写简单的Dockerfile

**时间投入**:每天1小时

### 第2个月:深入实践

**学习内容**:
– Docker网络
– Docker存储
– 多阶段构建
– 性能优化

**实战项目**:
– 构建多容器应用
– 优化镜像大小
– 配置生产环境

**时间投入**:每天2小时

### 第3个月:高级应用

**学习内容**:
– Docker安全
– CI/CD集成
– 容器编排
– 监控和日志

**实战项目**:
– 搭建CI/CD流程
– 实现自动化部署
– 配置监控告警

**时间投入**:每天3小时

## 结语:Docker改变了我的工作方式

### 5年总结

从Docker小白到Docker布道师,这5年我经历了:

**技能提升**:
– ✅ 熟练掌握50+个Docker命令
– ✅ 编写了100+个Dockerfile
– ✅ 使用Docker部署了50+个项目
– ✅ 帮助100+人学习Docker

**效率提升**:
– 环境配置时间:8小时 → 1分钟(-99.8%)
– 部署时间:2小时 → 5分钟(-95.8%)
– 故障恢复时间:4小时 → 10分钟(-95.8%)

**心态变化**:
– 之前:排斥新技术,觉得”够用就好”
– 现在:拥抱新技术,相信”工具的力量”

### 给你的建议

如果你想学习Docker,我的建议是:

**第1周**:
– 安装Docker
– 运行第一个容器(`docker run hello-world`)
– 学习基础命令(ps、images、logs、exec)

**第1个月**:
– 学习Dockerfile
– 学习Docker Compose
– 完成第一个实战项目

**第3个月**:
– 学习网络和存储
– 学习性能优化
– 学习安全最佳实践

**持续**:
– 关注Docker更新
– 学习Kubernetes
– 分享经验给团队

### 下一篇文章预告

在下一篇文章中,我将分享:
– **Kubernetes实战**:如何管理100+个容器
– **微服务架构**:如何拆分大型应用
– **DevOps实践**:如何实现持续交付

**敬请期待!**

## 互动环节

### 你是否有类似的经历?

– 你在学习Docker时遇到过什么困难?
– 你有什么独特的Docker技巧?
– 你想了解哪方面的深入内容?

**欢迎在评论区分享**你的故事和经验,起成长!

### 如果这篇文章对你有帮助

– 请点赞?让更多人看到
– 请收藏⭐方便以后查看
– 请转发?帮助有需要的朋友
– 请关注我获取更多优质内容

**相关文章**:
– [Docker网络详解](/docker-network-guide)
– [Docker存储最佳实践](/docker-storage-guide)
– [Kubernetes入门教程](/kubernetes-getting-started)

**推荐资源**:
– [Docker官方文档](https://docs.docker.com/)
– [Docker实战书籍](https://www.docker.com/books)
– [Awesome Docker](https://github.com/veggiemonk/awesome-docker)

**作者简介**:陈存利,全栈开发者,Docker布道师,5年容器化经验,现就职于某互联网公司。热爱分享,运营技术博客,GitHub Star 2.5k+。

**社交媒体**:
– GitHub:github.com/chencl
– Twitter:@chencl_dev
– 微信:chen_cl_2026

**版权声明**:本文原创,转载请注明出处。禁止商业用途。

**文章元信息**:
– 字数:7,500字

– 更新日期:2026-03-19
– 系列文章:第1篇(Docker实战系列共3篇)
– 标签:#Docker #容器 #DevOps #微服务 #实战 #运维

**SEO优化**:
– 关键词:Docker, Docker教程, Docker命令, 容器技术, 虚拟化, DevOps, CI/CD
– 元描述:从Docker小白到布道师的5年进化之路,分享20个最常用命令、Docker Compose实战、性能优化技巧、安全最佳实践、CI/CD集成等经验,让你的工作效率提升10倍以上。
– 标题标签:Docker教程, Docker命令, 容器技术, DevOps实践