4. Kubernetes进阶:Service、Ingress、ConfigMap与Secret
好,咱们继续往下走。前面几章我们把Pod、Deployment这些基础概念聊透了,现在该聊聊真正让Kubernetes变得「有用」的几个核心组件了。说白了,你部署了一堆Pod,它们怎么互相通信?怎么对外暴露?配置和敏感信息又该怎么管理?这就是今天要解决的四个问题。
4.1 Service:Pod的稳定入口
Pod这东西,说白了就是「朝生暮死」的。今天跑得好好的,明天一升级IP就变了。你总不能每次重启都去改配置文件吧?Service就是来解决这个问题的——它给一组Pod提供一个固定的虚拟IP和DNS名称。
我个人习惯把Service理解成一个「负载均衡器+服务发现」的组合体。它通过Label Selector找到匹配的Pod,然后把流量分发过去。
4.1.1 Service的四种类型
| 类型 | 访问方式 | 适用场景 |
|---|---|---|
| ClusterIP | 集群内部虚拟IP | 内部服务间调用,默认类型 |
| NodePort | 节点IP + 固定端口 | 开发测试、临时对外暴露 |
| LoadBalancer | 云厂商LB + 外部IP | 生产环境对外暴露 |
| ExternalName | CNAME到外部域名 | 将外部服务映射到集群内 |
嗯,这里要注意:NodePort的端口范围默认是30000-32767。我曾经在生产环境踩过坑,安全组忘了开这个范围的端口,结果服务一直连不上,排查了半天才发现是防火墙的问题。
4.1.2 动手创建一个Service
apiVersion: v1
kind: Service
metadata:
name: my-app-svc
spec:
selector:
app: my-app
ports:
- protocol: TCP
port: 80 # Service暴露的端口
targetPort: 8080 # Pod里容器的端口
type: ClusterIP
你想想看,这个YAML干了什么?它告诉Kubernetes:帮我创建一个叫my-app-svc的Service,把所有带有app=my-app标签的Pod的8080端口,映射到Service的80端口上。其他Pod访问my-app-svc:80就能找到这些Pod了。
4.2 Ingress:七层流量入口
Service解决了Pod的访问问题,但有个尴尬的地方——每个Service只能暴露一个端口。你想想看,一个微服务架构可能有几十个服务,每个都开一个NodePort?那端口管理就是噩梦。
Ingress就是干这个的。它工作在七层(HTTP/HTTPS),可以根据域名、路径把流量路由到不同的Service。说白了,它就是Kubernetes里的「反向代理+路由网关」。
4.2.1 Ingress的工作原理
Ingress本身只是一个资源定义,真正干活的是Ingress Controller。常见的实现有Nginx Ingress Controller、Traefik、HAProxy等。我项目里用得最多的是Nginx Ingress Controller,稳定、社区活跃、文档齐全。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: api.example.com
http:
paths:
- path: /v1
pathType: Prefix
backend:
service:
name: v1-service
port:
number: 80
- path: /v2
pathType: Prefix
backend:
service:
name: v2-service
port:
number: 80
这段配置的意思是:当用户访问api.example.com/v1时,流量打到v1-service;访问/v2时,打到v2-service。是不是很直观?
4.3 ConfigMap:配置与代码分离
做开发的都知道,配置不应该硬编码在代码里。环境不同(开发、测试、生产),配置就不同。ConfigMap就是Kubernetes用来管理配置的利器。
说白了,ConfigMap就是一个键值对存储。你可以把它挂载成环境变量,也可以挂载成文件。我个人更推荐挂载成文件的方式,因为配置更新后,Pod不需要重建就能生效(虽然有些应用需要手动reload)。
4.3.1 创建ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
app.properties: |
db.host=mysql-service
db.port=3306
db.name=myapp
redis.host: redis-service
redis.port: "6379"
这里有个细节:value可以是多行文本(用|符号),也可以是单行字符串。注意数字类型的值要加引号,否则YAML解析会出问题。
4.3.2 在Pod中使用ConfigMap
apiVersion: v1
kind: Pod
metadata:
name: my-app-pod
spec:
containers:
- name: my-app
image: my-app:latest
volumeMounts:
- name: config-volume
mountPath: /etc/config
volumes:
- name: config-volume
configMap:
name: app-config
这样,ConfigMap里的app.properties文件就会被挂载到Pod的/etc/config目录下。应用直接读取这个文件就能拿到配置了。
4.4 Secret:敏感信息的保险箱
ConfigMap存的是非敏感配置,那密码、API Key、证书这些敏感信息怎么办?用Secret。它的用法和ConfigMap几乎一样,区别在于数据是Base64编码的,而且Kubernetes会加密存储(如果开启了加密功能)。
嗯,这里要纠正一个常见误区:Base64不是加密,只是编码。任何拿到Base64字符串的人都能解码。所以Secret的真正安全依赖于Kubernetes的RBAC和存储加密。
4.4.1 创建Secret
apiVersion: v1
kind: Secret
metadata:
name: db-secret
type: Opaque
data:
username: cm9vdA== # root的Base64
password: cGFzc3dvcmQxMjM= # password123的Base64
你也可以用kubectl命令来创建,省去手动编码的麻烦:
kubectl create secret generic db-secret \
--from-literal=username=root \
--from-literal=password=password123
4.4.2 在Pod中使用Secret
apiVersion: v1
kind: Pod
metadata:
name: my-app-pod
spec:
containers:
- name: my-app
image: my-app:latest
env:
- name: DB_USERNAME
valueFrom:
secretKeyRef:
name: db-secret
key: username
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: password
这样,Pod启动时就会自动从Secret里读取username和password,设置成环境变量。应用代码里直接读环境变量就行,不用关心敏感信息是怎么存储的。
4.5 综合实践:一个完整的微服务配置
最后,咱们把今天学的四个组件串起来,看一个完整的例子。假设我们有一个订单服务,需要连接数据库和Redis:
# 1. 创建Secret存储数据库密码
apiVersion: v1
kind: Secret
metadata:
name: order-secret
type: Opaque
data:
db-password: bXlzcWxwYXNz
---
# 2. 创建ConfigMap存储非敏感配置
apiVersion: v1
kind: ConfigMap
metadata:
name: order-config
data:
db.host: mysql-service
db.port: "3306"
redis.host: redis-service
redis.port: "6379"
---
# 3. 创建Service暴露内部服务
apiVersion: v1
kind: Service
metadata:
name: order-service
spec:
selector:
app: order
ports:
- port: 80
targetPort: 8080
---
# 4. 创建Ingress对外暴露
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: order-ingress
spec:
rules:
- host: order.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: order-service
port:
number: 80
你想想看,这个架构的好处是什么?配置和敏感信息分离,Service提供稳定的内部访问入口,Ingress统一管理外部流量。每个组件各司其职,互不干扰。
好了,这一章的内容就到这儿。Service、Ingress、ConfigMap、Secret这四个组件,说白了就是Kubernetes里最常用的「基础设施」。把它们搞明白了,你就能搭建出既灵活又安全的微服务体系。下一章咱们聊聊存储,PersistentVolume和PersistentVolumeClaim,到时候见。