2、Kubernetes核心实战:Pod创建与管理、Deployment部署与扩缩容、Service服务发现、ConfigMap与Secret配置管理
好,咱们直接进入正题。Kubernetes 这东西,说白了就是一个「管家」,帮你管着你的应用容器。这一章我们就把最核心的几个概念撸一遍:Pod、Deployment、Service,还有配置管理用的 ConfigMap 和 Secret。这些都是你每天都会打交道的玩意儿。
本章核心脉络: 从最小的调度单元 Pod 开始,到用 Deployment 管理 Pod 的「生老病死」,再到用 Service 把 Pod 的网络暴露出去,最后用 ConfigMap 和 Secret 把配置和敏感信息剥离出来。一条线串下来,你就知道一个应用在 K8s 里是怎么跑起来的。
2.1 Pod:K8s 里最小的「兵」
Pod 是啥?你可以把它想象成一个「容器盒子」。一个 Pod 里可以放一个容器,也可以放多个紧密耦合的容器。但记住,Pod 是 K8s 调度的最小单位,不是容器本身。
我个人习惯把 Pod 比作「豆荚」—— 里面包着几颗豆子(容器),共享同一个网络命名空间和存储卷。它们之间用 localhost 就能通信,方便得很。
创建一个 Pod 很简单,写个 YAML 文件就行:
apiVersion: v1
kind: Pod
metadata:
name: my-nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.25
ports:
- containerPort: 80
然后 kubectl apply -f pod.yaml 就起来了。想看看状态?kubectl get pods。想进去看看?kubectl exec -it my-nginx -- /bin/bash。
小技巧: 我刚开始用的时候,老是记不住 Pod 的完整 YAML 结构。后来发现 kubectl run my-pod --image=nginx --dry-run=client -o yaml 这个命令能直接帮你生成模板,省事多了。
不过,直接创建 Pod 有个问题 —— 它挂了就真挂了,没人管。所以生产环境我们很少直接搞 Pod,而是用 Deployment 来管它。
2.2 Deployment:让 Pod 永不掉线
Deployment 是什么?说白了,它是一个「Pod 管家」。你告诉它「我要跑 3 个 nginx 实例」,它就帮你盯着,哪个 Pod 挂了就立刻再拉一个起来。
我记得有一次线上服务半夜挂了,就是因为 Pod 被 OOM Kill 了,但 Deployment 自动重建了一个,用户几乎没感知。嗯,这就是声明式管理的魅力。
来个 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.25
ports:
- containerPort: 80
这里 replicas: 3 就是告诉 K8s:我要 3 个副本。想扩缩容?简单:
kubectl scale deployment nginx-deployment --replicas=5
或者直接改 YAML 里的 replicas 再 apply 一次。我个人更推荐后者,因为 YAML 才是「真相来源」,命令行操作容易忘记。
注意: 扩缩容不是瞬间完成的。K8s 会先拉镜像、启动容器、等就绪检查通过,才会把新 Pod 纳入服务。我曾经遇到过镜像拉取超时导致扩容卡住的情况,所以建议提前把镜像拉到节点上,或者配置好镜像拉取策略。
Deployment 还有一个大招 —— 滚动更新。你改了镜像版本,apply 一下,它会逐个替换 Pod,不会一次性全干掉。这招在线上更新时特别有用。
2.3 Service:给 Pod 一个稳定的「门牌号」
Pod 是动态的,今天在这台机器上,明天可能就跑到另一台了。IP 地址也会变。那客户端怎么访问它?这就轮到 Service 出场了。
Service 相当于一个「反向代理 + 负载均衡」。它有一个固定的虚拟 IP(ClusterIP),你只要访问这个 IP,它就把流量转发到后端的 Pod 上。
你想想看,如果没有 Service,每次 Pod 重启你都得去查新 IP,那得多崩溃。
创建一个 Service:
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
type: ClusterIP
这里 selector 就是告诉 Service:去找那些带有 app: nginx 标签的 Pod。然后 port: 80 是 Service 的端口,targetPort: 80 是 Pod 里容器的端口。
Service 的类型有几种:
| 类型 | 说明 | 适用场景 |
|---|---|---|
| ClusterIP | 集群内部可访问,外部不行 | 内部微服务调用 |
| NodePort | 在每个节点上开一个端口,外部可通过节点IP+端口访问 | 开发测试、简单暴露 |
| LoadBalancer | 云厂商提供负载均衡器,外部直接访问 | 生产环境对外暴露 |
避坑指南: 我曾经把 Service 的 selector 写错了标签,结果流量全打到了错误的 Pod 上。排查了半天才发现是标签不匹配。所以创建 Service 前,先用 kubectl get pods --show-labels 确认一下 Pod 的标签。
2.4 ConfigMap 与 Secret:配置与敏感信息分离
应用总得有些配置吧?比如数据库地址、日志级别。这些如果硬编码在镜像里,换个环境就得重新打包,太蠢了。ConfigMap 就是用来干这个的。
Secret 呢?跟 ConfigMap 差不多,但它是用来存敏感信息的,比如密码、API Key。数据会做 base64 编码,虽然不算绝对安全,但至少不会明文暴露在 YAML 里。
先看 ConfigMap:
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
app.properties: |
db.host=mysql-service
db.port=3306
log.level=INFO
然后在 Pod 里引用它:
spec:
containers:
- name: my-app
image: my-app:latest
envFrom:
- configMapRef:
name: app-config
这样配置就注入到环境变量里了。你也可以挂载成文件,看需求。
Secret 的用法几乎一样,只是 data 里的值需要 base64 编码:
apiVersion: v1
kind: Secret
metadata:
name: db-secret
type: Opaque
data:
db.password: bXlwYXNzd29yZA== # 这是 "mypassword" 的 base64
安全提醒: base64 不是加密,只是编码。任何能拿到 YAML 的人都能解码。真正生产环境,建议用外部密钥管理服务(比如 Vault、AWS Secrets Manager),或者用 Sealed Secrets 这类工具。我之前在一个项目里看到有人把生产数据库密码直接 base64 放在 Git 里,吓得我赶紧让他改了。
嗯,到这里,Kubernetes 的核心实战四件套就讲完了。Pod 是基础,Deployment 保证高可用,Service 搞定网络,ConfigMap 和 Secret 管好配置。把这几个玩转了,你就能在 K8s 上跑起一个像样的应用了。