Docker 完全指南
从零开始理解容器化技术,掌握现代软件交付的核心能力。适合有技术背景但未接触过 Docker 的开发者。
01. 什么是 Docker
核心痛点:环境不一致
"在我的机器上明明是好的啊,怎么到你那就挂了?" — 这就是 Docker 要解决的根本问题。
没有 Docker 时
- 本机:JDK 1.8 + MySQL 5.7
- 测试环境:JDK 11 + MySQL 8.0
- 结果:报错满天飞
- 排查时间:2天+
有了 Docker
- 将代码 + JDK + 配置打包
- 测试环境直接运行
- 结果:环境完全一致
- 部署时间:分钟级
一句话概括
Docker 把你的程序和它运行所需的所有"依赖",打包成了一个轻量级的、隔离的、可移植的"闭环"。
02. Docker vs 虚拟机
Docker 和虚拟机都能实现环境隔离,但本质完全不同。
虚拟机架构
- 模拟完整硬件
- 需要完整操作系统
- 镜像大小:GB 级
- 启动时间:分钟级
Docker 架构
- 共享宿主机内核
- 进程级隔离
- 镜像大小:MB 级
- 启动时间:秒级
| 特性 | 虚拟机 | Docker |
|---|---|---|
| 启动速度 | 分钟级 | 秒级 |
| 资源占用 | 高(完整OS) | 低(共享内核) |
| 隔离性 | 硬件级隔离 | 进程级隔离 |
| 镜像大小 | GB 级 | MB 级 |
| 性能损耗 | 5-15% | 接近原生 |
03. 核心概念
理解 Docker 的三个核心概念,用"面向对象"的类比最贴切。
镜像
相当于"类" 或"安装包"
镜像是只读模板,包含了运行应用所需的所有内容:代码、运行时、库、环境变量和配置文件。
- 只读,不可修改
- 通过 Dockerfile 构建
- 存储在 Registry(仓库)中
容器
相当于"对象" 或"实例"
容器是镜像的运行实例。它是一个隔离的进程,拥有自己的文件系统、网络和进程空间。
- 可读写,状态可变
- 一个镜像可启动多个容器
- 容器之间相互隔离
仓库
相当于 GitHub / Maven Central
Registry 是存储和分发镜像的地方。可以是公共的(如 Docker Hub),也可以是私有的。
- Docker Hub:最大的公共仓库
- 私有仓库:Harbor、阿里云容器镜像服务
- 支持镜像版本管理
类比关系
04. 安装与配置
# 官方一键安装脚本(推荐)
curl -fsSL https://get.docker.com | sh
# 将当前用户加入 docker 组(免 sudo)
sudo usermod -aG docker $USER
# 启动 Docker 服务
sudo systemctl start docker
sudo systemctl enable docker
# 验证安装
docker --version
docker run hello-world
# 使用 Homebrew 安装
brew install --cask docker
# 或者下载 Docker Desktop for Mac
# https://www.docker.com/products/docker-desktop
# 安装完成后启动 Docker Desktop 应用
# 验证安装
docker --version
docker run hello-world
# 使用 winget 安装
winget install Docker.DockerDesktop
# 或者下载 Docker Desktop for Windows
# https://www.docker.com/products/docker-desktop
# 注意:需要启用 WSL2 或 Hyper-V
# 验证安装
docker --version
docker run hello-world
国内镜像加速
编辑 /etc/docker/daemon.json,添加国内镜像源可显著提升拉取速度。
05. 常用命令速查
掌握这些命令,你就能应对 90% 的日常场景。
$ docker pull nginx:latest # 拉取镜像
$ docker images # 查看本地镜像
$ docker build -t myapp:v1 . # 构建镜像
$ docker tag myapp:v1 user/myapp:v1 # 打标签
$ docker push user/myapp:v1 # 推送到仓库
$ docker rmi nginx:latest # 删除镜像
$ docker image prune # 清理悬空镜像
$ docker run -d -p 80:80 --name web nginx # 运行容器
$ docker ps -a # 查看所有容器
$ docker logs -f web # 查看日志(实时)
$ docker exec -it web bash # 进入容器
$ docker stop web # 停止容器
$ docker start web # 启动容器
$ docker rm web # 删除容器
$ docker rm -f $(docker ps -aq) # 强制删除所有容器
$ docker info # 查看 Docker 信息
$ docker stats # 实时资源使用情况
$ docker system df # 磁盘使用情况
$ docker system prune # 清理未使用资源
$ docker system prune -a # 深度清理(慎用)
docker run 核心参数详解
docker run -d # 后台运行
-p 8080:80 # 端口映射:主机:容器
--name mynginx # 容器名称
-v /data:/usr/... # 挂载卷:主机路径:容器路径
--restart=always # 重启策略
-e MYSQL_ROOT_PASSWORD=root # 环境变量
--network=mynet # 指定网络
--link db:db # 链接其他容器(已废弃,用 network)
nginx:latest # 镜像名:标签
06. Dockerfile 详解
Dockerfile 是构建镜像的"配方",定义了从基础镜像到最终镜像的所有步骤。
FROM openjdk:11-jre-slim # 基础镜像
WORKDIR /app # 设置工作目录
COPY target/my-app.jar app.jar # 复制文件
EXPOSE 8080 # 声明端口
ENTRYPOINT ["java", "-jar", "app.jar"] # 启动命令
指令参考
FROM
指定基础镜像。所有 Dockerfile 都必须以 FROM 开头。
示例:FROM node:18-alpine FROM python:3.11-slim
WORKDIR
设置工作目录。后续指令都在此目录下执行。
示例:WORKDIR /app
COPY / ADD
复制文件到镜像。ADD 支持自动解压 tar 和 URL,推荐用 COPY。
示例:COPY . . ADD app.tar.gz /opt/
RUN
执行命令并提交结果。用于安装软件包、创建目录等。
示例:RUN apt-get update && apt-get install -y curl
CMD / ENTRYPOINT
容器启动时执行的命令。CMD 可被覆盖,ENTRYPOINT 更持久。
示例:CMD ["node", "app.js"] ENTRYPOINT ["java", "-jar"]
ENV / ARG
设置环境变量。ENV 持久化,ARG 仅在构建时有效。
示例:ENV NODE_ENV=production ARG VERSION=1.0
EXPOSE
声明容器监听端口。仅作文档用途,不实际发布端口。
示例:EXPOSE 80 443
VOLUME
声明匿名卷。用于持久化数据。
示例:VOLUME /data
HEALTHCHECK
健康检查。Docker 会定期执行命令判断容器健康状态。
示例:HEALTHCHECK CMD curl -f http://localhost/ || exit 1
USER
指定运行后续命令的用户。安全最佳实践。
示例:USER appuser
进阶技巧:多阶段构建
用一个 Dockerfile 完成编译和运行,最终镜像不包含编译工具,体积更小。
# 第一阶段:构建
FROM maven:3.8-openjdk-11 AS builder
WORKDIR /build
COPY pom.xml .
COPY src ./src
RUN mvn clean package -DskipTests
# 第二阶段:运行
FROM openjdk:11-jre-slim
WORKDIR /app
COPY --from=builder /build/target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
07. 分层存储原理
理解分层存储,是写出高效 Dockerfile 的关键。
UnionFS 联合文件系统
优势一:空间高效利用
多个镜像共享相同的基础层。10 个 Java 应用只需存储一份 JDK 基础层。
优势二:构建缓存加速
重新构建时,未修改的层直接复用缓存。修改代码不会触发依赖重新下载。
优势三:快速分发
拉取镜像时,已有的层不会重复下载。镜像更新只传输变化的层。
最佳实践:优化层缓存
把变化最少的指令放前面(如安装依赖),变化最多的放后面(如复制代码)。
# 推荐:先复制依赖描述文件,充分利用缓存
COPY package.json package-lock.json ./
RUN npm install
COPY . .
# 不推荐:每次代码改动都触发 npm install
COPY . .
RUN npm install
08. .dockerignore 配置
像 .gitignore 一样,.dockerignore 排除不需要打包的文件,减小镜像体积、加快构建速度。
# Git 相关
.git
.gitignore
# 依赖目录
node_modules
vendor
# 构建产物
dist
build
target
# 日志和临时文件
*.log
*.tmp
.env
# IDE 配置
.idea
.vscode
*.swp
# Docker 相关
Dockerfile
docker-compose.yml
.docker
09. Docker Compose 编排
单机多容器应用的神器。用一个 YAML 文件定义、运行、管理多个服务。
version: '3.8'
services:
db:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: rootpwd
MYSQL_DATABASE: myapp
volumes:
- db_data:/var/lib/mysql
networks:
- backend
backend:
build: ./backend
depends_on:
- db
environment:
SPRING_DATASOURCE_URL: jdbc:mysql://db:3306/myapp
networks:
- backend
- frontend
nginx:
image: nginx:latest
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
depends_on:
- backend
networks:
- frontend
volumes:
db_data:
networks:
backend:
frontend:
服务发现
在同一个 Compose 网络中,服务名即主机名。后端连接数据库直接用 db:3306,无需关心容器 IP。
常用命令
$ docker-compose up -d # 后台启动所有服务
$ docker-compose down # 停止并删除所有容器
$ docker-compose logs -f # 实时查看所有日志
$ docker-compose ps # 查看服务状态
$ docker-compose exec backend bash # 进入 backend 容器
$ docker-compose build # 重新构建镜像
$ docker-compose pull # 拉取最新镜像
$ docker-compose restart # 重启所有服务
环境变量配置
敏感信息不要写进 compose 文件,使用 .env 文件:
DB_PASSWORD=super_secret_password
API_KEY=your_api_key_here
NODE_ENV=production
environment:
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
10. 网络配置
Docker 网络让容器之间、容器与外部世界能够通信。
bridge(默认)
每个容器有独立 IP,通过 NAT 访问外部。适合单机场景。
host
容器共享宿主机网络栈,性能最好。但端口冲突风险高。
none
完全隔离,没有网络接口。适合安全敏感的任务。
overlay
跨主机网络,用于 Swarm/Kubernetes 集群。
$ docker network ls # 列出所有网络
$ docker network create mynet # 创建自定义网络
$ docker network inspect mynet # 查看网络详情
$ docker run --network mynet ... # 使用自定义网络
11. 数据卷管理
容器是临时的,数据需要持久化。Volume 是 Docker 数据管理的核心。
Bind Mount(绑定挂载)
直接将宿主机目录挂载到容器。适合开发环境,修改立即生效。
docker run -v /host/path:/container/path nginx
Named Volume(命名卷)
Docker 管理的存储卷。适合生产环境,数据独立于宿主机路径。
docker run -v mydata:/var/lib/mysql mysql
tmpfs(临时文件系统)
数据存储在内存中,容器停止后消失。适合敏感临时数据。
docker run --tmpfs /tmp nginx
数据卷命令
$ docker volume ls # 列出所有卷
$ docker volume create mydata # 创建卷
$ docker volume inspect mydata # 查看卷详情
$ docker volume rm mydata # 删除卷
$ docker volume prune # 清理未使用的卷
12. 域名绑定与反向代理
生产环境通常通过反向代理将域名映射到容器服务。
请求流向
方法一:宿主机 Nginx(简单直接)
server {
listen 80;
server_name www.myapp.com;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
方法二:Traefik(云原生推荐)
自动服务发现,自动 HTTPS,无需手动配置。
services:
traefik:
image: traefik:v2.10
command:
- "--api.insecure=true"
- "--providers.docker=true"
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
myapp:
image: myapp:latest
labels:
- "traefik.http.routers.myapp.rule=Host(`www.myapp.com`)"
- "traefik.http.routers.myapp.tls.certresolver=letsencrypt"
13. 私有镜像仓库
企业级部署需要私有仓库来存储和管理镜像。
Docker Registry
官方开源仓库,功能基础,适合小型团队。
$ docker run -d -p 5000:5000 --name registry registry:2
$ docker tag myapp localhost:5000/myapp
$ docker push localhost:5000/myapp
Harbor
企业级仓库,支持 RBAC、漏洞扫描、镜像签名。
适合中大型团队,提供 Web 管理界面。
云服务商
阿里云容器镜像服务、腾讯云 TCR、AWS ECR。
无需运维,开箱即用,国内访问速度快。
14. 日志管理
容器化环境的日志收集与传统应用不同,需要统一方案。
最佳实践:日志输出到 stdout/stderr
不要在容器内写日志文件。让 Docker 管理日志,配合日志收集工具统一处理。
ELK 技术栈
Elasticsearch
存储和搜索日志
Logstash / Filebeat
收集和解析日志
Kibana
可视化界面
日志驱动配置
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}
15. 监控方案
没有监控的系统是盲人摸象。Prometheus + Grafana 是云原生监控的标准组合。
监控架构
Prometheus
时序数据库,主动拉取指标,支持告警规则。
Grafana
可视化平台,丰富的仪表盘模板,支持多种数据源。
cAdvisor
容器资源监控,自动收集 CPU、内存、网络、磁盘指标。
Node Exporter
宿主机硬件和 OS 指标采集。
services:
prometheus:
image: prom/prometheus
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
grafana:
image: grafana/grafana
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
cadvisor:
image: gcr.io/cadvisor/cadvisor
ports:
- "8080:8080"
volumes:
- /:/rootfs:ro
- /var/run:/var/run:ro
- /sys:/sys:ro
16. 安全最佳实践
容器安全不容忽视,这些实践能显著降低风险。
不要以 root 运行容器
在 Dockerfile 中指定 USER,限制容器权限。
RUN useradd -m myuser
USER myuser
使用最小化基础镜像
Alpine 镜像只有 5MB,攻击面极小。
FROM node:18-alpine
扫描镜像漏洞
使用 Trivy 或 Clair 检测镜像中的安全漏洞。
$ trivy image myapp:latest
限制容器资源
防止容器耗尽宿主机资源。
docker run --memory="512m" --cpus="0.5" myapp
只读文件系统
防止容器被篡改。
docker run --read-only myapp
不要暴露 Docker Socket
挂载 /var/run/docker.sock 等于给容器 root 权限,极度危险。
17. Kubernetes 入门
当单机 Docker 无法满足需求时,Kubernetes 登场。它是容器编排的事实标准。
Docker
- 单机容器管理
- 手动部署
- 手动扩缩容
- 简单服务发现
适合:开发环境、小型项目
Kubernetes
- 集群容器编排
- 自动调度
- 自动扩缩容
- 服务网格
适合:生产环境、大规模系统
核心概念
Pod
K8s 最小调度单元,一个或多个容器的组合。
Deployment
声明式部署,管理 Pod 副本数和更新策略。
Service
服务发现和负载均衡,暴露 Pod 网络。
ConfigMap / Secret
配置和敏感信息管理,与镜像解耦。
Ingress
HTTP 路由,将域名映射到 Service。
部署示例
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
replicas: 3
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: myapp:v1.0
ports:
- containerPort: 8080
18. CI/CD 流水线
自动化是现代开发流程的核心。从代码提交到部署上线,全程无需人工干预。
流水线流程
常用工具
GitLab CI
GitLab 内置,配置简单,适合中小团队。
Jenkins
老牌 CI 工具,插件丰富,生态成熟。
GitHub Actions
GitHub 原生支持,云端运行,无需维护。
ArgoCD
GitOps 工具,声明式部署,适合 K8s。
GitLab CI 配置示例
stages:
- build
- test
- deploy
build:
stage: build
image: docker:latest
script:
- docker build -t myapp:$CI_COMMIT_SHA .
- docker push myapp:$CI_COMMIT_SHA
test:
stage: test
image: myapp:$CI_COMMIT_SHA
script:
- npm test
deploy:
stage: deploy
script:
- kubectl set image deployment/myapp myapp=myapp:$CI_COMMIT_SHA
only:
- main
19. 最佳实践总结
掌握这些原则,让你的容器化之路更顺畅。
1 镜像构建
- 使用最小化基础镜像
- 利用构建缓存,把变化少的放前面
- 多阶段构建减小镜像体积
- 不要在镜像中存敏感信息
2 容器运行
- 容器应该是无状态的
- 一个容器只做一件事
- 日志输出到 stdout/stderr
- 配置通过环境变量注入
3 数据管理
- 持久化数据使用 Volume
- 开发环境用 Bind Mount
- 生产环境用 Named Volume
- 定期备份重要数据
4 网络安全
- 不要暴露不必要的端口
- 使用自定义网络隔离服务
- 定期扫描镜像漏洞
- 限制容器资源使用
5 运维监控
- 配置健康检查
- 设置合理的重启策略
- 集中收集日志
- 监控资源使用和告警
命令速查表
镜像操作
docker build -t name .
docker pull image
docker push image
docker images
docker rmi image
容器操作
docker run -d -p 80:80 img
docker ps -a
docker logs -f container
docker exec -it c cmd
docker rm container
Compose 操作
docker-compose up -d
docker-compose down
docker-compose logs -f
docker-compose exec svc cmd
docker-compose build
系统操作
docker info
docker stats
docker system df
docker system prune
docker volume ls