FEATURED · 精选文章

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

发布时间 / 2026/9/6 3:48:09
来源 / 创域科博编辑部
栏目 / 资讯中心
有了Docker为什么还要学K8s?一文讲透容器编排核心价值 这次我们不聊具体工具怎么装而是先解决一个很多人卡了很久的概念问题Docker 我已经用得挺顺手了容器能启动、端口能映射、数据能挂载为什么社区、公司、面试题里还要天天提 K8sDocker 和 K8s 到底是不是二选一的关系先说结论Docker 解决的是“怎么把应用打包成标准单元并跑起来”的问题K8s 解决的是“几百上千个这样的单元如何调度、容灾、升级、对外提供服务”的问题。两者是不同层级的工具不是替代关系。你可以只用 Docker但一旦应用规模变大、节点变多、发布变频繁纯手工维护 Docker 容器会非常痛苦这时候 K8s 的价值就出来了。这篇文章会把 Docker 与 K8s 的定位差异、K8s 解决的典型问题、集群环境下的部署与常用操作讲清楚。文章末尾还整理了从 Docker 过渡到 K8s 的常见问题和排查思路如果你正在准备 K8s 相关学习或面试这篇可以直接收藏。1. Docker 与 K8s 核心能力速览在深入之前先把两者放在一张表里对比后面所有内容都围绕这张表展开。能力项DockerKubernetesK8s定位容器引擎负责镜像构建、容器生命周期管理容器编排平台负责大规模容器的调度和管理核心对象镜像、容器、网络、数据卷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 在单个节点上做的事情非常出色。你写一个 Dockerfilebuild 出镜像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 部署思路现在很多实际业务是 LNMPLinux Nginx MySQL PHP架构或 MySQL 主从架构。这类有状态服务在 K8s 里部署方式与无状态应用差别很大这也是从 Docker 迁移到 K8s 时最容易踩坑的地方。5.1 无状态应用PHP-FPM NginxPHP-FPM 和 Nginx 都是无状态应用适合用 Deployment 部署。典型做法是 Nginx 和 PHP-FPM 分开两个 DeploymentPHP-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 namespaces6.2 部署一个应用首先创建一个 Deployment 文件保存为 nginx.yamlapiVersion: 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/bash6.3 暴露服务对外访问# 将 Deployment 暴露为 NodePort 类型的 Service kubectl expose deployment nginx-deployment --typeNodePort --port80 # 获取 Service 信息 kubectl get svc看到类似80:30080/TCP的输出后就可以通过http://任意节点IP:30080访问 Nginx 服务了。6.4 弹性伸缩# 手动扩容到 5 个副本 kubectl scale deployment nginx-deployment --replicas5 # 查看扩容结果 kubectl get pods # 手动缩容到 3 个副本 kubectl scale deployment nginx-deployment --replicas36.5 滚动更新与回滚# 更新镜像到 1.26 版本 kubectl set image deployment/nginx-deployment nginxnginx:1.26 # 查看滚动更新状态 kubectl rollout status deployment/nginx-deployment # 如果更新失败回滚到上一个版本 kubectl rollout undo deployment/nginx-deployment # 查看历史版本 kubectl rollout history deployment/nginx-deployment6.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 --imagecurlimages/curl -it --rm -- shendpoints 为空是 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 并绑定到 Deploymentkubectl create secret docker-registry regcred \ --docker-serverregistry.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: 512Mi8.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 显存调度、自定义指标伸缩等概念等这篇文章里的内容都掌握了可以往这个方向继续挖。
RELATED — 相关阅读

相关资讯

LATEST — 最新资讯

最新发布

TODAY — 本日精选

新闻

WEEKLY — 本周精选

新闻

MONTHLY — 本月精选

新闻