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-0mysql-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,看看怎么把这些配置管理得井井有条。