Kubernetes高级调度 Initcontainer、Ephemeral containers和HPA

        在前面的章节,已经学习过 Kubernetes 的调度基础,实现了将自己的服务部署到Kubernetes,但是在生产环境中,调度远远比自己想象的要复杂。
        比如:

  • 某些程序只能部署在固定的几台机器上。
  • 某些机器只能部署指定的 Pod。
  • 节点挂了怎么快速恢复。
  • 节点挂了如何让影响度最小。
  • 在线 Debug 没有命令怎么办。

        上述只是列举了一些需求,真实的情况可能更为复杂,所以我们需要更高级的调度方式、更实用的功能来解决上述各种问题。Kubernetes 原生有很多功能均能解决上述问题。本章我们就来学习Kubernetes 更高级的调度。

一、初始化容器 Initcontainer

        首先来看初始化容器,顾名思义,初始化容器是用来进行初始化操作的。很多情况下,程序的启动需要依赖各类配置、资源。但是又不能继承在原有的启动命令或者镜像当中,因为程序的镜像可能并没有加载配置命令,此时 Initcontainer 就起了很大的作用。

1.Initcontainer 的基本概念

        Initcontainer 是 Kubernetes 的初始化容器(也可称之为 Init 容器),它是一种特殊的容器,在Pod 内的应用容器启动之前运行,可以包括一些应用镜像中不存在的使用工具和安装脚本,用以在程序启动时进行初始化,比如创建文件、修改内核参数、等待依赖程序启动等。
        每个 Pod 中可以包含多个容器,同时 Pod 也可以有一个或多个先于应用程序启动的 Init 容器,在 Pod定义中和 container 同级,按顺序逐个执行,当所有的 Init 容器运行完成时,Kubernetes 才会启动 Pod内的普通容器。

Init 容器与普通的容器非常像,除了如下几点:

  • 他们总是运行到完成。
  • 上一个运行完成才会运行下一个。
  • 如果 Pod 的 Init 容器失败,Kubernetes 会不断地重启该 Pod,直到 Init 容器成功为止,但是如果 Pod 对应的 restartPolicy 值为 Never,Kubernetes 则不会重新启动 Pod。

        为Pod 设置 Init 容器需要在 Pod的 spec 中添加 initcontainer 字段,该字段和应用的 containers属组同级相邻,配置方式和 containers 中的普通容器差不多,Init 容器支持应用容器的全部字段和特性,包括资源限制、数据卷和安全设置。但是 Init 容器对资源请求和限制的处理稍有不同,Init 容器不支持 lifecycle、livenessProbe、readinessProbe 和 startupProbe,因为他们必须在 Pod 就绪之前运行完成。

        在生产环境中,为了应用的安全和优化镜像的体积,业务镜像一般不会安装高危工具和并不常用的运维工具,比如 cur1、sed、awk、python 或 dig 等,同时建议使用非 root 用户去启动容器。但是某些应用启动之前可能需要检查依赖的服务有没有成功运行,或者需要更高的权限去修改一些系统级的配置,而这些检测或配置更改都是一次性的,所以在制作业务镜像时没有必要为了一次配置的变更去安装一个配置工具,更没有必要因为使用一次高权限而把整个镜像改成以root 身份运行。

        考虑到上述问题和需求,Kubernetes 引入了初始化容器的概念,Init 容器具有与应用容器分离的单独镜像,其启动相关代码具有如下优势:

  • Init 容器可以包含安装过程中应用容器中不存在的实用工具或个性化代码。
  • Init 容器可以安全地运行这些工具,避免这些工具导致应用镜像的安全性降低。
  • Init 容器可以以 root 身份运行,执行一些高权限命令
  • Init 容器相关操作执行完成后就会退出,不会给业务容器带来安全隐患。

        由于 Init 容器必须在应用容器启动之前运行完成,因此 Init 容器提供了一种机制来阻塞或延迟应用容器的启动,知道满足一组先决条件,Pod内的所有应用容器才会并行启动。

2.延迟指定时间后启动

        创建一个 pod,initcontainers 指定初始化容器,command:["sh","-c","sleep 15"]表示初始化容器需要休眠 15 秒。

[root@master ~]# vim init01.yml apiVersion: v1
kind: Pod
metadata:creationTimestamp: nulllabels:run: initc01name: initc01
spec:terminationGracePeriodSeconds: 0containers:- image: nginx:1.7.9imagePullPolicy: IfNotPresentname: n1resources: {}initContainers:- name: initc01image: nginx:1.7.9imagePullPolicy: IfNotPresentcommand: ["sh","-c","sleep 15"]dnsPolicy: ClusterFirstrestartPolicy: Never
status: {}
[root@master ~]# ku create -f init01.yml 
pod/initc01 created

不断地查看Pod启动状态,15秒后会发现Pod开始启动

[root@master ~]# ku get pod
NAME      READY   STATUS     RESTARTS   AGE
initc01   0/1     Init:0/1   0          3s
[root@master ~]# ku get pod
NAME      READY   STATUS     RESTARTS   AGE
initc01   0/1     Init:0/1   0          12s
[root@master ~]# ku get pod
NAME      READY   STATUS     RESTARTS   AGE
initc01   0/1     Init:0/1   0          13s
[root@master ~]# ku get pod
NAME      READY   STATUS    RESTARTS   AGE
initc01   1/1     Running   0          86s

3.使用初始化容器修改内核参数

        在容器里修改内核参数,实际上修改的就是物理机的内核参数,为了安全性,一般不允许在容器里修改内核参数,Seccomp 代表安全计算(Secure computing)模式,seccomp控制了容器能做哪些操作,添加 securitycontext 参数之后就可以修改内核参数了。
        创建一个 pod,initcontainers 初始化容器里的 securityContext:privileged:true 表示该容器具有特权,可以执行命令"sh","-c","/sbin/sysctl -w vm.swappiness=0",vm.swappiness 设置为8表示尽量少使用 swap 内存。

[root@master ~]# vim init02.yml apiVersion: v1
kind: Pod
metadata:creationTimestamp: nulllabels:run: initc02name: initc02
spec:terminationGracePeriodSeconds: 0containers:- image: nginx:1.7.9imagePullPolicy: IfNotPresentname: n1resources: {}initContainers:- name: initc02image: alpineimagePullPolicy: IfNotPresentcommand: ["sh","-c","/sbin/sysctl -w vm.swappiness=0"]securityContext:privileged: truednsPolicy: ClusterFirstrestartPolicy: Never
status: {}
[root@master ~]# ku create -f init02.yml
pod/initc02 created
[root@master ~]# ku get pod
NAME      READY   STATUS    RESTARTS   AGE
initc01   1/1     Running   0          8m53s
initc02   1/1     Running   0          5s

查看Pod中的容器

[root@master ~]# ku get pod -o wide
NAME      READY   STATUS    RESTARTS   AGE     IP               NODE    NOMINATED NODE   READINESS GATES
initc01   1/1     Running   0          9m23s   10.244.104.7     node2   <none>           <none>
initc02   1/1     Running   0          35s     10.244.166.135   node1   <none>           <none>

査看 k8s-node01 机器上的 swappiness 值是否为 0

[root@node1 ~]# cat /proc/sys/vm/swappiness 
0

4.等待依赖服务启动

        有时某些服务需要依赖其他组件才能启动,比如后端应用需要数据库启动之后,应用才能正常启动,此时需要检测数据库实例是否正常,等待数据库可以正常使用时,在启动后端应用,此时可以使用初始化容器进行控制。

(1)创建第一个 Pod

        该 Pod 内要依赖两个条件才能启动,一个是利用 busybox 容器检测 redis-service 服务是否生成第二个是检测 mysql-server 服务是否生成。

[root@master ~]# vim myapp.yaml apiVersion: v1
kind: Pod
metadata:name: nginxlabels:name: nginx
spec:containers:- name: nginximage: nginx:1.7.9ports:- containerPort: 80initContainers:- name: init-redisimage: busybox:1.28command: ['sh', '-c', 'until nslookup redis-service; do echo waiting for nginx01; sleep 2; done;']- name: init-mysqlimage: busybox:1.28command: ['sh', '-c', 'until nslookup mysql-service; do echo waiting for nginx02; sleep 2; done;']
[root@master ~]# ku create -f myapp.yaml 
pod/nginx created
[root@master ~]# ku get pod
NAME      READY   STATUS     RESTARTS   AGE
initc01   1/1     Running    0          19m
initc02   1/1     Running    0          11m
nginx     0/1     Init:0/2   0          3s
(2)创建第一个被依赖的service
[root@master ~]# vim redis-deployment.yaml apiVersion: apps/v1
kind: Deployment
metadata:labels:app: redisname: redis
spec:replicas: 1selector:matchLabels:app: redistemplate:metadata:labels:app: redisspec:containers:- image: redis:5.0imagePullPolicy: IfNotPresentname: redis
---
apiVersion: v1
kind: Service
metadata:labels:app: redisname: redis-service
spec:ports:- port: 6379protocol: TCPtargetPort: 6379selector:app: redistype: NodePort
[root@master ~]# ku create -f redis-deployment.yaml 
deployment.apps/redis created
service/redis-service created
[root@master ~]# ku get pod
NAME                     READY   STATUS     RESTARTS   AGE
initc01                  1/1     Running    0          23m
initc02                  1/1     Running    0          15m
nginx                    0/1     Init:1/2   0          4m4s
redis-56bcf55554-l2cx9   1/1     Running    0          12s
[root@master ~]# ku get svc
NAME            TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
kubernetes      ClusterIP   10.96.0.1        <none>        443/TCP          7d23h
redis-service   NodePort    10.105.228.231   <none>        6379:31759/TCP   57s
(3)创建第二个被依赖的service 
[root@master ~]# vim mysql-deployment.yaml apiVersion: apps/v1
kind: Deployment
metadata:labels:app: mysqlname: mysql
spec:replicas: 1selector:matchLabels:app: mysqltemplate:metadata:labels:app: mysqlspec:containers:- env:- name: MYSQL_ROOT_PASSWORDvalue: 'moonfdd'image: 'mysql:8.0'imagePullPolicy: IfNotPresentname: mysqlvolumeMounts:- mountPath: /var/lib/mysqlname: volvvolumes:- hostPath:path: /root/k8s/moonfdd/mysql/var/lib/mysqltype: DirectoryOrCreatename: volv
---
apiVersion: v1
kind: Service
metadata:labels:app: mysqlname: mysql-service
spec:ports:- port: 3306protocol: TCPtargetPort: 3306selector:app: mysqltype: NodePort
[root@master ~]# ku create -f mysql-deployment.yaml 
deployment.apps/mysql created
service/mysql-service created
[root@master ~]# ku get svc
NAME            TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
kubernetes      ClusterIP   10.96.0.1        <none>        443/TCP          7d23h
mysql-service   NodePort    10.107.70.144    <none>        3306:31785/TCP   27s
redis-service   NodePort    10.105.228.231   <none>        6379:31759/TCP   2m25s
[root@master ~]# ku get pod
NAME                     READY   STATUS    RESTARTS   AGE
initc01                  1/1     Running   0          26m
initc02                  1/1     Running   0          17m
mysql-7f5d669b6c-9t9t4   1/1     Running   0          30s
nginx                    1/1     Running   0          6m20s
redis-56bcf55554-l2cx9   1/1     Running   0          2m28s

        到这里可以发现,当把 redis-service 和 mysq1-service 两个服务创建出来后,nginx 的 Pod 就正常运行了。

5.pause 容器

(1)Pause 容器特点

镜像非常小,目前在 700KB 左右

是pod中其他各个容器的父容器

提供网络命名空间

网络接口

pod生命周期管理

(2)Pause 容器背景

        像 Pod 这样一个东西,本身是一个逻辑概念。那在机器上,它究竟是怎么实现的呢?这就是我们要解释的一个问题。
        既然说 Pod 要解决这个问题,核心就在于如何让一个 Pod 里的多个容器之间最高效的共享某些资源和数据。
        因为容器之间原本是被 Linux Namespace 和 cgroups 隔开的,所以现在实际要解决的是怎么去打破这个隔离,然后共享某些事情和某些信息。这就是 Pod 的设计要解决的核心问题所在。
        所以说具体的解法分为两个部分:网络和存储,

        Pause 容器就是为解决 Pod 中的网络问题而生的。

(3)Pause 容器实现

        Pod 里的多个容器怎么去共享网络?下面是个例子:
        比如说现在有一个 Pod,其中包含了一个容器 A 和一个容器 B,它们两个就要共享 NetworkNamespace。在 Kubernetes 里的解法是这样的:它会在每个 Pod 里,额外起一个 Infra(基础)container 小容器来共享整个 Pod的 Network Namespace。
        Infra container 是一个非常小的镜像,大概 70KB 左右,是一个 ( 语言写的、永远处于 “暂停”状态的容器。由于有了这样一个 Infra container 之后,其他所有容器都会通过 Join Namespace的方式加入到 Infra container 的Network Namespace 中。

        Infra container 是一个非常小的镜像,大概 780KB 左右,是一个 ( 语言写的、永远处于"暂停”状态的容器。由于有了这样一个 Infra container 之后,其他所有容器都会通过 Join Namespace的方式加入到 Infra container 的Network Namespace 中。
        所以说一个 Pod 里面的所有容器,它们看到的网络视图是完全一样的。即:它们看到的网络设备IP 地址、Mac地址等等,跟网络相关的信息,其实全是一份,这一份都来自于 Pod 第一次创建的这个Infra container。这就是 Pod 解决网络共享的一个解法。
        在 Pod 里面,一定有一个 IP 地址,是这个 Pod 的 Network Namespace 对应的地址,也是这个Infra container 的 IP 地址。所以大家看到的都是一份,而其他所有网络资源,都是一个 Pod 一份并且被 Pod 中的所有容器共享。这就是Pod 的网络实现方式。
        由于需要有一个相当于说中间的容器存在,所以整个 Pod 里面,必然是 Infra container 第一个启动。并且整个 Pod 的生命周期是等同于 Infra container 的生命周期的,与容器 A 和 B 是无关的。这也是为什么在 Kubernetes 里面,它是允许去单独更新 Pod 里的某一个镜像的,即:做这个操作,整个 Pod 不会重建,也不会重启,这是非常重要的一个设计。

查看nginx的Pod运行在的主机

[root@master ~]# ku get pod -o wide
NAME                     READY   STATUS    RESTARTS   AGE   IP               NODE    NOMINATED NODE   READINESS GATES
initc01                  1/1     Running   0          37m   10.244.104.7     node2   <none>           <none>
initc02                  1/1     Running   0          28m   10.244.166.135   node1   <none>           <none>
mysql-7f5d669b6c-9t9t4   1/1     Running   0          11m   10.244.104.9     node2   <none>           <none>
nginx                    1/1     Running   0          17m   10.244.104.8     node2   <none>           <none>
redis-56bcf55554-l2cx9   1/1     Running   0          13m   10.244.166.136   node1   <none>           <none>

在k8s-node01主机上查看Pod中的pause容器

[root@node1 ~]# docker ps | grep nginx
8762d2183660   84581e99d807                                        "nginx -g 'daemon of…"   30 minutes ago      Up 30 minutes                k8s_n1_initc02_default_552fe78f-a04c-4568-8d49-aca2eda5f31f_0

二、临时容器 Ephemeral containers

        在生产环境中,为了优化镜像的体积和提高镜像的安全性,并不会在容器中安装太多高危工具。比如cur1、wget、dig 以及常用的 net-tools 等。这样做虽然提高了镜像的安全性,但是也带来了一些不便,比如无法査看容器内的进程情况、无法査看容器内的链接情况、服务出了问题无法很方便的进行排査等。因为上述操作并非经常使用,所以我们并没有必要从一开始就安装这些工具,但是等到用他们的时候再安装也是一件很麻烦的事情,那么我们该如何处理这个问题呢?
        为了解决这类问题,在 1.16 版本后,Kubernetes 引入了 Ephemeral containers 的概念,可以不用安装第三方工具即可实现在线 Debug 操作。

1.临时容器的概念

        临时容器与其他容器的不同之处在于,临时容器是被临时添加到 Pod 上,用于在线调试应用的,他永远不会自动重启,因此不适用与构建应用程序,临时容器的声明和普通容器类似,但是临时容器没有端口配置,因此不能使用像 ports、livenessprobe、readnessProbe、resources 这样的字段,当然,临时容器只是用来调试程序的,它的状态不会影响其他正常容器,所以它并不需要这些字段配置。
        临时容器使用 API 中一种特殊的 Ephemeral Containers 处理器进行创建,而不是直接添加到pod.spec 字段,因此无法使用 kubectl edit 来添加临时容器,与常规容器一样,将临时容器添加到 Pod后,将不能更改或删除临时容器,但是当添加了临时容器的 Pod 重启后,临时容器就会被销毁。

        因为临时容器是为了调试程序而设计的,所以在添加临时容器时,最好使用一个包含所有常用工具的镜像进行创建。当业务容器崩溃或容器镜像不包含调试工具而导致 kubectl exec 不可用时,临时容器对于交互故障排査和在线 Debug 很有用。尤其是在使用像不包含任何 shell 和其他工具的 destroless 镜像作为基础镜像时,虽然可以减少攻击面和漏洞,但对于问题的排査会变得尤为棘手,此时临时容器就可以发挥很大的作用,带来诸多便利性。

2.开启临时容器功能

        开启临时容器比较简单,只需要在 featrue-gates 字段添加 Ephemeral containers=true,然后使用临时容器的资源开启共享命名空间 shareProcessNamespace:true。具体操作如下:

(1)在所有Kubernetes Node节点配置 kubelet 参数
[root@master ~]# vim /etc/kubernetes/kubelet.conf

在文件末尾添加:

dratureGates:
Ephemeracontainers:true

修改完成后重启kubelet进程

[root@k8s-node01 ~]# systemctl daemon-reload
[root@k8s-node01 ~]# systemctl restart kubelet
(2)在所有master节点配置 APIServer 参数
[root@k8s-master ~]# vim /usr/lib/systemd/system/kubelet.service
[Service]
Execstart=/usr/bin/kubelet--feature-gates=Ephmemralcontainers=true
Restart=always
StartLimitInteryal=0
RestartSec=10
[root@k8s-master ~]# vim /etc/kubernetes/manifests/kube-apiserver.yaml
spec:containers:- command:- kube-apiserver- --advertise-address=192.168.10.101。。。- --tls-private-key-file=/etc/kubernetes/pki/apiserver.key- --feature-gates=Ephemeralcontainers=true  ##在 command 字段末尾增加
[root@k8s-master ~l# vim /etc/kubernetes/manifests/kube-scheduler.yaml
spec:containers:- command:- kube-scheduler- --authentication-kubeconfig=/etc/kubernetes/scheduler.conf- --authorization-kubeconfig=/etc/kubernetes/scheduler.conf- --bind-address=127.0.0.1- --kubeconfig=/etc/kubernetes/scheduler.conf- --leader-elect=true- --feature-gates=EphemeralContainers=true   ##在 command 字段末尾增加
[root@k8s-master ~]# vim /etc/sysconfig/kubelet
KUBELET EXTRA ARGS="--feature-gates=EphemeralContainers=true"   ##添加

 修改完成后重启kubelet进程

[root@k8s-master ~]#systemctl daemon-reload
[root@k8s-master ~]#systemctl restart kubelet

3.临时容器的使用

(1)创建一个tomcat的资源清单
[root@master ~]# vim pod-tomcat.yaml apiVersion: v1
kind: Pod
metadata:name: tomcat-testnamespace: defaultlabels:app:  tomcat
spec:containers:- name:  tomcat-javaports:- containerPort: 8080image: kubeguide/tomcat-app:v1imagePullPolicy: IfNotPresent
(2)创建Pod
[root@master ~]# ku create -f pod-tomcat.yaml 
pod/tomcat-test created
[root@master ~]# ku get pod
NAME                     READY   STATUS    RESTARTS   AGE
initc01                  1/1     Running   0          57m
initc02                  1/1     Running   0          48m
mysql-7f5d669b6c-9t9t4   1/1     Running   0          31m
nginx                    1/1     Running   0          37m
redis-56bcf55554-l2cx9   1/1     Running   0          33m
tomcat-test              1/1     Running   0          8s
 (3)为tomcat的pod创建临时容器
[root@master ~]# ku debug -it tomcat-test --image=busybox:1.28 --target=tomcat-java 
Targeting container "tomcat-java". If you don't see processes from this container it may be because the container runtime doesn't support this feature.
Defaulting debug container name to debugger-rqj55.
If you don't see a command prompt, try pressing enter.

 执行后稍等一会,能够进入tomcat容器的交互界面,如下所示:

/ # ps -ef | grep tomcat1 root      0:04 /usr/lib/jvm/java-7-openjdk-amd64/jre/bin/java -Djava.util.logging.config.file=/usr/local/tomcat/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djdk.tls.ephemeralDHKeySize=2048 -Djava.endorsed.dirs=/usr/local/tomcat/endorsed -classpath /usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar -Dcatalina.base=/usr/local/tomcat -Dcatalina.home=/usr/local/tomcat -Djava.io.tmpdir=/usr/local/tomcat/temp org.apache.catalina.startup.Bootstrap start40 root      0:00 grep tomcat
 (4)查看tomcat-test这个pod是否已经有临时容器
[root@master ~]# ku describe pods tomcat-test
Name:         tomcat-test
Namespace:    default
Priority:     0
Node:         node1/192.168.10.102
Start Time:   Tue, 27 Aug 2024 09:57:04 +0800
Labels:       app=tomcat
Annotations:  cni.projectcalico.org/containerID: 07a67467244facb494b06a92799d7b0cf0eaa7f71cdb5224c183790fc6ff9933cni.projectcalico.org/podIP: 10.244.166.137/32cni.projectcalico.org/podIPs: 10.244.166.137/32
Status:       Running
IP:           10.244.166.137
IPs:IP:  10.244.166.137
Containers:tomcat-java:Container ID:   docker://dc2dd371997d5f521e4229514d25e1355b290825334293d382a0cec9cc28dc42Image:          kubeguide/tomcat-app:v1Image ID:       docker://sha256:a29e200a18e9b15176cd795710b71d7b1bc97207ed6fcdebba645769c3b01669Port:           8080/TCPHost Port:      0/TCPState:          RunningStarted:      Tue, 27 Aug 2024 09:57:05 +0800Ready:          TrueRestart Count:  0Environment:    <none>Mounts:/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-pds5b (ro)
Ephemeral Containers:debugger-rqj55:Container ID:   docker://93f164ded538991533f8eb44f21d74ed86c05b44c0efaae372971608ce5eb97cImage:          busybox:1.28Image ID:       docker://sha256:8c811b4aec35f259572d0f79207bc0678df4c736eeec50bc9fec37ed936a472aPort:           <none>Host Port:      <none>State:          TerminatedReason:       CompletedExit Code:    0Started:      Tue, 27 Aug 2024 10:02:13 +0800Finished:     Tue, 27 Aug 2024 10:03:20 +0800Ready:          FalseRestart Count:  0Environment:    <none>Mounts:         <none>
Conditions:Type              StatusInitialized       True Ready             True ContainersReady   True PodScheduled      True 
Volumes:kube-api-access-pds5b:Type:                    Projected (a volume that contains injected data from multiple sources)TokenExpirationSeconds:  3607ConfigMapName:           kube-root-ca.crtConfigMapOptional:       <nil>DownwardAPI:             true
QoS Class:                   BestEffort
Node-Selectors:              <none>
Tolerations:                 node.kubernetes.io/not-ready:NoExecute op=Exists for 300snode.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:Type    Reason     Age    From               Message----    ------     ----   ----               -------Normal  Scheduled  6m59s  default-scheduler  Successfully assigned default/tomcat-test to node1Normal  Pulled     6m58s  kubelet            Container image "kubeguide/tomcat-app:v1" already present on machineNormal  Created    6m58s  kubelet            Created container tomcat-javaNormal  Started    6m58s  kubelet            Started container tomcat-javaNormal  Pulled     110s   kubelet            Container image "busybox:1.28" already present on machineNormal  Created    110s   kubelet            Created container debugger-rqj55Normal  Started    110s   kubelet            Started container debugger-rqj55

三、自动扩缩容HPA

        在集群安装的过程中,我们可以安装一个叫 Metrics Server 的组件,该组件在集群中负责采集 Pod和 Node 的度量值指标,比如 Pod 的 CPU、内存使用率和节点的内存、CPU 使用率,而且安装的 Dashboard可以展示 CPU、内存信息也是依靠 Metrics server 的。当然,该组件不仅仅是用来展示数据的,还可以使用 Metrics Server 提供的数据结合 Kubernetes 的 HPA 功能实现 Pod 的自动扩缩容。

1.什么是HPA

        HPA(Horizontal Pod Autoscaler,水平 Pod 自动伸缩器)可以根据观察到的 CPU、内存使用率或自定义度量标准来自动扩展或缩容 Pod 的数量。注意 HPA不适用于无法缩放的对象,比如 Daemonset。
        HPA 控制器会定期调整 RC或 Deployment 的副本数,以使观察到的平均 CPU 利用率与用户指定的目标相匹配。

        HPA 需要 Metrics Server 获取度量指标,如果已经部署了 Metrics Server,本节的实践部就分无须再次安装 Metrics Server。如果没有安装Metrics Server,可以参考其他实验文档自行部署。

2.HPA 实践--实现 Web 服务器的自动伸缩特性

        在生产环境中,总会有一些意想不到的事情发生,比如公司网站流量突然升高,此时之前创建的 Pod已不足以支撑所有的访问,而运维人员也不可能 24 小时守着业务服务,这时就可以通过配置 HPA,实现负载过高的情况下自动扩容 Pod 副本数以分摊高并发的流量,当流量恢复正常后,HPA 会自动缩减 Pod 的数量。
        本节将测试实现一个 web 服务器的自动伸缩特性,具体步骤如下:

(1)首先用 Deployment 启动一个 Nginx服务(须配置 requests 参数):
[root@master ~]# vim nginx-deployment.yaml apiVersion: apps/v1
kind: Deployment
metadata:name: nginx-serverlabels:name: nginx-server
spec:replicas: 2selector:matchLabels:app: nginxtemplate:metadata:labels:app: nginxspec:containers:- name: nginxresources:requests:cpu: 10mimage: nginx:1.7.9ports:- name: nginxcontainerPort: 80
[root@master ~]# ku create -f nginx-deployment.yaml 
deployment.apps/nginx-server created
(2)配置nginx-server的service
[root@master ~]# ku expose deployment nginx-server --port=80
service/nginx-server exposed
(3)使用 kubectl autoscale 命令创建 HPA
[root@master ~]# ku autoscale deployment nginx-server --cpu-percent=10 --min=1 --max=10 
horizontalpodautoscaler.autoscaling/nginx-server autoscaled

        此 HPA 将根据 CPU的使用率自动增加和减少副本数量,上述设置的是 CPU 使用率超过 10%(--cpu-percent 参数指定)就会增加 Pod 的数量,以保持所有 Pod 的平均 CPU 利用率为 10%,允许最大的 Pod 数量为 10(--max),最少的 Pod 数为1(--min)。

(4)查看当前 HPA 的状态

因为未对其发送任何请求,所以当前 CPU 使用率为0%

[root@master ~]# ku get hpa
NAME           REFERENCE                 TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
nginx-server   Deployment/nginx-server   0%/10%    1         10        2          26s

备注:

如果看不到TARGET的CPU利用率,可以多等十几秒

(5)查看当前Ngmx的Service地址
[root@master ~]# ku get service -n default
NAME            TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
kubernetes      ClusterIP   10.96.0.1        <none>        443/TCP          8d
mysql-service   NodePort    10.107.70.144    <none>        3306:31785/TCP   83m
nginx-server    ClusterIP   10.105.216.27    <none>        80/TCP           32m
redis-service   NodePort    10.105.228.231   <none>        6379:31759/TCP   85m
(6)压力测试(打开一个新的终端) 

新开一个终端,使用一个“死”循环或其他压测工具模拟访问该Service,从而增加该Pod的负载

[root@master ~]# while true;do wget -q -O- http://10.105.216.27 >/dev/null;done
(7)查看HPA状态

等待一分钟左右,再次查看HPA,可以看到Pod的CPU已经升高

[root@master ~]# ku get hpa
NAME           REFERENCE                 TARGETS    MINPODS   MAXPODS   REPLICAS   AGE
nginx-server   Deployment/nginx-server   170%/10%   1         10        8          32m
 (8)再次查看Pod,可以看到已经扩容(Pod副本增加到了10个)
[root@master ~]# ku get pod
NAME                            READY   STATUS    RESTARTS   AGE
initc01                         1/1     Running   0          115m
initc02                         1/1     Running   0          106m
mysql-7f5d669b6c-9t9t4          1/1     Running   0          89m
nginx                           1/1     Running   0          95m
nginx-server-6ddcfd4c8f-97884   1/1     Running   0          2m52s
nginx-server-6ddcfd4c8f-gm9pw   1/1     Running   0          2m37s
nginx-server-6ddcfd4c8f-kj525   1/1     Running   0          3m7s
nginx-server-6ddcfd4c8f-pv6vc   1/1     Running   0          2m52s
nginx-server-6ddcfd4c8f-sc2hn   1/1     Running   0          2m52s
nginx-server-6ddcfd4c8f-sjdjc   1/1     Running   0          2m37s
nginx-server-6ddcfd4c8f-tdj6t   1/1     Running   0          40m
nginx-server-6ddcfd4c8f-wt6w6   1/1     Running   0          3m7s
nginx-server-6ddcfd4c8f-z4826   1/1     Running   0          2m52s
nginx-server-6ddcfd4c8f-zcwmm   1/1     Running   0          3m7s
redis-56bcf55554-l2cx9          1/1     Running   0          91m
tomcat-test                     1/1     Running   0          58m
(9)停止压力测试

Ctrl+C终止终端的测试,等待一分钟左右,再次查看HPA状态

[root@master ~]# ku get hpa
NAME           REFERENCE                 TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
nginx-server   Deployment/nginx-server   5%/10%    1         10        10         4m32s
(10)查看pod的副本数
[root@master ~]# ku get pod
NAME                            READY   STATUS    RESTARTS   AGE
initc01                         1/1     Running   0          101m
initc02                         1/1     Running   0          93m
mysql-7f5d669b6c-9t9t4          1/1     Running   0          76m
nginx                           1/1     Running   0          82m
nginx-server-6ddcfd4c8f-tdj6t   1/1     Running   0          27m
redis-56bcf55554-l2cx9          1/1     Running   0          78m
tomcat-test                     1/1     Running   0          45m

备注:

需要多等待几分钟后,才能看到缩容后的pod

(11)清除
kubectl delete -f nginx-deployment.yamlkubectl delete -f mysql-deployment.yaml
kubectl delete -f redis-deployment.yaml
kubectl delete -f inito1.yml
kubectl delete -f init02.yml

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/52690.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用ffmpeg+node-media-server实现从rtsp服务器拉流再推送至rtmp服务器,实现http+flv进行web播放

最近由于项目的需要&#xff0c;需要从海康的摄像头中读取视频流然后在web页面上展示。 由于海康摄像头使用了rtsp协议提供视频拉流服务&#xff0c;而web页面目前使用的插件不支持直接播放rtsp协议的视频流&#xff1b;因此考虑使用ffmpeg从rtsp中拉流&#xff0c;再推流至rtm…

PDF招生简章如何转二维码?

​随着科技的不断发展&#xff0c;招生报名方式也在不断创新。如今&#xff0c;许多学校和企业都采用PDF招生简章来宣传招生。然而&#xff0c;传统的纸质招生简章存在携带不便、易损坏等问题。为了解决这些问题&#xff0c;将PDF招生简章转换为二维码成为了一种趋势。那你知道…

随身携带的android TV盒子以及tvbox-fongmi版的安装

https://www.everythingkodibuilds.com/p/install-android-tv-on-usb.html 现在大家都有笔记本,只要一个U盘,笔记本就能变身android电视盒子,这样也不错.这个文章就是介绍了这样的思路和实现的方法. 如果手里有x86的小型机,还能直接放在家里. 下面进入正题,先说上文中的流程和要…

微信小程序开发--详情【开发一次 多端覆盖】

目录 1、准备工作 了解 uni-app : 准备开发工具&#xff1a; 下载 &#xff1a; 安装完成后&#xff0c;打开这个开发者工具&#xff1a; 对微信小程序进行配置&#xff1a; 使用开发工具HBuilderX:&#xff1a; 先安装终端插件 2、初始化一个demo 创建项目&#xff1…

2024广东省职业技能大赛云计算赛项实战——安装ELK日志分析服务

安装ELK日志分析服务 前言 ELK是一个用于处理和分析日志数据的开源技术栈&#xff0c;由三个主要组件组成&#xff0c;E即Elasticsearch&#xff0c;L即Logstash&#xff0c;K即Kibana。 Elasticsearch是一个分布式搜索和分析引擎&#xff0c;用于存储、搜索和分析大量数据&…

OpenCV绘图函数(4)绘制轮廓线的函数drawContours()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 函数会在图像中绘制轮廓线&#xff0c;如果 thickness ≥ 0&#xff0c;则绘制轮廓线&#xff1b;如果 thickness < 0&#xff0c;则填充由轮…

使用Spring Cloud Consul实现微服务注册与发现的全面指南

使用 Spring Cloud Consul 实现微服务注册与发现的全面指南 在微服务架构中&#xff0c;服务之间需要频繁地相互通信和协作&#xff0c;为了使服务能够动态发现彼此的存在&#xff0c;我们需要一个服务注册与发现的机制。Spring Cloud Consul 是基于 Consul 的微服务注册与发现…

某系统任意用户创建漏洞

初来人间不知苦&#xff0c;潦倒半生一身无&#xff0c;转身回望来时路&#xff0c;方知生时为何哭。 漏洞描述 某系统存在任意用户创建漏洞&#xff0c;发送特定的请求包攻击者可以创建管理员账户登录后台 漏洞实战 出现漏洞的文件为 userproce.php&#xff0c;出现漏洞的…

基于STM32开发的智能垃圾桶系统

目录 引言环境准备工作 硬件准备软件安装与配置系统设计 系统架构硬件连接代码实现 系统初始化超声波传感器检测与垃圾桶开关控制状态显示与声音提示Wi-Fi通信与满溢通知应用场景 家庭环境的智能垃圾桶管理办公室与公共场所的智能垃圾处理常见问题及解决方案 常见问题解决方案…

POJO、PO、DTO、VO、BO到底是什么?都如何使用?(基础概念+传输示意图+示例代码)带你一次玩转层出不穷的Object

文章目录 前言一、解释关系二、POJO、PO、DTO、VO、DAO、BO1.什么是POJO&#xff08;Plain Old Java Object&#xff09;2.什么是PO&#xff08;Persistent Object&#xff09;3.什么是DTO&#xff08;Data Transfer Object&#xff09;4.什么是VO&#xff08;View Object&…

TCP三次握手过程详解

三次握手过程&#xff1a; 客户端视角&#xff1a; 1.客户端调用connect&#xff0c;开启计时器&#xff0c;发送SYN包&#xff0c;如果重传超时&#xff0c;认为连接失败 2.如果收到服务端的ACK&#xff0c;则进入ESTABLISHED状态 3.清除重传计时器&#xff0c;发送ACK&…

牛客D题连线

牛客周赛 57 D题&#xff0c;不知道为什么错了。。。 while(a.size()){cout<<a.back()<< ;a.pop_back();cout<<a.back()<< <<N<<endl;} //我最开始是这样写的,过样例的时候,多了一行 //1 0 N //问题1: 你的循环条件是while(a.size())&am…

NoSQL数据库-Redis集群详解及案例实现

一、 关系型数据库和 NoSQL 数据库 1.1 数据库主要分为两大类&#xff1a;关系型数据库与 NoSQL 数据库 关系型数据库&#xff0c;是建立在关系模型基础上的数据库&#xff0c;其借助于集合代数等数学概念和方法来处理数据库中的数据主流的 MySQL、Oracle、MS SQL Server 和 D…

mac 虚拟机PD19运行E-prime实验遇到E-prime unable to set display mode:0*80004001问题解决

作者&#xff1a;50% unable to set display mode问题 总结&#xff1a; 1. 修改该Experiment的Devices中的Dispaly为640*680&#xff0c;Color Bit Depth设置为32。&#xff08;这个分辨率仅限于学习用&#xff0c;实际实验应该还是在真机上&#xff09; 2. 右键开始菜单中的E…

删除顺序表指定区间的元素

题型一&#xff1a;从顺序表中删除给定值s和t之间&#xff08;包含s和t&#xff0c;要求s<t&#xff09;的所有元素。 思想&#xff1a;从前往后扫描&#xff0c;用k记录s和t之间的元素个数&#xff0c;若扫描的值不在s和t之间&#xff0c;将该值前移K个位置&#xff0c;否…

取模+背包

前言&#xff1a;一开始我想错了&#xff0c;一开始我想的是直接统计每一项模完后的和&#xff0c;我们只要能够取到一半&#xff0c;那么就有解&#xff0c;但是时间复杂度太大了 我们做推导 x y s u m x y sum xysum x − y k ∗ n x - y k * n x−yk∗n 那么我们可…

Mysql语句性能优化

SQL查询过程 查询缓存&#xff1a; 执行查询语句的时候&#xff0c;会先查询缓存&#xff08;MySQL 8.0 版本后移除&#xff0c;因为这个功能不太实用&#xff09;。分析器&#xff1a; 没有命中缓存的话&#xff0c;SQL 语句就会经过分析器&#xff0c;分析器说白了就是要先看…

C程序设计——类型转换

什么是类型转换 当两个不同类型的数据&#xff0c;进行算数运算时&#xff0c;就需要将两个数据转换成同一类型&#xff0c;再运算&#xff0c;这就叫类型转换。 注意&#xff0c;类型转换只是发生在计算过程中&#xff0c;并不更改变量或常量本身的类型。 隐式类型转换 经…

趋动科技联合云轴科技推出GPU云原生超融合解决方案

近日&#xff0c;趋动科技VirtAITech携手云轴科技ZStack推出GPU云原生超融合联合解决方案&#xff0c;提供全面、可扩展的云原生GPU存算一体化解决方案。 该方案基于云原生超融合及GPU资源池化技术&#xff0c;使得GPU资源管理变得更加简便易用&#xff0c;能够帮助企业用户在…

2024年第十五届蓝桥杯图形化省赛真题分享包含答案

Scratch初级:8月24日9:30-11:00 Scratch中级:8月24日14:00-15:30 Python:8月25日9:30-11:00 C++:8月25日14:00-15:30 这次考了哪些内容呢,我们来大概看看(编程题没有答案,编程题有,大家可以评论群留言单选题的答案): <