Docker KubernetesNotes

第 01 章:容器全景

zjc 于 2026-01-01 发布

这是《Docker 与 Kubernetes 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开,代码块保留了原书可直接运行的版本。 容器的本质是被隔离和受限制的进程。Docker 让镜像构建、分发和运行变得简单,Kubernetes 则让成千上万个容器可以被调度、扩缩容、发布和治理。

本章建立容器技术全景:容器解决什么问题、和虚拟机的区别、核心依赖的内核能力、镜像与容器的生命周期、容器编排要解决什么问题。

1.1 环境不一致问题

传统部署:

开发本机
  -> 测试服务器
  -> 生产服务器

常见问题:

  1. 操作系统版本不同;
  2. Python / Java / Node 版本不同;
  3. 依赖库缺失;
  4. 配置文件差异;
  5. 端口占用冲突;
  6. 启动命令不同;
  7. 磁盘路径不同。

于是出现经典对话:

在我机器上是好的。

容器把应用运行所需的内容打包成镜像:

Application Code
Runtime
Dependencies
Config Template
Entrypoint

镜像构建一次,可以在开发、测试、生产中运行同一个版本。

1.2 容器不是虚拟机

维度 虚拟机 容器
隔离级别 硬件级虚拟化 进程级隔离
内核 每个 VM 独立内核 共享宿主机内核
启动速度 分钟级 秒级
镜像大小 GB 级 MB 到数百 MB
密度 较低 较高
安全边界 相对弱
典型软件 KVM、VMware Docker、containerd

虚拟机:

Host OS
  -> Hypervisor
     -> Guest OS
        -> App

容器:

Host OS
  -> Container Runtime
     -> App Process

容器共享内核,因此不能把容器视为绝对安全边界。强隔离需求应考虑虚拟机、Kata Containers、gVisor 等方案。

1.3 容器核心依赖的内核能力

Namespace

Namespace 让进程看不到全局系统资源,实现视图隔离。

Namespace 隔离内容
PID 进程编号
NET 网络栈、网卡、路由、端口
MNT 文件系统挂载点
UTS 主机名和域名
IPC 进程间通信
USER 用户和组映射
Cgroup Cgroup 视图
Time 系统时间视图

查看进程 namespace:

ls -l /proc/$$/ns

Cgroup

Cgroup 限制和统计资源,例如:

  1. CPU;
  2. 内存;
  3. IO 带宽;
  4. PID 数量;
  5. 设备访问。

示例限制:

docker run --cpus=1 --memory=512m nginx

内存限制不是“建议值”。超过限制的容器可能被 OOM Kill。

UnionFS

容器镜像采用分层文件系统。

Image Layer 1: Base OS
Image Layer 2: Runtime
Image Layer 3: Dependencies
Image Layer 4: App Code
Container Layer: Writable

特点:

  1. 镜像层只读;
  2. 容器层可写;
  3. 层可以被复用;
  4. 构建缓存可以加速;
  5. 删除容器会丢失容器层。

1.4 Docker 的核心对象

对象 说明
Image 只读分层模板
Container 镜像的运行实例
Dockerfile 镜像构建脚本
Registry 镜像仓库
Volume 持久化数据卷
Network 容器网络
Compose 多容器编排工具

基本命令:

docker version
docker info
docker images
docker ps
docker pull nginx:1.27
docker run -d --name web -p 8080:80 nginx:1.27
docker logs -f web
docker exec -it web sh
docker stop web
docker rm web

1.5 镜像与容器生命周期

Dockerfile
  -> docker build
     -> Image
        -> docker push
           -> Registry
        -> docker pull
     -> docker run
        -> Container
           -> start / stop / restart
           -> rm

一个简单 Dockerfile:

FROM eclipse-temurin:17-jre

WORKDIR /app
COPY target/order-service.jar app.jar

ENV JAVA_OPTS="-XX:MaxRAMPercentage=70"
EXPOSE 8080

ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar /app/app.jar"]

生产镜像要求:

  1. 使用固定基础镜像版本;
  2. 不把密码打进镜像;
  3. 使用非 root 用户运行;
  4. 镜像尽量小;
  5. 构建可复现;
  6. 按变更频率分层;
  7. 扫描漏洞;
  8. 有清晰健康检查。

1.6 为什么需要 Kubernetes

单机 Docker 可以运行几个容器,但生产系统需要:

问题 Kubernetes 能力
容器挂了怎么办 自愈、重启、重建
多机如何调度 Scheduler
流量如何接入 Service、Ingress
如何滚动发布 Deployment
如何扩缩容 HPA、VPA
配置如何管理 ConfigMap、Secret
存储如何挂载 PV、PVC
秘密如何保护 Secret、RBAC
多服务如何治理 网络策略、服务网格

Kubernetes 集群组成:

Control Plane
  |-- API Server
  |-- etcd
  |-- Scheduler
  +-- Controller Manager

Worker Node
  |-- kubelet
  |-- kube-proxy
  +-- Container Runtime
组件 职责
API Server 集群入口和 REST API
etcd 保存集群状态
Scheduler 选择 Pod 运行节点
Controller Manager 维护期望状态
kubelet 管理节点上的 Pod
kube-proxy Service 流量转发

1.7 声明式模型

传统运维是命令式:

启动 3 个容器

Kubernetes 是声明式:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: order-service
spec:
  replicas: 3
  selector:
    matchLabels:
      app: order-service
  template:
    metadata:
      labels:
        app: order-service
    spec:
      containers:
        - name: order-service
          image: registry.example.com/order-service:1.0.0

含义是:

我希望始终有 3 个健康副本

如果 Pod 异常,控制器会创建新 Pod;如果节点故障,Pod 会被重新调度。

1.8 云原生部署观念

云原生应用应尽量满足:

  1. 配置外置;
  2. 无状态优先;
  3. 健康检查完善;
  4. 优雅启动和退出;
  5. 日志输出标准流;
  6. 指标暴露;
  7. 水平扩展;
  8. 故障可自愈;
  9. 发布可回滚;
  10. 依赖下游可降级。

容器只是起点。真正改变系统稳定性的是围绕容器的配置、观测、发布和治理体系。

本章小结

容器是依赖 Namespace、Cgroup 和分层文件系统运行的隔离进程,它解决了环境一致性和快速交付问题。Docker 负责单机镜像与容器,Kubernetes 负责多节点调度、自愈、流量、配置、存储和发布。理解容器的隔离边界和声明式模型,是学习云原生的基础。

思考题

  1. 容器和虚拟机的隔离边界有什么区别?
  2. Namespace 和 Cgroup 分别解决什么问题?
  3. 镜像层和容器可写层有什么关系?
  4. 为什么容器内数据需要 Volume?
  5. Kubernetes 的声明式模型带来哪些运维方式变化?