侧边栏壁纸
  • 累计撰写 51 篇文章
  • 累计创建 23 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

K8s Pod 和 Service 7

zhanjie.me
2020-11-14 / 0 评论 / 0 点赞 / 1 阅读 / 0 字

7.1 手动扩缩容

通过命令 kubectl scale 可以进行手动扩缩容,使用参数 --replicas 指定需要增加或是减少 Pod 的数量到某个指定的数字。

通过一个实例来体会手动扩缩容的效果,新建 nginx-deployment.yaml 文件,并向其中写入如下内容:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 3
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: nginx:1.19
          ports:
            - containerPort: 80

执行创建:

$ kubectl create -f nginx-deployment.yaml
deployment.apps/nginx-deployment created

现在预期会有 3 个 nginx-deployment Pod 副本运行中:

$ kubectl get pods
NAME                                READY   STATUS    RESTARTS   AGE
nginx-deployment-687548bb8c-7skkg   1/1     Running   0          38s
nginx-deployment-687548bb8c-h27kj   1/1     Running   0          38s
nginx-deployment-687548bb8c-xcbnq   1/1     Running   0          38s

首先,进行扩容,将 nginx-deployment Pod 副本数量从 3 个扩容到 5 个:

$ kubectl scale deployment nginx-deployment --replicas=5
deployment.apps/nginx-deployment scaled

可以看到有两个新创建的pod:

$ kubectl get pods
NAME                                READY   STATUS    RESTARTS   AGE
nginx-deployment-687548bb8c-7skkg   1/1     Running   0          2m29s
nginx-deployment-687548bb8c-h27kj   1/1     Running   0          2m29s
nginx-deployment-687548bb8c-hq4n4   1/1     Running   0          19s
nginx-deployment-687548bb8c-s4rlc   1/1     Running   0          19s
nginx-deployment-687548bb8c-xcbnq   1/1     Running   0          2m29s

然后,进行缩容,将 nginx-deployment Pod 副本数量从 5 个缩容到 1 个:

$ kubectl scale deployment nginx-deployment --replicas=1
deployment.apps/nginx-deployment scaled

可以看出,系统 kill 掉了一些运行中的 Pod,只保留了一个 Pod 来实现缩容:

$ kubectl get pods
NAME                                READY   STATUS    RESTARTS   AGE
nginx-deployment-687548bb8c-7skkg   1/1     Running   0          4m10s

7.2 自动扩缩容

从 Kubernetes v1.1 版本开始,添加了名为 Horizontal Pod Autoscaler(HPA) 的控制器,用于实现 Pod 自动扩缩容的功能。HPA 控制器基于 Master 的 kube-controller-manager 服务启动参数 --horizontal-pod-autoscaler-sync-period 定义的检测周期(默认值为 15s),周期性检测目标 Pod 的资源性能指标,并与 HPA 资源对象中的扩缩容条件进行对比,当满足条件时对 Pod 副本数量进行调整。

通常而言,扩缩容会根据内存、CPU 资源使用率、或是自定义的业务监控指标作为资源性能指标,前面介绍过现在 Kubernetes 系统的资源采集指标主要由两种 API 进行实现(而传统的 Heapster 监控已经被废弃):

  • Resource Metrics API(通过 metrics-server 实现):负责采集 Node、Pod 的核心资源数据
  • Custom Metrics API(通常使用 Prometheus 实现):负责自定义的指标数据采集,比如:网卡流量、磁盘 IOPS、HTTP 请求数、数据库连接数等

image-zipawgbo.png

扩缩容算法

Autoscaler 控制器从聚合 API 获取到 Pod 性能指标数据之后,通过下面的算法计算目标 Pod 副本数量:

desiredReplicas = ceil[currentReplicas * ( currentMetricValue / desiredMetricValue )]
目标副本数量 = 当前副本数 * (当前指标值/期望指标值)

注意上面公式的计算结果需要向上取整,然后将目标副本数量与当前副本数量进行对比,就可以判断是否需要进行扩容或是缩容。

以 CPU 请求数量为例,假设当前系统运行了一个 Pod 副本,用户设置的期望值为 100m:

  • 如果当前实际使用的指标值为 200m,则:目标副本数量 = 1 * (200/100) = 2,也就是期望 Pod 副本数量为 2,这个时候就会进行 Pod 扩容
  • 如果当前实际使用的指标值为 50m,则:目标副本数量 = 1 * (50/100) = 0.5,将计算结果向上取整为 1,也就是期望 Pod 副本数量为 1,这个时候就不会改变 Pod 的数量

当计算结果与 1 非常接近时,可以设置一个容忍度使系统不做扩缩容处理,通过 kube-controller-manager 服务的启动参数 --horizontal-pod-autoscaler-tolerance 进行设置,该参数的默认值为 0.1(10%),所以上述算法计算结果在正负 10% 的区间中都不会执行扩缩容操作。

期望指标值(desiredMetricValue)也可以是指标的平均值,比如:targetAverageValue,这时当前指标值(currentMetricValue)的算法为:

当前指标值 = 所有 Pod 副本当前指标值总和 / Pod 副本数量

php-apache 自动扩缩容实例

先来运行一个自动扩缩容的例子进行实际的体验。

首先在系统中应部署好资源监控 metrics-server,当能够成功获取 Pod 的 CPU 和 MEMORY 信息时说明 metrics-server 已经部署好:

$ kubectl top pods -n kube-system
NAME                                       CPU(cores)   MEMORY(bytes)
calico-kube-controllers-589b5f594b-g86zn   2m           18Mi
calico-node-5rpwf                          17m          45Mi
calico-node-66cl4                          20m          44Mi
calico-node-xqf6p                          23m          42Mi
coredns-67c766df46-4vg25                   3m           17Mi
coredns-67c766df46-wkwf5                   4m           14Mi
etcd-kubesphere01                          11m          284Mi
kube-apiserver-kubesphere01                34m          634Mi
kube-controller-manager-kubesphere01       11m          87Mi
kube-proxy-7gxj2                           3m           22Mi
kube-proxy-frjw4                           5m           21Mi
kube-proxy-tx6n7                           1m           19Mi
kube-scheduler-kubesphere01                2m           29Mi
metrics-server-66444bf745-7vwd5            1m           23Mi
nfs-client-provisioner-7f959768b5-vchmj    2m           10Mi
tiller-deploy-6d8dfbb696-r968q             1m           17Mi

本次实验中将会运行一个自定义的 hpa-example 镜像,本镜像由基础镜像 php-apache 修改制作而成,Dockerfile 的内容如下所示:

FROM webdevops/php-apache:latest
ADD index.php /app/index.php
RUN chmod a+rx /app/index.php

其中使用到的 index.php 页面的内容如下:

<?php
  $x = 0.0001;
  for ($i = 0; $i <= 1000000; $i++) {
    $x += sqrt($x);
  }
  echo "OK!";
?>

使用 hpa-example 镜像运行一个 Deployment,并使用 80 端口对外提供服务:

$ kubectl run php-apache --image=hpa-example:1.0 --requests=cpu=200m --limits=cpu=500m --expose --port=80
kubectl run --generator=deployment/apps.v1 is DEPRECATED and will be removed in a future version. Use kubectl run --generator=run-pod/v1 or kubectl create instead.
service/php-apache created
deployment.apps/php-apache created

查看是否创建好:

# 获取到 php-apache 服务的虚拟集群 IP 地址:10.96.115.130,后面将会使用到
$ kubectl get services
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
php-apache   ClusterIP   10.96.115.130   <none>        80/TCP    19s
# 可以发现这个时候只运行了一个 Pod
$ kubectl get deployments
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
php-apache         1/1     1            1           28s

当服务创建好以后,使用 kubectl autoscale 命令创建 Pod 水平自动伸缩,下面的命令指定了 php-apache Deployment 的 Pod 副本数量范围:最少为 1 个,最多为 10 个;同时我们指定平均 CPU 利用率为 50%,简单的说 HPA 会通过增加或是减少 Pod 的副本数量,来维持所有 Pod 的平均 CPU 利用率为 50%(前面在创建 Deployment 时指定最少的 CPU 为 200m,所以平均 CPU 的利用率为 100m)。

$ kubectl autoscale deployment php-apache --cpu-percent=50 --min=1 --max=10
horizontalpodautoscaler.autoscaling/php-apache autoscaled

查看刚刚创建的 HPA:

# 由于目前没有向服务器发送请求,所以当前 CPU 的消耗为 0%,这里的数值为所有 Pod 的 CPU 消耗平均值
$ kubectl get hpa
NAME         REFERENCE               TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
php-apache   Deployment/php-apache   0%/50%    1         10        1          25s

接下来将会增加服务的工作负荷,以此来观察 Pod 水平自动伸缩的效果。使用 busybox 镜像创建并启动一个名为 load-generator 的 Pod,并执行命令无限循环的向 php-apache 服务发送查询请求,新开一个终端执行如下命令:(可以看到每一次查询成功都会有一个 OK!输出)

$ kubectl run -it load-generator --image=busybox /bin/sh
/ # while true;do wget -q -O- http://10.96.115.130/index.php;done
OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK!OK...

大概等半分钟左右,查看 php-apache HPA 的信息可以发现由于持续不断的查询请求导致 CPU 负载变高,现在已经超过定义的平均值 50% 激增到 250% 了:

$ kubectl get hpa
NAME         REFERENCE               TARGETS    MINPODS   MAXPODS   REPLICAS   AGE
php-apache   Deployment/php-apache   250%/50%   1         10        1          7m38s
...
$ kubectl get hpa
NAME         REFERENCE               TARGETS    MINPODS   MAXPODS   REPLICAS   AGE
php-apache   Deployment/php-apache   84%/50%   1         10        4          20m
...
$ kubectl get hpa
NAME         REFERENCE               TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
php-apache   Deployment/php-apache   52%/50%   1         10        9          25m

由于 CPU 平均消耗超过了预设值,这个时候就会触发 Kubernetes 系统 Pod 的水平自动扩容,但是扩容范围也必须少于设定的最大值 10:

$ kubectl get deployment php-apache
NAME         READY   UP-TO-DATE   AVAILABLE   AGE
php-apache   9/9     9            9           28m
$ kubectl get pods
NAME                                READY   STATUS    RESTARTS   AGE
load-generator-5fb4fb465b-92884     1/1     Running   0          24m
php-apache-78d7965bbb-4qkdc         1/1     Running   0          5m7s
php-apache-78d7965bbb-6bp4q         1/1     Running   0          5m7s
php-apache-78d7965bbb-7zghg         1/1     Running   0          3m4s
php-apache-78d7965bbb-7zzp2         1/1     Running   0          7m49s
php-apache-78d7965bbb-cc9pc         1/1     Running   0          3m4s
php-apache-78d7965bbb-ffqqv         1/1     Running   0          4m51s
php-apache-78d7965bbb-ffxhk         1/1     Running   0          4m6s
php-apache-78d7965bbb-lz4d6         1/1     Running   0          4m6s
php-apache-78d7965bbb-p2dm2         1/1     Running   0          5m7s

现在停止服务请求的发送,在运行 busybox 镜像的终端按 Ctrl+C 停止。当请求停止,CPU 工作负载降低,这个时候就会触发 Kubernetes 系统 Pod 的水平自动缩容,缩容范围也不能小于设定的最小值 1:(这个自动缩容的过程可能需要持续好几分钟的时间才能完成,请耐心等待一下才能够查看到效果。)

# 由于停止了请求,最终 HPA 显示的 CPU 平均负载会固定到 0%
$ kubectl get hpa
NAME         REFERENCE               TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
php-apache   Deployment/php-apache   0%/50%    1         10        1          31m

# HPA 完成了自动缩容,现在 php-apache Deployment 只有一个 Pod 在运行中了,其余的 Pod 都被系统 kill 掉了
$ kubectl get deployments.apps
NAME               READY   UP-TO-DATE   AVAILABLE   AGE
php-apache         1/1     1            1           35m

# 查看最终剩下的一个 Pod 的名称
$ kubectl get pods
NAME                                READY   STATUS    RESTARTS   AGE
load-generator-5fb4fb465b-92884     1/1     Running   0          31m
php-apache-78d7965bbb-7zzp2         1/1     Running   0          15m

# 查看整个 php-apache Deployment 的 Events,可以发现 Pod 的数量变化过程
$ kubectl describe deployments.apps php-apache
...
Events:
  Type    Reason             Age               From                   Message
  ----    ------             ----              ----                   -------
  Normal  ScalingReplicaSet  36m               deployment-controller  Scaled up replica set php-apache-5c744c6969 to 1
  Normal  ScalingReplicaSet  26m               deployment-controller  Scaled up replica set php-apache-5c744c6969 to 4
  Normal  ScalingReplicaSet  26m               deployment-controller  Scaled up replica set php-apache-5c744c6969 to 5
  Normal  ScalingReplicaSet  20m               deployment-controller  Scaled down replica set php-apache-5c744c6969 to 1
  Normal  ScalingReplicaSet  16m               deployment-controller  Scaled up replica set php-apache-78d7965bbb to 1
  Normal  ScalingReplicaSet  16m               deployment-controller  Scaled down replica set php-apache-5c744c6969 to 0
  Normal  ScalingReplicaSet  13m               deployment-controller  Scaled up replica set php-apache-78d7965bbb to 4
  Normal  ScalingReplicaSet  13m               deployment-controller  Scaled up replica set php-apache-78d7965bbb to 5
  Normal  ScalingReplicaSet  12m               deployment-controller  Scaled up replica set php-apache-78d7965bbb to 7
  Normal  ScalingReplicaSet  3m (x2 over 11m)  deployment-controller  (combined from similar events): Scaled down replica set php-apache-78d7965bbb to 1

查看当前 php-apache HPA 的详细信息:

$ kubectl describe hpa php-apache
...
Events:
  Type     Reason                        Age                  From                       Message
  ----     ------                        ----                 ----                       -------
  Warning  FailedGetResourceMetric       17m (x2 over 17m)    horizontal-pod-autoscaler  unable to get metrics for resource cpu: no metrics returned from resource metrics API
  Warning  FailedComputeMetricsReplicas  17m (x2 over 17m)    horizontal-pod-autoscaler  invalid metrics (1 invalid out of 1), first error is: failed to get cpu utilization: unable to get metrics for resource cpu: no metrics returned from resource metrics API
  Warning  FailedComputeMetricsReplicas  16m (x4 over 17m)    horizontal-pod-autoscaler  invalid metrics (1 invalid out of 1), first error is: failed to get cpu utilization: did not receive metrics for any ready pods
  Warning  FailedGetResourceMetric       16m (x4 over 17m)    horizontal-pod-autoscaler  did not receive metrics for any ready pods
  Normal   SuccessfulRescale             15m (x2 over 28m)    horizontal-pod-autoscaler  New size: 4; reason: cpu resource utilization (percentage of request) above target
  Normal   SuccessfulRescale             14m (x2 over 27m)    horizontal-pod-autoscaler  New size: 5; reason: cpu resource utilization (percentage of request) above target
  Normal   SuccessfulRescale             14m                  horizontal-pod-autoscaler  New size: 7; reason: cpu resource utilization (percentage of request) above target
  Normal   SuccessfulRescale             12m                  horizontal-pod-autoscaler  New size: 9; reason: cpu resource utilization (percentage of request) above target
  Normal   SuccessfulRescale             4m16s (x2 over 22m)  horizontal-pod-autoscaler  New size: 1; reason: All metrics below target

上面的整个过程就向我们完整的展示了 HPA 自动扩缩容的过程。


7.3 配置 HPA

在前面我们使用的是命令行的方式直接定义扩缩容规则,这一般用于简单规则的情况。对于需要定义复杂或是多样的扩缩容规则,则可以使用 HorizontalPodAutoscaler 资源对象来实现自定义。

HorizontalPodAutoscaler 资源对象属于 autoscaling API 组,它包括两个版本:

  • v1版本:只支持基于 CPU 使用率的自动扩缩容配置
  • v2版本:支持基于任意指标的自动扩缩容配置,比如:资源使用率、Pod 指标、其它指标等,目前广泛使用的版本为 autoscaling/v2beta2

v1 版本

在前面的示例中,通过 CPU 的平均使用率配置扩缩容,在上面使用的是命令的方式直接配置,其实也可以手动使用 YAML 文件创建自动伸缩,可以直接使用 autoscaling/v1 版本,新建 php-apache-hpa.yaml 文件,并写入如下内容:

apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
  name: php-apache
  namespace: default
spec:
  # 目标作用对象 scaleTargetRef
  scaleTargetRef:
    apiVersion: apps/v1
    # 类型 kind,可以为 Deployment、rc 或是 rs
    kind: Deployment
    name: php-apache
  # Pod 副本数量的最小值
  minReplicas: 1
  # Pod 副本数量的最大值
  maxReplicas: 10
  # 期望每个 Pod 的 CPU 使用率 targetCPUUtilizationPercentage,这里设置为 50%,这个使用率基于 Pod 设置的 CPU Request 值进行计算,在前面设置了 requests cpu 为 200m,所以系统会维持 Pod 的实际 CPU 使用率为 100m
  targetCPUUtilizationPercentage: 50

v2beta2 版本

如果使用 autoscaling/v2beta2 API 版本进行设置,则前面定义的 YAML 文件内容应该改写为如下所示:

apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
  name: php-apache
  namespace: default
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: php-apache
  minReplicas: 1
  maxReplicas: 10
  # 在 v2beta2 版本中,使用 metrics 字段定义目标指标值
  metrics:
    # type 字段表示指标类型
    - type: Resource
      resource:
        name: cpu
        # target 字段定义指标的目标值,系统在指标数据达到目标值时将触发扩缩容操作
        target:
          type: Utilization
          averageUtilization: 50

metrics.type 指标类型可以设置为如下三种中的任一一个或是多个的组合:

  • Resource: 基于资源的指标值,这里的资源指的是 CPU 和内存 Memory
  • Pods: 基于 Pod 的指标值,会将系统中全部 Pod 的指标值进行平均值计算
  • Object: 基于某种资源对象(比如 Ingress)的指标值,或是自定义的指标值

对于 Resource 类型指标而言:

  • CPU 使用率:在 target.averageUtilization 字段中设置目标平均 CPU 使用率
  • 内存 Memory 资源:在 target.AverageValue 字段中设置目标平均内存使用值
  • 指标数据通过 metrics.k8s.io API 进行查询
  • 必须先启动 Metrics Server 服务

Pods 和 Object 类型指标都属于自定义指标类型,它们的共同点在于:

  • 指标数据通过搭建自定义 Metrics Server 服务和监控工具获取
  • 指标数据通过 custom.metrics.k8s.io API 进行查询
  • 必须先启动自定义的 Metrics Server 服务

Pods 类型指标的数据是从系统中所有 Pod 获取到的,所以 target.type 字段只能使用 AverageValue,比如我们需要设置一个 Pods 类型指标名为 packets-per-second,要求在目标指标平均值为 1000 时触发扩缩容操作,则对应的 YAML 文件定义如下所示:

metrics:
  # type 字段表示指标类型
  - type: Pods
    Pods:
      # metrics.name 字段设置指标的名字
      metrics:
        name: packets-per-second
      # target 字段定义指标的目标值,系统在指标数据达到目标值时将触发扩缩容操作
      target:
        type: AverageValue
        averageValue: 1k

Object 类型指标数据来源于其它资源对象或是自定义指标,target.type 字段可以为 Value 或是 AverageValue(这时会根据 Pod 数量计算平均值),这里可以看两个示例:

  1. 数据来源于其它资源对象:设置一个 Object 类型指标名为 requests-per-second,它的值来源于 Ingress “main-route”,当目标值为 2000 时触发扩缩容操作,对应的 YAML 文件格式内容如下:
metrics:
  - type: Object
    object:
      metrics:
        name: requests-per-second
      describedObject:
        apiVersion: networking.k8s.io/v1beta1
        kind: Ingress
        name: main-route
      target:
        type: Value
        value: 2k
  1. 数据来源于自定义指标:设置一个 Object 类型指标名为 http_requests,且必须具有标签 “verb=GET”,当指标平均值达到 500 时触发扩缩容操作,对应的 YAML 文件格式内容如下:
metrics:
  - type: Object
    object:
      metrics:
        name: "http_requests"
        selector: "verb=GET"
      target:
        type: AverageValue
        averageValue: 500

当一个 HPA 资源对象定义了多种类型的指标时,系统会针对每一种类型的指标都计算 Pod 目标值,最终会以结果中最大的 Pod 值进行扩缩容操作。

从 Kubernetes v1.10 版本开始,metrics.type 指标类型新增了一个名为 External 的值:

  • 可以支持外部系统指标,比如公有云服务商提供的消息服务或是外部负载均衡器,
  • 指标数据通过 external.metrics.k8s.io API 进行查询
  • 必须先启动自定义的 Metrics Server 服务

比如设置一个 External 类型指标名为 queue_messages_ready,且必须具有标签 “queue=worker_tasks”,当指标平均值达到 30 时触发扩缩容操作,对应的 YAML 文件格式内容如下:

metrics:
  - type: External
    object:
      metrics:
        name: queue_messages_ready
        selector: "queue=worker_tasks"
      target:
        type: AverageValue
        averageValue: 30

不过依然推荐尽量使用 Object 类型的资源对象,因为它和 Kubernetes 系统的集成更加自然紧密。

0

评论区