AI Infra 训练营
总览
  • Day 1 · 集群起步 + CNI
  • Day 2 · 控制面 + etcd
  • Day 3 · CRD + Operator + Webhook
  • Day 4 · 存储深度
  • Day 5 · 卷扩容 + 安全
  • Day 6 · 调度 + 可观测
  • Day 7 · Harbor + ArgoCD + Mesh
  • Day 8 · AI Infra
  • Day 9 · Triton + GPU
  • Day 10 · MIG + HPA + 量化
  • Day 11 · AI Agent 端到端
  • Day 12 · 灾备
  • Day 13 · Operator + 联邦 + Mesh + RAG
  • Day 14 · CKA / CKS + 总结
  • LLM 训练手册
  • RAG + Agent 手册
  • 推理优化手册
  • 上下文工程手册
  • Agent 开发手册
  • 面试深度复盘
  • 训练 v2 深度手册
  • 心智模型
  • 看懂命令输出
  • 容器网络底层
  • K8s 网络深入
  • DNS 全套
  • 故障排查方法论
  • 心智模型
  • 容器挂载完整指南
  • K8s Volumes 大全
  • PV/PVC/CSI 深入
  • NFS 深入
  • 分布式存储概览
  • 故障排查 runbook
HiHuo 主站
GitHub
总览
  • Day 1 · 集群起步 + CNI
  • Day 2 · 控制面 + etcd
  • Day 3 · CRD + Operator + Webhook
  • Day 4 · 存储深度
  • Day 5 · 卷扩容 + 安全
  • Day 6 · 调度 + 可观测
  • Day 7 · Harbor + ArgoCD + Mesh
  • Day 8 · AI Infra
  • Day 9 · Triton + GPU
  • Day 10 · MIG + HPA + 量化
  • Day 11 · AI Agent 端到端
  • Day 12 · 灾备
  • Day 13 · Operator + 联邦 + Mesh + RAG
  • Day 14 · CKA / CKS + 总结
  • LLM 训练手册
  • RAG + Agent 手册
  • 推理优化手册
  • 上下文工程手册
  • Agent 开发手册
  • 面试深度复盘
  • 训练 v2 深度手册
  • 心智模型
  • 看懂命令输出
  • 容器网络底层
  • K8s 网络深入
  • DNS 全套
  • 故障排查方法论
  • 心智模型
  • 容器挂载完整指南
  • K8s Volumes 大全
  • PV/PVC/CSI 深入
  • NFS 深入
  • 分布式存储概览
  • 故障排查 runbook
HiHuo 主站
GitHub

docker —— 单机容器(构建和本地开发)

一句话定义

docker 是最早最普及的容器引擎和 CLI。K8s 1.24+ 已经移除 Docker 作 runtime(节点上是 containerd),但 docker 在本地构建镜像、本地开发、CI 构建这几个场景仍然不可替代。

典型场景

  • 构建镜像:docker build -t myapp:v1 .
  • 推镜像:docker push registry/myapp:v1
  • 本地跑容器测试:docker run -p 8080:80 nginx
  • 进容器排错:docker exec -it abc bash
  • 多阶段构建优化镜像大小
  • 看本机所有镜像 / 容器:docker images / docker ps

节点上 K8s 不用 docker——用 crictl 看节点容器。docker 主要在你的笔记本 / CI 机上。


装

# 一键脚本(开发机)
curl -fsSL https://get.docker.com | bash

# 或者按发行版
apt install -y docker.io docker-compose-v2

# macOS / Windows
# 装 Docker Desktop(自带 docker / compose / k8s 模式)

启动:

systemctl enable --now docker
docker version

把当前用户加 docker 组(避免每次 sudo):

usermod -aG docker $USER
# 重新登录生效

加 docker 组等于 root —— 不要随便给生产服务器用户 docker 组。


容器:基础动作

docker run nginx                                       # 跑容器(前台)
docker run -d nginx                                    # 后台
docker run -it ubuntu bash                              # 交互式
docker run -p 8080:80 nginx                            # 端口映射
docker run -v $(pwd):/app -w /app python:3.11 python script.py
                                                       # 挂载当前目录 + 设工作目录
docker run --rm alpine echo hi                          # 跑完自动删
docker run --name web nginx                            # 命名容器
docker run -e VAR=value alpine env                      # 环境变量
docker run --network host alpine ip a                    # 用宿主网络

# 看容器
docker ps                                              # 跑着的
docker ps -a                                            # 含已停止的
docker ps -aq                                           # 只 ID

# 停 / 启 / 删
docker stop <container>                                 # 停(SIGTERM)
docker kill <container>                                 # SIGKILL
docker start <container>                                # 启动
docker restart <container>
docker rm <container>                                   # 删(必须先停)
docker rm -f <container>                                # 强删(stop+rm)

# 进容器
docker exec -it <container> bash
docker exec <container> ls /

# 日志
docker logs <container>
docker logs -f --tail=100 <container>

# 详情
docker inspect <container>
docker inspect <container> | jq '.[0].State'
docker inspect --format='{{.NetworkSettings.IPAddress}}' <container>

镜像:基础动作

docker pull nginx:1.25                                  # 拉
docker push registry/myapp:v1                            # 推
docker images                                           # 列本地镜像
docker rmi <image>                                       # 删
docker rmi $(docker images -q --filter "dangling=true")  # 清没 tag 的镜像
docker image prune -a                                    # 清所有没被引用的(慎用)

docker tag myapp:v1 myapp:latest                         # 重 tag
docker tag myapp:v1 registry.example.com/myapp:v1        # 加远程仓库前缀

docker save myapp:v1 -o myapp.tar                        # 导出 tarball
docker load -i myapp.tar                                  # 导入

docker history myapp:v1                                   # 看每层是什么命令产生的
docker inspect myapp:v1                                   # 镜像元数据

docker build —— 构建镜像

最基础:

docker build -t myapp:v1 .                              # . 是 build context
docker build -t myapp:v1 -f Dockerfile.prod .            # 指定 Dockerfile
docker build -t myapp:v1 --no-cache .                    # 不用 cache(强制全部 rebuild)
docker build -t myapp:v1 --build-arg VERSION=2.0 .
docker build -t myapp:v1 --target=production .            # 多阶段构建选某 stage
docker build -t myapp:v1 --platform=linux/amd64 .          # 指定架构(mac M1 必加)

Dockerfile 基础语法

FROM python:3.11-slim                                    # 基础镜像

WORKDIR /app                                             # 工作目录

COPY requirements.txt .                                   # 拷文件
RUN pip install -r requirements.txt                       # 跑命令(生成新 layer)

COPY src/ ./src/

ENV PYTHONUNBUFFERED=1                                    # 环境变量
ARG VERSION=dev                                            # 构建时变量

USER 1000                                                  # 切非 root(**生产推荐**)

EXPOSE 8080                                                # 文档作用(不真开端口)

CMD ["python", "src/main.py"]                              # 默认命令

多阶段构建(镜像瘦身利器)

# Stage 1: builder
FROM golang:1.21 AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o /myapp ./cmd/myapp

# Stage 2: runtime
FROM gcr.io/distroless/static:nonroot
COPY --from=builder /myapp /myapp
USER nonroot
ENTRYPOINT ["/myapp"]

跑 docker build 之后只保留 stage 2 的产物——最终镜像 5-30 MB,比单阶段 1GB+ 小得多。

生产 Go / Rust / Java 应用必用多阶段。


.dockerignore(很重要)

build 时 docker 把整个 build context 发给 daemon。不写 .dockerignore → 几 GB 的 node_modules / .git / .venv 都被发——慢,泄漏,镜像可能也大。

# .dockerignore
.git
.gitignore
node_modules
.venv
__pycache__
*.pyc
.env
*.log
.DS_Store
build/
dist/

最低限度。


镜像优化几个套路

1. 用小的 base image

FROM python:3.11-slim                                   # 100 MB
# FROM python:3.11                                        # 900 MB
# FROM python:3.11-alpine                                  # 50 MB(注意 alpine 用 musl 不是 glibc)

2. 合并 RUN

# ❌ 多层(每个 RUN 一层、不可清)
RUN apt-get update
RUN apt-get install -y curl
RUN apt-get clean

# ✅ 单层 + 清缓存
RUN apt-get update \
  && apt-get install -y --no-install-recommends curl \
  && rm -rf /var/lib/apt/lists/*

3. 利用 layer 缓存

# ❌ 每次代码改都重新装依赖
COPY . .
RUN pip install -r requirements.txt

# ✅ 依赖变了才重装
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .                                                # 代码改也不影响上面缓存

频繁变的放后面、稳定的放前面。

4. 多阶段去掉构建工具

见上面 Go 例子。运行时不需要 gcc / make / node_modules / 测试文件。


docker network

docker network ls
docker network create mynet
docker run --network mynet --name db postgres
docker run --network mynet --name app myapp                # 同 network 里 app 可以 host=db 访问 db

默认 bridge / host / none:

网络含义
bridge默认;容器有自己的网络
host用宿主网络(端口直接暴露)
none无网络
自定义容器间用 DNS 名互相找

docker volume

docker volume create mydata
docker run -v mydata:/data alpine sh -c 'echo hello > /data/file'
docker run -v mydata:/data alpine cat /data/file       # hello

docker volume ls
docker volume inspect mydata
docker volume rm mydata
docker volume prune                                     # 清所有未引用的

bind mount 直接挂宿主目录

docker run -v /host/dir:/container/dir alpine

-v 第一个参数:

  • 不含 /(如 mydata) → 命名 volume
  • 含 /(如 /host/dir) → bind mount

docker compose(多容器编排)

# docker-compose.yml
version: '3.8'
services:
  app:
    build: .
    ports:
      - "8080:8080"
    environment:
      - DB_HOST=db
    depends_on:
      - db

  db:
    image: postgres:15
    environment:
      POSTGRES_PASSWORD: secret
    volumes:
      - db-data:/var/lib/postgresql/data

volumes:
  db-data:

用法:

docker compose up -d                                    # 启动
docker compose logs -f                                   # 看日志
docker compose ps
docker compose exec app bash
docker compose down                                      # 停 + 删容器
docker compose down -v                                   # 连 volume 也删

Docker Compose 是本地多服务开发首选。生产用 K8s。


排错 / 资源

docker stats                                            # top 风格的实时资源
docker top <container>                                  # 容器里的进程
docker system df                                         # 磁盘占用
docker system prune -a --volumes                         # 清所有未用的(**核选项**)
docker info                                              # 引擎信息

镜像层数过多

docker history myapp:v1
# 看每层、可以重写 Dockerfile 减少

容器卡住 / 不响应

docker logs <container> --tail=200
docker exec <container> ps aux
docker inspect <container> | jq '.[0].State'
docker kill <container>                                 # SIGKILL(最后手段)

docker buildx —— 跨架构构建

M1 Mac / ARM 服务器需要构建 amd64+arm64:

docker buildx create --use --name multi-arch
docker buildx build \
  --platform linux/amd64,linux/arm64 \
  -t registry/myapp:v1 \
  --push .

K8s 集群有不同架构节点时必用 multi-arch 镜像。


私有 registry

docker login registry.example.com                       # 输用户名密码
docker tag myapp:v1 registry.example.com/myapp:v1
docker push registry.example.com/myapp:v1

凭证存 ~/.docker/config.json(base64 不是加密——小心)。

docker logout registry.example.com

K8s pull 私有镜像

kubectl create secret docker-registry regcred \
  --docker-server=registry.example.com \
  --docker-username=user \
  --docker-password=pass

# Pod spec 加:
# spec:
#   imagePullSecrets:
#   - name: regcred

常见踩坑

坑 1:M1 Mac 拉的镜像在 amd64 集群跑不起来

docker pull myapp:v1                                    # 默认拉宿主架构(arm64)
docker push ...                                         # 推上去的是 arm64
# K8s 集群上 amd64 节点上跑:exec format error

修:用 buildx 多架构,或者明确指定:

docker build --platform=linux/amd64 -t myapp:v1 .
docker pull --platform=linux/amd64 myapp:v1

坑 2:build context 太大、build 慢

docker build -t myapp:v1 .
# Sending build context to Docker daemon  2.5GB

.dockerignore 没写好。node_modules / .git / .venv 都被发了。

坑 3:镜像越攒越大

docker system df
# RECLAIMABLE 30 GB
docker system prune -a --volumes                         # 清

CI / 开发机经常忘了清。定期跑 prune(每周 cron)。

坑 4:容器以 root 跑

FROM ubuntu
COPY app /
CMD ["/app"]                                            # 默认 root

容器 root 在某些攻击场景能逃逸到宿主 root。

USER 1000                                                # 切非 root

K8s 里也可以 podSpec.securityContext.runAsUser=1000 强制。

坑 5:把 secret 放 ENV 或 ARG

ARG DB_PASSWORD                                          # ❌ docker history 能看到
ENV DB_PASSWORD=$DB_PASSWORD                              # ❌ 容器 env 显示
docker history myapp:v1
# 显示 ARG DB_PASSWORD=secret

Build-time secret 用 BuildKit --mount=type=secret:

# syntax=docker/dockerfile:1
RUN --mount=type=secret,id=mysecret cat /run/secrets/mysecret
docker build --secret id=mysecret,src=./secret.txt .

Runtime secret 用 K8s Secret + 环境变量 / volume。

坑 6:CMD 用 shell 形式而不是 exec 形式

CMD python app.py                                        # shell 形式:实际跑 sh -c "python app.py"
                                                          # → 主进程是 sh、收不到 SIGTERM
CMD ["python", "app.py"]                                  # exec 形式:直接跑 python
                                                          # → SIGTERM 能正常处理(K8s graceful shutdown 需要)

K8s graceful shutdown 要应用响应 SIGTERM。永远用 exec 形式。

坑 7:DOCKER_BUILDKIT 没开

docker build .                                          # 老 builder 慢、缓存差

新版默认开 BuildKit,但老 Docker 不。开:

export DOCKER_BUILDKIT=1
docker build .

或者 /etc/docker/daemon.json:

{
  "features": {
    "buildkit": true
  }
}

坑 8:用 latest tag

docker pull myapp:latest
# 每次拿到不同版本,复现问题难

生产永远固定 tag(v1.2.3、abc1234)。latest 适合临时测试。

坑 9:在 K8s 节点上误用 docker 命令

ssh m4 'docker ps'
# Cannot connect to the Docker daemon

K8s 1.24+ 节点没装 docker(用 containerd)。要看节点容器:crictl。

坑 10:把 docker.sock 挂进容器

docker run -v /var/run/docker.sock:/var/run/docker.sock alpine

容器里能控制宿主 docker daemon —— 等于宿主 root。除非你完全清楚为什么这么做,不要这样。

K8s 里类似的 CVE:容器里挂 /run/containerd/containerd.sock。


docker vs containerd vs podman

工具用途K8s 场景
docker本地开发 / 构建❌ 节点不用
containerdK8s 节点 runtime✅
podmanrootless 容器 / docker 替代部分开发场景
buildah专门构建(不需要 daemon)CI 推荐
kaniko在 K8s 里构建(不需要 docker)CI on K8s

K8s 节点用 crictl 操作 containerd。本地开发 docker。CI 构建用 docker / buildah / kaniko。


关联命令

  • crictl —— K8s 节点上的"docker"
  • kubectl —— 把镜像跑成 K8s pod
  • helm —— 镜像 + chart
  • make —— make build 包装 docker build
  • git —— git describe 拿 tag 给镜像
  • openssl —— TLS 证书给私有 registry
在 GitHub 上编辑此页