Contents

k8s hpa

Contents

HPA

pod数扩容和缩减可以使用kubectl scale进行操作,这个是完全手动操作的,k8s提供一个自动scale,Horizontal Pod Autoscaling(Pod 水平自动伸缩),简称 HPA ,HPA 通过监控分析一些控制器控制的所有 Pod 的负载变化情况来确定是否需要调整 Pod 的副本数量

HPA(Horizontal Pod Autoscaler)是kubernetes的一种资源对象,能够根据某些指标对在statefulset、replicacontroller、replicaset等集合中的pod数量进行动态伸缩,使运行在上面的服务对指标的变化有一定的自适应能力。

HPA目前支持四种类型的指标,分别是Resource、Object、External、Pods

注意:Pod的自动缩放不适用于无法缩放的对象。

HPA 是一个控制器(Controller),它周期性(默认每 15 秒)检查目标 Pod 的指标数据,并将其与用户定义的目标值进行比较。

  • 扩容 (Scale Up):当指标高于阈值时,增加 Pod 副本数。
  • 缩容 (Scale Down):当指标低于阈值时,减少 Pod 副本数。

HPA 本身不采集数据,它依赖以下组件获取指标:

  1. Metrics Server:提供基础资源指标(CPU、内存)。这是大多数集群的标配。
  2. Custom Metrics API / External Metrics API:通常由 Prometheus Adapter 或其他监控系统提供,用于支持自定义指标(如 QPS、队列长度、延迟)。

HPA 可以控制实现了 /scale 子资源的控制器,主要包括:

  • Deployment

  • ReplicaSet

  • StatefulSet

  • ReplicationController
    

    注意:HPA 不能直接控制 PodDaemonSet

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: php-apache
  namespace: default
spec:
  # HPA的伸缩对象描述,HPA会动态修改该对象的pod数量
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: php-apache
  # HPA的最小pod数量和最大pod数量
  minReplicas: 1
  maxReplicas: 10
  # 监控的指标数组,支持多种类型的指标共存
  metrics:
  # Object类型的指标
  - type: Object
    object:
      metric:
        # 指标名称
        name: requests-per-second
      # 监控指标的对象描述,指标数据来源于该对象
      describedObject:
        apiVersion: networking.k8s.io/v1beta1
        kind: Ingress
        name: main-route
      # Value类型的目标值,Object类型的指标只支持Value和AverageValue类型的目标值
      target:
        type: Value
        value: 10k
  # Resource类型的指标
  - type: Resource
    resource:
      name: cpu
      # Utilization类型的目标值,Resource类型的指标只支持Utilization和AverageValue类型的目标值
      target:
        type: Utilization
        averageUtilization: 50
  # Pods类型的指标
  - type: Pods
    pods:
      metric:
        name: packets-per-second
      # AverageValue类型的目标值,Pods指标类型下只支持AverageValue类型的目标值
      target:
        type: AverageValue
        averageValue: 1k
  # External类型的指标
  - type: External
    external:
      metric:
        name: queue_messages_ready
        # 该字段与第三方的指标标签相关联
        selector:
          matchLabels:
            env: "stage"
            app: "myapp"
      # External指标类型下只支持Value和AverageValue类型的目标值
      target:
        type: AverageValue
        averageValue: 30

亲和性与反亲和性

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app-with-affinity
  namespace: default
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web-app
  template:
    metadata:
      labels:
        app: web-app
    spec:
      containers:
      - name: nginx
        image: nginx:1.27
        resources:
          requests:
            cpu: "100m"
            memory: "128Mi"

      # ======================================================================
      # 核心部分:亲和性配置 (Affinity)
      # ======================================================================
      affinity:
        
        # ------------------------------------------------------------------
        # 1. 节点亲和性 (Node Affinity)
        # 目的:让 Pod 优先调度到带有特定标签的节点上 (例如:高性能节点)
        # ------------------------------------------------------------------
        nodeAffinity:
          # 【必需】规则:如果不满足,Pod 绝对不会被调度到这里
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: disktype
                operator: In
                values:
                - ssd
                # 含义:Pod 必须调度到标签为 disktype=ssd 的节点上
            
          # 【偏好】规则:尽量满足,如果不满足也可以调度到其他节点
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 100 # 权重 (1-100),越高越优先
            preference:
              matchExpressions:
              - key: zone
                operator: In
                values:
                - cn-hangzhou-a
                # 含义:如果有 cn-hangzhou-a 的节点,优先选它;没有也无所谓

        # ------------------------------------------------------------------
        # 2. Pod 亲和性 (Pod Affinity)
        # 目的:让当前 Pod 尽量和“其他特定 Pod”调度在同一个节点上
        # 场景:缓存应用紧挨着后端应用,减少网络延迟
        # ------------------------------------------------------------------
        podAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - redis-cache
            topologyKey: "kubernetes.io/hostname"
            # 含义:当前 Pod 必须和标签为 app=redis-cache 的 Pod 运行在【同一台节点】上

        # ------------------------------------------------------------------
        # 3. Pod 反亲和性 (Pod Anti-Affinity) ⭐ 最常用 (配合 HPA)
        # 目的:让当前 Pod 尽量【远离】“其他特定 Pod”
        # 场景:高可用。当 HPA 扩容出 3 个副本时,确保它们不在同一台机器上
        # ------------------------------------------------------------------
        podAntiAffinity:
          
          # 【软策略】(推荐用于生产环境)
          # 含义:尽量分开,但如果资源紧张,允许挤在一起 (避免死锁导致无法扩容)
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 100
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: app
                  operator: In
                  values:
                  - web-app
              topologyKey: "kubernetes.io/hostname"
              # 含义:尽量不和 app=web-app 的其他 Pod 在同一台节点 (hostname) 上

          # 【硬策略】(慎用)
          # 含义:绝对不允许在一起。如果找不到空闲节点,Pod 将一直处于 Pending 状态
          # 风险:如果集群只有 1 个节点,且设置了硬策略,新副本永远无法启动
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - web-app
            topologyKey: "topology.kubernetes.io/zone"
            # 含义:绝对不允许和 app=web-app 的其他 Pod 在同一个【可用区 (Zone)】内
            # 这实现了跨可用区的高可用容灾

# ==============================================================================
# 关键概念解释:
# 1. requiredDuringScheduling... (硬策略): 
#    - 必须满足。不满足则不调度 (Pending)。
#    - 风险:可能导致无法扩容。
#
# 2. preferredDuringScheduling... (软策略): 
#    - 尽量满足。不满足也能调度。
#    - 推荐:配合 HPA 使用时,通常首选“软策略”,防止因资源不足导致扩容失败。
#
# 3. topologyKey (拓扑域):
#    - kubernetes.io/hostname: 指具体的某一台物理/虚拟机节点。
#    - topology.kubernetes.io/zone: 指可用区 (如 杭州可用区A)。
#    - topology.kubernetes.io/region: 指地域 (如 华东1)。
# ==============================================================================