2. Kubernetes核心概念回顾:Pod、Service、Deployment、StatefulSet、ConfigMap与Secret
说实话,很多刚接触Kubernetes的朋友,一上来就被这些概念搞晕了。Pod、Service、Deployment……名字都挺像,到底谁管谁?
我个人的习惯是,先把它们分成两类:一类是“跑应用的”,一类是“管配置的”。前者负责你的业务进程怎么部署、怎么暴露、怎么伸缩;后者负责你的配置和敏感信息怎么注入。今天咱们就把这两类核心概念捋一遍。
2.1 Pod:最小的调度单元
Pod是Kubernetes里你能创建和部署的最小单元。说白了,一个Pod就是一个或多个容器的“共享沙箱”。这些容器共享同一个网络命名空间、存储卷,以及一些资源限制。
我在项目中遇到过一个问题:有个同事把两个需要通信的服务放在同一个Pod里,结果发现端口冲突了。嗯,这里要注意——同一个Pod里的容器,不能用相同的端口号。
核心要点:
- Pod是短暂的,随时可能被销毁重建
- 一个Pod通常只运行一个主容器,加上一些辅助容器(sidecar)
- Pod内的容器可以通过localhost互相访问
# 一个简单的Pod定义
apiVersion: v1
kind: Pod
metadata:
name: my-app-pod
labels:
app: my-app
spec:
containers:
- name: my-app-container
image: nginx:1.21
ports:
- containerPort: 80
2.2 Deployment:声明式更新与扩缩容
你想想看,如果每次更新版本都要手动删Pod、建Pod,那运维得多累?Deployment就是来解决这个问题的。它帮你管理Pod的“期望状态”。
我曾经踩过一个坑:直接修改了Deployment管理的Pod的标签,结果Deployment立刻创建了一个新Pod,旧Pod也没删。为什么?因为Deployment通过标签选择器来识别它管理的Pod,你改了标签,它就认为那个Pod“不属于它了”。
我的建议:永远不要手动修改Deployment管理的Pod。要更新,就更新Deployment的模板。这才是声明式运维的正确姿势。
# Deployment示例
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app-deployment
spec:
replicas: 3
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: my-app
image: my-app:v2
ports:
- containerPort: 8080
2.3 Service:稳定的网络入口
Pod的IP是动态的,重启一次就变了。那客户端怎么访问?Service就是那个“固定入口”。它为一组Pod提供稳定的虚拟IP和DNS名称。
我记得有一次排查线上故障,发现Service的selector写错了,导致流量全打到了错误的Pod上。说白了,Service就是靠标签选择器来找到后端Pod的,标签对不上,服务就断了。
| Service类型 | 适用场景 |
|---|---|
| ClusterIP | 集群内部访问,默认类型 |
| NodePort | 通过节点IP+端口从集群外部访问 |
| LoadBalancer | 云厂商提供的负载均衡器 |
| ExternalName | 将服务映射到外部DNS名称 |
# Service示例
apiVersion: v1
kind: Service
metadata:
name: my-app-service
spec:
selector:
app: my-app
ports:
- protocol: TCP
port: 80
targetPort: 8080
type: ClusterIP
2.4 StatefulSet:有状态应用的守护者
Deployment适合无状态应用,比如Web服务。但数据库、消息队列这类有状态应用怎么办?它们需要稳定的网络标识、持久化存储、有序的部署和伸缩。这时候就该StatefulSet上场了。
我在项目中用StatefulSet部署过一套Elasticsearch集群。每个Pod都有一个固定的主机名,比如es-0、es-1,即使Pod重建,名字和存储卷都不会变。这一点Deployment做不到。
注意:StatefulSet的删除操作要小心。默认情况下,删除StatefulSet不会删除关联的PVC,需要手动清理。我曾经因为忘记清理PVC,导致测试环境存储爆满。
# StatefulSet示例
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: my-db
spec:
serviceName: "my-db"
replicas: 3
selector:
matchLabels:
app: my-db
template:
metadata:
labels:
app: my-db
spec:
containers:
- name: db
image: mysql:8.0
volumeMounts:
- name: data
mountPath: /var/lib/mysql
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 10Gi
2.5 ConfigMap与Secret:配置与敏感信息管理
应用配置和密码不应该硬编码在镜像里。ConfigMap用来存非敏感配置,Secret用来存敏感信息(密码、密钥、证书)。
我见过有人把数据库密码直接写在Deployment的YAML里,然后提交到Git仓库。嗯,这很危险。正确的做法是用Secret,然后通过环境变量或挂载卷的方式注入到Pod里。
最佳实践:
- ConfigMap适合存配置文件、环境变量、命令行参数
- Secret的数据是Base64编码的,但这不是加密,只是编码。需要配合RBAC和加密存储来保证安全
- 更新ConfigMap或Secret后,Pod不会自动更新。需要手动重启Pod或使用工具(如Reloader)
# ConfigMap示例
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
app.properties: |
log.level=INFO
max.connections=100
# Secret示例
apiVersion: v1
kind: Secret
metadata:
name: db-secret
type: Opaque
data:
username: YWRtaW4= # admin
password: cGFzc3dvcmQ= # password
2.6 知识体系总览
为了让你更直观地理解这些核心概念之间的关系,我画了一张图。你可以看到Pod是基础,Deployment和StatefulSet负责管理Pod的生命周期,Service提供稳定的访问入口,而ConfigMap和Secret则负责配置注入。
这张图里,箭头方向代表了“谁管理谁”或“谁依赖谁”。Deployment和StatefulSet管理Pod的生命周期,Service为Pod提供稳定的访问入口,ConfigMap和Secret则向Pod注入配置和敏感信息。理解了这张图,Kubernetes的核心逻辑就掌握了大半。