FEATURED · 精选文章

Kubernetes核心概念与集群部署运维实战指南

发布时间 / 2026/9/11 7:45:36
来源 / 创域科博编辑部
栏目 / 资讯中心
Kubernetes核心概念与集群部署运维实战指南 1. Kubernetes到底是干什么的1.1 从一个运维崩溃现场说起先讲个真实经历。早些年我负责一套微服务系统大概三十多个服务用脚本加配置文件部署在十几台机器上。每次上线都像拆炸弹——先备份、再停服、然后按依赖顺序逐个启动服务、挨个检查健康检查接口。如果哪个服务启动失败脚本不会告诉你为什么只会留一堆半死不活的进程让你自己排查。有一次凌晨三点发布一个服务依赖了另一个还没启动完成的配置中心整个链路全部超时线上直接雪崩。那天晚上我盯着满屏的报错日志脑子里只有一个念头这个活儿不能再这么干了。后来我接触到了Kubernetes也就是很多人常说的K8s这个问题才真正有了系统性的解法。Kubernetes本质上是一个容器编排平台它做的事可以简单概括成两句话你告诉它“我要跑哪些应用、每个应用需要多少资源”它帮你把这些应用调度到合适的机器上并且持续保证它们按你期望的状态运行。你不需要操心具体哪个容器跑在哪台机器上也不需要手动处理应用的扩容、故障转移和负载均衡。我见过不少刚入门的朋友被各种抽象概念绕晕之前其实最缺的就是一个接地气的理解方式。拿滴滴或者高德打比方你只告诉平台从哪儿到哪儿平台自动派单、规划路线、处理拥堵和司机临时取消的情况。Kubernetes就是应用世界的调度平台容器就是那一辆辆网约车而你的应用部署描述文件就是乘客下的单。1.2 为什么Kubernetes成了事实标准很多人会问容器编排工具那么多Docker Swarm、Mesos当年也火过为什么最后是Kubernetes胜出我的理解是它赢在三个方面。第一是声明式管理。你没听错就是那句著名的“你想要什么状态而不是怎么达到这个状态”。在Docker Swarm时代你更多是给系统下发指令——帮我启动三个副本、帮我更新镜像。而Kubernetes里你写一份YAML文件告诉它“我希望这个应用一直保持三个副本在运行”剩下的扩缩容、故障重启、滚动更新全部由控制平面自动完成。这个理念经过这么多年检验确实是最适合大规模分布式系统的。第二是生态极其完整。从服务发现到配置管理、从存储挂载到灰度发布、从监控日志到安全策略Kubernetes周围长出了一个巨大的生态圈。你需要什么能力基本都能找到对应的开源组件不需要自己从零造轮子。第三是社区和厂商的强力背书。几乎所有主流云厂商都提供了托管的Kubernetes服务这也就是说你在本地跑的一套配置上了云基本不用大改。这种可移植性对于企业来说太重要了谁也不想被某一家云厂商锁死。如果你正准备学Kubernetes或者你们团队正在调研容器化改造这篇文章我会尽量站在一个实操过多年集群、踩过无数坑的老兵角度把最核心的概念、部署思路、面试经常问的点、以及运维中的常见问题一次讲清楚。2. 核心概念拆解一句话讲明白一个2.1 PodKubernetes里最小的调度单位很多人学Kubernetes第一个疑惑就是为什么不能直接跑容器答案是Pod比容器更适合作为编排的原子单位。一个Pod里面可以有一个或多个容器这些容器共享同一个网络命名空间、共享存储卷可以通过localhost互相访问。你可以把Pod理解成同一台“虚拟主机”上的多个进程合作小组。比如一个应用容器需要记录日志旁边伴着一个Filebeat容器负责采集日志这两个容器放在同一个Pod里就非常合适——它们生命周期相同、共享网络、共享磁盘协作起来特别顺手。但如果你把一个Web应用和一个数据库放进同一个Pod那就是给自己挖坑因为这俩东西需要独立扩缩容、独立升级绑定在一起非常不利于运维。有个细节值得记住一个Pod通常对应一个主容器。如果只是跑单个容器那Pod和容器基本是一对一的关系。这也就是为什么你用kubectl get pods看到的数量和你期望的副本数一致而不是和容器数一致。2.2 Deployment你真正日常打交道最多的对象Deployment是Kubernetes里最常用的工作负载控制器。你平时说要发布一个应用99%的情况是在定义一个Deployment。它的核心职责是管理一组无状态应用的Pod副本确保任何时候都有指定数量的Pod在运行。打个比方Deployment像一个项目经理它不直接写代码但它负责管着手下那一批“外包员工”——也就是Pod。如果某个Pod挂了它会立刻重新调度一个新的Pod出来顶上如果你需要从3个副本扩到10个副本只需要改一下副本数剩下的它全包了。而且Deployment支持滚动更新默认策略是“先起一个新的、等它就绪、再杀掉一个旧的”整个过程服务不中断。实操中我建议你务必配置好resources字段里的requests和limits。没有资源限制的Deployment就像没有预算上限的项目很容易把一个节点内存吃爆。requests告诉调度器“我需要这么多资源才能跑”limits告诉kubelet“最多只能用这么多资源”。这两个值配好集群稳定性直接上一个台阶。2.3 Service稳定的访问入口Pod的生命周期是短暂的随时可能被重建IP地址也会随之变化。那服务之间怎么互相访问靠Service。Service提供了一组Pod的稳定访问入口它有一个固定的虚拟IPClusterIP和DNS名字。无论后端的Pod怎么变动客户端只需要访问Service的名字或者IP就行了。Service通过标签选择器selector来匹配一组Pod。比如你的应用有多个副本它们都带着app: nginx这个标签那么Service就会自动把流量负载均衡到这些Pod上。这里有一个特别容易踩坑的点Service的selector没写对、或者Pod的标签拼写不一致Service就发现不了任何后端表现为“访问不通但也没报错”。Service有好几种类型ClusterIP、NodePort、LoadBalancer。我用一句话总结一下使用场景集群内部访问用ClusterIP想要外部通过节点IP加端口访问用NodePort在云厂商环境想要自动创建负载均衡器用LoadBalancer。还有更高级的Ingress它工作在七层可以根据域名和路径做路由分发相当于Kubernetes世界里的Nginx。2.4 Namespace多环境隔离的第一道门Namespace提供了资源的逻辑隔离。同一个集群里你可以创建多个Namespace分别对应开发环境、测试环境、生产环境。资源名字在同一个Namespace内唯一在不同Namespace之间可以重名。你还可以通过ResourceQuota给每个Namespace设定资源总量上限防止某个团队把整个集群的资源都占光。在我经手的项目里即使是一个很小的集群我也会建议从一开始就规划好Namespace。不要等业务多了再拆那时候改配置的成本会高很多。但也要注意Namespace不是安全隔离的边界它只是逻辑上的划分。如果有人想在集群内部跨Namespace访问你的Pod默认网络策略下他是可以做到的。真正要做到严格隔离需要配合NetworkPolicy使用。3. 一次完整的Kubernetes集群部署实录3.1 环境准备选择工具与规划资源部署Kubernetes的方式有很多生产环境可以用kubeadm手动搭建本地学习和开发可以用minikube、kind这类轻量工具云上则直接用托管服务。这里分享一套我用kubeadm在裸金属服务器上搭建三节点集群的完整过程这套思路同样适用于虚拟化环境。先规划机器。至少准备三台Linux服务器一台作为控制平面节点master两台作为工作节点node。操作系统我选的是Ubuntu 22.04 LTS内核版本5.15兼容性很好。每台机器的配置最低建议2核4G内存实际上为了跑一些示例应用4核8G会比较舒服。磁盘给个50G以上容器镜像和日志增长快别抠门。以下操作在所有节点上都要执行我精简成关键步骤# 更新系统并安装基础依赖 sudo apt update sudo apt install -y apt-transport-https ca-certificates curl # 安装containerd作为容器运行时 sudo apt install -y containerd sudo mkdir -p /etc/containerd containerd config default | sudo tee /etc/containerd/config.toml # 关键一步启用SystemdCgroup否则kubelet无法正常工作 sudo sed -i s/SystemdCgroup false/SystemdCgroup true/ /etc/containerd/config.toml sudo systemctl restart containerd这里有个我栽过大跟头的坑。如果你不把containerd的SystemdCgroup改成truekubelet会一直报failed to run Kubelet errfailed to run kubelet看起来像是网络问题实际上就是cgroup驱动不一致。这个错误很隐蔽日志里不会直接告诉你原因排查成本特别高。所以一定别忘了这一行。然后关闭swap这个也是硬性要求sudo swapoff -a sudo sed -i /swap/s/^/#/ /etc/fstab3.2 安装kubeadm、kubelet、kubectl并初始化集群继续在所有节点上安装这三个核心组件。注意版本必须一致否则会出现控制平面和工作节点版本不匹配的问题。# 添加Kubernetes官方APT仓库 curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.28/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg echo deb [signed-by/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.28/deb/ | sudo tee /etc/apt/sources.list.d/kubernetes.list sudo apt update sudo apt install -y kubelet kubeadm kubectl sudo apt-mark hold kubelet kubeadm kubectl然后在控制平面节点上初始化集群。这一步会通过kubeadm生成证书、启动控制平面组件API Server、etcd、Controller Manager、Scheduler这个过程需要拉取好几个镜像网络不好时容易超时。sudo kubeadm init \ --apiserver-advertise-address192.168.1.10 \ --pod-network-cidr10.244.0.0/16 \ --kubernetes-versionv1.28.2--pod-network-cidr这个参数非常关键它决定了Pod网络的IP段要和后面安装的网络插件保持一致。我这里选的10.244.0.0/16是为Flannel网络插件准备的。如果你用Calico可能会改成192.168.0.0/16。这个网段不能和你的物理机网段冲突否则会出诡异的路由问题。初始化成功后会有一段提示告诉你如何配置kubectl、如何把工作节点加入集群。按提示执行这几条命令mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config3.3 安装网络插件与加入工作节点集群初始化完成后控制平面节点处于NotReady状态。这很正常因为还没有安装Pod网络插件。Kubernetes本身不负责Pod网络的实现需要借助CNI插件。我习惯用Flannel因为配置简单、适合中小规模集群但如果你对网络性能要求很高或者需要精细化的网络策略Calico是更好的选择。kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml安装完成后等一两分钟再用kubectl get nodes查看节点状态应该变成Ready。工作节点加入集群的命令很简单kubeadm init输出的内容里有一长串kubeadm join命令复制到工作节点上执行就行。sudo kubeadm join 192.168.1.10:6443 --token xxxx --discovery-token-ca-cert-hash sha256:xxxx如果token过期了也不用重新初始化可以通过kubeadm token create --print-join-command重新生成一条完整的join命令。全部节点加入后运行以下命令验证集群状态kubectl get nodes kubectl get pods -n kube-system看到所有节点都是Ready状态核心组件都在Running你的集群就算真正可用了。这一步完成的时候我通常会部署一个nginx测试应用验证一下集群的调度和服务发现是否正常工作而不是急着往上搬业务。4. 高频面试题与答案也是架构设计的必答题4.1 控制平面与工作节点的组件都有哪些面试时只要问到Kubernetes这个问题几乎是必出。我整理一下标准答案同时补充一些自己的理解。控制平面Control Plane由四个组件组成。kube-apiserver是整个集群的入口所有的请求都要经过它它负责认证、授权、准入控制并和etcd通信读写数据。etcd是集群状态的数据库所有配置信息和实际状态都存在这里所以etcd必须做高可用数据也要备份。kube-controller-manager运行着各种控制器比如节点控制器、副本控制器、端点控制器它们负责把集群的实际状态掰向期望状态。kube-scheduler负责决定一个新Pod该放到哪个节点上它会综合资源请求、污点容忍、节点亲和性等因素做决策。工作节点Worker Node上跑三个组件。kubelet是节点上的代理它监听API Server下发的Pod配置确保容器真正运行起来并且健康。kube-proxy负责实现Service的负载均衡规则通过iptables或IPVS把流量转发到正确的Pod。container runtime也就是我们前面说的containerd或者CRI-O负责真正的容器启停和镜像管理。这里我建议你延伸想一个问题如果API Server挂了集群还能继续跑吗答案是已经运行的Pod不会挂因为kubelet不依赖API Server来维持容器运行但它无法接收新的调度指令也做不了健康检查后的重建操作所以集群实际上处于“只能死不能活”的状态。4.2 Deployment、StatefulSet、DaemonSet的区别这三个工作负载的对比也是面试高频题更是日常选型的核心依据。Deployment管理无状态应用每个Pod都是可替换的数据不保留在本地适合Web服务、API后端。StatefulSet管理有状态应用每个Pod有稳定的网络标识和独立的持久化存储适合数据库、消息队列、ZooKeeper这类需要稳定身份的组件。DaemonSet保证集群中每个节点上都有一个Pod副本适合节点监控比如Prometheus Node Exporter、日志采集Fluentd、CNI网络插件这些基础设施组件。面试时如果光背这三个定义很容易被追问到细节。比如面试官会问“StatefulSet里的Pod是怎么保证顺序的”答案是在创建时从0开始依次创建更新时倒序更新删除时也是从最后一个开始删而且每个Pod的名字带有序号比如web-0、web-1。这个设计确保了有状态服务的领导者选举和主从关系能正确建立。4.3 如何实现滚动更新和回滚Deployment的滚动更新机制是Kubernetes的杀手锏之一。默认情况下你只要修改了Deployment的镜像版本它就会自动执行滚动更新——先创建新的ReplicaSet新副本Ready之后旧的ReplicaSet再逐步缩容。滚动更新的两个关键参数是maxUnavailable和maxSurge。maxUnavailable表示更新过程中允许不可用Pod的最大数量默认是25%maxSurge表示允许超出期望副本数的最大数量默认也是25%。这两个值决定了更新速度和可用性之间的平衡。如果追求零中断部署可以把maxUnavailable设为0maxSurge设为1这样系统会先启动一个新Pod再杀一个旧Pod。实操中我建议保留多个版本的ReplicaSet历史记录这样回滚起来非常方便。只需一条命令kubectl rollout undo deployment/myapp --to-revision2但注意如果更新时同时修改了Deployment的多个字段比如镜像版本和资源配额回滚会把所有字段一起回退到指定版本。所以细粒度的发布最好做成一个个小的变更不要一次改一堆东西。4.4 ConfigMap和Secret在使用时有什么关键区别ConfigMap和Secret都是用来向Pod注入配置的区别在于数据敏感性和编码方式。ConfigMap以明文存储配置数据适合环境变量、配置文件这些不敏感的内容。Secret中的数据在etcd里以Base64编码存储注意是编码不是加密适合存储密码、API Key这类敏感信息。这里必须提醒一句很多人以为Secret是加密的这是误解。只要控制了etcd的访问权限或者有get secret权限的人都能轻松解码看到明文。所以生产环境一定要开启etcd加密或者配合外部密钥管理系统比如Vault、云厂商的KMS使用。还有一个常见用法上的坑Pod引用了不存在的ConfigMap或Secret会导致启动失败。这个故障非常隐蔽因为没有明显报错提示你“引用的对象不存在”Pod只会反复处于ContainerCreating状态。排查时一定先检查引用的配置对象是不是真的存在。5. 日常运维中我踩过的坑与排查思路5.1 节点NotReady怎么排查节点突然变成NotReady这个场景只要是运维就一定会遇到。我处理这类问题的标准流程是先看kubelet状态再看容器运行时状态最后看节点资源。具体来说登录到节点上执行systemctl status kubelet查看kubelet是否活着然后journalctl -u kubelet -f实时查看日志。最常见的两个原因第一是节点磁盘空间满了导致kubelet无法正常运行第二是容器运行时挂了或者版本不兼容。如果kubelet日志里出现Failed to connect to containerd那问题大概率出在containerd上。执行systemctl status containerd查看状态如果它也是挂的重启即可。有一次我遇到的情况是containerd进程活着但API通信超时排查到最后发现是磁盘I/O被大量日志写入拖垮了节点上的容器几乎全部卡死。解决方法是前面提到的给日志和数据目录单独挂盘不要和系统盘放在一起。5.2 Pod一直Pending或ContainerCreatingPod卡在Pending状态说明调度器还没有为它找到合适的节点。最常见的原因是资源不足——集群里没有任何一个节点能满足该Pod的CPU或内存请求。排查方法kubectl describe pod xxx查看Events信息里面会明确写着类似0/3 nodes are available: 3 insufficient cpu的调度失败原因。还有一种情况是节点上有污点Taint而Pod没有对应的容忍Toleration。默认情况下控制平面节点是带node-role.kubernetes.io/control-plane:NoSchedule污点的就是不让普通Pod调度上去。如果你想在一个单节点集群上跑业务Pod需要给这个节点加上容忍。Pod卡在ContainerCreating最常见的原因就是镜像拉取失败。如果你在本地没有缓存镜像而且网络环境不好PullImage超时会持续很久。解决思路一是提前把需要的镜像拉到各节点上二是配置好镜像仓库的认证信息通过imagePullSecrets三是如果是私有仓库记得先docker login并创建对应的Secret。5.3 服务访问不通的排查顺序服务访问不通我强烈建议按照“自底向上”的顺序排查不要一上来就去抓包那样效率太低。第一步确认Pod是Running且Ready状态kubectl get pods -o wide第二步确认Service的Endpoint存在kubectl get endpoints my-service如果Endpoints为空说明Service的selector和Pod的标签没对应上。这是我在实际运维中遇到最多的原因。类似app: my-app和app: myapp这种细微差别足够让你排查很久。我的建议是定义Service和Deployment时尽量把标签写规范并且写完后用命令核对一下。第三步进入集群内部测试Service的ClusterIP能不能通kubectl run test-pod --imagenginx -it --rm -- /bin/bash curl http://my-service:80如果集群内部能通外部不通那就要检查Service类型是NodePort还是LoadBalancer以及云厂商的安全组规则是否放行了对应端口。5.4 资源配额与LimitRange的隐藏陷阱给Namespace配了ResourceQuota之后Pod创建失败的频率会明显上升。原因是配额限制的是requests和limits的和而不是实际使用量。举个例子你给Namespace配了4核CPU的配额但每个Pod请求了1核那么最多只能同时运行4个Pod。看起来很简单对吧但如果某个Pod设置了非整数请求比如0.5核那可能跑7个Pod后调度器就开始报配额不足了。还有一个容易忽略的问题如果Namespace里配置了ResourceQuota那么该Namespace内所有Pod都必须显式声明resources字段否则创建时会被拒绝提示failed quota: must specify limits.cpu。这个报错对于开发环境还行但对于已有大量历史应用的环境一下子要给所有应用补资源声明工作量不小。LimitRange则是用来给没有显式设置资源请求的Pod提供默认值的。合理配置LimitRange可以避免“配额卡死但Pod没有默认值”的尴尬。建议在生产集群里每个Namespace都配上ResourceQuota和LimitRange组合使用提前把规范定好。6. 我对Kubernetes学习路径的几点实在建议如果你是从零开始学Kubernetes我特别不建议直接拿个复杂的生产集群来练手那样只会被各种概念淹没。最有效的路径是先在本地用minikube或kind搭一个单节点集群把Pod、Deployment、Service、ConfigMap这几个核心对象玩熟再尝试用kubeadm自己搭一个多节点集群然后逐步引入存储、网络策略、监控这些进阶内容。在学习过程中一定要养成看kubectl describe和kubectl logs的习惯。这两个命令是排查问题的左膀右臂。很多人卡在一个小问题上几个小时大概率是因为连describe都没跑过光在那里猜原因。别问我怎么知道的我也是从那种状态熬过来的。生产环境使用Kubernetes我的建议很简单能用托管服务就用托管服务。自己搭建和维护控制平面的成本远超你的想象etcd备份、证书续期、版本升级每一个环节都藏着坑。云厂商的托管Kubernetes服务把这些都抽象掉了你可以把精力放在业务应用的容器化改造上这才是真正能产生价值的地方。最后说一个我自己的习惯每学一个新特性我都会小规模验证之后再推到生产。Kubernetes的API很强大但也很容易用错。比如Pod的terminationGracePeriodSeconds、preStop钩子、readinessProbe和livenessProbe的区别这些细节用错了不一定马上爆雷但会在大促、发布、节点故障的时候给你来一个措手不及。把基础概念吃透多在生产环境摸爬滚打几次你对Kubernetes的理解会越来越深。
RELATED — 相关阅读

相关资讯

LATEST — 最新资讯

最新发布

TODAY — 本日精选

新闻

WEEKLY — 本周精选

新闻

MONTHLY — 本月精选

新闻