Docker 简介与特点:从零基础到熟练部署
·
一、真实场景下的Docker救场
场景还原:
上周,团队新来的开发同事小王遇到了一个令人头疼的问题。他在本地开发了一个基于Node.js 18.0.0的应用,一切运行正常。但当他把代码交给测试同学时,测试同学反馈:“代码在我的机器上报错,提示Node版本不匹配,我的是16.x版本”。
问题本质:这就是经典的"在我机器上能跑"问题。不同的开发环境、测试环境、生产环境之间的差异导致应用行为不一致。
Docker解决方案:
# 小王创建了Dockerfile
FROM node:18.0.0-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["node", "app.js"]
# 构建镜像
docker build -t myapp:1.0 .
# 测试同学直接运行
docker run -p 3000:3000 myapp:1.0
# 运行结果:应用成功启动,无版本兼容问题
这个简单的例子展示了Docker的核心价值:环境一致性。
二、Docker到底是什么?
2.1 官方定义
Docker是一个开源的容器化平台,允许开发者将应用及其依赖打包到一个标准化的单元中,这个单元包含了应用运行所需的一切:代码、运行时、系统工具、系统库和设置。
2.2 与传统虚拟机的对比
传统虚拟机结构:
┌─────────────────────────────────────────────────────┐
│ 应用1 应用2 应用3 │
├─────────────────────────────────────────────────────┤
│ Guest Operating System │
├─────────────────────────────────────────────────────┤
│ Guest Operating System │
├─────────────────────────────────────────────────────┤
│ Guest Operating System │
├─────────────────────────────────────────────────────┤
│ Hypervisor (虚拟机监控程序) │
├─────────────────────────────────────────────────────┤
│ Host Operating System │
└─────────────────────────────────────────────────────┘
Docker容器结构:
┌─────────────────────────────────────────────────────┐
│ 应用1 应用2 应用3 │
├─────────────────────────────────────────────────────┤
│ Docker Engine (容器运行时) │
├─────────────────────────────────────────────────────┤
│ Host Operating System │
└─────────────────────────────────────────────────────┘
关键差异:
| 特性 | 传统虚拟机 | Docker容器 |
|---|---|---|
| 启动时间 | 分钟级 | 秒级 |
| 磁盘占用 | GB级别 | MB级别 |
| 性能损耗 | 较高(15-20%) | 很低(3-5%) |
| 系统资源 | 每个VM需完整OS | 共享宿主机OS内核 |
| 隔离性 | 完全隔离 | 进程级隔离 |
三、Docker核心概念详解
3.1 镜像(Image)
镜像是只读的模板,包含运行应用所需的所有文件和配置。镜像是分层的,每一层都是对前一层的修改。
# 查看本机镜像
docker images
# 输出结果:
# REPOSITORY TAG IMAGE ID CREATED SIZE
# nginx latest abc123def456 2 weeks ago 133MB
# ubuntu 20.04 xyz789uvw012 3 weeks ago 72.8MB
# 查看镜像详细信息
docker inspect nginx:latest
3.2 容器(Container)
容器是镜像的运行实例。一个镜像可以创建多个容器,每个容器都是独立隔离的。
# 运行一个容器
docker run -it --name my-ubuntu ubuntu:20.04 /bin/bash
# 进入容器后,执行:
root@容器ID:/# cat /etc/os-release
# 输出结果:
# NAME="Ubuntu"
# VERSION="20.04.4 LTS (Focal Fossa)"
# ID=ubuntu
# ID_LIKE=debian
# PRETTY_NAME="Ubuntu 20.04.4 LTS"
# VERSION_ID="20.04"
# HOME_URL="https://www.ubuntu.com/"
# SUPPORT_URL="https://help.ubuntu.com/"
3.3 仓库(Registry)
存储镜像的地方,分为公共仓库(Docker Hub)和私有仓库。
# 从Docker Hub拉取镜像
docker pull mysql:8.0
# 输出结果:
# 8.0: Pulling from library/mysql
# Digest: sha256:3d7ae561cf6095f6aca8c61aac6f297f5a6f35862c4813676c7b3f6c5e3a8e7a
# Status: Downloaded newer image for mysql:8.0
# 推送镜像到私有仓库
docker tag myapp:1.0 myregistry.com/myapp:1.0
docker push myregistry.com/myapp:1.0
四、Docker完整架构解析
Docker整体架构:
┌─────────────────────────────────────────────────────────────────────┐
│ Docker Client │
│ (docker CLI、Docker Desktop、第三方工具如Portainer) │
└──────────────────────────────┬──────────────────────────────────────┘
│ REST API (HTTP/HTTPS)
┌──────────────────────────────▼──────────────────────────────────────┐
│ Docker Host │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ Docker Daemon (dockerd) │ │
│ │ ┌───────────┐ ┌───────────┐ ┌───────────┐ │ │
│ │ │ Container │ │ Container │ │ Container │ │ │
│ │ │ (Nginx) │ │ (MySQL) │ │ (Redis) │ │ │
│ │ └─────┬─────┘ └─────┬─────┘ └─────┬─────┘ │ │
│ │ │ │ │ │ │
│ │ ┌─────▼──────────────▼──────────────▼─────┐ │ │
│ │ │ Container Runtime │ │ │
│ │ │ (containerd + runc) │ │ │
│ │ └─────────────────────────────────────────┘ │ │
│ └──────────────────────────────────────────────────────────────┘ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │
│ │ Images │ │ Networks │ │ Volumes │ │ │
│ │ (镜像存储) │ │ (网络配置) │ │ (数据存储) │ │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │ │
└─────────────────────────────────────────────────────────────────────┘
│
┌──────────────────────────────▼──────────────────────────────────────┐
│ Docker Registry │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ Docker Hub (公共仓库) │ │
│ │ ┌────────────────────────────────────────────────────────┐ │ │
│ │ │ Private Registry (私有仓库) │ │ │
│ │ └────────────────────────────────────────────────────────┘ │ │
│ └──────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
五、Docker完整命令分类详解
5.1 镜像管理命令
# 1. 搜索镜像
docker search nginx
# 输出结果:
# NAME DESCRIPTION STARS OFFICIAL AUTOMATED
# nginx Official build... 18000 [OK]
# jwilder/... Nginx proxy... 2000 [OK]
# 2. 拉取镜像
docker pull nginx:1.23.0
# 输出结果:
# 1.23.0: Pulling from library/nginx
# 7b1a6ab2e44d: Pull complete
# Status: Downloaded newer image for nginx:1.23.0
# 3. 查看镜像历史
docker history nginx:latest
# 输出结果:
# IMAGE CREATED CREATED BY
# abc123def456 2 weeks ago /bin/sh -c #(nop) CMD ["nginx" "-g" "daemon...
# def456ghi789 2 weeks ago /bin/sh -c #(nop) STOPSIGNAL SIGQUIT
# ...
# 4. 删除镜像
docker rmi ubuntu:20.04
# 输出结果:
# Untagged: ubuntu:20.04
# Deleted: sha256:xyz789uvw012
# 5. 导出导入镜像
# 导出
docker save nginx:latest > nginx.tar
# 导入
docker load < nginx.tar
5.2 容器生命周期管理
# 1. 创建并启动容器
docker run -d --name web-server -p 80:80 nginx:latest
# 输出结果:容器ID(如:a1b2c3d4e5f6)
# 2. 查看运行中的容器
docker ps
# 输出结果:
# CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
# a1b2c3d4e5f6 nginx:latest "nginx..." 2 minutes ago Up 2 minutes 0.0.0.0:80->80/tcp web-server
# 3. 查看所有容器(包括已停止的)
docker ps -a
# 输出结果:
# CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
# a1b2c3d4e5f6 nginx:latest "nginx..." 5 minutes ago Up 5 minutes 0.0.0.0:80->80/tcp web-server
# b2c3d4e5f6a1 ubuntu:20.04 "/bin/bash" 2 days ago Exited (0) 2 days ago test-container
# 4. 进入容器
docker exec -it web-server /bin/bash
# 在容器内执行:
root@a1b2c3d4e5f6:/# nginx -v
# 输出结果:nginx version: nginx/1.23.0
# 5. 查看容器日志
docker logs web-server
# 输出结果:
# 2023-10-01T10:00:00.000Z 172.17.0.1 - - [01/Oct/2023:10:00:00 +0000] "GET / HTTP/1.1" 200 612
# 6. 停止容器
docker stop web-server
# 输出结果:web-server
# 7. 启动已停止的容器
docker start web-server
# 输出结果:web-server
# 8. 重启容器
docker restart web-server
# 输出结果:web-server
# 9. 删除容器
docker rm web-server
# 输出结果:web-server
5.3 网络管理命令
# 1. 查看网络
docker network ls
# 输出结果:
# NETWORK ID NAME DRIVER SCOPE
# abc123def456 bridge bridge local
# def456ghi789 host host local
# ghi789jkl012 none null local
# 2. 创建自定义网络
docker network create my-network
# 输出结果:网络ID
# 3. 查看网络详情
docker network inspect bridge
# 输出结果(JSON格式):
# [
# {
# "Name": "bridge",
# "Id": "abc123def456",
# "Created": "2023-10-01T00:00:00Z",
# "Scope": "local",
# "Driver": "bridge",
# "Containers": {
# "a1b2c3d4e5f6": {
# "Name": "web-server",
# "IPv4Address": "172.17.0.2/16"
# }
# }
# }
# ]
# 4. 容器连接到网络
docker network connect my-network web-server
# 5. 断开网络连接
docker network disconnect my-network web-server
# 6. 删除网络
docker network rm my-network
5.4 数据卷管理命令
# 1. 创建数据卷
docker volume create mydata
# 输出结果:mydata
# 2. 查看数据卷
docker volume ls
# 输出结果:
# DRIVER VOLUME NAME
# local mydata
# 3. 查看数据卷详情
docker volume inspect mydata
# 输出结果:
# [
# {
# "CreatedAt": "2023-10-01T10:00:00Z",
# "Driver": "local",
# "Labels": {},
# "Mountpoint": "/var/lib/docker/volumes/mydata/_data",
# "Name": "mydata",
# "Options": {},
# "Scope": "local"
# }
# ]
# 4. 使用数据卷
docker run -d --name mysql \
-v mysql-data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
mysql:8.0
# 查看数据卷使用情况
docker inspect mysql | grep -A 5 Mounts
# 输出结果:
# "Mounts": [
# {
# "Type": "volume",
# "Name": "mysql-data",
# "Source": "/var/lib/docker/volumes/mysql-data/_data",
# "Destination": "/var/lib/mysql"
# }
# ]
# 5. 删除数据卷
docker volume rm mydata
5.5 Docker系统命令
# 1. 查看系统信息
docker system info
# 输出结果:
# Client: Docker Engine - Community
# Version: 24.0.5
# Context: default
# Debug Mode: false
# Server: Docker Engine - Community
# Engine:
# Version: 24.0.5
# Containers: 5
# Running: 3
# Paused: 0
# Stopped: 2
# Images: 15
# Server Version: 24.0.5
# Storage Driver: overlay2
# ...
# 2. 查看磁盘使用情况
docker system df
# 输出结果:
# TYPE TOTAL ACTIVE SIZE RECLAIMABLE
# Images 5 3 1.2GB 600MB (50%)
# Containers 3 2 120MB 0B (0%)
# Local Volumes 2 1 200MB 100MB (50%)
# Build Cache 0 0 0B 0B
# 3. 清理无用资源
docker system prune
# 输出结果:
# WARNING! This will remove:
# - all stopped containers
# - all networks not used by at least one container
# - all dangling images
# - all build cache
# Are you sure you want to continue? [y/N] y
# Deleted Containers: 2
# Deleted Networks: 1
# Deleted Images: 3
# Total reclaimed space: 450MB
六、Docker运行参数详解
6.1 基础运行参数
# 完整示例
docker run -d \
--name my-app \
--hostname app-server \
--restart=always \
-p 8080:80 \
-p 8443:443 \
-v /data/app:/app \
-v /etc/localtime:/etc/localtime:ro \
-e NODE_ENV=production \
-e TZ=Asia/Shanghai \
--memory="512m" \
--cpus="1.0" \
--cpu-shares=512 \
--memory-swap="1g" \
--memory-reservation="256m" \
--blkio-weight=500 \
--ulimit nofile=1024:1024 \
--log-driver=json-file \
--log-opt max-size=10m \
--log-opt max-file=3 \
--health-cmd="curl -f http://localhost/health || exit 1" \
--health-interval=30s \
--health-timeout=3s \
--health-retries=3 \
--network=my-network \
--dns=8.8.8.8 \
--dns-search=mydomain.com \
nginx:latest
6.2 常用参数说明表
| 参数 | 说明 | 示例 | 默认值 |
|---|---|---|---|
-d | 后台运行容器 | -d | 前台运行 |
-it | 交互式终端 | -it | 无 |
--name | 容器名称 | --name web | 随机名称 |
-p | 端口映射 | -p 80:80 | 无 |
-P | 随机端口映射 | -P | 无 |
-v | 数据卷挂载 | -v /data:/app | 无 |
-e | 环境变量 | -e KEY=value | 无 |
--network | 网络连接 | --network bridge | bridge |
--restart | 重启策略 | --restart=always | no |
--memory | 内存限制 | --memory="512m" | 无限制 |
--cpus | CPU限制 | --cpus="1.5" | 无限制 |
七、Dockerfile最佳实践示例
# 多阶段构建示例
# 第一阶段:构建阶段
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
# 第二阶段:运行时阶段
FROM node:18-alpine
WORKDIR /app
# 创建非root用户
RUN addgroup -g 1001 -S nodejs && \
adduser -S nodejs -u 1001
# 从构建阶段复制文件
COPY --from=builder /app/node_modules ./node_modules
COPY . .
# 设置权限
RUN chown -R nodejs:nodejs /app
USER nodejs
# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD node healthcheck.js || exit 1
# 暴露端口
EXPOSE 3000
# 启动命令
CMD ["node", "server.js"]
构建命令:
# 构建镜像
docker build -t myapp:1.0.0 .
# 查看构建历史
docker history myapp:1.0.0
# 输出结果:
# IMAGE CREATED BY SIZE
# abc123def456 CMD ["node" "server.js"] 0B
# def456ghi789 USER nodejs 0B
# ghi789jkl012 RUN /bin/sh -c chown -R nodejs:nodejs /app 4.5kB
# ...
# 使用多架构构建
docker buildx build --platform linux/amd64,linux/arm64 -t myapp:multi-arch .
八、Docker Compose实战示例
8.1 完整docker-compose.yml
version: '3.8'
services:
# Web服务
web:
image: nginx:1.23.0-alpine
container_name: my-web
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/conf.d:/etc/nginx/conf.d:ro
- ./html:/usr/share/nginx/html
- ./logs:/var/log/nginx
environment:
- TZ=Asia/Shanghai
- NGINX_PORT=80
env_file:
- .env
networks:
- frontend
depends_on:
- app
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
deploy:
resources:
limits:
cpus: '0.5'
memory: 512M
reservations:
cpus: '0.25'
memory: 256M
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
# 应用服务
app:
build:
context: .
dockerfile: Dockerfile
args:
NODE_ENV: production
image: myapp:1.0.0
container_name: my-app
restart: always
expose:
- "3000"
volumes:
- app-data:/app/data
- /etc/localtime:/etc/localtime:ro
environment:
- DATABASE_URL=postgresql://user:pass@db:5432/mydb
- REDIS_URL=redis://cache:6379/0
networks:
- frontend
- backend
depends_on:
db:
condition: service_healthy
cache:
condition: service_started
# 数据库服务
db:
image: postgres:15-alpine
container_name: my-db
restart: unless-stopped
environment:
POSTGRES_USER: admin
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_DB: mydb
volumes:
- postgres-data:/var/lib/postgresql/data
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
networks:
- backend
healthcheck:
test: ["CMD-SHELL", "pg_isready -U admin"]
interval: 10s
timeout: 5s
retries: 5
ports:
- "5432:5432"
# 缓存服务
cache:
image: redis:7-alpine
container_name: my-cache
command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD}
volumes:
- redis-data:/data
networks:
- backend
ports:
- "6379:6379"
# 监控服务
prometheus:
image: prom/prometheus:latest
container_name: prometheus
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus-data:/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
ports:
- "9090:9090"
networks:
- monitoring
grafana:
image: grafana/grafana:latest
container_name: grafana
volumes:
- grafana-data:/var/lib/grafana
environment:
- GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD}
ports:
- "3000:3000"
networks:
- monitoring
depends_on:
- prometheus
networks:
frontend:
driver: bridge
ipam:
config:
- subnet: 172.20.0.0/16
backend:
driver: bridge
monitoring:
driver: bridge
volumes:
app-data:
driver: local
postgres-data:
driver: local
redis-data:
driver: local
prometheus-data:
driver: local
grafana-data:
driver: local
8.2 Compose常用命令
# 1. 启动服务
docker-compose up -d
# 输出结果:
# Creating network "project_frontend" with driver "bridge"
# Creating network "project_backend" with driver "bridge"
# Creating network "project_monitoring" with driver "bridge"
# Creating volume "project_app-data" with driver "local"
# Creating volume "project_postgres-data" with driver "local"
# Creating volume "project_redis-data" with driver "local"
# Creating volume "project_prometheus-data" with driver "local"
# Creating volume "project_grafana-data" with driver "local"
# Creating my-cache ... done
# Creating my-db ... done
# Creating my-app ... done
# Creating prometheus ... done
# Creating grafana ... done
# Creating my-web ... done
# 2. 查看服务状态
docker-compose ps
# 输出结果:
# Name Command State Ports
# ------------------------------------------------------------------------------------
# grafana /run.sh Up 0.0.0.0:3000->3000/tcp
# my-app docker-entrypoint.sh node ... Up 3000/tcp
# my-cache docker-entrypoint.sh redis ... Up 0.0.0.0:6379->6379/tcp
# my-db docker-entrypoint.sh postgres Up 0.0.0.0:5432->5432/tcp
# my-web /docker-entrypoint.sh ngin ... Up 0.0.0.0:443->443/tcp, 0.0.0.0:80->80/tcp
# prometheus /bin/prometheus --config.f ... Up 0.0.0.0:9090->9090/tcp
# 3. 查看日志
docker-compose logs -f
# 输出结果(实时日志):
# my-app | Server running on port 3000
# my-db | database system is ready to accept connections
# my-web | 172.20.0.1 - - [01/Oct/2023:10:00:00 +0000] "GET / HTTP/1.1" 200 612
# 4. 执行命令
docker-compose exec app npm test
# 在app服务中执行npm test命令
# 5. 停止服务
docker-compose stop
# 输出结果:
# Stopping my-web ... done
# Stopping grafana ... done
# Stopping prometheus ... done
# Stopping my-app ... done
# Stopping my-db ... done
# Stopping my-cache ... done
# 6. 停止并删除资源
docker-compose down
# 输出结果:
# Stopping my-web ... done
# Removing my-web ... done
# Removing grafana ... done
# Removing prometheus ... done
# Removing my-app ... done
# Removing my-db ... done
# Removing my-cache ... done
# Removing network project_frontend
# Removing network project_backend
# Removing network project_monitoring
# Removing volume project_app-data
# Removing volume project_postgres-data
# Removing volume project_redis-data
# Removing volume project_prometheus-data
# Removing volume project_grafana-data
九、Docker配置深度解析
9.1 守护进程配置(/etc/docker/daemon.json)
{
"authorization-plugins": [],
"data-root": "/var/lib/docker",
"exec-opts": ["native.cgroupdriver=systemd"],
"dns": ["8.8.8.8", "114.114.114.114"],
"dns-opts": [],
"dns-search": ["mydomain.com"],
"hosts": [
"unix:///var/run/docker.sock",
"tcp://0.0.0.0:2376"
],
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3",
"labels": "production_status",
"env": "os,customer"
},
"storage-driver": "overlay2",
"storage-opts": [
"overlay2.override_kernel_check=true"
],
"labels": ["env=production"],
"live-restore": true,
"max-concurrent-downloads": 3,
"max-concurrent-uploads": 5,
"default-shm-size": "64m",
"shutdown-timeout": 15,
"debug": false,
"experimental": false,
"features": {
"buildkit": true
},
"registry-mirrors": [
"https://docker.mirrors.ustc.edu.cn",
"https://hub-mirror.c.163.com",
"https://mirror.baidubce.com"
],
"insecure-registries": [
"192.168.1.100:5000"
],
"runtimes": {
"nvidia": {
"path": "/usr/bin/nvidia-container-runtime",
"runtimeArgs": []
}
},
"default-ulimits": {
"nofile": {
"Name": "nofile",
"Hard": 65536,
"Soft": 65536
},
"nproc": {
"Name": "nproc",
"Hard": 65536,
"Soft": 65536
}
},
"log-level": "info",
"iptables": true,
"ip-forward": true,
"ip-masq": true,
"userland-proxy": true,
"userland-proxy-path": "/usr/libexec/docker-proxy",
"ip": "0.0.0.0",
"bridge": "",
"bip": "",
"fixed-cidr": "",
"fixed-cidr-v6": "",
"mtu": 0,
"default-gateway": "",
"default-gateway-v6": "",
"raw-logs": false,
"allow-nondistributable-artifacts": [],
"registry-configs": {},
"service-cluster-ip-range": "10.96.0.0/12",
"default-address-pools": [
{
"base": "172.80.0.0/16",
"size": 24
},
{
"base": "172.90.0.0/16",
"size": 24
}
]
}
9.2 配置项详解
| 配置项 | 说明 | 默认值 | 推荐值 |
|---|---|---|---|
data-root | Docker数据存储路径 | /var/lib/docker | 根据磁盘空间调整 |
log-driver | 日志驱动 | json-file | json-file或journald |
log-opts.max-size | 单个日志文件最大大小 | -1(无限制) | 10m |
log-opts.max-file | 最大日志文件数 | 1 | 3 |
storage-driver | 存储驱动 | 自动检测 | overlay2 |
registry-mirrors | 镜像加速器 | 无 | 国内镜像源地址 |
live-restore | 守护进程重启时保持容器 | false | true |
max-concurrent-downloads | 最大并发下载数 | 3 | 3-5 |
max-concurrent-uploads | 最大并发上传数 | 5 | 5 |
十、Docker网络模式详解
10.1 四种网络模式对比
# 1. bridge模式(默认)
docker run -d --name web1 --network bridge nginx
# 查看网络详情
docker network inspect bridge
# 输出结果:容器获得172.17.0.x网段IP
# 2. host模式
docker run -d --name web2 --network host nginx
# 容器直接使用宿主机网络,无IP隔离
# 验证:容器内执行ifconfig,与宿主机一致
# 3. none模式
docker run -d --name web3 --network none nginx
# 容器只有lo回环接口
docker exec web3 ip addr
# 输出结果:
# 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536
# 只有lo接口,无eth0
# 4. container模式
# 创建一个容器
docker run -d --name base-container nginx
# 共享网络命名空间
docker run -d --name shared-container --network container:base-container nginx
# 两个容器共享网络栈
docker exec base-container ip addr
docker exec shared-container ip addr
# 输出结果:两个容器的IP地址完全相同
10.2 自定义网络实战
# 创建自定义bridge网络
docker network create --driver bridge \
--subnet=172.20.0.0/16 \
--ip-range=172.20.1.0/24 \
--gateway=172.20.0.1 \
my-custom-network
# 查看网络配置
docker network inspect my-custom-network
# 输出结果:
# [
# {
# "Name": "my-custom-network",
# "Id": "network-id",
# "Created": "2023-10-01T10:00:00Z",
# "Scope": "local",
# "Driver": "bridge",
# "EnableIPv6": false,
# "IPAM": {
# "Driver": "default",
# "Options": {},
# "Config": [
# {
# "Subnet": "172.20.0.0/16",
# "IPRange": "172.20.1.0/24",
# "Gateway": "172.20.0.1"
# }
# ]
# },
# "Internal": false,
# "Attachable": false,
# "Ingress": false,
# "ConfigFrom": {
# "Network": ""
# },
# "ConfigOnly": false,
# "Containers": {},
# "Options": {},
# "Labels": {}
# }
# ]
# 在自定义网络中运行容器
docker run -d --name app1 --network my-custom-network nginx
docker run -d --name app2 --network my-custom-network nginx
# 测试网络连通性
docker exec app1 ping app2
# 输出结果:
# PING app2 (172.20.1.2) 56(84) bytes of data.
# 64 bytes from 172.20.1.2: icmp_seq=1 ttl=64 time=0.052 ms
# 64 bytes from 172.20.1.2: icmp_seq=2 ttl=64 time=0.043 ms
十一、Docker存储驱动原理
11.1 存储驱动对比
| 存储驱动 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
overlay2 | 性能好,内存使用少,支持最多128层 | 需要Linux内核4.0+ | 生产环境首选 |
aufs | 兼容性好,支持更多层 | 性能较差,官方不再推荐 | 旧系统兼容 |
devicemapper | 直接操作块设备 | 配置复杂,性能一般 | 特定场景 |
btrfs | 支持快照,压缩 | 稳定性有待验证 | 需要快照功能 |
zfs | 高级功能多 | 内存占用大 | 大规模存储 |
11.2 存储驱动配置
# 检查当前存储驱动
docker info | grep "Storage Driver"
# 输出结果:
# Storage Driver: overlay2
# Backing Filesystem: xfs
# Supports d_type: true
# Native Overlay Diff: true
# 修改存储驱动
# 编辑 /etc/docker/daemon.json
{
"storage-driver": "overlay2",
"storage-opts": [
"overlay2.override_kernel_check=true"
]
}
十二、Docker安全最佳实践
12.1 安全配置示例
# 1. 使用非root用户
# Dockerfile中
RUN addgroup -g 1000 -S appuser && \
adduser -S -D -H -u 1000 -h /app -s /sbin/nologin -G appuser appuser
USER appuser
# 2. 设置容器只读
docker run -d --read-only --tmpfs /tmp nginx:alpine
# 3. 限制能力
docker run -d --cap-drop=ALL --cap-add=NET_BIND_SERVICE nginx:alpine
# 4. 设置安全策略
docker run -d \
--security-opt=no-new-privileges \
--security-opt=seccomp=unconfined \
nginx:alpine
# 5. 使用AppArmor
docker run -d --security-opt apparmor=docker-default nginx:alpine
# 6. 资源限制
docker run -d \
--memory="256m" \
--memory-swap="512m" \
--cpus="0.5" \
--cpu-shares=512 \
--blkio-weight=100 \
--pids-limit=100 \
nginx:alpine
12.2 安全扫描
# 使用Docker安全扫描
docker scan nginx:latest
# 输出结果:
# ✗ High severity vulnerability found in apt/libapt-pkg6.0
# Description: Buffer Overflow
# Info: https://snyk.io/vuln/SNYK-DEBIAN11-APT-1916438
# Introduced through: apt@2.2.4, apt/libapt-pkg6.0@2.2.4
# From: apt@2.2.4
# From: apt/libapt-pkg6.0@2.2.4
# Fixed in: 2.2.4-1
#
# ✗ Medium severity vulnerability found in openssl/libssl1.1
# ...
# 使用Trivy扫描
trivy image nginx:latest
十三、Docker性能监控与调优
13.1 监控命令
# 1. 查看容器资源使用
docker stats
# 输出结果:
# CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
# a1b2c3d4e5f6 web1 0.05% 15.3MiB / 1GiB 1.50% 1.2kB / 648B 0B / 0B 3
# b2c3d4e5f6a1 db1 2.15% 120.4MiB / 2GiB 5.88% 12.4kB / 8.2kB 0B / 0B 12
# 2. 查看容器详情
docker inspect --format='{{json .State}}' my-container
# 输出结果:
# {"Status":"running","Running":true,"Paused":false,"Restarting":false,...
# 3. 查看容器进程
docker top my-container
# 输出结果:
# UID PID PPID C STIME TTY TIME CMD
# root 1234 5678 0 10:00 ? 00:00:00 nginx: master process
# nginx 1235 1234 0 10:00 ? 00:00:00 nginx: worker process
# 4. 性能分析
docker run -d --name perf-container \
--memory="512m" \
--cpus="1.0" \
--cpu-quota=100000 \
--cpu-period=100000 \
nginx:alpine
13.2 性能优化配置
# 创建优化配置的容器
docker run -d --name optimized-app \
# CPU限制
--cpus="2" \
--cpu-shares=1024 \
--cpuset-cpus="0-3" \
--cpu-quota=200000 \
--cpu-period=100000 \
# 内存限制
--memory="1g" \
--memory-swap="2g" \
--memory-reservation="512m" \
--kernel-memory="256m" \
--memory-swappiness=60 \
# IO限制
--blkio-weight=500 \
--device-read-bps="/dev/sda:10mb" \
--device-write-bps="/dev/sda:10mb" \
--device-read-iops="/dev/sda:1000" \
--device-write-iops="/dev/sda:1000" \
# 进程限制
--pids-limit=200 \
--ulimit nofile=65536:65536 \
--ulimit nproc=65536:65536 \
# 网络优化
--network=host \
--dns="8.8.8.8" \
--dns-option="timeout:3" \
--dns-option="attempts:2" \
nginx:alpine
十四、企业级生产环境部署实战
14.1 完整部署脚本
#!/bin/bash
# deploy.sh - Docker生产环境部署脚本
set -e # 遇到错误立即退出
# 配置变量
APP_NAME="myapp"
VERSION="1.0.0"
REGISTRY="registry.mycompany.com"
ENVIRONMENT="production"
# 1. 清理旧容器和镜像
echo "清理旧资源..."
docker stop ${APP_NAME} 2>/dev/null || true
docker rm ${APP_NAME} 2>/dev/null || true
docker rmi ${REGISTRY}/${APP_NAME}:${VERSION} 2>/dev/null || true
# 2. 拉取最新镜像
echo "拉取镜像..."
docker pull ${REGISTRY}/${APP_NAME}:${VERSION}
# 3. 检查镜像安全
echo "安全扫描..."
docker scan ${REGISTRY}/${APP_NAME}:${VERSION} --json > scan-report.json
# 4. 运行容器
echo "启动容器..."
docker run -d \
--name ${APP_NAME} \
--hostname ${APP_NAME}-$(hostname) \
--restart=always \
--log-driver=json-file \
--log-opt max-size=10m \
--log-opt max-file=3 \
--memory="2g" \
--memory-swap="3g" \
--cpus="2.0" \
--cpu-quota=200000 \
--cpu-period=100000 \
--pids-limit=200 \
--ulimit nofile=65536:65536 \
--ulimit nproc=65536:65536 \
--security-opt=no-new-privileges \
--cap-drop=ALL \
--cap-add=NET_BIND_SERVICE \
--health-cmd="curl -f http://localhost:8080/health || exit 1" \
--health-interval=30s \
--health-timeout=5s \
--health-retries=3 \
--health-start-period=60s \
-p 8080:8080 \
-p 8443:8443 \
-v /data/${APP_NAME}/logs:/app/logs \
-v /data/${APP_NAME}/data:/app/data \
-v /etc/localtime:/etc/localtime:ro \
-v /etc/timezone:/etc/timezone:ro \
-e NODE_ENV=${ENVIRONMENT} \
-e TZ=Asia/Shanghai \
-e APP_VERSION=${VERSION} \
--env-file .env.production \
--label "com.mycompany.app=${APP_NAME}" \
--label "com.mycompany.version=${VERSION}" \
--label "com.mycompany.environment=${ENVIRONMENT}" \
--label "com.mycompany.maintainer=devops@mycompany.com" \
${REGISTRY}/${APP_NAME}:${VERSION}
# 5. 等待健康检查
echo "等待应用启动..."
for i in {1..30}; do
if docker inspect --format='{{.State.Health.Status}}' ${APP_NAME} | grep -q "healthy"; then
echo "应用健康检查通过"
break
fi
echo "等待应用就绪... ($i/30)"
sleep 2
done
# 6. 验证部署
echo "验证部署..."
CONTAINER_IP=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' ${APP_NAME})
if curl -sf http://${CONTAINER_IP}:8080/health > /dev/null; then
echo "✅ 部署成功!应用运行在: http://$(hostname -I | awk '{print $1}'):8080"
else
echo "❌ 部署失败!"
docker logs ${APP_NAME} --tail 50
exit 1
fi
# 7. 清理旧镜像
echo "清理无用镜像..."
docker image prune -f
echo "部署完成!"
14.2 监控与告警配置
# docker-compose.monitoring.yml
version: '3.8'
services:
# 指标收集
node-exporter:
image: prom/node-exporter:latest
container_name: node-exporter
restart: unless-stopped
volumes:
- /proc:/host/proc:ro
- /sys:/host/sys:ro
- /:/rootfs:ro
command:
- '--path.procfs=/host/proc'
- '--path.rootfs=/rootfs'
- '--path.sysfs=/host/sys'
- '--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)'
ports:
- "9100:9100"
networks:
- monitoring
cadvisor:
image: gcr.io/cadvisor/cadvisor:latest
container_name: cadvisor
restart: unless-stopped
volumes:
- /:/rootfs:ro
- /var/run:/var/run:ro
- /sys:/sys:ro
- /var/lib/docker/:/var/lib/docker:ro
- /dev/disk/:/dev/disk:ro
ports:
- "8080:8080"
networks:
- monitoring
# 日志收集
loki:
image: grafana/loki:latest
container_name: loki
restart: unless-stopped
ports:
- "3100:3100"
command: -config.file=/etc/loki/local-config.yaml
networks:
- monitoring
promtail:
image: grafana/promtail:latest
container_name: promtail
restart: unless-stopped
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /var/lib/docker/containers:/var/lib/docker/containers:ro
command: -config.file=/etc/promtail/config.yml
networks:
- monitoring
# 告警管理
alertmanager:
image: prom/alertmanager:latest
container_name: alertmanager
restart: unless-stopped
ports:
- "9093:9093"
volumes:
- ./alertmanager.yml:/etc/alertmanager/alertmanager.yml
command:
- '--config.file=/etc/alertmanager/alertmanager.yml'
- '--storage.path=/alertmanager'
networks:
- monitoring
# 可视化
grafana:
image: grafana/grafana:latest
container_name: grafana
restart: unless-stopped
environment:
- GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD}
- GF_INSTALL_PLUGINS=grafana-piechart-panel
volumes:
- grafana-data:/var/lib/grafana
- ./dashboards:/etc/grafana/provisioning/dashboards
- ./datasources:/etc/grafana/provisioning/datasources
ports:
- "3000:3000"
networks:
- monitoring
depends_on:
- prometheus
- loki
networks:
monitoring:
driver: bridge
volumes:
grafana-data:
driver: local
十五、Docker故障排查与调试
15.1 常见问题排查命令
# 1. 容器启动失败排查
docker run -d --name test nginx:latest
# 如果启动失败,查看日志
docker logs test
# 输出错误信息
# 2. 容器无法连接网络
docker exec test ping 8.8.8.8
# 如果ping不通,检查网络配置
docker network inspect bridge
docker inspect test | grep -A 20 "NetworkSettings"
# 3. 容器性能问题
# 查看容器资源使用
docker stats test
# 查看容器内进程
docker top test
# 进入容器查看
docker exec -it test bash
# 在容器内执行:
top
free -m
df -h
netstat -tulpn
# 4. 镜像构建失败
docker build -t myapp .
# 如果失败,使用--no-cache重新构建
docker build --no-cache -t myapp .
# 或者查看中间层
docker history myapp
# 5. 数据卷问题
# 查看数据卷挂载
docker inspect test | grep -A 10 Mounts
# 检查数据卷权限
docker exec test ls -la /data
# 6. 端口冲突
# 查看已占用端口
netstat -tulpn | grep :80
# 或者使用lsof
lsof -i :80
# 修改端口映射
docker run -d -p 8080:80 nginx
# 7. DNS解析问题
# 检查容器DNS配置
docker run --rm alpine nslookup google.com
# 如果解析失败,检查宿主机DNS
cat /etc/resolv.conf
# 或者指定DNS
docker run --dns=8.8.8.8 --rm alpine nslookup google.com
15.2 调试工具使用
# 1. 使用docker events监控事件
docker events --filter 'type=container' --since '2023-10-01'
# 输出结果:
# 2023-10-01T10:00:00.000000000Z container create a1b2c3d4e5f6 (image=nginx, name=web)
# 2023-10-01T10:00:01.000000000Z container start a1b2c3d4e5f6 (image=nginx, name=web)
# 2. 使用docker diff查看容器文件变化
docker diff test-container
# 输出结果:
# A /app/newfile.txt # 新增文件
# C /etc/nginx/nginx.conf # 修改文件
# D /tmp/oldfile.txt # 删除文件
# 3. 使用docker checkpoint进行检查点
# 创建检查点
docker checkpoint create my-container checkpoint1
# 恢复检查点
docker start --checkpoint checkpoint1 my-container
# 4. 使用docker system df查看磁盘使用
docker system df
# 输出结果:
# TYPE TOTAL ACTIVE SIZE RECLAIMABLE
# Images 5 3 1.5GB 800MB (53%)
# Containers 3 2 200MB 0B (0%)
# Local Volumes 2 1 300MB 150MB (50%)
# Build Cache 0 0 0B 0B
# 5. 使用docker system prune清理资源
docker system prune -a
# 输出结果:
# Total reclaimed space: 2.1GB
十六、Docker与其他技术集成
16.1 Docker与Kubernetes集成
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.23.0
ports:
- containerPort: 80
resources:
requests:
memory: "128Mi"
cpu: "250m"
limits:
memory: "256Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 10
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 10
volumeMounts:
- name: nginx-config
mountPath: /etc/nginx/nginx.conf
subPath: nginx.conf
volumes:
- name: nginx-config
configMap:
name: nginx-config
16.2 Docker与CI/CD集成
# .gitlab-ci.yml
stages:
- build
- test
- scan
- deploy
variables:
DOCKER_HOST: tcp://docker:2375
DOCKER_DRIVER: overlay2
CONTAINER_IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
build:
stage: build
image: docker:20.10
services:
- docker:20.10-dind
script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker build -t $CONTAINER_IMAGE .
- docker push $CONTAINER_IMAGE
only:
- main
- develop
test:
stage: test
image: $CONTAINER_IMAGE
script:
- echo "Running tests..."
- npm test
needs: ["build"]
scan:
stage: scan
image: docker:20.10
services:
- docker:20.10-dind
script:
- docker pull $CONTAINER_IMAGE
- docker scan $CONTAINER_IMAGE --json > scan-report.json
- cat scan-report.json
allow_failure: true
needs: ["build"]
deploy:
stage: deploy
image: alpine:latest
script:
- apk add --no-cache curl
- |
curl -X POST \
-H "Content-Type: application/json" \
-d '{"image": "'$CONTAINER_IMAGE'"}' \
https://deploy.mycompany.com/api/deploy
environment:
name: production
url: https://myapp.mycompany.com
when: manual
only:
- main
十七、总结与最佳实践
17.1 Docker使用总结
通过本指南,你应该已经掌握了:
- 基础概念:镜像、容器、仓库的核心概念
- 常用命令:完整的Docker命令分类和使用
- 高级特性:网络、存储、安全、监控
- 生产实践:企业级部署、监控、故障排查
- 生态集成:与Kubernetes、CI/CD的集成
17.2 最佳实践清单
✅ 镜像管理
- 使用官方基础镜像
- 保持镜像最小化(使用Alpine版本)
- 多阶段构建减少镜像大小
- 定期更新基础镜像安全补丁
✅ 容器运行
- 使用非root用户运行
- 设置资源限制
- 配置健康检查
- 使用只读文件系统
✅ 网络配置
- 使用自定义网络
- 避免使用host网络模式
- 合理规划IP段
- 配置DNS解析
✅ 存储管理
- 使用数据卷持久化重要数据
- 备份数据卷
- 监控存储使用
- 合理选择存储驱动
✅ 安全实践
- 最小权限原则
- 定期安全扫描
- 使用安全上下文
- 配置网络策略
✅ 监控告警
- 配置资源监控
- 设置日志收集
- 配置告警规则
- 定期审计
17.3 下一步学习路径
- Docker Compose高级用法
- Docker Swarm集群管理
- Kubernetes容器编排
- Service Mesh服务网格
- 云原生全栈技术
从简单的单容器应用开始,逐步尝试多容器编排,最终实现完整的CI/CD流水线。
更多推荐
所有评论(0)