4. Kubernetes进阶:Ingress、Volume、StatefulSet、DaemonSet、HPA、RBAC
好,咱们继续往下走。上一章我们把Pod、Deployment、Service这些基础概念捋了一遍。说实话,那些只是Kubernetes的入门功夫。真正到了生产环境,你会发现光靠那几板斧根本不够用。
这一章,我带你看看Kubernetes里几个真正「进阶」的玩意儿。Ingress怎么统一入口?Volume怎么管理数据?StatefulSet和DaemonSet又是什么鬼?还有HPA自动伸缩、RBAC权限控制——这些才是你从「会用K8s」到「用好K8s」的分水岭。
嗯,咱们一个一个来。
4.1 Ingress:统一入口的「大门」
先说说Ingress。你想想看,如果你的微服务有几十个,每个都要对外暴露一个端口,那管理起来得多崩溃?
Ingress就是干这个的——它像一个「智能大门」,根据请求的域名或路径,把流量转发到对应的Service上。
核心概念:Ingress是Kubernetes的API对象,它定义了从集群外部到集群内部服务的HTTP/HTTPS路由规则。而Ingress Controller(比如Nginx Ingress、Traefik)才是真正干活的那个组件。
我个人习惯,在生产环境里统一用Nginx Ingress Controller。为什么?稳定,社区活跃,踩过的坑网上都有答案。
来看一个简单的Ingress配置:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: myapp-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: myapp.example.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: api-service
port:
number: 80
- path: /web
pathType: Prefix
backend:
service:
name: web-service
port:
number: 80
这个配置的意思是:访问 myapp.example.com/api 的请求,转发到 api-service 的80端口;访问 /web 的,转发到 web-service。
小技巧:Ingress的annotation非常强大。比如你想限制IP访问、配置HTTPS证书、做灰度发布,都可以通过annotation实现。我建议你花点时间看看Nginx Ingress的官方文档,那里面的annotation列表能解决你80%的网关问题。
4.2 Volume:数据持久化的「保险箱」
Pod是临时性的,这你知道。但数据库的数据不能丢啊,日志不能丢啊。怎么办?用Volume。
Kubernetes里的Volume,说白了就是给Pod挂载一块「持久化存储」。Pod挂了重启,数据还在。
常见的Volume类型有:
- emptyDir:Pod内临时共享目录,Pod删除数据就没了。适合缓存。
- hostPath:挂载宿主机目录。测试环境用用还行,生产环境不推荐。
- PersistentVolumeClaim (PVC):这才是生产环境的主角。它像是一个「存储申请单」,你告诉K8s你需要多大空间、什么读写模式,K8s会自动给你分配一个PersistentVolume (PV)。
我曾经在项目里遇到过一个问题:开发同学直接用了hostPath,结果Pod被调度到另一台机器上,数据全丢了。嗯,从那以后我强制要求所有有状态服务必须用PVC。
看一个PVC的例子:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mysql-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: standard
然后在Pod里引用它:
volumes:
- name: mysql-storage
persistentVolumeClaim:
claimName: mysql-pvc
注意:PVC的回收策略要搞清楚。Retain(保留)、Delete(删除)、Recycle(回收),选错了可能导致数据被误删。我个人习惯用Retain,手动清理更安全。
4.3 StatefulSet:有状态应用的「身份证」
Deployment适合无状态应用,比如你的API服务、前端页面。但数据库、消息队列、缓存这些有状态应用呢?它们需要稳定的网络标识、有序的启停、持久化的存储。
StatefulSet就是为这个而生的。
它和Deployment最大的区别是什么?
- 稳定的Pod名称:每个Pod有唯一的名称,比如
mysql-0、mysql-1,不会变。 - 有序的启停:启动时从0到N,停止时从N到0。适合主从架构。
- 每个Pod独立存储:每个Pod可以绑定自己的PVC,数据不共享。
我记得有一次帮客户搭MySQL集群,他们一开始用Deployment,结果Pod重启后IP变了,主从复制全乱套。换成StatefulSet后,问题迎刃而解。
StatefulSet的配置大概长这样:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql
spec:
serviceName: mysql-headless
replicas: 3
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:8.0
volumeMounts:
- name: data
mountPath: /var/lib/mysql
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 10Gi
注意那个 volumeClaimTemplates,它会自动为每个Pod生成一个PVC。Pod mysql-0 对应 data-mysql-0,Pod mysql-1 对应 data-mysql-1。干净利落。
4.4 DaemonSet:每个节点一个的「哨兵」
有些应用需要在每个节点上都运行一个副本,比如日志采集器(Fluentd)、监控代理(Prometheus Node Exporter)、网络插件(Calico)。
DaemonSet就是干这个的。你定义一个DaemonSet,K8s会保证每个节点上都有一个Pod在运行。新节点加入集群,自动创建Pod;节点被删除,Pod也跟着消失。
说白了,它就是集群里的「哨兵」,无处不在。
来看一个简单的DaemonSet配置:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluentd
spec:
selector:
matchLabels:
name: fluentd
template:
metadata:
labels:
name: fluentd
spec:
containers:
- name: fluentd
image: fluent/fluentd:v1.14
volumeMounts:
- name: varlog
mountPath: /var/log
volumes:
- name: varlog
hostPath:
path: /var/log
这个配置会在每个节点上部署一个Fluentd容器,采集宿主机上的日志。
经验之谈:DaemonSet的Pod默认会调度到所有节点,包括Master节点。如果你不想让Master节点也跑这些Pod,可以给Master节点打上污点(Taint),然后在DaemonSet里加上容忍度(Toleration)。
4.5 HPA:自动伸缩的「智能管家」
流量高峰来了怎么办?手动扩容?太慢了。提前预留资源?浪费钱。
HPA(Horizontal Pod Autoscaler)就是K8s的「智能管家」。它会根据CPU、内存使用率,或者自定义指标,自动调整Pod的副本数。
配置起来很简单:
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: myapp-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: myapp
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
这个配置的意思是:当CPU使用率超过70%时,自动扩容,最多到10个副本;低于70%时,自动缩容,最少保留2个。
我曾经遇到过一个问题:HPA配置了,但就是不生效。查了半天,发现是Pod没有设置资源请求(requests)。HPA需要知道Pod的基准资源使用率,没有requests它就没法算。嗯,这个坑我帮你踩过了。
注意:HPA的缩容有默认的冷却时间(cooldown),默认5分钟。这是为了防止频繁伸缩导致的「抖动」。你可以通过 --horizontal-pod-autoscaler-downscale-stabilization 参数调整这个时间。
4.6 RBAC:权限控制的「守门员」
集群安全怎么办?不能让所有人都能删Pod、改Deployment吧?
RBAC(Role-Based Access Control)就是K8s的权限控制机制。它通过角色(Role)和角色绑定(RoleBinding)来控制谁可以做什么。
核心概念就三个:
- Subject:谁?可以是用户、服务账号(ServiceAccount)、组。
- Resource:操作什么?Pod、Service、Deployment等。
- Verb:做什么?get、list、create、delete等。
来看一个例子:创建一个只能读取Pod信息的角色。
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: default
name: pod-reader
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]
然后把这个角色绑定给一个服务账号:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: read-pods
namespace: default
subjects:
- kind: ServiceAccount
name: my-sa
namespace: default
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
这样,my-sa 这个服务账号就只能读取Pod信息,干不了别的。
最佳实践:我建议你遵循「最小权限原则」。每个服务账号只给它需要的权限,不要图省事直接给cluster-admin。我曾经见过一个团队,所有服务都用同一个管理员账号,结果一个CI/CD脚本出问题,把整个集群搞崩了。权限控制,说白了就是给你的集群上把锁。
好了,这一章的内容就到这里。Ingress管流量、Volume管数据、StatefulSet管有状态应用、DaemonSet管节点级服务、HPA管自动伸缩、RBAC管权限——这六个组件,基本覆盖了生产环境K8s集群的核心需求。
下一章,我们聊聊Helm和Kustomize,看看怎么把这些配置管理得井井有条。