4. Kubernetes进阶:ConfigMap与Secret管理、Ingress控制器、持久化存储(PV/PVC)、Helm包管理
好,咱们继续往下走。前面几章我们把Kubernetes的基础概念和核心工作负载都过了一遍。说实话,光会部署个无状态应用,在真正的生产环境里是远远不够的。这一章,我带你看看几个真正让Kubernetes变得“好用”的关键组件。说白了,就是解决配置管理、外部访问、数据持久化和应用打包这几个痛点。
4.1 ConfigMap与Secret:配置与敏感信息管理
先聊聊配置管理。你想想看,一个应用通常有各种配置:数据库地址、日志级别、功能开关……以前我们怎么做?要么写死在代码里,要么丢在环境变量里。但到了Kubernetes里,容器是随时可能被销毁重建的,配置必须和镜像解耦。
ConfigMap 就是干这个的。它用来存储非敏感的配置数据,比如配置文件内容、命令行参数、环境变量等。
我举个例子,创建一个ConfigMap,里面放一个应用配置文件:
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
app.properties: |
database.url=jdbc:mysql://db-service:3306/crm
log.level=INFO
feature.flag.new-ui=true
然后,在Pod里通过卷挂载的方式使用它:
apiVersion: v1
kind: Pod
metadata:
name: crm-app
spec:
containers:
- name: crm
image: crm-app:latest
volumeMounts:
- name: config-volume
mountPath: /etc/config
volumes:
- name: config-volume
configMap:
name: app-config
这样,配置文件和镜像就彻底分开了。改配置?更新ConfigMap,重启Pod就行。我在项目中遇到过,有一次线上需要紧急调整日志级别排查问题,直接改了ConfigMap,滚动更新一下Pod,几分钟就搞定了,不用重新构建镜像,省大事了。
Secret 和ConfigMap很像,但它是用来存敏感信息的,比如密码、API密钥、TLS证书。它的数据是Base64编码的,但这只是序列化方式,不是加密。Kubernetes本身会对Secret进行加密存储(如果开启了加密配置)。
创建Secret的示例:
apiVersion: v1
kind: Secret
metadata:
name: db-secret
type: Opaque
data:
username: Y3JtX3VzZXI= # crm_user
password: cGFzc3dvcmQxMjM= # password123
在Pod里引用时,可以挂载成文件,也可以直接作为环境变量注入。我个人习惯用文件挂载的方式,因为环境变量在Pod启动后如果Secret更新了,环境变量不会自动刷新,而挂载的文件会自动更新(虽然应用需要自己监听文件变化)。
4.2 Ingress控制器:统一入口管理
好,配置管理说完了。接下来是外部访问的问题。你的CRM系统肯定要对外提供服务吧?用NodePort?可以,但端口管理太乱了,而且不支持7层路由。用LoadBalancer?每个服务一个公网IP,成本太高。
Ingress 就是来解决这个问题的。它提供了一种统一的方式,把外部HTTP/HTTPS流量路由到集群内部的服务。你可以把它理解成一个智能的“大门”,根据请求的域名和路径,把流量分发给不同的后端服务。
但注意,Ingress只是一个API对象,真正干活的是 Ingress Controller。常见的实现有Nginx Ingress Controller、Traefik、HAProxy等。我用的最多的是Nginx Ingress Controller,稳定,社区活跃,坑也少。
部署一个Ingress的YAML示例:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: crm-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- host: crm.example.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: crm-api-service
port:
number: 8080
- path: /web
pathType: Prefix
backend:
service:
name: crm-web-service
port:
number: 80
这个配置的意思是:访问 crm.example.com/api 的请求,转发到 crm-api-service 的8080端口;访问 /web 的,转发到 crm-web-service 的80端口。
ingressClassName 字段,结果Ingress Controller根本不认这个资源,流量一直404。后来查了半天文档才发现,新版本的Kubernetes里,这个字段是必须的。另外,rewrite-target 注解也很容易搞错,不配置的话,后端服务收到的请求路径会包含前缀,比如 /api/users,如果你的应用不期望这个前缀,就会报404。
4.3 持久化存储(PV/PVC):让数据不随Pod消失
接下来是存储。Pod是临时性的,重启后里面的数据就没了。但CRM系统里的客户数据、附件、日志,这些都是要持久保存的。怎么办?用 PersistentVolume(PV) 和 PersistentVolumeClaim(PVC)。
简单理解:PV是集群管理员预先准备好的存储资源,比如一块NFS共享目录、一个Ceph RBD块设备、或者云服务商的云盘。PVC是用户(开发者)对存储资源的“需求申请”,比如“我需要5GB的读写一次存储”。Kubernetes会负责把PVC和合适的PV绑定起来。
举个例子,先创建一个PV:
apiVersion: v1
kind: PersistentVolume
metadata:
name: crm-data-pv
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
nfs:
path: /data/crm
server: 192.168.1.100
然后,在Pod里通过PVC来申请使用:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: crm-data-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: crm-db
spec:
replicas: 1
selector:
matchLabels:
app: crm-db
template:
metadata:
labels:
app: crm-db
spec:
containers:
- name: mysql
image: mysql:8.0
volumeMounts:
- name: data
mountPath: /var/lib/mysql
volumes:
- name: data
persistentVolumeClaim:
claimName: crm-data-pvc
这样,即使Pod被删除了,数据还在PV里。下次重建Pod,只要PVC还在,数据就能恢复。我在项目中遇到过,有一次集群节点宕机,Pod被调度到其他节点,但因为PVC绑定的PV是NFS共享存储,数据一点没丢,服务自动恢复了。嗯,这就是持久化存储的价值。
persistentVolumeReclaimPolicy 字段决定了PVC被删除后PV的行为。Retain表示保留数据,需要管理员手动清理;Delete表示自动删除底层存储;Recycle表示清空数据后重新可用。生产环境我建议用Retain,安全第一。
4.4 Helm包管理:一键部署复杂应用
最后,我们聊聊Helm。你有没有觉得,每次部署一个稍微复杂点的应用,都要写一堆YAML文件?Deployment、Service、ConfigMap、Secret、Ingress……而且每个环境(开发、测试、生产)的配置还不一样。手动改来改去,很容易出错。
Helm 就是Kubernetes的包管理器。它把一组相关的Kubernetes资源打包成一个 Chart,通过模板化的方式,让你可以用不同的配置值来生成不同的YAML文件。说白了,就是“一次编写,到处部署”。
Helm的核心概念有三个:
- Chart:一个Helm包,包含了一组Kubernetes资源的模板和默认配置。
- Release:一个Chart在某个集群中的一次部署实例。同一个Chart可以部署多次,生成多个Release。
- Repository:存放Chart的仓库,类似Docker Hub。
安装一个Helm Chart的示例:
# 添加仓库
helm repo add bitnami https://charts.bitnami.com/bitnami
# 安装MySQL
helm install my-mysql bitnami/mysql \
--set auth.rootPassword=secretpassword \
--set persistence.size=20Gi
就这么一行命令,Kubernetes里就多了一个MySQL实例,包含了Deployment、Service、PVC、Secret等一堆资源。是不是很方便?
我自己写Chart时,通常会这样组织目录结构:
crm-chart/
├── Chart.yaml # Chart的元数据
├── values.yaml # 默认配置值
├── templates/ # 模板文件
│ ├── deployment.yaml
│ ├── service.yaml
│ ├── ingress.yaml
│ ├── configmap.yaml
│ └── _helpers.tpl # 辅助模板函数
└── charts/ # 子Chart依赖
在 values.yaml 里定义好所有可配置的参数,然后在模板里用 {{ .Values.replicaCount }} 这样的语法引用。部署不同环境时,只需要提供不同的 values.yaml 文件即可。
values.yaml 里,导致文件变得非常庞大。后来我学会了用 --set 参数覆盖少量配置,用 -f 指定环境特定的values文件。另外,helm template 命令可以预览生成的YAML,调试时非常有用,建议多用。
好了,这一章的内容就到这里。ConfigMap和Secret帮你管理配置和敏感信息,Ingress解决了外部访问的统一入口问题,PV/PVC让数据有了“家”,Helm则让整个部署过程变得标准化和可重复。这些工具组合起来,你的CRM系统才能真正做到“云原生”——灵活、可靠、易于管理。