尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Kubernetes核心概念实战梳理:从架构到集群部署

Kubernetes核心概念实战梳理:从架构到集群部署 我当年刚接触 Kubernetes 的时候第一反应是“这玩意儿的核心概念怎么这么多”。Pod、Deployment、Service、Namespace、Ingress……每个名词单独看都能看懂合在一起就懵。后来自己动手装集群、部署应用、排查故障踩了无数坑才算把这些概念真正串成了一条线。坦白讲k8s 的核心概念并不复杂难的是你缺一张“地图”不知道每个概念解决什么问题、放在哪一层、和谁关联。这篇文章我就用自己实际折腾的经验把 k8s 的核心概念按“从底层到上层、从原理到实操”的顺序给你捋一遍。不光讲名词定义还会解释为什么需要它、实际怎么用、常见坑在哪。不管你是准备考 CKA、还是公司要上容器化看完至少能建立起一套完整的心智模型遇到报错也知道往哪个方向查。1. 先从宏观架构说起k8s 到底由哪些“零件”组成在聊 Pod、Namespace 这些抽象概念之前得先搞清楚 k8s 这台“机器”本身长什么样。很多新手看 k8s 文档一上来就学 Pod、Deployment结果连 kube-apiserver 是干嘛的都不知道排障的时候完全无从下手。1.1 控制平面集群的“大脑”k8s 采用主从架构控制平面Control Plane就是集群的大脑负责所有决策和状态管理。我拆解一下核心组件每个组件说人话是什么角色etcd整个集群的“数据库”所有配置、状态、期望值全部存在这里。它选型用的是 Raft 一致性算法保证多节点数据一致。说直白点etcd 就是 k8s 的“账本”集群里发生的一切最终都要落到 etcd 里。这也意味着 etcd 挂了整个集群的管理能力就瘫痪了。kube-apiserver所有组件交互的唯一入口。你可以把它理解成公司的“前台窗口”任何请求——无论是 kubectl 命令、控制器回调、还是节点上报状态——都必须经过 apiserver 校验后写入 etcd。它本身不做业务决策重点是认证、授权、限流和校验。kube-scheduler负责决定“新创建的 Pod 放在哪个节点上”。它像 HR 分配工位依据的是资源请求、节点亲和性、污点容忍等策略。kube-controller-manager一堆控制器的集合。所谓“控制器”就是一个死循环不断对比“当前状态”和“期望状态”然后通过 apiserver 下发指令去修正差异。比如 ReplicaSet 控制器发现 Pod 数量少了就会去创建新的。注意早期版本有个组件叫 kube-discovery、kube-proxy 不在这层别搞混。控制平面的核心就是 etcd apiserver scheduler controller-manager。1.2 工作节点真正干活的地方控制平面只做决策真正运行容器的是工作节点Worker Node。节点上主要有三个组件kubelet每个节点上的“监工”负责管理本节点所有 Pod 的生命周期。它通过 apiserver 监听分配给本节点的 Pod 定义然后调用容器运行时去创建、启停容器并且持续上报节点状态和 Pod 状态。kubelet 出问题节点上的 Pod 就没人管了。kube-proxy负责节点上的网络规则实现 Service 的负载均衡和服务发现。它主要操作 iptables 或 IPVS把访问 Service 的流量转发到对应的 Pod 上。容器运行时Container Runtime真正拉镜像、跑容器的软件最常见的是 containerd也有用 CRI-O 的。Docker 本身也可以通过 cri-dockerd 适配器接入不过现在普遍推荐直接上 containerd层级更少、性能更好、排障也更直接。这里我要特别点一句k8s 和 Docker 不是竞争关系而是分工关系。Docker 负责“单个容器怎么构建、怎么跑”k8s 负责“成百上千个容器怎么调度、怎么协同、怎么自愈”。你可以把 Docker 比作“单台服务器的机箱”而 k8s 是“整个数据中心的操作系统”。理解了这个层次后面学 Pod、Deployment 就顺了。2. 从容器到 Pod理解 k8s 的最小调度单位很多初学者会问一个问题“k8s 为什么不直接调度 Docker 容器非要套一层 Pod”我当初也有同样的疑问直到我亲手部署了一个包含主从架构的 Redis 集群才彻底明白 Pod 这个抽象的必要性。2.1 为什么不能“一个容器一个坑”Docker 容器本身是“孤立”的进程它有自己的文件系统、进程空间、网络栈。但在真实业务里有些场景需要多个进程共享网络栈和存储卷。最典型的例子是“边车Sidecar模式”主容器跑业务逻辑边车容器负责日志采集、流量劫持或者健康检查代理。这两个容器必须住在同一个网络命名空间里共享 localhost否则边车根本拦截不到主容器的流量。Pod 就是 k8s 给出的答案Pod 是 k8s 中调度、创建和管理的最小单元一个 Pod 内可以有一个或多个容器。Pod 内的容器共享同一个网络命名空间、同一个 IPC 命名空间以及可以共享存储卷Volume。也就是说Pod 内部的容器用 localhost 就能互相通信不需要走任何网络代理。2.2 Pod 是“临时演员”不是“正式员工”这是新手最容易踩的认知误区以为 Pod 是长期稳定存在的东西。实际上Pod 的默认设计就是“短命且可替换”的。节点崩溃、资源不足、有人误删Pod 会随时被终止然后控制器会创建一个新的 Pod 替换它。新 Pod 的 IP 地址、节点位置、甚至名字都变了就跟“临时演员”一样。这带来一个关键问题谁来保证 Pod 的数量和存活答案就是工作负载控制器Workload Controller。这里有几张明牌Deployment适合无状态应用。它就管三件事——副本数量对不对、发布新版本、回滚旧版本。Deployment 的典型特征是所有副本可以被随意替换不需要区分身份。StatefulSet适合有状态应用典型如 Redis Cluster、ZooKeeper、MySQL 主从。StatefulSet 会给每个 Pod 一个稳定的网络标识和存储卷Pod 重建后名字和卷都保持不变。我在部署 Redis 集群的时候必须用 StatefulSet因为每个 Redis 节点的角色主/从、数据文件位置都不能乱。DaemonSet适合每个节点都要跑一个副本的场景比如日志采集器 Fluentd、节点监控 Node Exporter。Job / CronJob跑一次性任务或定时任务。拿 Redis 集群举例你用 Deployment 部署 Redis 主从问题不大但一旦 Pod 重建IP 换了客户端缓存的主节点地址就失效了非常痛苦。换成 StatefulSet 之后每个 Pod 有稳定的 DNS 名称比如redis-0.redis-headless.default.svc.cluster.local客户端只需要解析这个稳定域名Pod 怎么迁移都不怕。2.3 Pod 内部细节容器生命周期管理Pod 支持多种容器类型这个在排查问题的时候特别有用Init Container初始化容器在普通容器启动前运行用来做前置准备比如等待数据库就绪、初始化目录权限。Init Container 执行完毕后会被终止不会常驻。普通业务容器你真正运行的应用。Sidecar 容器伴随业务容器常驻提供辅助能力。Pod 的状态也不只是 Running 和 Pending还有 CrashLoopBackOff、ImagePullBackOff、Terminating 等。CrashLoopBackOff是实操中最常见的“噩梦”业务容器一启动就崩溃kubelet 反复重启间隔不断加长直到变成 5 分钟上限。这个和 Docker 原生的 restart 策略不是一个玩意排起来要结合日志和 probe 一起看。3. Namespace集群里的“隔间”“k8s种namespace”这个词条搜索量一直很高原因很简单——Namespace 是你开始多人协作、多环境管理时第一个要搞明白的概念。3.1 Namespace 到底隔离了什么k8s 默认有几个内置 Namespacedefault无状态默认空间、kube-system系统组件驻留、kube-public公开信息、kube-node-lease节点心跳租约。我强烈建议别把业务资源直接塞进default不然过几个月资源列表乱成一锅粥。Namespace 最常见的用途有三层环境隔离dev、staging、prod各占一个 Namespace。有人可能会说“我直接建三套集群不就行了”可以但成本太高。单集群多 Namespace 是成本和隔离的折中。权限隔离通过 RBACRole-Based Access Control把某个用户或 ServiceAccount 的权限限制在指定 Namespace 内。比如开发人员只能操作dev下的 Pod动不了prod。资源配额隔离通过 ResourceQuota 限制一个 Namespace 内所有 Pod 的 CPU、内存总量。这样某个团队不会“吃光”整个集群。LimitRange 则可以设置单个 Pod 的资源上下限防止有人申请 32G 内存却不干活。这里要补一个细节大部分 k8s 资源是 Namespace 级别的但有些资源是集群级别的。比如 Node、PVPersistentVolume、ClusterRole、Namespace 自身就是集群级资源你创建 Pod 时可以用kubectl get nodes看到所有节点这个操作不受 Namespace 限制。而 PVCPersistentVolumeClaim、ConfigMap、Secret、Service 是 Namespace 级别的。要查当前 Namespace 下所有资源用kubectl api-resources --namespacedtrue就能列出清单免得记混。3.2 实操Namespace 里的经典组合拳想真正把 Namespace 用明白你得把它和 Label、Selector 配合起来。比如我在prodNamespace 里部署一套 Redis 集群资源文件头部会写namespace: prod。然后我在 Deployment 的 selector 里配app: redisService 的 selector 也配app: redis。这样 Service 就能自动关联到对应 Pod 上。创建 Namespace命令很简单kubectl create namespace prod或者直接写在 YAML 的 metadata 里。查看 Namespace 资源使用量kubectl top pod -n prod要装 metrics-server 才有数据。切换默认 Namespacekubectl config set-context --current --namespaceprod不然每次命令都要加-n prod容易手滑忘掉导致操作到默认空间。我自己踩过一个坑某次在default空间里创建了一个 ConfigMap结果应用部署到prod后一直报找不到配置文件。后来才发现 ConfigMap 是 Namespace 隔离的根本不会跨空间生效。记住连接 ConfigMap、Secret、PVC 的资源必须和它们在同一个 Namespace 下。这跟环境变量不同跨 Namespace 只能通过“把数据复制过去”的方式处理没有引用机制。4. 安装部署实战Master 初始化不健康的原因排查搜索引擎里关于“k8s控制节点master初始化显示the api server is not healthy after 4m0.00747357s”这类报错的提问特别多。我自己在 Rocky Linux 上装 k8s 的时候也遇到过这个问题这里把经验完整分享出来。4.1 这个报错到底在说什么kubeadm init初始化控制平面时会依次启动 etcd、kube-apiserver、kube-scheduler、kube-controller-manager。初始化完成后kubeadm会执行一个健康检查反复访问localhost:6443/healthz如果 apiserver 在 4 分钟超时时间内没有返回正常状态就报 “the api server is not healthy” 并失败。注意这个报错的根因大概率不是 apiserver 本身而是它依赖的底层东西没就绪。我根据实操经验整理出排查顺序先看 etcd 状态apiserver 启动时必连 etcdetcd 都起不来apiserver 自然会跟着挂。可以用systemctl status etcd或者看容器日志。我用的是 containerd可以用crictl ps -a | grep etcd查看 etcd 容器状态再用crictl logs container_id看日志。最常见的问题是 etcd 容器反复重启原因通常是/etc/kubernetes/manifests/etcd.yaml里的 hostPath 目录不存在或权限不对。检查容器运行时如果用的是 containerd而且系统里同时装了 Docker极容易发生“Docker 创建了容器但 containerd 不认识”的情况。需要确保containerd配置里的sandbox_image指向的 pause 镜像能正常拉取。crictl pull registry.k8s.io/pause:3.9可以手动测试。检查 swap 是否关闭kubelet 默认要求关闭 swap没关会直接报错表现为 kubelet 起不来或者持续 CrashLoopBackOff。查 kubelet 日志journalctl -u kubelet -f --no-pager | tail -n 100这是锁定根因最快的路径。kubelet 日志会明确提到是 CRI 连接失败、还是证书过期、还是节点注册失败。提示如果是虚拟机上测试踩中 4 分钟超时的最常见原因很简单——pause 镜像拉不下来。apiserver 是以容器方式运行的它得先用 pause 镜像创建沙箱pause 镜像拉不动apiserver 永远起不来。所以先确认网络能访问镜像仓库或者提前手动把镜像导入到 containerd。4.2 Rocky Linux 上装 k8s 的额外注意点Rocky 系发行版包括 AlmaLinux、CentOS Stream有个特色就是默认防火墙是 firewalldSELinux 也是 Enforcing 模式这两个东西容易在初始化后导致节点间通信异常。安装阶段建议按这套流程来# 1. 关闭 swap swapoff -a sed -i / swap / s/^/#/ /etc/fstab # 2. 加载内核模块 modprobe overlay modprobe br_netfilter # 3. 写入内核参数 cat EOF | tee /etc/sysctl.d/k8s.conf net.bridge.bridge-nf-call-iptables 1 net.bridge.bridge-nf-call-ip6tables 1 net.ipv4.ip_forward 1 EOF sysctl --system # 4. 配置 containerd 使用 systemd cgroup driver containerd config default | tee /etc/containerd/config.toml # 编辑 config.toml找到 SystemdCgroup改成 true第 4 步的SystemdCgroup是个非常高发的坑。如果 containerd 用的 cgroup driver 是 cgroupfs而 kubelet 用的是 systemd两者直接打架Pod 会一直起不来。在 K8s 1.24 的版本里这个配置是不是对基本决定了集群能不能正常跑。初始化命令本身没啥花样kubeadm init --apiserver-advertise-address控制节点IP --pod-network-cidr10.244.0.0/16注意--pod-network-cidr要跟你选的网络插件匹配。我用的是 Flannel就必须指定10.244.0.0/16如果你用 Calico 默认则可能是192.168.0.0/16。这个网段一旦定下来后面不想改就推倒重来。关于版本你在搜索里会看到类似“1.36”的版本号实际上到本文写作时官方主线还没发布到那个数字但不管版本号怎么变安装流程这几板斧是不变的镜像拉得来、swap 关掉、cgroup driver 对齐、内核转发打开。版本号只是数字把原理搞懂才是真本事。4.3 Master 节点起不来时最有效的三招初始化报错之后先把心理预期放低别指望一把过。我自己的排查套路看容器实例而非镜像crictl ps -a全部容器状态Pending、Exited、Running 一目了然。apiserver 容器若一直ContainerCreating多半是镜像或存储卷问题若CrashLoopBackOff则是启动参数或 etcd 问题。看 kubelet 的“抱怨”journalctl -u kubelet --since 5 min ago。kubelet 比 apiserver 先启动它连接不上 apiserver 也照样会心烦日志里会写得很明白。确认证书和 token如果初始化失败重新来过记得先kubeadm reset -f否则旧证书残留会导致新 apiserver 起不来。很多人的所谓“玄学报错”其实就是 namespace 里残留了上次失败的状态。5. 核心概念关联实战一次 Redis 集群部署全流程聊完安装部署我建议你把前面那些概念放在一个真实场景里再走一遍。我拿 “k8s redis 集群” 来说这是最经典的主从分片案例也最能检验你对 Service、StatefulSet、Headless Service 的理解。5.1 为什么 Redis 集群必须用 StatefulSet Headless ServiceRedis 主从节点各自有身份和数据不能像 Deployment 那样随便替换。StatefulSet 保证每个 Pod 名字固定redis-0、redis-1、redis-2。同时需要给这套 Pod 配一个 Headless ServiceclusterIP: None目的就是去掉负载均衡这层“中介”让客户端能从 DNS 直接拿到每个 Pod 的 IP。我之前遇到的经典错误就是给 Redis 集群配了一个普通 Service结果 sentinel 连上的总是同一个 VIP 后面的某个 Pod根本发现不了全部主从节点。Headless Service 的 DNS 解析会返回所有后端 Pod 的 IP这样 redis-cli 才能感知完整拓扑。5.2 Service 的类型和暴露层级Service 是连接 Pod 与外部流量的桥梁它通过 Label Selector 找到对应 Pod然后提供固定 VIP 和 DNS。新手容易把 Service 和 Ingress 搞混这里我放一张对照表用文字描述不如表格直观类型作用层级典型场景ClusterIP集群内部内部微服务调用默认类型NodePort节点端口对集群外暴露端口范围 30000-32767LoadBalancer云厂商 LB公有云环境自动创建负载均衡器IngressHTTP 路由层按域名/路径转发到不同 Service实际部署时外部访问入口推荐用 Ingress因为 NodePort 会占用大量端口且没有七层路由能力。Ingress 本质上是一组规则真正干活的是 Ingress Controller比如 Nginx Ingress Controller两者别混淆。IngressController 是个常驻 Pod/DeploymentIngress 是规则对象。5.3 运行一个最小 Redis 集群的 Yaml 模板下面我给一个 StatefulSet Headless Service 的最小化模板跑通概念足够apiVersion: v1 kind: Service metadata: name: redis-headless namespace: prod spec: clusterIP: None selector: app: redis ports: - port: 6379 targetPort: 6379 --- apiVersion: apps/v1 kind: StatefulSet metadata: name: redis namespace: prod spec: serviceName: redis-headless replicas: 3 selector: matchLabels: app: redis template: metadata: labels: app: redis spec: containers: - name: redis image: redis:7.0 command: [redis-server] args: [--appendonly, yes] ports: - containerPort: 6379这段配置你把三个核心概念都对应上了Namespace 约束资源范围、Headless Service 固定身份解析、StatefulSet 管理有状态副本。你可以在本地用 kind 或 minikube 起一个单节点集群跑起来试试比只看文档记得牢得多。不要在生产环境直接照抄这个模板Redis 集群还需要 Secret 密码、TLS、持久化存储VolumeClaimTemplate、以及节点亲和性调度否则 Pod 漂移后数据容易丢。生产至少要把 PVC 挂上用volumeClaimTemplates字段而不是把数据写在容器层。6. 常见问题速查概念理解与排障中的高频坑我把平时答疑时遇到的高频问题整理成一个速查表按“症状—原因—排查方向”三列来写方便你直接对照症状常见原因排查/解决方向Pod 一直 Pending节点资源不足kubectl describe pod看事件查节点 CPU/内存水位CrashLoopBackOff 无限重启启动命令错误/探针失败查看logs检查 liveness/readiness 探针配置ImagePullBackOff镜像名写错或镜像仓库不可达crictl images查本地镜像crictl pull手动验证Service 能通但外部访问不了NodePort 端口范围/防火墙检查 kube-proxy 规则iptables -L -nfirewalld 放行端口DNS 解析不到 ServiceService selector 没匹配上 Podkubectl get endpoints看 endpoint 是否被填充StatefulSet Pod 创建不出来Headless Service 不健康检查 service 是否clusterIP: NonePVC 是否 BoundNode 状态 NotReadykubelet 异常systemctl status kubelet看网络插件是否就绪pod 删除后一直 Terminating有挂载卷或 finalizer强制删--force --grace-period0再清 Finalizer你可能会觉得上面这些表里的问题五花八门其实底层逻辑只有一个k8s 是一个声明式系统你告诉它你要什么它不停地把现实往你要的方向拉。一旦没拉过去就会产生偏差反映出来就是状态异常。排查的时候先看“声明”对不对YAML、再看“控制器”Deployment/StatefulSet、最后看“执行者”kubelet/CRI就不会乱。另外很多人问“k8s 学习笔记应该怎么做”。我个人的习惯是概念别背跑一遍记一遍。比如你想搞懂 Namespace 隔离就真的建两个 Namespace分别在里面对应 ConfigMap 和 PVC然后体验一次跨空间报错你想搞懂 StatefulSet 稳定性就删一个 Redis Pod 等着它自动重建观察它的名字和 IP 会不会变。纸上得来终觉浅在容器化领域这句话尤其成立。说句掏心窝的话k8s 的核心难点从不在“某个命令怎么写”而在于你能不能把“控制器思想”内化。刚开始你会觉得这玩意反直觉——为什么一个进程还要来个“期望状态”和“实际状态”的循环调谐可等你真的经历过一次节点宕机后 Pod 自动恢复你才会感叹这套设计有多妙。这篇文章能帮你把地图画出来但真正的路还是得自己走一遍。
返回列表