目錄
一:初始化容器 Initcontainer
1:Initcontainer 的基本概念
2:示例 1--延遲指定時間后啟動
3:示例 2--使用初始化容器修改內核參數
4:示例 3--等待依賴服務啟動
4:pause容器
二:臨時容器 Ephemeral Containers
1.臨時容器的概念
2.臨時容器的使用
三:自動擴縮容HPA
1:什么是 HPA
2:HPA 的工作原理
3:HPA 的工作流程
4:HPA 的應用場景
5:HPA 實踐--實現 web 服務器的自動伸縮特性
一:初始化容器 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 容器失敗,Kubernetes 會不斷地重啟該 Pod,直到 Init 容器成功為止,但是
如果 Pod 對應的 restartPolicy 值為 Never,Kubernetes 則不會重新啟動 Pod。
備注:
lifecycle 主要指的是容器在其運行環境中經歷的不同階段,以及 Kubernetes 如何管理和響應這些階段的能力。Kubernetes 提供了容器生命周期鉤子(Container Lifecycle Hooks),這是一種允許用戶指定在容器生命周期的特定點上運行代碼片段或命令的功能。
容器生命周期鉤子主要包括以下兩個部分:Poststart:這個鉤子在容器被創建之后立即調用,但需要注意的是,在鉤子執行的時候容器內的主進程尚未啟動。這可以用于執行一些初始化任務,比如建立文件系統的緩存目錄或其他類型的準備動作。Prestop:這個鉤子在發送信號給容器內的主進程之前調用,這意味著這是在容器被終止之前可以執行一些清理工作的最后機會。它常被用來做一些資源釋放的工作,比如關閉已經打開的數據庫連接或網絡連接等。
在生產環境中,為了應用的安全和優化鏡像的體積,業務鏡像一般不會安裝高危工具和并不常用的運維工具,比如 cur1、sed、awk、python 或 dig 等,同時建議使用非 root 用戶去啟動容器。但是某些應用啟動之前可能需要檢査依賴的服務有沒有成功運行,或者需要更高的權限去修改一些系統級的配置,而這些檢測或配置更改都是一次性的,所以在制作業務鏡像時沒有必要為了一次配置的變更去安裝一個配置工具,更沒有必要因為使用一次高權限而把整個鏡像改成以root 身份運行。
考慮到上述問題和需求,Kubernetes 引入了初始化容器的概念,Init 容器具有與應用容器分離的單
獨鏡像,其啟動相關代碼具有如下優勢:
- Init 容器可以包含安裝過程中應用容器中不存在的實用工具或個性化代碼。
- Init 容器可以安全地運行這些工具,避免這些工具導致應用鏡像的安全性降低。
- Init 容器可以以 root 身份運行,執行一些高權限命令。
- Init 容器相關操作執行完成后就會退出,不會給業務容器帶來安全隱患。
由于 Init 容器必須在應用容器啟動之前運行完成,因此 Init 容器提供了一種機制來阻塞或延遲應用容器的啟動,直到滿足一組先決條件,Pod內的所有應用容器才會并行啟動。
2:示例 1--延遲指定時間后啟動
創建一個 pod,initcontainers 指定初始化容器,command:["sh","-c","sleep 15"]表示初始化容器需要休眠 15 秒。
[root@k8s-master ~]# cat init01.yml?
apiVersion: v1
kind: Pod
metadata:
? creationTimestamp: null
? labels:
? ? run: initc01
? name: initc01
spec:
? terminationGracePeriodSeconds: 0
? containers:
? - image: nginx:1.7.9
? ? imagePullPolicy: IfNotPresent
? ? name: n1
? ? resources: {}
? initContainers:
? - name: initc01
? ? image: nginx:1.7.9
? ? imagePullPolicy: IfNotPresent
? ? command: ["sh","-c","sleep 15"]
? dnsPolicy: ClusterFirst
? restartPolicy: Never
status: {}
啟動pod,15秒后會發現pod開始啟動
[root@k8s-master ~]# kubectl create -f init01.yml?
pod/initc01 created
[root@k8s-master ~]# kubectl get pod
NAME ? ? ?READY ? STATUS ? ?RESTARTS ? AGE
initc01 ? 1/1 ? ? Running ? 0 ? ? ? ? ?3m44s
3:示例 2--使用初始化容器修改內核參數
在容器里修改內核參數,實際上修改的就是物理機的內核參數,為了安全性,一般不允許在容器里修改內核參數,Seccomp 代表安全計算(Secure computing)模式,seccomp 控制了容器能做哪些操作,添加 securitycontext 參數之后就可以修改內核參數了。
創建一個 pod,initcontainers 初始化容器里的 securitycontext:privileged:true 表示該容器具有特權,可以執行命令"sh","-c”,"/sbin/sysctl -w vm.swappiness=0",vm.swappiness 設置為8表示盡量少使用 swap 內存。
[root@k8s-master ~]# cat init02.yml?
apiVersion: v1
kind: Pod
metadata:
? creationTimestamp: null
? labels:
? ? run: initc02
? name: initc02
spec:
? terminationGracePeriodSeconds: 0
? containers:
? - image: nginx:1.7.9
? ? imagePullPolicy: IfNotPresent
? ? name: n1
? ? resources: {}
? initContainers:
? - name: initc02
? ? image: alpine
? ? imagePullPolicy: IfNotPresent
? ? command: ["sh","-c","/sbin/sysctl -w vm.swappiness=0"]
? ? securityContext:
? ? ? privileged: true
? dnsPolicy: ClusterFirst
? restartPolicy: Never
status: {}
[root@k8s-master ~]# kubectl create -f init02.yml?
pod/initc02 created
[root@k8s-master ~]# kubectl get pod
NAME ? ? ?READY ? STATUS ? ?RESTARTS ? AGE
initc01 ? 1/1 ? ? Running ? 0 ? ? ? ? ?20m
initc02 ? 1/1 ? ? Running ? 0 ? ? ? ? ?15s
查看pod中的容器
[root@k8s-master ~]# kubectl get pod -o wide
NAME ? ? ?READY ? STATUS ? ?RESTARTS ? AGE ? IP ? ? ? ? ? ? ?NODE ? ? ? ? NOMINATED NODE ? READINESS GATES
initc01 ? 1/1 ? ? Running ? 0 ? ? ? ? ?20m ? 10.244.85.193 ? k8s-node01 ? <none> ? ? ? ? ? <none>
initc02 ? 1/1 ? ? Running ? 0 ? ? ? ? ?24s ? 10.244.58.195 ? k8s-node02 ? <none> ? ? ? ? ? <none>
查看節點機器上的值是否為0
[root@k8s-node02 ~]# cat /proc/sys/vm/swappiness
0
4:示例 3--等待依賴服務啟動
有時某些服務需要依賴其他組件才能啟動,比如后端應用需要數據庫啟動之后,應用才能正常啟動,此時需要檢測數據庫實例是否正常,等待數據庫可以正常使用時,在啟動后端應用,此時可以使用初始化容器進行控制。
(1)創建第一個 Pod
該 Pod 內要依賴兩個條件才能啟動,一個是利用 busybox 容器檢測 redis-service 服務是否生成第二個是檢測 mysql-server 服務是否生成。
[root@k8s-master ~]# cat myapp.yaml?
apiVersion: v1
kind: Pod
metadata:
? name: nginx
? labels:
? ? name: nginx
spec:
? containers:
? - name: nginx
? ? image: nginx:1.7.9
? ? ports:
? ? - containerPort: 80
? initContainers:
? ? - name: init-redis
? ? ? image: busybox:1.28
? ? ? command: ['sh', '-c', 'until nslookup redis-service; do echo waiting for nginx01; sleep 2; done;']
? ? - name: init-mysql
? ? ? image: busybox:1.28
? ? ? command: ['sh', '-c', 'until nslookup mysql-service; do echo waiting for nginx02; sleep 2; done;']
[root@k8s-master ~]# kubectl create -f myapp.yaml?
pod/nginx created
[root@k8s-master ~]# kubectl get pod
NAME ? ?READY ? STATUS ? ? RESTARTS ? AGE
nginx ? 0/1 ? ? Init:0/2 ? 0 ? ? ? ? ?4s
(2)創建第一個被依賴的service
[root@k8s-master ~]# cat redis-deployment.yaml?
apiVersion: apps/v1
kind: Deployment
metadata:
? labels:
? ? app: redis
? name: redis
spec:
? replicas: 1
? selector:
? ? matchLabels:
? ? ? app: redis
? template:
? ? metadata:
? ? ? labels:
? ? ? ? app: redis
? ? spec:
? ? ? containers:
? ? ? ? - image: redis:5.0
? ? ? ? ? imagePullPolicy: IfNotPresent
? ? ? ? ? name: redis
---
apiVersion: v1
kind: Service
metadata:
? labels:
? ? app: redis
? name: redis-service
spec:
? ports:
? ? - port: 6379
? ? ? protocol: TCP
? ? ? targetPort: 6379
? selector:
? ? app: redis
? type: NodePort
[root@k8s-master ~]# kubectl create -f ?redis-deployment.yaml?
deployment.apps/redis created
service/redis-service created
[root@k8s-master ~]# kubectl get svc
NAME ? ? ? ? ? ?TYPE ? ? ? ?CLUSTER-IP ? ? ?EXTERNAL-IP ? PORT(S) ? ? ? ? ?AGE
kubernetes ? ? ?ClusterIP ? 10.96.0.1 ? ? ? <none> ? ? ? ?443/TCP ? ? ? ? ?3d19h
redis-service ? NodePort ? ?10.103.135.15 ? <none> ? ? ? ?6379:30083/TCP ? 6s
[root@k8s-master ~]# kubectl get pod
NAME ? ? ? ? ? ? ? ? ? ? READY ? STATUS ? ? RESTARTS ? AGE
nginx ? ? ? ? ? ? ? ? ? ?0/1 ? ? Init:1/2 ? 0 ? ? ? ? ?2m24s
redis-56bcf55554-5ww9w ? 1/1 ? ? Running ? ?0 ? ? ? ? ?24s
(3)創建第二個被依賴的service
[root@k8s-master ~]# cat mysql-deployment.yaml?
apiVersion: apps/v1
kind: Deployment
metadata:
? labels:
? ? app: mysql
? name: mysql
spec:
? replicas: 1
? selector:
? ? matchLabels:
? ? ? app: mysql
? template:
? ? metadata:
? ? ? labels:
? ? ? ? app: mysql
? ? spec:
? ? ? containers:
? ? ? ? - env:
? ? ? ? ? ? - name: MYSQL_ROOT_PASSWORD
? ? ? ? ? ? ? value: 'moonfdd'
? ? ? ? ? image: 'mysql:8.0'
? ? ? ? ? imagePullPolicy: IfNotPresent
? ? ? ? ? name: mysql
? ? ? ? ? volumeMounts:
? ? ? ? ? ? - mountPath: /var/lib/mysql
? ? ? ? ? ? ? name: volv
? ? ? volumes:
? ? ? ? - hostPath:
? ? ? ? ? ? path: /root/k8s/moonfdd/mysql/var/lib/mysql
? ? ? ? ? ? type: DirectoryOrCreate
? ? ? ? ? name: volv
---
apiVersion: v1
kind: Service
metadata:
? labels:
? ? app: mysql
? name: mysql-service
spec:
? ports:
? ? - port: 3306
? ? ? protocol: TCP
? ? ? targetPort: 3306
? selector:
? ? app: mysql
? type: NodePort
[root@k8s-master ~]# kubectl create -f mysql-deployment.yaml?
deployment.apps/mysql created
service/mysql-service created
[root@k8s-master ~]# kubectl get svc
NAME ? ? ? ? ? ?TYPE ? ? ? ?CLUSTER-IP ? ? ?EXTERNAL-IP ? PORT(S) ? ? ? ? ?AGE
kubernetes ? ? ?ClusterIP ? 10.96.0.1 ? ? ? <none> ? ? ? ?443/TCP ? ? ? ? ?3d20h
mysql-service ? NodePort ? ?10.102.9.40 ? ? <none> ? ? ? ?3306:32586/TCP ? 17s
redis-service ? NodePort ? ?10.103.135.15 ? <none> ? ? ? ?6379:30083/TCP ? 29m
[root@k8s-master ~]# kubectl get pod
NAME ? ? ? ? ? ? ? ? ? ? READY ? STATUS ? ?RESTARTS ? AGE
mysql-7f5d669b6c-xcg5k ? 1/1 ? ? Running ? 0 ? ? ? ? ?33s
nginx ? ? ? ? ? ? ? ? ? ?1/1 ? ? Running ? 0 ? ? ? ? ?31m
redis-56bcf55554-5ww9w ? 1/1 ? ? Running ? 0 ? ? ? ? ?29m
到這里可以發現,當把 redis-service 和 mysq1-service 兩個服務創建出來后,nginx 的 Pod 就正常運行了。
4:pause容器
在 Kubernetes 中,pause 容器并不是指暫停容器的執行,而是指一個特殊的輔助容器,它被用于每個 Pod 以幫助實現網絡命名空間。pause 容器是 Kubernetes 中每個 Pod 的第一個容器,它的主要作用是
作為 Pod 內所有其他容器共享網絡命名空間的基礎。每個 Kubernetes Pod 都有一個 pause 容器,它是 Pod 的第一個容器,也是唯一必須運行的容器即使 Pod 中的其他容器都停止了,只要 pause 容器還在運行,Pod 就不會被 Kubernetes 認為是完全停止的。
(1)pause 容器的作用
網絡命名空間:pause 容器為 Pod 內的所有容器提供了一個共享的網絡命名空間。這意味著 Pod 內的所有容器都共享同一個 IP 地址和端口空間,從而使得它們可以直接通過 localhost 或者其他指定方式相互通信。
網絡接口:pause 容器負責設置 Pod 的網絡接口,使得 Pod 內的容器能夠通過這個接口訪問外部網絡。
穩定性:如果 Pod 中的所有聲明的容器都被刪除或停止,pause 容器將保持運行,從而保證 Pod 的網絡命名空間不會丟失。這也意味著 Pod 的網絡配置仍然保留,直到整個 Pod 被刪除。
生命周期管理:pause 容器是一個非常簡單的容器,其鏡像只包含一個命令/pause,該命令實際上是-個無限循環,保持容器處于運行狀態。它不執行任何業務邏輯,僅僅是作為 Pod 網絡基礎設施的-部分。
(2)使用 pause 容器的好處
- 簡化了 Pod 內的網絡配置。
- 提高了 Pod 網絡的一致性。
- 減少了管理 Pod 網絡復雜性的開銷。
總的來說,pause 容器對于實現 Kubernetes Pod 的網絡功能至關重要,它是 Kubernetes 網絡模型的一個核心組成部分。
(3)Pause 容器實現
Pod 里的多個容器怎么去共享網絡?下面是個例子:
比如說現在有一個 Pod,其中包含了一個容器 A 和一個容器 B,它們兩個就要共享 NetworkNamespace。在 Kubernetes 里的解法是這樣的:它會在每個 Pod 里,額外起一個 Infra(基礎)container 小容器來共享整個Pod 的 Network Namespace。
Infra container 是一個非常小的容器,大概 700KB 左右,是一個( 語言寫的、永遠處于 “暫停”狀態的容器。由于有了這樣一個 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@k8s-master ~]# kubectl get pod -o wide
NAME ? ? ? ? ? ? ? ? ? ? READY ? STATUS ? ?RESTARTS ? AGE ? IP ? ? ? ? ? ? ?NODE ? ? ? ? NOMINATED NODE ? READINESS GATES
mysql-7f5d669b6c-xcg5k ? 1/1 ? ? Running ? 0 ? ? ? ? ?52m ? 10.244.85.195 ? k8s-node01 ? <none> ? ? ? ? ? <none>
nginx ? ? ? ? ? ? ? ? ? ?1/1 ? ? Running ? 0 ? ? ? ? ?83m ? 10.244.85.194 ? k8s-node01 ? <none> ? ? ? ? ? <none>
redis-56bcf55554-5ww9w ? 1/1 ? ? Running ? 0 ? ? ? ? ?81m ? 10.244.58.196 ? k8s-node02 ? <none> ? ? ? ? ? <none>
在node01主機上查看pod中的pause容器
[root@k8s-node01 ~]# docker ps | grep nginx
e8bf858f89f7 ? 84581e99d807 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?"nginx -g 'daemon of…" ? 53 minutes ago ? ? ?Up 53 minutes ? ? ? ? ? ? ? ?k8s_nginx_nginx_default_c1238bdc-166b-4450-985d-1f858c8735d9_0
75ca92d09c39 ? registry.aliyuncs.com/google_containers/pause:3.6 ? "/pause" ? ? ? ? ? ? ? ? ?About an hour ago ? Up About an hour ? ? ? ? ? ? k8s_POD_nginx_default_c1238bdc-166b-4450-985d-1f858c8735d9_0
二:臨時容器 Ephemeral Containers
在生產環境中,為例優化鏡像體積和提高鏡像的安全性,并不會在容器中安裝太多高危工具,比如culr ,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 很有用。尤其是在使用像不包含任何 shel1 和其他工具的 destroless 鏡像作為基礎鏡像時,雖然可以減少攻擊面和漏洞,但對于問題的排査會變得尤為棘手,此時臨時容器就可以發揮很大的作用,帶來諸多便利性。
2.臨時容器的使用
(1)創建一個nginx的資源清單
[root@k8s-master ~]# cat pod-tomcat.yaml?
apiVersion: v1
kind: Pod
metadata:
? name: nginx-test
? namespace: default
? labels:
? ? app: ?nginx
spec:
? containers:
? - name: ?nginx-java
? ? ports:
? ? - containerPort: 80
? ? image: nginx:1.7.9
? ? imagePullPolicy: IfNotPresent
(2)創建pod
[root@k8s-master ~]# kubectl get pod
NAME ? ? ? ? ? ? ? ? ? ? READY ? STATUS ? ?RESTARTS ? AGE
mysql-7f5d669b6c-xcg5k ? 1/1 ? ? Running ? 0 ? ? ? ? ?62m
nginx ? ? ? ? ? ? ? ? ? ?1/1 ? ? Running ? 0 ? ? ? ? ?93m
nginx-test ? ? ? ? ? ? ? 1/1 ? ? Running ? 0 ? ? ? ? ?10s
(3)為nginx的pod容器創建臨時容器
[root@k8s-master ~]# kubectl debug -it nginx-test --image=busybox:1.28 --target=nginx-java
Targeting container "nginx-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-nxf4t.
If you don't see a command prompt, try pressing enter.
/ # ip a
(4)查看nginx-tesst這個pod是否
[root@k8s-master ~]# kubectl describe pods nginx-test
Name: ? ? ? ? nginx-test
Namespace: ? ?default
Priority: ? ? 0
Node: ? ? ? ? k8s-node02/192.168.10.103
Start Time: ? Fri, 11 Jul 2025 11:23:42 +0800
Labels: ? ? ? app=nginx
Annotations: ?cni.projectcalico.org/containerID: 3e427a8c5fd207493006ed7ba047fb43cac64970b39964df611b290b3186ec67
? ? ? ? ? ? ? cni.projectcalico.org/podIP: 10.244.58.197/32
? ? ? ? ? ? ? cni.projectcalico.org/podIPs: 10.244.58.197/32
Status: ? ? ? Running
IP: ? ? ? ? ? 10.244.58.197
IPs:
? IP: ?10.244.58.197
Containers:
? nginx-java:
? ? Container ID: ? docker://085aed38e78b961e1ba697465aa88a5ba4a908132cbe7afa58dd14dfeaf2f13c
? ? Image: ? ? ? ? ?nginx:1.7.9
? ? Image ID: ? ? ? docker://sha256:84581e99d807a703c9c03bd1a31cd9621815155ac72a7365fd02311264512656
? ? Port: ? ? ? ? ? 80/TCP
? ? Host Port: ? ? ?0/TCP
? ? State: ? ? ? ? ?Running
? ? ? Started: ? ? ?Fri, 11 Jul 2025 11:23:44 +0800
? ? Ready: ? ? ? ? ?True
? ? Restart Count: ?0
? ? Environment: ? ?<none>
? ? Mounts:
? ? ? /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-nwjj4 (ro)
Ephemeral Containers:
? debugger-nxf4t:
? ? Container ID: ? docker://193c71245c23d89fe296267b5cfca0e5a613f4c5d27c206fdbdddbeac153ee41
? ? Image: ? ? ? ? ?busybox:1.28
? ? Image ID: ? ? ? docker://sha256:8c811b4aec35f259572d0f79207bc0678df4c736eeec50bc9fec37ed936a472a
? ? Port: ? ? ? ? ? <none>
三:自動擴縮容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 的工作原理
- HPA 根據觀察到的 CPU、內存使用率或自定義度量標準來自動擴展或縮容 Pod 的數量。
- HPA 控制器會定期調整 RC(Replication controller)或 Deployment 的副本數,以使觀察到的平均 CPU 利用率(或其他度量標準)與用戶指定的目標相匹配。
- HPA 需要 Metrics Server 獲取度量指標,Metrics Server 負責采集 Pod 和 Node 的度量值指標,如 CPU、內存使用率等。
3:HPA 的工作流程
- 配置 HPA:使用 kubectl autoscale 命令為 Deployment、Replicaset 或 statefulset 等資
- 源創建 HPA 對象,并指定目標 CPU 利用率、最小副本數和最大副本數。
- 度量指標采集: Metrics Server 定期采集 Pod 和 Node 的度量值指標,并將這些數據提供給 HPA控制器。
- 伸縮決策:HPA 控制器根據當前 Pod 的度量指標和目標利用率進行比較,如果當前利用率高于目標利用率,則增加 Pod 副本數;如果當前利用率低于目標利用率,則減少 Pod 副本數(在最小副本數和最大副本數之間調整)。
- Pod 伸縮:Kubernetes 根據 HPA 控制器的決策自動調整 Pod 的副本數,以實現自動擴縮容。
4:HPA 的應用場景
- 應對流量波動:在 web 服務中,流量可能會隨時間變化而波動。HPA 可以根據流量變化自動調整Pod 副本數,以確保服務的穩定性和響應速度。
- 資源優化:通過自動擴縮容,HPA可以在保證服務質量的同時最大化資源利用率,降低運營成本。
5:HPA 實踐--實現 web 服務器的自動伸縮特性
在生產環境中,總會有一些意想不到的事情發生,比如公司網站流量突然升高,此時之前創建的 Pod已不足以支撐所有的訪問,而運維人員也不可能 24 小時守著業務服務,這時就可以通過配置 HPA,實現負載過高的情況下自動擴容 Pod 副本數以分攤高并發的流量,當流量恢復正常后,HPA 會自動縮減 Pod 的數量。
本節將測試實現一個 web 服務器的自動伸縮特性,具體步驟如下:
(1)首先用Deployment 啟動一個Nginx 服務(須配置 requests 參數):
[root@k8s-master ~]# cat nginx-deployment.yaml?
apiVersion: apps/v1
kind: Deployment
metadata:
? name: nginx-server
? labels:
? ? name: nginx-server
spec:
? replicas: 2
? selector:
? ? matchLabels:
? ? ? app: nginx
? template:
? ? metadata:
? ? ? labels:
? ? ? ? app: nginx
? ? spec:
? ? ? containers:
? ? ? ? - name: nginx
? ? ? ? ? resources:
? ? ? ? ? ? requests:
? ? ? ? ? ? ? cpu: 10m
? ? ? ? ? image: nginx:1.7.9
? ? ? ? ? ports:
? ? ? ? ? ? - name: nginx
? ? ? ? ? ? ? containerPort: 80
root@k8s-master ~]# kubectl create -f nginx-deployment.yaml?
deployment.apps/nginx-server created
(2)配置nginx-server的service
[root@k8s-master ~]# kubectl expose deployment nginx-server --port=80
service/nginx-server exposed
(3)使用kubectl autoscale命令創建HPA
[root@k8s-master ~]# kubectl 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@k8s-master ~]# kubectl get hpa
NAME ? ? ? ? ? REFERENCE ? ? ? ? ? ? ? ? TARGETS ? MINPODS ? MAXPODS ? REPLICAS ? AGE
nginx-server ? Deployment/nginx-server ? 0%/10% ? ?1 ? ? ? ? 10 ? ? ? ?2 ? ? ? ? ?74s
(5)查看當前nginx的service地址
[root@k8s-master ~]# kubectl get service
NAME ? ? ? ? ? TYPE ? ? ? ?CLUSTER-IP ? ? ?EXTERNAL-IP ? PORT(S) ? AGE
kubernetes ? ? ClusterIP ? 10.96.0.1 ? ? ? <none> ? ? ? ?443/TCP ? 3d21h
nginx-server ? ClusterIP ? 10.100.216.91 ? <none> ? ? ? ?80/TCP ? ?3m13s
(6)壓力測試
新開一個終端,使用-個“死”循環或其他壓測工具模擬訪問該 Service,從而增加該 Pod的負載
[root@k8s-node02 ~]# while true;do wget -q -O- http://10.100.216.91 >/dev/null;done
?
備注:
-q 是不輸出 wget 的頭信息。
-0-(大寫字母 0)選項表示將下載的內容輸出到標準輸出(通常是終端),而不是保存到文件。
(7)查看HPA 狀態
等待一分鐘左右,再次査看 HPA,可以看到 Pod 的 CPU 已經升高。
[root@k8s-master ~]# kubectl get hpa
NAME ? ? ? ? ? REFERENCE ? ? ? ? ? ? ? ? TARGETS ? MINPODS ? MAXPODS ? REPLICAS ? AGE
nginx-server ? Deployment/nginx-server ? 45%/10% ? 1 ? ? ? ? 10 ? ? ? ?2 ? ? ? ? ?4m6s
(8)再次查看pod,可以看到已經擴容
[root@k8s-master ~]# kubectl get pod
NAME ? ? ? ? ? ? ? ? ? ? ? ? ? ?READY ? STATUS ? ?RESTARTS ? AGE
nginx-server-6ddcfd4c8f-5sjvc ? 1/1 ? ? Running ? 0 ? ? ? ? ?31s
nginx-server-6ddcfd4c8f-7r9jl ? 1/1 ? ? Running ? 0 ? ? ? ? ?7m7s
nginx-server-6ddcfd4c8f-ndrnz ? 1/1 ? ? Running ? 0 ? ? ? ? ?46s
nginx-server-6ddcfd4c8f-nr2dw ? 1/1 ? ? Running ? 0 ? ? ? ? ?7m7s
nginx-server-6ddcfd4c8f-p9pnj ? 1/1 ? ? Running ? 0 ? ? ? ? ?61s
nginx-server-6ddcfd4c8f-qjbq7 ? 1/1 ? ? Running ? 0 ? ? ? ? ?61s
nginx-server-6ddcfd4c8f-rhkn8 ? 1/1 ? ? Running ? 0 ? ? ? ? ?46s
nginx-server-6ddcfd4c8f-vnpjm ? 1/1 ? ? Running ? 0 ? ? ? ? ?46s
nginx-server-6ddcfd4c8f-vzchv ? 1/1 ? ? Running ? 0 ? ? ? ? ?31s
nginx-server-6ddcfd4c8f-z9ts9 ? 1/1 ? ? Running ? 0 ? ? ? ? ?46s
(8)停止壓力測試,再次查看HPA狀態
[root@k8s-master ~]# kubectl get hpa
NAME ? ? ? ? ? REFERENCE ? ? ? ? ? ? ? ? TARGETS ? MINPODS ? MAXPODS ? REPLICAS ? AGE
nginx-server ? Deployment/nginx-server ? 0%/10% ? ?1 ? ? ? ? 10 ? ? ? ?10 ? ? ? ? 6m4s
(9)查看pod的副本數
[root@k8s-master ~]# kubectl get pod
NAME ? ? ? ? ? ? ? ? ? ? ? ? ? ?READY ? STATUS ? ?RESTARTS ? AGE
nginx-server-6ddcfd4c8f-nr2dw ? 1/1 ? ? Running ? 0 ? ? ? ? ?14m