news 2026/9/6 3:47:51

有了Docker为什么还要学K8s?一文讲透容器编排核心价值

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
有了Docker为什么还要学K8s?一文讲透容器编排核心价值

这次我们不聊具体工具怎么装,而是先解决一个很多人卡了很久的概念问题:Docker 我已经用得挺顺手了,容器能启动、端口能映射、数据能挂载,为什么社区、公司、面试题里还要天天提 K8s?Docker 和 K8s 到底是不是二选一的关系?

先说结论:Docker 解决的是“怎么把应用打包成标准单元并跑起来”的问题,K8s 解决的是“几百上千个这样的单元如何调度、容灾、升级、对外提供服务”的问题。两者是不同层级的工具,不是替代关系。你可以只用 Docker,但一旦应用规模变大、节点变多、发布变频繁,纯手工维护 Docker 容器会非常痛苦,这时候 K8s 的价值就出来了。

这篇文章会把 Docker 与 K8s 的定位差异、K8s 解决的典型问题、集群环境下的部署与常用操作讲清楚。文章末尾还整理了从 Docker 过渡到 K8s 的常见问题和排查思路,如果你正在准备 K8s 相关学习或面试,这篇可以直接收藏。

1. Docker 与 K8s 核心能力速览

在深入之前,先把两者放在一张表里对比,后面所有内容都围绕这张表展开。

能力项DockerKubernetes(K8s)
定位容器引擎,负责镜像构建、容器生命周期管理容器编排平台,负责大规模容器的调度和管理
核心对象镜像、容器、网络、数据卷Pod、Deployment、Service、Namespace、ConfigMap 等
单机/集群单机为主,Docker Swarm 可做简单集群但能力有限天然面向多节点集群
弹性伸缩需要手动起容器,没有内置自动伸缩支持 HPA 自动伸缩,根据 CPU、内存或自定义指标扩缩容
故障恢复容器挂了不会自动重启到其他机器通过 ReplicaSet 和控制器保证期望实例数
滚动更新需要自己写了脚本或用 Compose 手动更新原生支持滚动更新、金丝雀发布、回滚
服务发现与负载均衡需要自己搭或依赖外部组件内置 kube-proxy 和 Service 机制
配置管理通过环境变量或挂载文件ConfigMap + Secret,支持动态挂载
存储编排支持 volume 挂载,但跨节点数据迁移麻烦PV/PVC 抽象,存储与 Pod 生命周期解耦
学习成本低,几天能上手较高,涉及控制平面、工作节点、网络插件等多个概念
适合场景本地开发、单机部署、CI/CD 构建镜像生产环境多节点、高可用、弹性伸缩、微服务治理

从表格能看出来,Docker 是“工具”,K8s 是“平台”。K8s 本身不构建镜像,它运行的就是 Docker(或其他符合 CRI 标准的运行时)构建出来的容器。

2. 为什么 Docker 足够好,但还是不够?

Docker 在单个节点上做的事情非常出色。你写一个 Dockerfile,build 出镜像,run 起容器,映射端口,挂载数据,一套流程非常顺滑。配合 Docker Compose,你甚至可以用一个 YAML 文件把 Web 服务、MySQL、Redis 一次性拉起来,本地开发体验很好。

但生产环境的问题不是“跑起来”,而是“持续稳定地跑”。

举几个实际场景:

第一,节点故障。假设你有 10 台服务器,每台跑着 20 个容器。某一台服务器硬件损坏或系统崩溃,这 20 个容器就全部不可用了。如果靠人工发现并去其他机器上重新启动,恢复时间取决于你的响应速度,可能十分钟,也可能半天。K8s 的做法是:kubelet 定期上报节点状态,控制平面发现节点失联后,会把该节点上的 Pod 调度到其他健康节点重新创建,整个过程无需人工干预。

第二,流量突增。你的服务突然被大量用户访问,Docker 环境下手动再起几个容器,还要手动改负载均衡配置,操作繁琐且容易出错。K8s 里只需要调整 Deployment 的副本数,或者配置好 HPA,让系统根据 CPU 使用率自动扩容。流量下降后再自动缩容,既保证可用性又节约资源。

第三,发布与回滚。每次更新代码,Docker 环境下的常规操作是:停止旧容器、拉新镜像、启动新容器。这个过程会导致服务短暂不可用。如果更新出问题,还要重新拉旧镜像再启动一次。K8s 的 Deployment 支持滚动更新,默认策略下会先启动一个新的 Pod,等它健康检查通过后再杀掉一个旧 Pod,逐个替换,整个过程中服务不中断。如果更新失败,一条命令就能回滚到上一个版本。

第四,服务发现与负载均衡。Docker 容器重启后 IP 会变化,A 服务要调用 B 服务,如果 B 的 IP 变了,A 就要跟着改配置。这在微服务架构下完全不可接受。K8s 的 Service 资源为一组 Pod 提供稳定的虚拟 IP 和 DNS 名称,Pod 挂了重建,Service 会自动更新后端列表,调用方无感知。

这四个场景就是 K8s 存在的核心理由:自动调度、弹性伸缩、滚动更新、服务发现。

3. K8s 核心架构:控制平面与工作节点

理解了为什么需要 K8s,再来看它是怎么实现的。K8s 的架构可以分成两部分:控制平面(Control Plane)和工作节点(Worker Node)。

3.1 控制平面组件

控制平面是集群的“大脑”,负责做出全局决策。主要组件如下:

  • kube-apiserver:所有组件和 kubectl 命令的入口,提供 REST API,是集群的通信枢纽。
  • etcd:分布式键值存储,保存集群全部状态数据,包括 Pod 信息、配置、期望状态等。etcd 挂了集群就“失忆”了,所以生产环境至少要三节点 etcd 保证高可用。
  • kube-scheduler:负责决定新创建的 Pod 应该放在哪个节点上。调度时会考虑节点资源、亲和性、污点等因素。
  • kube-controller-manager:运行各种控制器,比如节点控制器、副本控制器、端点控制器等。它确保集群的实际状态不断趋向于用户声明的期望状态。

3.2 工作节点组件

工作节点是真正跑业务容器的地方。每个节点上必须有以下组件:

  • kubelet:节点上的“代理人”,负责与 apiserver 通信,管理本节点 Pod 的生命周期,执行启动、停止、健康检查等操作。
  • kube-proxy:维护节点上的网络规则,实现 Service 的流量转发和负载均衡。
  • 容器运行时:真正创建和运行容器的组件,常见的是 containerd,也有用 CRI-O 的,Docker 本身也可以作为运行时,但新版本 K8s 中已不推荐直接依赖 Docker 守护进程。

3.3 核心资源对象

K8s 的一切操作都围绕资源对象展开。以下是最常用的一组:

  • Pod:最小的调度单元。一个 Pod 可以包含一个或多个容器,这些容器共享网络命名空间和存储卷。通常一个 Pod 只放一个主容器。
  • Deployment:无状态应用的控制器。声明期望副本数,管理 Pod 的创建、更新、回滚。绝大多数 Web 服务都是用 Deployment 部署的。
  • Service:为一组 Pod 提供稳定的访问入口。通过 Label Selector 选择后端 Pod,支持 ClusterIP、NodePort、LoadBalancer 三种常见类型。
  • Namespace:逻辑隔离单元。不同团队、不同环境可以放在不同 Namespace 下,避免资源命名冲突。
  • ConfigMap 与 Secret:配置管理。ConfigMap 存放普通配置,Secret 存放敏感信息,两者都可以以环境变量或文件方式挂载到 Pod 中。

4. Docker Compose 与 K8s 的定位区别

很多人在学习时会有一个疑问:Docker Compose 也是用 YAML 描述多容器应用,也能一次启动多个服务,它和 K8s 有什么区别?

简单说,Compose 是单机多容器的编排工具,K8s 是跨节点大规模容器编排平台。

Compose 的 YAML 文件里定义 service、network、volume,然后一条docker compose up -d就能把整套应用拉起来。这在开发环境非常方便。但 Compose 本身不管节点故障、不管自动扩容、不管滚动更新。你在 Compose 里定义了 3 个副本,某一台机器挂了,这 3 个副本不会自动跑到别的机器上。

K8s 中也有类似 Compose 的声明式文件,但描述的资源对象更丰富。比如下面这个文件,描述了一个 Nginx 应用的期望状态:

apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.25 ports: - containerPort: 80

这份 YAML 的含义是:我希望集群中有 3 个带有app: nginx标签的 Pod,每个 Pod 运行一个 nginx:1.25 容器。提交给 K8s 后,控制平面会保证集群里始终有 3 个这样的 Pod 在运行。如果你手动删掉一个,控制器会马上创建一个新的补上。

再配合 Service 暴露访问入口:

apiVersion: v1 kind: Service metadata: name: nginx-service spec: selector: app: nginx ports: - protocol: TCP port: 80 targetPort: 80 type: NodePort

这条 Service 会把集群内所有标签为app: nginx的 Pod 自动纳入负载均衡池。Pod IP 无论怎么变化,这个 Service 的访问入口始终保持稳定。

5. K8s 集群环境下的 LNMP 与 MySQL 部署思路

现在很多实际业务是 LNMP(Linux + Nginx + MySQL + PHP)架构或 MySQL 主从架构。这类有状态服务在 K8s 里部署方式与无状态应用差别很大,这也是从 Docker 迁移到 K8s 时最容易踩坑的地方。

5.1 无状态应用:PHP-FPM + Nginx

PHP-FPM 和 Nginx 都是无状态应用,适合用 Deployment 部署。典型做法是 Nginx 和 PHP-FPM 分开两个 Deployment,PHP-FPM 通过 Service 暴露给 Nginx 调用。这里的思路是:Nginx 的配置里不再是写死 PHP-FPM 的 IP,而是写 PHP-FPM 这个 Service 的 DNS 名称。

如果 Nginx 和 PHP-FPM 需要共享代码目录,使用 NFS 或对象存储挂载到两个 Pod 上。这里强调一下,不要把代码打进镜像。代码应该挂载到共享存储里,这样更新代码时只需要重新挂载即可,不需要重新构建镜像。

5.2 有状态应用:MySQL 主从

MySQL 这类数据库不能直接用 Deployment 部署,因为每个 Pod 的存储必须独立,并且实例之间需要稳定的网络标识。K8s 提供了 StatefulSet 来解决这个问题。

StatefulSet 的特点是:每个 Pod 有固定的名称和稳定的网络标识,Pod 重建后名称不变,存储卷也不会被删除。

MySQL 主从在 K8s 中的常见方案有两种:一种是手动部署一主一从两个 StatefulSet,通过配置指定主从关系;另一种是使用 Operator 自动化管理,比如 Percona Operator 或 KubeBlocks。Operator 本质上是一个扩展控制器,能感知 MySQL 集群状态,自动处理故障切换、备份恢复等复杂逻辑。

如果你刚入门,建议先从手动方式开始,理解 StatefulSet 的存储和网络行为后再考虑 Operator。

5.3 Single Node 场景:K8s 单节点部署

如果你只是想学习 K8s,不打算一开始就搭多节点集群,可以用以下方式快速入门:

  • Minikube:本地单节点集群,适合学习和开发测试。
  • Kubeadm:官方推荐的集群搭建工具,支持单节点控制平面和工作节点合并部署。
  • Kind:把 K8s 集群跑在 Docker 容器里,适合 CI 环境。

单节点集群能覆盖大部分学习场景,比如 Deployment 发布、Service 暴露、ConfigMap 使用等。但生产环境的高可用能力(节点故障迁移、多副本调度)在单节点上是体验不到的。

6. K8s 常用命令与实际操作示例

这里整理一套从零开始的操作流程。假设你已经通过 kubeadm 或 Minikube 搭好了一个 K8s 集群,并且 kubectl 已经配置好。

6.1 查看集群状态

# 查看节点信息 kubectl get nodes # 查看节点详细信息 kubectl describe node <node-name> # 查看所有 Namespace kubectl get namespaces

6.2 部署一个应用

首先创建一个 Deployment 文件,保存为 nginx.yaml:

apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.25 ports: - containerPort: 80

然后执行:

# 提交资源定义到集群 kubectl apply -f nginx.yaml # 查看 Deployment 状态 kubectl get deployment # 查看 Pod 列表 kubectl get pods -o wide # 查看 Pod 日志 kubectl logs <pod-name> # 进入 Pod 内部排查 kubectl exec -it <pod-name> -- /bin/bash

6.3 暴露服务对外访问

# 将 Deployment 暴露为 NodePort 类型的 Service kubectl expose deployment nginx-deployment --type=NodePort --port=80 # 获取 Service 信息 kubectl get svc

看到类似80:30080/TCP的输出后,就可以通过http://任意节点IP:30080访问 Nginx 服务了。

6.4 弹性伸缩

# 手动扩容到 5 个副本 kubectl scale deployment nginx-deployment --replicas=5 # 查看扩容结果 kubectl get pods # 手动缩容到 3 个副本 kubectl scale deployment nginx-deployment --replicas=3

6.5 滚动更新与回滚

# 更新镜像到 1.26 版本 kubectl set image deployment/nginx-deployment nginx=nginx:1.26 # 查看滚动更新状态 kubectl rollout status deployment/nginx-deployment # 如果更新失败,回滚到上一个版本 kubectl rollout undo deployment/nginx-deployment # 查看历史版本 kubectl rollout history deployment/nginx-deployment

6.6 删除资源

# 删除 Deployment,连带删除它管理的全部 Pod kubectl delete deployment nginx-deployment # 删除 Service kubectl delete svc nginx-service

注意:kubectl delete会直接删除资源,没有任何确认提示,生产环境操作前务必确认资源名称。

7. K8s 故障排查与解决方法

K8s 排查问题的难度比 Docker 高一截,因为涉及组件更多。下面按「应用层 -> 网络层 -> 集群层」梳理排查路径。

7.1 Pod 一直 Pending

现象:kubectl get pods显示 Pod 状态为 Pending,没有变成 Running。

可能原因:

  • 集群资源不足,没有节点能满足 Pod 的 CPU/内存请求。
  • 存在节点亲和性或污点限制,Pod 无法调度到任何节点。
  • 节点上有资源配额限制。

排查方式:

kubectl describe pod <pod-name>

输出里会明确写出调度失败的原因,比如0/3 nodes are available: insufficient cpu。解决方式就是扩容节点、下调资源请求配置,或修改亲和性规则。

7.2 Pod 一直 CrashLoopBackOff

现象:Pod 反复创建又崩溃,状态为 CrashLoopBackOff。

可能原因:

  • 容器启动命令错误或应用启动即退出。
  • 启动依赖的配置缺失,比如 ConfigMap 没挂载对。
  • 健康检查探针配置不合理,应用还没就绪就被判定为错误。

排查方式:

# 查看完整事件信息 kubectl describe pod <pod-name> # 查看容器日志 kubectl logs <pod-name> --previous

--previous参数很关键,Pod 崩溃后当前日志可能已经为空了,加了这个参数才能看到容器上一次运行的输出。

7.3 Service 无法访问

现象:Pod 都正常,但通过 Service 访问不通。

排查思路按顺序进行:

# 1. 检查 Service 是否选中了正确的 Pod kubectl get endpoints <service-name> # 2. 如果 endpoints 为空,说明 selector 标签没匹配上 kubectl describe svc <service-name> # 3. 检查 Pod 标签 kubectl get pods --show-labels # 4. 进入集群内测试 Service DNS 解析 kubectl run curl-test --image=curlimages/curl -it --rm -- sh

endpoints 为空是 Service 不通的最常见原因,基本都是 selector 里的标签写错了。

7.4 节点 NotReady

现象:kubectl get nodes显示节点处于 NotReady 状态。

可能原因:

  • 节点上的 kubelet 服务停了。
  • 节点资源耗尽。
  • 网络插件问题导致节点与控制平面通信异常。

排查方式:

# 查看节点事件 kubectl describe node <node-name> # 登录到该节点,查看 kubelet 状态 systemctl status kubelet # 查看 kubelet 日志 journalctl -u kubelet -f

节点 NotReady 时,控制平面会等待一段时间后把该节点上的 Pod 调度到其他节点。如果集群只有这一个节点,Pod 会一直处于 Pending 状态,直到节点恢复。

7.5 镜像拉取失败

现象:Pod 状态为 ImagePullBackOff。

可能原因:

  • 镜像名或标签写错。
  • 私有仓库需要认证信息,Pod 没有配置 imagePullSecrets。
  • 节点无法访问镜像仓库,尤其是国内访问部分公共仓库不稳定时。

排查与解决:

kubectl describe pod <pod-name>

输出里会显示拉取失败的具体原因。如果是认证问题,创建 Secret 并绑定到 Deployment:

kubectl create secret docker-registry regcred \ --docker-server=registry.example.com \ --docker-username=<用户名> \ --docker-password=<密码> # 在 Deployment 的 template 下增加 imagePullSecrets 配置
spec: template: spec: imagePullSecrets: - name: regcred containers: - name: app image: registry.example.com/app:v1

国内访问公共镜像仓库慢的问题,可以通过配置镜像加速器或使用自建仓库方案解决,这部分内容按实际环境调整即可。

8. 从 Docker 到 K8s:最佳实践与建议

8.1 先保持 Docker 习惯,再渐进式引入 K8s

不要把已有业务一次性全部迁移到 K8s。建议路径是:先保持 Docker Compose 支撑现有业务,同时搭一套 K8s 测试环境,把非核心服务先迁过去跑一段时间,验证稳定后再扩大范围。

8.2 给容器加上资源请求与限制

K8s 调度器依赖容器的资源请求(requests)来做调度决策,不设置 requests 会导致调度失衡。同时设置 limits 防止单个 Pod 耗尽节点内存。建议所有 Deployment 都显式配置这两个参数:

resources: requests: cpu: 100m memory: 128Mi limits: cpu: 500m memory: 512Mi

8.3 使用 ConfigMap 管理配置,不要把配置打进镜像

镜像只包含应用代码和基础环境,环境相关的配置全部放到 ConfigMap 和 Secret 中。这样同一份镜像可以在测试、预发、生产三个环境复用,只是挂载的配置不同。

8.4 设计好健康检查探针

K8s 默认情况下只检查容器进程是否存活,进程活着但应用可能已经无法响应请求了。给关键服务配置 livenessProbe 和 readinessProbe,尤其是 Web 服务,让 K8s 能准确感知服务真实状态。

8.5 有状态服务单独管理

MySQL、Redis、Elasticsearch 这类有状态服务,不要和无状态应用混在一起用 Deployment 部署。优先使用 StatefulSet 或成熟的 Operator 方案。如果数据量不大且对可用性要求不高,初期也可以继续用云数据库托管服务,减少运维压力。

8.6 关注权限边界

K8s 的 RBAC 权限模型比较复杂。初期可以先用 Namespace 做逻辑隔离,不同团队使用不同 Namespace,避免互相影响。给 CI/CD 系统配置独立的 ServiceAccount,只授予所需的最小权限,不要直接使用管理员证书。

8.7 日志和监控要提前规划

没有日志和监控的 K8s 集群,出问题排查会非常痛苦。建议在集群搭建初期就部署指标监控和日志采集方案,至少要保证 kubelet 日志、容器 stdout 日志、kube-apiserver 审计日志都能留存。常用的开源方案有 Prometheus 生态和 Loki 日志栈,具体选型按团队熟悉度来定。

9. 什么时候不需要 K8s?

也来明确一下反面场景。不是所有项目都适合上 K8s,以下情况可以继续用 Docker 或 Docker Compose:

  • 单机部署的个人项目或内部工具,没有多节点需求。
  • 应用实例数常年只有 1 到 2 个,没有自动扩容需求。
  • 没有专职运维或对基础设施不熟悉的小团队。
  • 项目生命周期短,上线一次后很少更新。

K8s 是有学习成本和运维成本的。控制平面组件、网络插件、存储插件、证书管理、升级维护,每一项都需要人力和时间去维护。如果你的业务用 Docker Compose 就能稳定跑,没必要为了“技术先进”强行引入 K8s。

10. 总结

回到题目本身:有了 Docker,为什么还要 K8s?答案不是“Docker 不好”,而是“单机工具无法解决集群问题”。Docker 把应用标准化为镜像和容器,K8s 在标准化的基础上提供了调度、伸缩、自愈、滚动更新、服务发现等平台级能力。两者是协作关系,Docker 负责“打包”,K8s 负责“编排”。

如果你正在学习 K8s,第一步别急着部署集群。先用 Docker 把容器、镜像、数据卷、网络这些基础概念吃透,再通过 Minikube 或 kubeadm 搭一套单节点集群,按本文第三节和第六节的流程把 Deployment、Service、滚动更新依次跑一遍。跑通之后再尝试模拟故障场景:删掉一个 Pod 看它怎么恢复,更新镜像看它怎么滚动,把节点停掉看它怎么迁移。这些实验做完,你对 K8s 的理解会比看十篇原理文章都深入。

最后留一个可以继续深入的方向:K8s 的 GPU 调度与 AI 推理服务部署。当前很多团队把模型推理服务跑在 K8s 上,利用其弹性伸缩和资源调度能力管理 GPU 资源。这一步涉及 Device Plugin、GPU 显存调度、自定义指标伸缩等概念,等这篇文章里的内容都掌握了,可以往这个方向继续挖。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/6 3:47:26

AI模型部署测试指南:从环境配置到性能验证全流程

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/6 3:46:54

海信ES60-DY10Pro电热水器评测:60L容量与3200W功率详解

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/6 3:42:55

SMC打击垫与FM-1合成器联动全攻略:从MIDI映射到音色设计

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/6 3:38:51

ABAP程序源代码批量导出:基于RPY_PROGRAM_READ的完整实现方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/6 3:33:33

MySQL主库出问题了,从库怎么办?备库为什么会延迟好几个小时?

课程&#xff1a;B站大学 记录学习极客时间团队MySQL45讲&#xff0c;进阶数据分析和数据处理 MySQL主库和备库备库为什么会延迟好几个小时&#xff1f;一、问题背景coordinator 分发的两点基本要求二、MySQL 5.5&#xff1a;按表分发 & 按行分发2.1 按表分发策略2.2 按行分…

作者头像 李华