ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Kubernetes入门:容器编排核心概念与实战指南

Kubernetes入门:容器编排核心概念与实战指南 1. 先说清楚Kubernetes到底帮你解决了什么问题很多朋友学Kubernetes一上来就背一堆名词Pod、Deployment、Service、Ingress……背完一个月问他要拿这玩意儿干嘛还是说不清楚。我今天换个思路先从问题出发——你日常部署应用时是不是经常遇到这些场景用Docker启动了一个Nginx容器结果进程一崩没人帮你拉起来只能等监控报警了再人工处理。业务量涨了想从1个实例扩到10个实例你得手动逐个docker run还得自己写脚本分发流量。发布新版本时希望一次只替换一部分实例、随时可以回滚纯靠脚本写这套逻辑维护成本并不低。多个服务之间怎么互相发现A服务怎么知道B服务的地址变成了什么单个容器规模小的时候靠脚本和人工还能扛。一旦服务数量上到几十个、上百个这些重复劳动就会耗尽你的精力而且出错率极高。Kubernetes就是来解决这一系列问题的——它是一套容器编排系统说白了就是帮你自动化管理容器化的应用。这里最常见的误解是Kubernetes是Docker的替代品。不是的。Kubernetes本身不直接创建容器实例它调度、管理容器底层还得靠容器运行时比如containerd、CRI-O来真正把容器跑起来。你可以把它理解成一个大规模容器运维团队——你告诉它我要10个Nginx副本它就负责把这10个副本拉起、监控、故障重启、流量分发全程不需要你逐台登录服务器操作。Kubernetes最核心的设计思想叫声明式管理Declarative。在传统运维里我们习惯命令式——执行这条命令把服务启动而Kubernetes强调的是描述最终状态剩下的交给它。比如你声明集群里必须有3个Nginx副本在跑当你手动杀掉其中1个控制器会发现实际状态与期望状态不符然后自动补一个新的副本。你不需要写如果进程死了就重启它这样一步步的条件逻辑Kubernetes的控制器会自动帮你维护平衡。这套思想的底层机制叫控制循环Control Loop类似空调的恒温器设定温度期望状态→ 检测当前温度实际状态→ 做调节执行变更→ 循环往复。理解了这个模型后续学到Deployment、ReplicaSet就都能串起来了。所以这篇文章写给谁已经用过Docker、熟悉基本容器概念但还没有系统学Kubernetes的开发者。我会从架构、核心概念、实际部署、常见坑这几个维度带你入门看完之后你至少能明白Kubernetes在干什么并且有能力动手把第一个应用跑起来。2. 骨架拆解控制平面与工作节点各司其职Kubernetes集群一听好像很复杂其实从物理构成上就两大类节点Master节点控制平面和Worker节点工作节点。控制平面负责大脑功能做决策工作节点负责手脚功能真正跑业务容器。2.1 控制平面集群的大脑控制平面通常由三个核心组件组成我一个个说它们各自在干什么。API Serverkube-apiserver整个集群的交通枢纽。所有增删改查操作都要经过它其他组件之间的通信也大多以它为中介。你敲的每条kubectl命令本质上是向API Server发起HTTPS请求。它不做业务调度只负责认证、授权、校验请求并把数据写入持久化存储。没有它整个集群就是瘫的。etcdKubernetes的持久化数据库所有集群状态都存在这里——有哪些节点、有哪些Pod、期望副本数是多少等等。它是一个分布式键值存储采用Raft一致性算法保证数据一致性。需要记住的重点是etcd是整个集群唯一的真理来源source of truth控制平面的控制器们都是拿etcd里的数据做比对的。Schedulerkube-scheduler负责决定新Pod落在哪个节点。它就像一个房产中介手里有各节点的资源剩余清单CPU、内存、磁盘新Pod等同于是个租房需求它根据约束条件比如指定节点、资源请求量和打分策略选出一个最合适的节点。Controller Managerkube-controller-manager集群里的监工。它内部包含一堆控制器Controller比如节点控制器、副本控制器、端点控制器等每个控制器都在做同一件事——盯着当前状态对比期望状态然后不断地把当前状态拉向期望状态。你声明要3个副本ReplicaSet控制器发现当前只有2个就会调API Server再创建一个。2.2 工作节点跑业务的地方工作节点上的组件相对简单核心有这几个kubelet节点上的首席运营官是控制平面在节点上的代理人。它接收API Server下发的Pod定义调用容器运行时创建容器周期性上报节点状态和容器健康状态。一句话所有真正执行容器的动作都由kubelet完成。kube-proxy负责节点上的网络规则维护。它实现Service后面会讲的流量转发通常通过iptables或IPVS规则把发往Service的流量转发给后端的某个Pod。容器运行时Container Runtime真正干活的角色。Kubernetes通过CRIContainer Runtime Interface容器运行时接口与具体运行时交互常见的有containerd、CRI-ODocker也通过docker-shim兼容过新版本已弃用。这里要注意Docker Engine和containerd不是同一个东西在Kubernetes生态里containerd用得更多。这三类组件配合关系是这样的你通过kubectl告诉API Server我要创建一个Deployment→ API Server把数据写入etcd → Deployment控制器发现变化创建ReplicaSet → ReplicaSet控制器算出还差几个Pod → Scheduler为Pod选节点 → 目标节点的kubelet收到指令调containerd拉镜像、启动容器 → kube-proxy维护好网络规则。整个链路清晰且松散耦合。3. 三条核心概念Pod、Service、Deployment先搞明白Kubernetes的概念很多但如果只挑三个必须搞懂的我首推Pod、Service、Deployment。这三个概念一懂其他的大多能顺水推舟。3.1 PodKubernetes里最小的调度单位很多人一开始没转过弯Docker里最小的是容器为什么Kubernetes又搞出个Pod我打个比方。Docker容器像一件衣服穿好就能出门而Pod像一个合租套房里面可以住一个或多个关系亲密的容器。这些容器共享同一个网络命名空间——即共享IP、共享端口范围彼此可以通过localhost直接互通——共享同一个存储卷。为什么要这么设计因为有些业务场景下多个容器必须部署在同一台机器上比如一个主容器负责跑业务逻辑另一个边车Sidecar容器负责收集日志、做代理或健康检查它们之间需要频繁通信、共享数据文件。如果拆到不同机器上通信延迟和数据同步就成了大问题。Pod的典型特点是短暂性Pod可能会因节点故障、资源不足、手动删除等原因被销毁重建重建后IP会变。所以在设计时尽量不要把Pod当成永久的服务节点而要把它当作随时可能被替换的兵。3.2 Service不变的访问入口正因为Pod的IP是飘忽不定的所以需要一个稳定入口去访问一组Pod这个稳定入口就是Service。Service像是一个代理收件地址不管后面仓库里的人员Pod怎么变动、搬到哪个分拣中心节点往这个地址寄件永远都能送达。Service通过Label Selector标签选择器挑选一组Pod作为自己的后端。举个例子你创建了一个Service名叫nginx-service它会拿到一个稳定的虚拟IPClusterIP和对应的DNS名。当其他应用访问nginx-service:80时kube-proxy会通过iptables/IPVS将流量转发给当前匹配标签的某个Nginx Pod。后端Pod增减、崩溃重启对调用方完全透明。Service的类型有四种常用模式我用表格整理一下类型访问方式适用场景ClusterIP集群内部虚拟IP外部无法访问服务间内部调用默认类型NodePort每个节点开放一个静态端口30000-32767需要外部快速访问、测试环境LoadBalancer依赖云厂商负载均衡器分配公网IP生产环境对外提供服务的标准姿势Headless Service无虚拟IP直接返回Pod IP列表需要直连Pod的场景如StatefulSet3.3 Deployment声明期望状态的运维机器人Deployment是你在Kubernetes里最常打交道的资源它负责管理无状态应用的部署和更新。Deployment的职责包括保证副本数声明replicas: 3它就保证集群里始终有3个Pod副本少了就补多了就删。滚动更新Rolling Update发布新版本时它逐个替换旧Pod期间新老Pod共存直到全部替换完成。可以通过参数控制每次最多增加几个、最多不可用几个。回滚Rollback新版本有问题一条命令可以回滚到上一个版本回滚过程同样是滚动执行的。Deployment内部不直接管Pod它管理的是ReplicaSet再由ReplicaSet管Pod。这个层级关系很多人会晕但其实理解起来就一句话ReplicaSet负责维持副本数Deployment负责管理ReplicaSet的版本。滚动更新的背后逻辑其实就是在不断创建新ReplicaSet、缩容旧ReplicaSet。3.4 三者关系怎么串用一个实际场景把三个概念串起来后端团队开发了一个用户服务user-service镜像版本是user-service:2.0。工程师创建了一个Deployment期望3个副本同时创建了一个Service选择标签appuser-service。此时Deployment控制器创建ReplicaSetReplicaSet创建3个Pod。Service通过标签选中这3个Pod分配一个稳定的虚拟IP。前端服务访问user-service:8080kube-proxy把请求转发给任一个Pod。某个Pod突然崩溃ReplicaSet发现副本数不够自动新建一个Pod。Pod的IP变了但Service的虚拟IP和DNS名都没变前端完全无感知。这套机制就是Kubernetes能让业务稳定对外的核心保障。4. 动手实践把Nginx部署到Kubernetes集群概念讲了那么多不动手等于白看。我用一个最经典也最有代表性的例子带大家走一遍把Nginx部署到Kubernetes集群并成功访问它。4.1 准备一个可用环境本地做实验我推荐两种轻量级方案Minikube单机模拟集群适合刚上手的人。它会帮你创建一个虚拟机或使用容器驱动跑整个集群隔离性好命令简单。KindKubernetes in Docker用Docker容器来充当节点启动速度快资源占用少我日常测试首选。安装完环境后先启动集群# minikube 方式 minikube start --cpus2 --memory2048 --driverdocker # kind 方式 kind create cluster --name demo等集群就绪后验证一下节点状态kubectl get nodes能看到Ready状态的节点基本就成功了。提醒一句刚启动时节点可能处于NotReady等一两分钟再查因为各组件在初始化。4.2 创建Deployment跑起Nginx现在我们创建一个Nginx的Deployment副本数为2kubectl create deployment nginx-demo --imagenginx:1.25 --replicas2这条命令做了什么它跟API Server说帮我建一个名叫nginx-demo的Deployment使用nginx:1.25镜像期望2个副本。接下来控制器会自动创建Pod无需你亲自docker run。查看Pod状态kubectl get pods -o wide如果你是第一次拉取Nginx镜像可能要花点时间Pod状态会先显示ContainerCreating过一会儿变成Running。关于nginx:1.25这个tag我顺便说几句我自己加Tag踩过的坑生产环境部署时尽量别用latest。因为latest是动态标签要么会拿不到更新的镜像要么你会意外拉到一个全新大版本导致配置不兼容。最好固定具体的版本号比如nginx:1.25.3并加上镜像摘要digest控制这里先不展开。4.3 用Service提供稳定访问入口Pod已经跑起来了但我们现在没法从集群外部访问它。现在就创建Service暴露服务kubectl expose deployment nginx-demo --port80 --target-port80 --typeNodePort--port是Service对外服务的端口--target-port是后端容器实际监听的端口Nginx默认80。我这里选了NodePort类型方便本地直接用浏览器访问。查看Service情况kubectl get service nginx-demo输出里会有一个PORT(S)列类似80:31567/TCP。其中31567就是NodePort——现在你可以通过http://本机IP:31567访问Nginx了。如果你用的是Minikube需要执行minikube service nginx-demo它会帮你自动打开浏览器并做好转发。如果想快速验证Pod里的内容也可以不用Service直接端口转发kubectl port-forward deployment/nginx-demo 8080:80然后浏览器访问http://localhost:8080。这种方式适合调试但生产环境不能用。4.4 验证弹性自愈能力Kubernetes最值得体验的功能是自愈。我们来做个测试手动杀掉一个Pod看它会不会自动恢复。kubectl delete pod nginx-demo-xxxxxxxxxxPod名用kubectl get pods查到替换成实际的名称。删掉之后马上去kubectl get pods你会看到类似下面的状态旅程一个老Pod变成Terminating同时一个新的Pod出现在ContainerCreating最终又有一个新Pod进入Running且数量始终是2。这正是ReplicaSet控制循环的作用发现实际数比期望数少1立刻补建一个。4.5 水平扩缩容业务高峰期2个副本不够了怎么办一条命令搞定kubectl scale deployment nginx-demo --replicas5再查看kubectl get pods你会看到Pod数量从2变成5而且这些新Pod会均匀分布在集群的各个节点上如果有多节点的话。缩容同样简单把--replicas改小就行。这里有一个新手常犯的错误——扩缩容前没确认资源是否够用。如果你的节点内存只有2G却硬要创建10个Nginx副本每个请求256M内存会导致Pod一直处于Pending状态。Scheduler会找不到足够资源的节点Pod就会排队等待。所以生产环境扩缩容前习惯性看一下资源使用情况kubectl top nodes kubectl top pods这两个命令能看到节点和Pod的实际资源用量判断扩容余量够不够。4.6 滚动更新与回滚假设Nginx 1.26发布了你要平滑升级kubectl set image deployment/nginx-demo nginxnginx:1.26这个命令会触发Deployment的滚动更新创建一个新ReplicaSet逐步替换旧Pod全程服务不中断。你可以多开一个终端窗口连续访问Service的NodePort地址观察更新过程中页面始终能打开。升级完后悔了想回滚kubectl rollout undo deployment/nginx-demo就回到上一版本了。这一套滚动更新回滚机制放在以前靠手工发布流程怎么也要写不少脚本在Kubernetes里是内置能力。5. 别急着啃源码Kubernetes的学习路径建议网上很多人一学就冲到《深入理解Kubernetes源码》这类书去了精神可嘉但顺序有点问题。我见过不少读者源码读了两个月回头问他们kubectl create deployment这条命令是怎么在集群里流转的还是讲不清。所以关于学习路径我说说我的顺序经验。5.1 第一阶段先把用户视角的操作练熟在这个阶段你不需要关心API Server内部怎么实现你需要的是熟练使用kubectl并且理解Kubernetes的核心资源模型掌握Deployment、Service、ConfigMap、Secret、Namespace、Ingress的日常用法。能看懂kubectl describe、kubectl logs、kubectl exec在排查问题时给出的信息。完成至少一次完整的服务部署包括配置注入、存储挂载、服务暴露、滚动更新。达到这个水平你已经能应付绝大多数日常开发部署工作了。5.2 第二阶段从操作上升到机制这时候可以开始读一些机制层面的资料比如客户端缓存机制、控制器的工作模式、调度器的调度策略。很多面试题其实都藏在这些机制里为什么kubectl删除Pod后状态会卡在Terminating很久Pod被驱逐Evicted后它会自动重建吗Service的endpoint更新为什么有延迟为什么很多方案推荐使用kubectl apply而不是kubectl create带着这些实际问题去查资料比死记硬背效率高得多。5.3 第三阶段再来看源码等到你对用户视角机制视角都有感觉了再打开《深入理解Kubernetes源码》这类书你会发现整本书读起来顺畅很多。我个人建议的源码阅读顺序是kubectl命令行先看这条命令如何解析参数、构建REST请求发到哪里。client-goKubernetes官方Go客户端理解informer机制List-Watch和本地缓存这是很多二次开发的基础。kube-controller-manager里的一个具体控制器找一个你熟悉的控制器比如ReplicaSet控制器看它维护副本数的完整逻辑。kube-scheduler看默认调度器的调度流程和打分策略。最后再啃kube-apiserverHTTP处理链路、认证授权、准入控制、etcd存储等。这样做的好处是你对Kubernetes的骨架已经有了认识源码只是在不断印证和深化你的理解。像《深入理解Kubernetes源码》这样的书是很好的答疑者而不是启蒙者。5.4 给坚持要早读源码的朋友几个具体建议有些朋友时间充裕就是想早点读源码我也拦不住那给你几个避坑建议建议选一个固定版本来读不要今天master分支明天v1.28。源码在不同版本之间差异可能很大跳来跳去只会一头雾水。建议选你本地集群版本对应的tag。看代码时带着这条链路的输入和输出分别是什么的问题优先梳理主干流程别陷在某个函数的异常分支里出不来。源码阅读尽量配合动手改代码验证比如fatal()打点日志或者加/去某个判断逻辑跑起来看变化。源码读了容易忘这是正常的不要气馁。真正的作用是建立这个功能大概在哪层实现的直觉后续遇到问题能快速定位。6. 生产环境实战需要提前知道的事前面讲的是入门流程最后这一节我按实战视角把新手最容易忽视但影响很大的几个点集中讲一遍。6.1 资源请求与限制必须设置很多新手写Deployment的时候只写镜像和副本数不写resources。这在测试环境没什么问题一旦上了生产就埋雷。resources.request表示Kubernetes调度Pod时至少要保证给Pod多少资源resources.limit表示Pod最多能用多少资源。如果不设limit一个异常进程可能会把节点内存占满导致同一节点上其他Pod被杀死。如果不设request调度器分配资源时认为它只需要极少的资源可能把所有Pod挤到同一台高配机器上造成资源分布极度不均。我贴一个我常用的配置供参考resources: requests: cpu: 250m memory: 256Mi limits: cpu: 500m memory: 512Mi250m表示0.25个CPU核1Gi表示1Gibibyte约1.073GB注意大小的进制区别。6.2 健康检查探针别偷懒默认情况下Kubernetes认为容器进程活着就代表业务健康——这显然不够。比如一个Java应用进程还在但线程池满了请求大面积超时这算不算健康肯定不算。所以要配置存活探针livenessProbe和就绪探针readinessProbelivenessProbe判断容器是否存活探针失败Kubernetes会重启容器。readinessProbe判断Pod是否可以被纳入Service的后端探针失败时流量不会转发给它。我见过最典型的案例是应用启动需要30秒做缓存预热但没配就绪探针流量一上来就直接打到还没准备好的Pod大量5xx错误。配上健康检查后新Pod没就绪前Service根本不会往它转发流量稳定多了。6.3 命名空间划分和资源配额一个集群可能跑着多个团队的应用如果不用Namespace隔离资源混在一起很难管理。建议按团队或业务域分Namespace并给每个Namespace设置ResourceQuota资源配额防止某个团队不小心创建了大量Pod把集群资源耗尽。查看当前所有命名空间和各资源使用情况kubectl get namespaces kubectl get top pods -A6.4 版本兼容性这个坑我踩过kubectl客户端和集群的版本差距别太大。我早年间试过用新版本kubectl去操作很老的集群莫名其妙报一些奇怪的格式错误。官方政策是——kubectl通常支持当前版本和前后各一个小版本的差异但时间久了就容易出兼容性问题。稳妥的做法是让kubectl版本与集群版本保持一致或接近。6.5 慎用latest镜像标签我在前面部署Nginx时也提过不要在Deployment里用latest标签。原因很实际副本恢复时kubelet不一定每次都重新拉取取决于imagePullPolicy可能拉到一个旧镜像而手动删除重建时可能又拉到最新的镜像导致同一个Deployment的各副本镜像版本不一致排查起来非常痛苦。固定版本号配合hash才是可追溯、可回滚的做法。6.6 数据存储别想当然有状态应用比如数据库和无状态应用在Kubernetes里的待遇完全不同。Deployment管理的Pod都是无状态的——数据一销毁就没了。如果你需要一个数据能持久化的应用请用StatefulSet加存储卷。对于存储卷至少要知道静态供给Static Provisioning和动态供给Dynamic Provisioning的概念前者要自己先创建PVPersistentVolume后者只要在PVCPersistentVolumeClaim里声明存储类StorageClass系统就会自动帮你创建的PV。大多数云厂商都支持动态供给用起来方便很多。7. 补充提一句电子书和官方文档的选择思路最后聊一个辅助性的话题。很多人问《深入理解Kubernetes源码》和其他电子书、官方文档如何取舍。我的态度是电子书适合构建大局观官方文档适合当字典。官方文档的交互教程比如Kubernetes官方文档里的“Learn Kubernetes Basics”适合入门时跟着点一遍。电子书分两类应用类讲如何部署、排障和源码类讲设计和实现。建议先读应用类再读源码类顺序不能反。官方文档的缺点是你一开始往往不知道该查哪一页因为它的结构是面向检索的而电子书是线性的适合从头读到尾。两套资料配合使用先依电子书建立体系遇到具体细节再翻官方文档确认。Kubernetes生态这么大学完概念真的只是万里长征第一步但把上面这些内容吃透你已经具备了在生产环境小心翼翼地用起来的基本功。剩下的事交给时间和实际踩坑来沉淀。
返回列表