Kubernetes 到现在已经成了容器编排领域的绝对霸主,换个角度看,现在的后端工程师要是不会点 K8s,出门都不好意思跟人打招呼。咱们这篇文章就基于目前最新的稳定版 Kubernetes 1.31(2024年8月刚发布)来聊,这个版本保持了 K8s 一贯的 4 个月一个迭代周期的节奏,稳定性没得说。
很多新手一上来就被 Master 节点、Worker 节点、API Server 这些词给整懵了。咱们换个思路,把 K8s 集群想象成一个厨房。
控制平面就是厨房的大厨,负责决策。它跑在 Master 节点上,核心组件都在这里:
灶台就是真正干活的地方,也就是我们的服务器。上面跑着两个关键东西:
在 K8s 里,我们不直接操作容器,而是操作“对象”。
现在很多公司在搞微服务架构,把大单体拆成小服务,用 K8s 管理这些服务的生命周期简直是绝配。另外,AI 训练也是 K8s 的大热门,特别是 2024 年这个节点,K8s 对 GPU 资源的调度越来越强,跑 TensorFlow 或者 PyTorch 的分布式训练任务特别合适。
🔧 实战技巧:
刚入门别去折腾二进制安装,直接上 Minikube 或者 Kind。Minikube 是在本地起一个单节点的 K8s 虚拟机,非常适合开发测试。除非你是做运维的,否则没必要在初期死磕集群搭建,那样只会消磨你的耐心。
既然咱们聊的是实战,那第一步肯定得把环境整起来。虽然最新的 K8s 1.31 刚出,但咱们本地开发用 Kind (Kubernetes in Docker) 是最快的,它不需要你装一堆虚拟机,直接利用 Docker 容器模拟节点,特别轻量。
首先你得有个 Docker 环境。然后安装 Kind 和 kubectl。
如果你用的是 Mac,直接用 brew:
`bash
brew install kubectl
`
Windows 用户可以用 Chocolatey 或者去 Kubernetes 官方 GitHub Release 页下载二进制文件。
咱们直接创建一个基于 K8s 1.31 的集群(如果 Kind 的镜像支持的话,或者指定最新的稳定版)。
`bash
# 安装 Kind
brew install kind
# 创建一个集群
kind create cluster --name my-k8s-demo
`
这一步会自动把配置写入你本地的 ~/.kube/config 文件。打个比方,这个文件就是你的通行证,kubectl 读取这个文件就知道该去连哪个集群了。
运行下面的命令,看看能不能拿到节点信息:
`bash
kubectl cluster-info
kubectl get nodes
`
如果看到 my-k8s-demo-control-plane 处于 Ready 状态,恭喜你,环境搞定了。
光有环境不行,咱们得跑点东西。很多人以为直接写个 Pod 文件就完事了,其实在生产环境,我们很少直接裸跑 Pod,因为 Pod 挂了就没了。但为了理解调度,咱们先看看 Pod 是怎么被分配到节点上的。
咱们写一个最简单的 Nginx Pod 定义文件 nginx-pod.yaml:
运行它:
你会看到 Pod 被调度到了 my-k8s-demo-control-plane 这个节点上。
K8s 的调度器(Scheduler)很聪明,但有时候我们需要手动干预。比如,我想让数据库跑在有 SSD 的机器上,或者不想让普通的 Web 服务跑在 Master 节点上。
这就涉及到了污点(Taints)和容忍(Tolerations)。Master 节点默认是有污点的,意思是“我很高贵,一般的 Pod 别来烦我”。
咱们试着给 Pod 加个容忍度,让它也能跑在 Master 上(虽然通常不推荐,但咱们为了演示):
⚡ 效率提示:
在本地用 Kind 或者 Minikube 的时候,经常遇到镜像拉取失败的问题(ImagePullBackOff)。核心要点:如果你用的是私有镜像或者网络不好,记得先 docker pull 把镜像拉下来,然后 Kind 支持直接把本地镜像加载进去:kind load docker-image nginx:1.25 --name my-k8s-demo,这样部署速度飞快,还能避开网络限制的坑。
上一章咱们跑了裸 Pod,但在真实项目里,那简直是自杀行为。想象一下,你的服务挂了,你得手动去重启;你想更新代码,得手动删掉旧的再建新的。这谁受得了?所以,咱们必须请出 Deployment。
Deployment 是 K8s 里管理无状态应用的核心。它不仅能帮你维持指定数量的 Pod 副本(比如你定义 3 个,它哪怕死了一个也会给你拉起一个新的),还支持滚动更新。
换个角度看,Deployment 就是个“监护人”。它下面管着 ReplicaSet(副本集),ReplicaSet 再管着具体的 Pod。这种层级结构保证了应用的高可用性。
假设我们有一个简单的 Go 微服务,镜像名叫 my-go-app:v1。咱们写一个 deployment.yaml。
运行部署:
你会看到 3 个 Pod 在启动。
Pod 有了,但是它们的 IP 是集群内部的,外网访问不到,Pod 之间互相访问也不方便。这时候就需要 Service 了。
K8s 的 Service 有几种类型,咱们得根据场景选:
咱们这里为了演示,用 NodePort 暴露服务,创建一个 service.yaml:
部署并查看:
你会看到一个 PORT(S) 列,显示类似 80:31234/TCP。这时候你可以通过 localhost:31234(如果是本地 Kind 集群,可能需要额外端口映射,或者直接用 kubectl port-forward)来访问服务。
咱们把镜像升级到 v2:
这时候 K8s 会滚动更新,先起一个新的,再杀一个旧的,保证服务不中断。
如果 v2 有 Bug,想回滚?一行命令搞定:
⚡ 效率提示:
写 YAML 文件的时候,千万别手写。强烈建议使用 Kustomize 或者 Helm。Kustomize 已经内置在 kubectl 里了,可以帮你管理不同环境(开发、测试、生产)的配置差异。另外,记得给容器加上 resources(资源限制),不限制 CPU 和内存的话,一个 Pod 跑飞了可能会把整个节点搞崩,这就是 K8s 的 QoS 机制在起作用,资源限制越明确,Pod 越不容易被驱逐。
你的服务跑起来了,但这才刚开始。如果流量突然暴涨怎么办?人工盯着扩容肯定来不及。K8s 提供了 HPA(Horizontal Pod Autoscaler) 来解决这个问题。
HPA 个自动伸缩器。它会监控你的 Pod 指标(比如 CPU 使用率),如果超过了阈值,它就自动增加 replica(副本数);如果降下来了,它就自动缩容。
注意:HPA 依赖 Metrics Server 来收集指标。在 Kind 集群里,你可能需要手动安装它。
`bash
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
`
如果因为证书问题起不来,可能需要给 deployment 加个 --kubelet-insecure-tls 参数,这是本地测试常用的“实战经验”解决方案。
咱们给刚才的 go-microservice 配置一个 HPA,目标是 CPU 使用率超过 50% 就扩容,最多扩到 10 个副本。
创建一个 hpa.yaml:
`yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: go-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: go-microservice
minReplicas: 1
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
`
应用它:
`bash
kubectl apply -f hpa.yaml
kubectl get hpa
`
现在你可以用压测工具(比如 ab 或 hey)去打你的服务,观察 Pod 数量的变化:
`bash
kubectl get pods -w
`
虽然我们之前用了 NodePort,但在生产环境,你不可能给每个微服务都开一个 NodePort。我们需要一个统一的入口,这就是 Ingress。
Ingress 是 K8s 的七层负载均衡(HTTP/HTTPS)。它根据域名和路径把流量转发到不同的 Service。
最新趋势:现在社区里 Gateway API 很火,被认为是下一代的 Ingress 标准,功能更强大。但 Ingress 目前依然是主流,咱们先搞定它。
要用 Ingress,你得先有个 Ingress Controller。Kind 里可以用 Nginx Ingress Controller。
`bash
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml
`
假设我们想通过 demo.local 这个域名访问我们的服务。
创建 ingress.yaml:
`yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: demo-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- host: demo.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: go-service
port:
number: 80
`
部署后,修改你本地的 /etc/hosts 文件,把 demo.local 指向你的集群节点 IP(如果是 Kind,通常指向 127.0.0.1 或者配合 port-forward 使用)。
然后访问:
`bash
curl http://demo.local
`
在 2024 年的 K8s 生态里,传统的网络方案(像 Flannel)正在被基于 eBPF 的技术取代,比如 Cilium。Cilium 利用 Linux 内核的新特性,让网络性能更好,安全性更高。如果你在搭建新集群,可以关注一下 Cilium 作为 CNI 插件的方案,这绝对是未来的主流方向。
💡 经验总结:
调试 HPA 和 Ingress 的时候,最头疼的是不知道为什么没生效。
kubectl describe hpa go-hpa,里面会告诉你为什么没扩容(比如 Metrics Server 没数据)。kubectl logs -n ingress-nginx ...),流量到底有没有进来,转发规则对不对,日志里一目了然。别光盯着你自己的应用日志看,那是没用的。可以这么理解,咱们写代码的最终目的还是为了上线跑起来。在 Kubernetes 这么一个复杂的集群环境里,你要是还靠手动敲 kubectl apply,那迟早得累死或者背锅背死。现在的主流玩法就是 CI/CD,而且最近社区里吵得火热的 GitOps 已经是事实上的标准了。
咱们先聊聊老牌劲旅 Jenkins。虽然现在都说 Jenkins 有点"老"了,但在很多公司里它依然是主力。结合 Kubernetes 1.31 这种新版本,我们通常会用 Jenkins 的 Kubernetes Plugin 来动态生成 Slave Pod。这意味着你跑构建任务的时候,K8s 才会临时起一个 Pod,跑完就销毁,资源利用率杠杠的。
不过,作为混迹圈内 5 年的开发者,我更推荐你关注 GitOps。这玩玩意儿的核心思想就是:Git 仓库里的状态就是真理。你不需要在 Jenkins 里写一堆复杂的脚本去调 K8s API,而是让一个控制器(Controller)去盯着你的 Git 仓库。目前社区里最火的两个工具就是 Argo CD 和 Flux CD。根据 2024 年的社区讨论热度,Argo CD 的 UI 界面更友好,上手更快,而 Flux CD 更偏向于云原生底层一些。
咱们直接上实战,看看怎么用 Argo CD 实现声明式交付。
假设你已经有一个K8s集群(1.31版本也没问题,向下兼容很好),先装 Argo CD:
装完后,咱们得有个应用配置。这里我写一个简单的 Application 资源定义。这就相当于告诉 Argo CD:嘿,去那个 Git 仓库把那个文件夹里的配置给我同步过来。
💡 经验总结:这里值得留意的是,,selfHeal: true 这个配置非常关键。简单来说,就是防止有人手贱去集群里手动改配置。只要 Git 里没改,Argo CD 发现集群状态和 Git 不一致,就会自动把它改回来,这叫"自我修复",跟 K8s 本身的机制异曲同工。
对比一下 Jenkins 的传统流水线(Pipeline)和 GitOps:
kubectl。现在大家都在搞 平台工程(Platform Engineering),很多团队基于 K8s 构建内部开发者平台(IDP),GitOps 就是这块的基石。你只需要把 YAML 丢进 Git,剩下的交给平台,这才是极致的开发体验。
另外,实际案例经验之谈:如果你用的是 Jenkins 且集成了 Docker 构建,记得现在 K8s 早就弃用 Dockershim 了。别再折腾 Docker in Docker (DinD) 了,直接上 kaniko 或者 buildah 在 Pod 里构建镜像,这才是正道。
---
做运维或者开发,最怕半夜报警说服务挂了。很多时候不是你代码崩了,而是 K8s 在"清理门户"。这一章节咱们聊聊两个容易让人懵圈的话题:Pod 驱逐和 CNI 选型。
先说 Pod 驱逐(Eviction)。可以这么理解,这事儿是 kubelet 干的。当你的节点(Node)资源不够用了,比如磁盘快满了(DiskPressure)或者内存爆了(MemoryPressure),kubelet 为了保证节点不宕机,就会开始杀 Pod。
这里有个 QoS(服务质量)的等级问题,这也是常见面试问题。K8s 会优先杀掉那些"不重要"的 Pod。优先级大概是:
来个实际的配置例子,教你怎么保命。如果你有个核心应用,千万别像下面这样写:
你应该这样写,保证它是 Guaranteed:
📌 要点提醒:一定要给关键的 Deployment 加上 resources 限制。别觉得设了 limits 就亏了,这其实是在保护你的 Pod,防止它因为节点资源不足被无情驱逐。
再聊聊 CNI 插件选型。CNI 就是负责给 Pod 分配 IP、打通网络的。现在市面上的插件太多了,新手直接看晕。根据 2024 年的趋势,eBPF 技术是个大热门,像 Cilium 这种基于 eBPF 的插件性能吊打传统插件。
咱们对比一下常见的几个:
这里有个简单的 Cilium 安装后查看状态的命令:
避雷经验预警:如果你是从 Docker 时代迁移过来的,记得 K8s 1.31 早就不支持 Dockershim 了。你得用 containerd 或者 CRI-O 作为运行时。有些 CNI(比如老版本的 Calico)跟 containerd 的适配如果不注意,会导致 Pod 一直 ContainerCreating,这时候去查 kubectl describe pod 里的事件,通常能看到是网络插件没起来。
另外,最近社区里还在吵 Gateway API 要替代传统的 Ingress。如果你在选型网络方案,选那些支持 Gateway API 的(比如 Cilium 或者 Istio),这样以后不用改代码就能平滑升级。
---
不知不觉咱们聊了这么多,从怎么部署一个应用,到怎么用 GitOps 自动化,再到怎么避坑。作为一个写了 5 年代码、踩了无数坑的全栈工程师,我想最后跟大家唠唠 Kubernetes 接下来的路怎么走。毕竟咱们学技术不能只盯着眼前的 YAML,得看看远方。
现在的 K8s 早已不是那个只能跑跑 Web 服务的工具了。根据目前的路线图,Kubernetes 1.31 之后的版本(发布周期大概是每 4 个月一个稳定版),正在往更深、更广的领域渗透。
首当其冲的就是 AI 与 K8s 的深度融合。以前跑 AI 训练任务,大家都是用裸机或者专门的调度系统。现在?全在往 K8s 上搬。为什么?因为 K8s 对 GPU、TPU 等异构资源的调度能力越来越强了。你现在可以用 K8s 很方便地管理 TensorFlow 或者 PyTorch 的分布式训练任务。比如,通过 Device Plugin 机制,你可以把特定的 GPU 卡分配给特定的 Pod,这在 2024-2026 年绝对是主流趋势。
💡 经验总结:如果你在做 AI 相关的平台,别再自己造轮子管 GPU 了,直接基于 K8s 的调度框架来。现在的调度器(如 Volcano)对批量任务的支持已经非常完善了。
第二个大趋势是 平台工程(Platform Engineering)。简单来说,就是不要让业务开发同学去直接面对复杂的 K8s YAML。我们这些搞基础架构的,要基于 K8s 构建一个 内部开发者平台(IDP)。就像咱们之前提到的 GitOps,开发只需要提交代码,平台自动帮你构建、部署、监控。K8s 作为底层的基石,提供了强大的编排能力,但上层的体验一定要做得像 Vercel 或者 Netlify 那样傻瓜化。
还有两个值得关注的点:
最后,咱们说回技术细节。现在 Serverless 也在往 K8s 上靠,Knative 这类框架越来越成熟。这意味着你以后写代码可能都不需要关心 Pod 了,只需要关心函数和流量,而 K8s 在底层帮你实现更细粒度的按需计费。
总之,K8s 已经成为了云原生的操作系统。不管你是做微服务、做 AI,还是做边缘计算,绕不开它。咱们作为开发者,与其焦虑,不如深入进去,把它的核心原理(比如调度、网络、存储)吃透,这才是应对变化最稳的姿势。