2024 完整版 技术向

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 和虚拟机都能实现环境隔离,但本质完全不同。

虚拟机架构

App A
Guest OS
Hypervisor
Host OS
物理服务器
  • 模拟完整硬件
  • 需要完整操作系统
  • 镜像大小:GB 级
  • 启动时间:分钟级

Docker 架构

App A
App B
App C
Docker Engine
Host OS
物理服务器
  • 共享宿主机内核
  • 进程级隔离
  • 镜像大小:MB 级
  • 启动时间:秒级
特性 虚拟机 Docker
启动速度 分钟级 秒级
资源占用 高(完整OS) 低(共享内核)
隔离性 硬件级隔离 进程级隔离
镜像大小 GB 级 MB 级
性能损耗 5-15% 接近原生

03. 核心概念

理解 Docker 的三个核心概念,用"面向对象"的类比最贴切。

镜像

相当于"类" 或"安装包"

镜像是只读模板,包含了运行应用所需的所有内容:代码、运行时、库、环境变量和配置文件。

  • 只读,不可修改
  • 通过 Dockerfile 构建
  • 存储在 Registry(仓库)中

容器

相当于"对象" 或"实例"

容器是镜像的运行实例。它是一个隔离的进程,拥有自己的文件系统、网络和进程空间。

  • 可读写,状态可变
  • 一个镜像可启动多个容器
  • 容器之间相互隔离

仓库

相当于 GitHub / Maven Central

Registry 是存储和分发镜像的地方。可以是公共的(如 Docker Hub),也可以是私有的。

  • Docker Hub:最大的公共仓库
  • 私有仓库:Harbor、阿里云容器镜像服务
  • 支持镜像版本管理

类比关系

Class 镜像
new Class() 容器
Git Repository 仓库

04. 安装与配置

Bash
# 官方一键安装脚本(推荐)
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
Bash
# 使用 Homebrew 安装
brew install --cask docker

# 或者下载 Docker Desktop for Mac
# https://www.docker.com/products/docker-desktop

# 安装完成后启动 Docker Desktop 应用

# 验证安装
docker --version
docker run hello-world
PowerShell
# 使用 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% 的日常场景。

镜像操作 pull / push / build / tag / rmi

$ 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 # 清理悬空镜像

容器操作 run / exec / logs / ps / rm

$ 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) # 强制删除所有容器

系统命令 info / stats / prune / system df

$ docker info # 查看 Docker 信息

$ docker stats # 实时资源使用情况

$ docker system df # 磁盘使用情况

$ docker system prune # 清理未使用资源

$ docker system prune -a # 深度清理(慎用)

docker run 核心参数详解

Bash
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 是构建镜像的"配方",定义了从基础镜像到最终镜像的所有步骤。

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 完成编译和运行,最终镜像不包含编译工具,体积更小。

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 联合文件系统

容器层 (可读写)
镜像层 N: 应用代码
镜像层 2: 依赖库
镜像层 1: 基础 OS

优势一:空间高效利用

多个镜像共享相同的基础层。10 个 Java 应用只需存储一份 JDK 基础层。

优势二:构建缓存加速

重新构建时,未修改的层直接复用缓存。修改代码不会触发依赖重新下载。

优势三:快速分发

拉取镜像时,已有的层不会重复下载。镜像更新只传输变化的层。

最佳实践:优化层缓存

把变化最少的指令放前面(如安装依赖),变化最多的放后面(如复制代码)。

Dockerfile
# 推荐:先复制依赖描述文件,充分利用缓存
COPY package.json package-lock.json ./
RUN npm install
COPY . .

# 不推荐:每次代码改动都触发 npm install
COPY . .
RUN npm install

08. .dockerignore 配置

像 .gitignore 一样,.dockerignore 排除不需要打包的文件,减小镜像体积、加快构建速度。

.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 文件定义、运行、管理多个服务。

docker-compose.yml
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 文件:

.env
DB_PASSWORD=super_secret_password
API_KEY=your_api_key_here
NODE_ENV=production
docker-compose.yml
environment:
  MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}

10. 网络配置

Docker 网络让容器之间、容器与外部世界能够通信。

1

bridge(默认)

每个容器有独立 IP,通过 NAT 访问外部。适合单机场景。

2

host

容器共享宿主机网络栈,性能最好。但端口冲突风险高。

3

none

完全隔离,没有网络接口。适合安全敏感的任务。

4

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/Traefik
Docker 容器

方法一:宿主机 Nginx(简单直接)

nginx.conf
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,无需手动配置。

docker-compose.yml
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 技术栈

E

Elasticsearch

存储和搜索日志

L

Logstash / Filebeat

收集和解析日志

K

Kibana

可视化界面

日志驱动配置

daemon.json
{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}

15. 监控方案

没有监控的系统是盲人摸象。Prometheus + Grafana 是云原生监控的标准组合。

监控架构

应用
cAdvisor
Prometheus
Grafana

Prometheus

时序数据库,主动拉取指标,支持告警规则。

Grafana

可视化平台,丰富的仪表盘模板,支持多种数据源。

cAdvisor

容器资源监控,自动收集 CPU、内存、网络、磁盘指标。

Node Exporter

宿主机硬件和 OS 指标采集。

docker-compose.yml
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。

部署示例

deployment.yaml
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 配置示例

.gitlab-ci.yml
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