3. Kubernetes核心概念:Pod、Service、Deployment、Namespace详解
好,咱们直接进入正题。Kubernetes 里概念不少,但真正每天都要打交道的,其实就是 Pod、Service、Deployment 和 Namespace 这四个。我刚开始学 K8s 的时候,总觉得 Pod 不就是个容器嘛,Service 不就是个负载均衡嘛…… 后来踩了坑才发现,每个概念背后都有它存在的道理。
3.1 Pod:最小的调度单元
Pod 是 K8s 里你能创建和管理的最小单位。说白了,它就是一个或多个容器的“共享沙箱”。
为什么需要 Pod?
你想想看,有时候两个进程需要共享网络栈,比如一个写日志的 sidecar 和一个主业务容器。它们需要共用同一个 IP、同一个端口空间。如果把它们拆成两个独立的容器去调度,网络配置就复杂了。Pod 就是来解决这个问题的。
核心要点:Pod 内的容器共享 Network Namespace、IPC Namespace,以及可选的共享存储卷。
我在项目中遇到过这样一个场景:一个 Java 应用需要收集指标数据,但不想改业务代码。我们就在同一个 Pod 里加了一个 Prometheus exporter 的 sidecar 容器。两个容器通过 localhost 通信,部署起来特别省事。
Pod 的典型 YAML 定义
apiVersion: v1
kind: Pod
metadata:
name: my-app-pod
labels:
app: my-app
spec:
containers:
- name: app-container
image: nginx:1.21
ports:
- containerPort: 80
- name: sidecar-container
image: busybox
command: ["sh", "-c", "while true; do echo hello; sleep 10; done"]
嗯,这里要注意:Pod 里的容器是“生死与共”的。任何一个容器挂了,整个 Pod 都会被重启(取决于 restartPolicy)。所以不要把两个生命周期完全独立的进程硬塞到一个 Pod 里。
3.2 Service:稳定的网络入口
Pod 是脆弱的。它随时可能因为节点故障、资源不足而被销毁重建。每次重建,IP 都会变。那问题来了——谁来记住这些 Pod 的地址?
Service 就是干这个的。它提供了一组 Pod 的稳定访问入口,不管后端 Pod 怎么变,Service 的 IP 和端口始终不变。
个人经验:我建议所有需要对外暴露的服务,都通过 Service 来暴露。直接访问 Pod IP 是开发环境里的坏习惯,到了生产环境会吃大亏。
Service 的类型
| 类型 | 说明 | 适用场景 |
|---|---|---|
| ClusterIP | 集群内部可访问,外部不可达 | 内部微服务间调用 |
| NodePort | 在每个节点上开放一个端口,外部可通过节点 IP + 端口访问 | 开发测试、小规模暴露 |
| LoadBalancer | 云厂商提供负载均衡器,自动分配公网 IP | 生产环境对外暴露 |
| ExternalName | 将 Service 映射到外部 DNS 名称 | 访问集群外部的服务 |
我曾经犯过一个错:在生产环境用了 NodePort 来暴露数据库管理界面。结果安全扫描一过,直接被运维叫去喝茶。NodePort 说白了就是开了一个“后门”,适合调试,不适合生产。
Service 如何找到 Pod?
靠标签选择器(selector)。Service 通过 label 匹配 Pod,然后自动维护一个端点列表(Endpoints)。
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: my-app
ports:
- protocol: TCP
port: 80
targetPort: 8080
这个 Service 会把流量转发给所有带有 app: my-app 标签的 Pod 的 8080 端口。注意,port 是 Service 的端口,targetPort 是 Pod 的端口。这两个可以不一样,我经常利用这个特性来做端口映射。
3.3 Deployment:声明式应用管理
Pod 是“一次性”的,Service 是“稳定入口”,那谁来管 Pod 的“生老病死”?谁来保证我想要的 3 个副本一直存在?
Deployment 就是干这个的。它声明了你想要的应用状态,然后 K8s 负责把实际状态调整到期望状态。
核心思想:你告诉 Deployment “我要 3 个 nginx 副本,版本 1.21”,剩下的扩容、缩容、滚动更新、回滚,它全包了。
Deployment 的典型用法
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.21
ports:
- containerPort: 80
我个人习惯把 Deployment 和 Service 分开定义。虽然可以写在一起,但分开管理更清晰。Deployment 管“有多少个 Pod”,Service 管“怎么访问这些 Pod”。
滚动更新与回滚
更新镜像版本时,Deployment 会逐步替换旧 Pod。你可以控制更新速度,比如一次只替换 25% 的 Pod。
kubectl set image deployment/nginx-deployment nginx=nginx:1.22
kubectl rollout status deployment/nginx-deployment
kubectl rollout undo deployment/nginx-deployment # 回滚到上一个版本
我记得有一次上线新版本,结果发现有个接口不兼容。当时心里一紧,但马上执行了 rollout undo,十几秒就恢复了。要是没有 Deployment,手动换 Pod 镜像,那场面…… 不敢想。
避坑指南:我曾经在更新 Deployment 时忘了改 selector.matchLabels,结果新 Pod 创建不出来,旧 Pod 也删不掉。记住:selector 一旦创建就不能修改,除非删掉重建 Deployment。
3.4 Namespace:逻辑隔离的利器
一个集群里可能有多个团队、多个环境(开发、测试、生产)。如果所有资源都混在一起,管理起来就是一场灾难。
Namespace 就是用来做逻辑隔离的。它把集群划分成多个虚拟空间,每个空间里的资源名称可以重复,互不干扰。
Namespace 的常见用途
- 环境隔离:dev、test、prod 各一个 Namespace
- 团队隔离:team-a、team-b 各一个 Namespace
- 权限控制:结合 RBAC,限制每个 Namespace 的访问权限
- 资源配额:给每个 Namespace 设置 CPU、内存上限
操作示例
# 创建 Namespace
kubectl create namespace dev
# 在指定 Namespace 中创建资源
kubectl run nginx --image=nginx -n dev
# 查看所有 Namespace 的资源
kubectl get pods --all-namespaces
嗯,这里有个小细节:很多初学者忘了加 -n 参数,结果资源创建到了 default 命名空间里。我建议在 kubeconfig 里设置默认 Namespace,或者用 kubens 工具快速切换。
个人建议:不要把所有东西都丢到 default 命名空间。哪怕是小项目,也至少分一个 dev 和一个 prod。等集群规模大了再想拆分,成本就高了。
3.5 四个概念的关系总结
这四个概念的关系,我用一句话总结:
Deployment 管理 Pod 的副本和生命周期,Service 为 Pod 提供稳定的访问入口,Namespace 为这一切提供隔离环境。
你想想看,一个典型的微服务部署流程就是:
- 写一个 Deployment YAML,定义你要的 Pod 副本数和镜像版本
- 写一个 Service YAML,定义如何访问这些 Pod
- 把它们部署到指定的 Namespace 里
- K8s 自动完成剩下的工作
我在做多云容器编排时,经常利用 Namespace 来区分不同的云环境。比如 aws-prod、gcp-staging,每个 Namespace 里都有相同的 Deployment 和 Service 定义,但底层资源来自不同的云厂商。这种模式在多云场景下特别实用。
好了,这一章的内容就到这里。Pod、Service、Deployment、Namespace 这四个概念,是 K8s 的基石。理解透了,后面的集群管理、网络策略、存储编排学起来就顺了。