2026-11-01·by Sijie Wang

kubernetes

Kubernetes(K8s)容器编排

Kubernetes(K8s)是容器编排系统:管理一组服务器上的容器,决定容器跑哪、跑几个、死了怎么办、怎么更新、流量怎么进。

为什么需要它。 一台机器上 Docker Compose 就够了,容器跑哪全靠手写。机器和容器一多,手写就失效了:机器一死,它的容器要找新家;流量一涨,要加副本;没人能靠手跟踪每一个容器。Kubernetes 用声明的期望状态加对账循环代替手写:你声明想要什么,系统持续把现实推向期望状态。

集群全景

一个集群就是一个控制面加一组服务器。用户流量和管理流量走两条线:用户流量不经过 API Server,管理流量不经过 Ingress。

容器

容器就是 Docker 那种容器:一个打包好的进程,带自己的文件系统,用 Linux 命名空间和 cgroup 跟别的进程隔开。 Kubernetes 自己不跑 Docker daemon,它通过容器运行时跑容器,默认是 containerd。Docker 仍是做镜像最常见的工具。

Pod

Pod 是部署的最小单位:一组容器,共享同一个 IP 和可共享的存储卷,调度时整组一起落到一台节点上,不跨节点。 调度单位必须是 Pod 而不是单个容器,因为调度器是按整组算资源账的:两个容器各要 1 核,分开看都放得下,合起来 2 核可能放不下。必须共享网络或存储、同生共死的容器才放进同一个 Pod,典型形状是边车模式:应用容器加一个日志或代理边车。能独立扩缩的服务留在各自的 Pod 里。

Pod 和节点是多对一,不是一对一。 一个 Pod 只落在一台节点上,一台节点上跑很多个 Pod。

节点、kubelet、kube-proxy、CNI

节点就是集群里的一台机器,物理机或虚拟机。 每台节点上跑三个节点级组件。kubelet 是节点上的系统进程,节点的管家:它不是 Pod,也不是容器。 它替控制面在节点上起停容器、跑探针、上报状态。kube-proxy 负责节点上 Service 的转发规则。 容器网络接口(Container Network Interface,CNI)插件给 Pod 分 IP、打通跨节点 Pod 网络。

控制面

控制面是集群的大脑。API Server 是唯一入口:所有读写都经过它,组件之间不直接通信。 etcd 是存整个集群期望状态的分布式键值数据库;控制面其他组件本身无状态,挂了重启能从 etcd 恢复。 调度器决定新 Pod 落哪台节点。 控制器管理器是一组控制器,各管一摊对账:Deployment 控制器管 ReplicaSet、ReplicaSet 控制器管 Pod 数、节点控制器管节点健康、Endpoints 控制器维护那张表。 云环境下还有云控制器,管负载均衡器、节点生命周期这些云厂商相关的活。

期望状态与对账

Kubernetes 里一切都是声明式的:你提交 Deployment、Service 这些对象,控制器跑对账循环,把现实推向声明的期望状态。Deployment 不直接管 Pod,它管 ReplicaSet,滚动更新就是一个 ReplicaSet 缩下去、另一个 ReplicaSet 升上来。

调度

调度是一次性决策。 Pod 一旦被调度到某台节点,正常情况下就待在那儿,Kubernetes 默认不会为了均衡去搬运行中的 Pod。placement 只在 Pod 重建时变:节点故障、驱逐、滚动更新、扩容产生新 Pod。流量本身不搬已运行的 Pod,流量通过扩缩容改变 Pod 数量,新 Pod 才有新的调度决策。

调度器读 Pod 定义,定义里一切都提前写清楚了:每个容器的资源需求、卷、节点选择、亲和性、容忍、端口。它把 Pod 里所有普通容器的 request 加起来作为整组要占的资源,过滤掉不符合条件的节点(资源不够、卷挂不上、有污点、亲和性不合),再打分挑最合适的。临时卷跟 Pod 走,不影响调度;持久卷才影响,因为盘可能只存在于某个可用区、只能挂到特定节点上。两个边界要记住:调度器按声明的 request 算账,不看容器运行时实际用了多少,request 写小了就会把太多 Pod 塞到一台节点上;limit 只管运行时不超用,不管调度。

探针

探针配在容器身上,写在 Pod 定义里每个容器自己的配置中,由所在节点的 kubelet 执行。 就绪探针决定容器进不进 Endpoints 表:起了但还没就绪的容器不接流量。存活探针决定挂了的容器重不重启:它只重启容器,不碰表。就绪管流量,存活管重启。

Service 与寻址

Service 对象就是全部要写的寻址配置,一个服务写一次:名字、对应哪组 Pod 的选择器、调用方用的端口、容器实际监听的目标端口。 默认的 Service 类型就是 ClusterIP,只在集群内有效。调用方代码里写的就是这个名字,不是 IP、不是节点、不是 Pod,这个名字永远不变。

名字背后跑三步:集群域名系统(Domain Name System,DNS)服务 CoreDNS 把名字解析到 ClusterIP;ClusterIP 是虚拟 IP,不对应任何真实网卡,所以不同服务都用 80 端口也不冲突,端口空间是按 IP 分的;kube-proxy 按 Endpoints 表把流量转发到就绪的 Pod。Pod 死了换节点、IP 变了,Endpoints 表自动更新,只有就绪的 Pod 才进表,调用方只认名字,一行代码不用改。

工作负载对象

ReplicaSet 管数量:保证指定数量的 Pod 副本一直跑着,死一个补一个,多了删掉。 它的副本是平等副本,个个都干活,没有主、没有备。高可用和容量是同一机制的两个效果:死一个还有剩下的接流量,N 个副本一起扛流量。ReplicaSet 只管数量、不管版本,一般不直接建,建 Deployment,Deployment 会替你建它、管着它。StatefulSet 管有状态服务:固定名字、固定盘、有序启停,换 Pod 不换盘。 DaemonSet 管每节点一份:每个符合条件的节点上恰好一个 Pod,跟着节点数走,不跟着副本数走,监控 agent、日志收集是典型用途。 Job 是跑完即停的一次性任务,CronJob 是定时版。

Ingress 与内外之分

Ingress 对象是纯配置:一条规则,写清楚哪个域名、哪条路径对应哪个 Service,它自己不收流量、不转发流量。 Ingress Controller 是真正干活的网关:现成的组件,一般是 Nginx、Traefik 跑成的 Pod,里面的控制循环盯着 Ingress 对象、规则一变就重新生成自己的网关配置并 reload,数据面真正收外部流量、按规则转发。 全新集群默认没有 Ingress Controller,得装一次,装好之后它就是集群里的普通工作负载、由 Kubernetes 自己管着。

对外暴露是 opt-in,内网是默认。 没有 Ingress 规则的 Service,外面根本进不来,不用额外配内网。服务和服务之间的调用不走 Ingress:东西向直连,服务 A 直接叫服务 B 的名字,集群 DNS 解析、kube-proxy 转发,Ingress 规则对内网调用完全不起作用。两点诚实补充:默认 Pod 之间是互通的,想真正隔离得加 NetworkPolicy(需要网络插件支持);管理流量(kubectl)不走 Ingress,走跳板机、VPN 或者云厂商的私有端点。

加节点

加节点是热操作:集群一直跑着,API Server、etcd、调度器都不重启,已有的 Pod 也不受影响。 自建集群用 kubeadm(Kubernetes 自带的集群搭建工具),控制面生成一条加入命令,里面有三样东西:API Server 的地址、一个短期邀请码(bootstrap token,有有效期,像一次性邀请码)、控制面证书的哈希(让新节点验明正身,确认自己连的是真的控制面、不是冒充的)。新节点的 kubelet 拿邀请码连上 API Server,做传输层安全协议(Transport Layer Security,TLS)bootstrap:提交证书申请,批下来后领到属于自己的节点证书,以后就用证书认证,邀请码就作废了。节点身份只有节点权限,不是管理员权限。托管集群更简单:调云厂商的 API,给节点池加节点,云厂商的自动化替你跑完加入流程。

新节点一注册(Node 对象进 API Server,kubelet 开始上报心跳),调度器马上把它当成可选节点,空节点在打分上占优,新 Pod 优先往那儿落。但已有 Pod 不自动搬家:SaaS 吃紧的正确操作是加节点加扩副本,手动扩或者配水平扩缩容(HorizontalPodAutoscaler,简称 HPA:按 CPU、内存或自定义指标自动调副本数),新副本调度到新节点上,负载就分流过去了。

全球与边缘

Kubernetes 只管一个集群以内,全球流量调度在它之上。 用户先到全球入口,全球入口选一个集群,然后才是 Kubernetes 的路由。全球层用地理或延迟 DNS 路由、Anycast、全球负载均衡器。两种声明不要混:放置声明(比如节点亲和性说这个服务只跑在欧洲节点上)是 Kubernetes 的事;用户调度声明(比如欧洲用户去欧洲集群)写在全球层(DNS 规则、负载均衡器规则),不在 Kubernetes YAML 里。边缘设备上的 Kubernetes(KubeEdge、k3s 这类轻量发行版)能跑在远端小节点上,但用户流量调度还是外层的事。多集群 Service API 管的是集群之间互相发现服务,不是给最终用户做流量调度的。

平台的平台

Kubernetes 故意做成可编程的:任何软件只要会调 API Server,就能控制 Kubernetes,不用改 Kubernetes 本身。 Operator 是最直接的形态:在集群里跑的控制器,监听自己定义的资源、操作 Kubernetes 对象,比如数据库 Operator 声明一个数据库集群就自动建 StatefulSet、配主从、做备份、故障切换,cert-manager 自动申请、续期 TLS 证书,Argo Rollouts 做金丝雀、蓝绿这些高级发布。第二层是人用的管理工具:kubectl、Dashboard、Lens、k9s,Helm 是给 YAML 打包的包管理器,Argo CD、Flux 是 GitOps 工具,盯着 Git 仓库、仓库里的 YAML 变了就自动同步到集群。第三层是平台层:Rancher、OpenShift、云厂商的托管 Kubernetes,给开发者更简单的界面,底下调 Kubernetes API 干活。

全景补齐

生产还要补几个机制,各一句话。发布旋钮:maxSurge 规定滚动更新最多多建几个,maxUnavailable 规定最多停几个,新版有问题一键回滚。StorageClass:声明要一块盘就自动建,不用管理员预建。自动扩缩三档:水平扩缩容(HorizontalPodAutoscaler,HPA)管副本数,垂直 Pod 扩缩容(Vertical Pod Autoscaler,VPA)管单个 Pod 的 request,Cluster Autoscaler 管节点数。可观测性不是内置的:容器标准输出之外的日志、指标、链路追踪得挂 Prometheus 加 Grafana、Loki 这类外挂。安全补三件:NetworkPolicy 做真正的隔离、Pod 安全上下文、Secret 静态加密(Secret 默认只是 base64 编码,不是加密)。规模再大一档,服务网格(Istio、Linkerd)补灰度、双向 TLS(mTLS)、熔断这些 plain Service 表达不了的东西。

什么时候不用 Kubernetes

Kubernetes 不是默认答案。 服务少、流量小,Docker Compose、Coolify 更划算。升级、运维、排障的复杂度只有规模到了才值。里面也一样:它是一套机制,一个需求对应一个机制,按需组合,不是整套照搬。

一句话收住:每个需求对应一个机制,机制组合起来用。

about this entry

One of sijie's wiki entries. The AI on this site is grounded in the same corpus and answers in sijie's voice, with citations back to entries like this one — answering costs sijie money, so it waits behind a code: enter an access code →