Docker 负责打包,Kubernetes 负责调度:一文吃透容器化与 K8s 编排

Docker 负责打包,Kubernetes 负责调度:一文吃透容器化与 K8s 编排

Docker 解决的是"应用如何被打包和运行",Kubernetes 解决的是"大量容器如何被部署、调度、发现、扩缩容和自愈"。把两者混为一谈,是学习容器技术时最常见的误区。pos_id=img-3aO9SG9f-1787067290924)

一、先用一句话理解 Docker 和 Kubernetes

可以先建立一个简单的分工模型:

复制代码
Docker:
把应用、依赖和运行环境打包成镜像,并在本机或服务器上运行容器。

Kubernetes:
管理一组机器上的容器化应用,负责调度、扩缩容、服务发现、滚动发布和故障恢复。

Docker 更像是"应用交付和容器运行工具",Kubernetes 更像是"容器集群操作系统"。

二者不是同一层产品:

复制代码
Dockerfile
  -> Docker Image
      -> Container
          -> Pod
              -> Deployment
                  -> Service
                      -> Kubernetes Cluster

这条链路中,每一层解决的问题不同。

二、为什么需要 Docker

传统部署常见的问题是:

  • 开发环境和生产环境版本不一致;
  • Java、Node、Python 版本冲突;
  • 系统依赖安装过程复杂;
  • 应用部署步骤依赖人工经验;
  • 服务之间互相污染;
  • 回滚困难;
  • 新机器很难快速恢复。

Docker 的核心思路是:

把应用和运行它所需要的文件、依赖、配置方式封装成标准化镜像,再以隔离进程的形式运行。

Docker 官方文档将容器描述为隔离进程,将镜像描述为包含运行应用所需文件、二进制、库和配置的标准化包。Docker 官方:什么是容器 Docker 官方:什么是镜像

三、Docker 的核心对象

1. Dockerfile

Dockerfile 是镜像构建说明书:

复制代码
FROM eclipse-temurin:21-jre
WORKDIR /app
COPY target/app.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]

常见指令:

  • FROM:指定基础镜像;
  • WORKDIR:设置工作目录;
  • COPY:复制文件;
  • RUN:构建阶段执行命令;
  • ENV:设置环境变量;
  • EXPOSE:声明容器端口;
  • CMD:默认参数;
  • ENTRYPOINT:默认启动入口。

2. Image

镜像是不可变的应用模板,通常由多个只读层组成。Docker 官方文档说明,镜像层代表一组文件系统变化,并且镜像构建过程会复用这些层。Docker 镜像层文档

镜像名称通常由以下部分组成:

复制代码
registry/namespace/repository:tag

例如:

复制代码
registry.example.com/team/order-service:1.4.2

生产环境不建议只使用 latest,因为它不能清晰表达版本,也不利于回滚。更可靠的方式是使用语义化版本、Git Commit ID 或不可变 Digest。

3. Container

容器是镜像的运行实例:

复制代码
docker run -d       --name order-service       -p 8080:8080       -e SPRING_PROFILES_ACTIVE=prod       order-service:1.4.2

常用命令:

复制代码
docker ps
docker ps -a
docker logs -f order-service
docker exec -it order-service sh
docker inspect order-service
docker stop order-service
docker rm order-service

容器通常是短生命周期对象。不要把重要数据只放在容器可写层中,数据应通过 Volume 或外部存储持久化。

4. Registry

Registry 用于存储和分发镜像:

复制代码
docker login registry.example.com
docker build -t registry.example.com/team/app:1.0.0 .
docker push registry.example.com/team/app:1.0.0
docker pull registry.example.com/team/app:1.0.0

常见实现包括 Docker Hub、Harbor、云厂商镜像仓库和云原生平台自带 Registry。

四、Docker 镜像为什么适合交付

镜像带来了几个重要能力:

可重复

同一个镜像在开发、测试和生产环境中具有相同的文件系统和启动入口。

可分发

镜像可以推送到 Registry,再由不同机器拉取。

可回滚

只要保留旧镜像版本,就可以把应用恢复到旧版本。

可缓存

镜像层可以复用,减少构建和传输成本。

可审计

可以对镜像做漏洞扫描、签名、SBOM 生成和来源追踪。

但镜像并不等于安全。基础镜像、系统包、第三方依赖和应用本身都可能存在漏洞。

五、为什么需要 Kubernetes

当只有一个服务和一台机器时,Docker 命令已经够用。

当服务数量增加后,会遇到:

  • 多台机器如何分配容器;
  • 某个容器挂了如何自动恢复;
  • 服务如何找到另一组动态变化的容器;
  • 如何运行多个副本;
  • 如何滚动升级;
  • 如何限制 CPU 和内存;
  • 如何处理节点故障;
  • 如何给外部流量提供稳定入口;
  • 如何实现配置和密钥管理。

Kubernetes 的核心不是"运行一个容器",而是:

用户声明期望状态,控制器持续观察实际状态,并不断把实际状态拉回期望状态。

例如:

复制代码
期望:order-service 运行 3 个副本
实际:当前只有 2 个健康副本
控制器:创建新的 Pod

这就是 Kubernetes 的声明式和控制器模型。

六、Kubernetes 核心架构

复制代码
flowchart LR
    U[用户或 CI/CD] --> API[API Server]
    API --> ETCD[(etcd)]
    API --> SCH[Scheduler]
    API --> CM[Controller Manager]
    API --> K[各节点 Kubelet]

    SCH --> POD[被调度的 Pod]
    CM --> DESIRED[期望状态控制]
    K --> CRI[Container Runtime]
    CRI --> C[Container]
    K --> CNI[CNI 网络插件]
    K --> CSI[CSI 存储插件]

    API --> SVC[Service]
    SVC --> PROXY[kube-proxy 或数据平面]
    PROXY --> POD

控制面主要负责:

  • API Server:统一 API 入口;
  • etcd:保存集群状态;
  • Scheduler:为 Pod 选择节点;
  • Controller Manager:维护各种资源的期望状态。

节点侧主要负责:

  • Kubelet:管理节点上的 Pod;
  • Container Runtime:创建和运行容器;
  • CNI:提供网络;
  • CSI:提供持久化存储;
  • kube-proxy 或其他数据平面:实现 Service 流量转发。

七、Pod:Kubernetes 最小部署单元

Kubernetes 官方文档将 Pod 定义为集群中运行一个或多个容器的最小可部署对象。Kubernetes Workloads 官方文档

Pod 不是简单的"容器别名"。

一个 Pod 中的容器通常共享:

  • 网络命名空间;
  • Pod IP;
  • localhost;
  • 部分存储卷;
  • 生命周期边界。

常见场景是:

复制代码
Pod
  ├── main application container
  └── sidecar container

例如主应用负责业务,Sidecar 负责日志采集、代理或配置同步。

但不要为了"容器越多越好"而把无关服务放到同一个 Pod。Pod 内的容器应该具有较强的协作关系,并且需要一起调度、一起部署。

一个简单 Pod 配置:

复制代码
apiVersion: v1
kind: Pod
metadata:
  name: web
  labels:
    app: web
spec:
  containers:
    - name: web
      image: nginx:1.27
      ports:
        - containerPort: 80

实际生产中通常不直接创建 Pod,而是使用 Deployment、StatefulSet 或 Job 管理 Pod。

八、Deployment:管理无状态应用

Deployment 适合管理无状态应用。它通过 ReplicaSet 维护指定数量的 Pod,并支持滚动更新和回滚。

复制代码
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: app
          image: registry.example.com/order-service:1.4.2
          ports:
            - containerPort: 8080
          resources:
            requests:
              cpu: "250m"
              memory: "256Mi"
            limits:
              cpu: "1"
              memory: "512Mi"

查看状态:

复制代码
kubectl get deployment
kubectl get rs
kubectl get pods -l app=order-service
kubectl describe deployment order-service

Deployment 的核心逻辑是:

复制代码
Deployment
  -> ReplicaSet
      -> Pod
          -> Container

当镜像版本变化时,Deployment 创建新的 ReplicaSet,再逐步替换旧 Pod。

九、Service:给动态 Pod 提供稳定访问入口

Pod 是易变的:

  • Pod 可能被重建;
  • Pod IP 可能变化;
  • 副本数量可能变化;
  • Pod 可能被调度到其他节点。

Service 提供一个稳定的访问抽象,将一组 Pod 暴露成统一的网络端点。Kubernetes 官方文档明确说明,Service 解决了客户端如何访问动态变化的 Pod 后端这一问题。Kubernetes Service 官方文档

复制代码
apiVersion: v1
kind: Service
metadata:
  name: order-service
spec:
  selector:
    app: order-service
  ports:
    - port: 80
      targetPort: 8080
  type: ClusterIP

常见类型:

  • ClusterIP:集群内部访问;
  • NodePort:通过节点端口暴露;
  • LoadBalancer:借助云平台负载均衡;
  • ExternalName:通过 DNS 别名访问外部服务。

Service 通过 selector 选择后端 Pod。selector 和 Pod labels 不匹配,是服务访问不到后端的常见原因。

十、Ingress 与 Gateway

Service 解决集群内服务发现,但外部 HTTP 请求通常还需要:

  • 域名路由;
  • TLS 终止;
  • 路径转发;
  • 多服务共享入口;
  • 证书管理;
  • 访问控制。

传统 Kubernetes 中常用 Ingress:

复制代码
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: app-ingress
spec:
  rules:
    - host: app.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: order-service
                port:
                  number: 80

Ingress 只是 API 对象,实际还需要 Ingress Controller。

在新的云原生网络设计中,也可以关注 Gateway API。实际选型要结合集群版本、云厂商能力和现有 Controller,不应只复制网上旧版本 YAML。

十一、ConfigMap 与 Secret

ConfigMap

保存非敏感配置:

复制代码
apiVersion: v1
kind: ConfigMap
metadata:
  name: order-config
data:
  LOG_LEVEL: info
  FEATURE_X_ENABLED: "true"

Secret

保存敏感配置,例如:

  • 数据库密码;

  • Token;

  • TLS 证书;

  • 镜像仓库认证信息。

    apiVersion: v1

    kind: Secret

    metadata:

    name: order-secret

    type: Opaque

    stringData:

    DB_PASSWORD: change-me

需要注意:Kubernetes Secret 并不天然等于强加密保险箱。生产环境还需要关注 etcd 加密、RBAC、密钥轮换、审计和外部 Secret 管理系统。

十二、健康检查:Readiness、Liveness、Startup

Readiness Probe

判断 Pod 是否可以接收流量。

如果应用还没完成启动或依赖不可用,Readiness 失败,Service 不应该把流量转给它。

Liveness Probe

判断进程是否已经失去自我恢复能力。如果持续失败,Kubelet 可能重启容器。

Startup Probe

适合启动时间较长的应用,避免应用还没启动完成就被 Liveness 判定为失败。

复制代码
startupProbe:
  httpGet:
    path: /actuator/health
    port: 8080
  failureThreshold: 30
  periodSeconds: 10

readinessProbe:
  httpGet:
    path: /actuator/health/readiness
    port: 8080
  initialDelaySeconds: 5
  periodSeconds: 5

探针不是越多越好。探针接口本身必须轻量、稳定、能准确反映服务状态。

十三、资源请求与限制

Kubernetes 通过 requests 和 limits 进行资源管理:

  • requests:调度时至少需要的资源;

  • limits:容器允许使用的上限。

    resources:

    requests:

    cpu: "500m"

    memory: "512Mi"

    limits:

    cpu: "2"

    memory: "1Gi"

CPU 单位:

复制代码
1000m = 1 个 CPU 核

资源设置不合理会导致:

  • requests 太小:节点超卖,运行时争抢严重;
  • requests 太大:Pod 难以调度;
  • memory limit 太小:容器 OOMKilled;
  • 没有 requests:调度和 QoS 不可控;
  • 没有 limits:单个服务可能占满节点资源。

十四、Kubernetes 中的容器运行时

这是 Docker 与 Kubernetes 最容易混淆的地方。

Kubernetes 通过 CRI 与容器运行时交互。官方文档要求运行时支持 CRI v1,并列出 containerd 等运行时。Kubernetes Container Runtimes

Kubernetes v1.24 移除了内置 dockershim。原因是 Docker Engine 不直接实现 CRI,过去需要 Kubernetes 内置的兼容层把 Docker 接到 kubelet。Kubernetes Dockershim Removal FAQ

这并不意味着:

  • Docker 镜像不能运行;
  • Docker 不能用于本地开发;
  • Docker 项目失去价值。

真正变化的是:

复制代码
Kubernetes 节点的容器运行时
不再默认通过内置 dockershim 连接 Docker Engine

Docker 构建的 OCI 兼容镜像仍然可以被 Kubernetes 使用。生产集群通常会使用 containerd 或 CRI-O 等 CRI 兼容运行时,也可以通过 cri-dockerd 使用 Docker Engine。

正确理解是:

复制代码
Docker CLI / Docker Engine
  -> 负责开发、构建、运行和分发

containerd / CRI-O
  -> 负责 Kubernetes 节点上的容器运行时

Kubernetes
  -> 负责集群级调度和生命周期管理

十五、Docker Compose 与 Kubernetes 的关系

Docker Compose 适合:

  • 本地开发;
  • 单机多容器;
  • 快速搭建依赖环境;
  • 集成测试;
  • Demo 和小型部署。

Kubernetes 适合:

  • 多节点集群;
  • 高可用;
  • 自动扩缩容;
  • 滚动发布;
  • 服务发现;
  • 资源调度;
  • 自愈和运维治理。

Compose 示例:

复制代码
services:
  app:
    build: .
    ports:
      - "8080:8080"
    depends_on:
      - db
  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: example

Compose 和 Kubernetes 不是严格替代关系。常见开发链路是:

复制代码
Dockerfile
  -> Docker Compose 本地联调
  -> CI 构建镜像
  -> 推送 Registry
  -> Kubernetes 部署

十六、滚动发布与回滚

更新 Deployment 镜像:

复制代码
kubectl set image deployment/order-service       app=registry.example.com/order-service:1.4.3

查看发布状态:

复制代码
kubectl rollout status deployment/order-service
kubectl rollout history deployment/order-service

回滚:

复制代码
kubectl rollout undo deployment/order-service

滚动发布需要结合:

  • Readiness Probe;
  • maxUnavailable;
  • maxSurge;
  • 版本不可变;
  • 监控;
  • 灰度策略;
  • 数据库兼容;
  • 回滚方案。

代码回滚不等于数据回滚。数据库 Migration 必须向前兼容,避免新代码写入旧版本无法识别的数据结构。

十七、Job、CronJob 和 StatefulSet

Job

适合一次性任务:

复制代码
数据迁移
批处理
初始化
离线计算

CronJob

适合定时任务:

复制代码
每天对账
定期清理
数据同步
定时备份

StatefulSet

适合需要稳定身份和持久存储的应用:

  • 数据库;
  • 消息队列;
  • 有状态集群;
  • 需要稳定网络标识的服务。

不要简单地把数据库放进 Deployment 就认为完成了生产部署。还需要考虑存储、备份、主从、故障转移、升级和数据一致性。

十八、持久化存储

容器本身是短生命周期的,持久数据通常需要:

  • Volume;
  • PersistentVolume;
  • PersistentVolumeClaim;
  • StorageClass;
  • CSI Driver。

基本关系:

复制代码
Pod
  -> PVC
      -> PV
          -> StorageClass / CSI
              -> 云盘、NAS 或分布式存储

应用是否有状态,决定了存储设计。日志、上传文件、数据库数据和缓存不应全部用同一种存储方案。

十九、Kubernetes 网络模型

Kubernetes 网络至少要解决:

  • Pod 到 Pod;
  • Pod 到 Service;
  • 外部到 Service;
  • Pod 到外部;
  • DNS 服务发现;
  • 网络策略。

常见网络组件包括:

  • CNI;
  • CoreDNS;
  • kube-proxy;
  • Ingress Controller;
  • NetworkPolicy;
  • 云厂商数据平面。

排查网络时,不要只看应用日志:

复制代码
kubectl get svc
kubectl get endpoints
kubectl get endpointslices
kubectl exec -it pod-a -- nslookup order-service
kubectl exec -it pod-a -- curl http://order-service

Service 存在但没有 Endpoints,通常说明 selector 没有匹配到 Ready 的 Pod。

二十、故障排查顺序

1. Pod 起不来

复制代码
kubectl get pods
kubectl describe pod <pod-name>
kubectl logs <pod-name>
kubectl logs <pod-name> --previous

重点查看:

  • ImagePullBackOff;
  • CrashLoopBackOff;
  • OOMKilled;
  • 探针失败;
  • 配置缺失;
  • Secret 不存在;
  • 节点资源不足。

2. Service 访问不到

复制代码
kubectl get svc
kubectl get endpoints
kubectl get pods --show-labels
kubectl describe svc <service-name>

检查:

  • selector 是否匹配;
  • Pod 是否 Ready;
  • targetPort 是否正确;
  • 应用是否监听正确地址;
  • NetworkPolicy 是否阻断;
  • DNS 是否正常。

3. Pod 一直 Pending

复制代码
kubectl describe pod <pod-name>

常见原因:

  • requests 太大;
  • 没有合适节点;
  • 节点污点;
  • nodeSelector 不匹配;
  • PVC 绑定失败;
  • 亲和性条件无法满足。

4. 发布后接口异常

检查:

  • 新版本镜像是否正确;
  • Readiness 是否误判;
  • 环境变量是否变化;
  • Service 是否仍然指向旧 Pod;
  • 数据库 Migration 是否兼容;
  • 应用是否有启动竞态;
  • 滚动发布策略是否合理。

二十一、生产环境最佳实践

镜像层面

  • 固定基础镜像版本;
  • 使用多阶段构建;
  • 尽量使用非 root 用户;
  • 减少镜像体积;
  • 扫描漏洞;
  • 生成 SBOM;
  • 使用镜像签名;
  • 不把密钥写入镜像;
  • 不使用 latest 作为生产版本。

Kubernetes 层面

  • 所有工作负载设置 requests 和 limits;
  • 配置 Readiness、Liveness 和 Startup;
  • 使用 PodDisruptionBudget;
  • 使用滚动发布;
  • 为关键服务配置反亲和;
  • 使用 NetworkPolicy;
  • 对 Secret 做加密和轮换;
  • 限制 ServiceAccount 权限;
  • 记录审计日志;
  • 使用命名空间隔离团队和环境。

研发流程

复制代码
提交代码
  -> 构建镜像
  -> 单元测试
  -> 镜像扫描
  -> 推送 Registry
  -> 部署测试环境
  -> 集成测试
  -> 灰度发布
  -> 监控验证
  -> 全量发布

二十二、Docker 与 Kubernetes 的完整协作链路

复制代码
开发者编写代码
  -> Dockerfile
  -> docker build
  -> Image
  -> Registry
  -> Kubernetes Deployment
  -> Scheduler 选择节点
  -> Kubelet 调用 CRI
  -> containerd 或 CRI-O 创建容器
  -> Pod Ready
  -> Service 加入 Endpoints
  -> Ingress 接收流量

这里的关键分工是:

环节 主要负责者
应用打包 Dockerfile / Docker Build
镜像存储 Registry
容器创建 Container Runtime
节点管理 Kubelet
Pod 调度 Scheduler
副本维护 Controller
服务发现 Service / CoreDNS
外部入口 Ingress 或 Gateway
配置管理 ConfigMap / Secret
存储管理 PVC / PV / CSI
集群治理 Kubernetes

二十三、常见误区

误区一:Kubernetes 就是 Docker 的集群版

不准确。Kubernetes 是容器编排系统,Docker 是容器开发和运行生态的一部分。

误区二:Kubernetes 不能运行 Docker 镜像

不准确。Docker 构建的镜像通常可以被 Kubernetes 使用。变化主要在于 Kubernetes 节点如何连接容器运行时。

误区三:Pod 就是一个容器

Pod 是 Kubernetes 的最小部署单元,一个 Pod 可以包含一个或多个紧密协作的容器。

误区四:Service 会自动暴露到公网

默认 ClusterIP 只提供集群内部访问。公网访问需要 LoadBalancer、NodePort、Ingress 或 Gateway 等方案。

误区五:容器重启就等于服务自愈

重启只能解决部分进程问题。真正的自愈还涉及副本、探针、调度、节点故障和业务依赖。

误区六:设置 limits 就完成资源治理

还需要合理设置 requests、QoS、HPA、节点容量和监控告警。

误区七:Kubernetes 适合所有项目

单体小项目或个人服务使用 Docker Compose 可能更简单。Kubernetes 的运维成本和学习成本都不低。

二十四、学习路线

建议按下面的顺序学习:

第一阶段:Linux 和容器基础

  • 进程;
  • Namespace;
  • Cgroups;
  • 文件系统;
  • 网络;
  • Docker CLI;
  • Dockerfile;
  • 镜像层;
  • Volume;
  • Registry。

第二阶段:Docker 工程实践

  • 多阶段构建;
  • Compose;
  • 日志;
  • 健康检查;
  • 镜像扫描;
  • 私有仓库;
  • CI 构建。

第三阶段:Kubernetes 基础对象

  • Pod;
  • Deployment;
  • ReplicaSet;
  • Service;
  • ConfigMap;
  • Secret;
  • Namespace;
  • Job;
  • CronJob。

第四阶段:Kubernetes 生产能力

  • Ingress;
  • Gateway;
  • Storage;
  • StatefulSet;
  • HPA;
  • RBAC;
  • NetworkPolicy;
  • 调度和亲和性;
  • 监控和日志;
  • Helm;
  • GitOps。

二十五、总结

Docker 和 Kubernetes 不是竞争关系,而是处在不同抽象层:

复制代码
Docker:
让应用能够被标准化打包、分发和运行。

Kubernetes:
让大量容器能够在集群中被声明式地调度、治理和恢复。

真正的云原生交付链路是:

复制代码
代码
  -> 镜像
  -> Registry
  -> Pod
  -> Deployment
  -> Service
  -> Ingress
  -> 集群运行

最重要的几个结论:

  1. 镜像是应用交付单元,容器是镜像的运行实例。
  2. Pod 是 Kubernetes 的最小部署单元,不等于单个容器。
  3. Deployment 管理无状态副本,Service 提供稳定访问入口。
  4. Docker Engine、containerd、CRI-O 和 Kubernetes 处于不同层次。
  5. Kubernetes 1.24 移除了内置 dockershim,生产集群应关注 CRI 兼容运行时。Kubernetes Dockershim Removal FAQ
  6. 生产系统不仅需要运行起来,还要考虑探针、资源、存储、权限、网络、发布、回滚和可观测性。

如果把 Docker 学成"怎么运行一个容器",把 Kubernetes 学成"怎么写 YAML",最后很容易停留在命令层面。

真正需要掌握的是:

应用如何被打包,容器如何运行,Pod 如何被调度,服务如何被发现,故障如何被恢复,发布如何被验证。

参考资料

相关推荐
xhaxy3 小时前
docker
docker·容器·eureka
上火的金鱼妹5 小时前
K8S基础组件作用和关系整理
linux·运维·服务器·kubernetes
一技安身5 小时前
【信创】Docker‑Compose V2 两种离线部署(独立模式、插件模式)简易教程
java·docker·eureka
鸿观工坊9 小时前
Docker 多阶段构建实践指南
docker
大牧师11 小时前
MySQL 学习教程
数据库·sql·mysql·docker·node·全栈·后端数据
MC丶科12 小时前
软考架构师90天冲刺|DAY44·Redis高级应用
数据库·数据仓库·redis·缓存·oracle·容器·规格说明书
天外天-亮13 小时前
docker + window 安装
运维·docker·容器
进击的小菜鸡dd13 小时前
docker 容器的挂载映射关系查看
运维·docker·容器
SLD_Allen13 小时前
从 HPA 到 KEDA:Kubernetes 弹性伸缩的进阶实践
云原生·容器·kubernetes
程序员老赵14 小时前
Docker 部署 TeX Live:轻松搭建 LaTeX 论文排版编译平台
前端·docker·latex