Kubernetes 資源管理對於應用程式效能和穩定性至關重要。本文除了資源配額和限制範圍的設定,也探討叢集擴充套件的機制,包含手動與自動擴充套件的策略。同時,文章也涵蓋了 Horizontal Pod Autoscaler (HPA) 和 Vertical Pod Autoscaler (VPA) 的使用方法,讓開發者可以根據 CPU 使用率、記憶體用量或自定義指標自動調整應用程式副本數量或資源請求。最後,文章也探討了 Kubernetes 網路安全策略的最佳實踐,例如使用 NetworkPolicy 定義 Pod 間的流量規則,以及如何透過設定 taints 和 tolerations 將 Pod 排程到特定的節點上,確保叢集的安全性。
資源管理與叢集擴充套件
在 Kubernetes 中,資源管理是確保應用程式高效執行的關鍵。本篇文章將探討資源配額(ResourceQuotas)、限制範圍(LimitRange)以及叢集擴充套件(Cluster Scaling)等主題。
資源配額(ResourceQuotas)
資源配額是一種用於限制名稱空間中資源使用量的機制。例如,在 team-1 名稱空間中設定 CPU、記憶體和儲存的配額:
kubectl create ns team-1
接著,套用資源配額:
apiVersion: v1
kind: ResourceQuota
metadata:
name: mem-cpu-demo
spec:
hard:
requests.cpu: 2
requests.memory: 2Gi
limits.cpu: 2
limits.memory: 2Gi
儲存為 resourcequota.yaml 並執行:
kubectl apply -f resourcequota.yaml -n team-1
內容解密:
此資源配額設定了 team-1 名稱空間中資源的硬性限制,包括 CPU 和記憶體的請求與限制。
測試資源配額
嘗試佈署一個應用程式以觀察資源配額的效果:
kubectl run nginx-quotatest --image=nginx --restart=Never --replicas=1 --port=80 --requests='cpu=500m,memory=4Gi' --limits='cpu=500m,memory=4Gi' -n team-1
由於記憶體請求超過了設定的 2 Gi 配額,此佈署將失敗:
Error from server (Forbidden): pods "nginx-quotatest" is forbidden: exceeded quota: mem-cpu-demo
限制範圍(LimitRange)
如果使用者未在 Pod 規格中設定請求和限制,Kubernetes 提供了 LimitRange 准入控制器來自動設定這些值。
首先,建立一個名稱空間:
kubectl create ns team-1
然後,套用 LimitRange:
apiVersion: v1
kind: LimitRange
metadata:
name: team-1-limit-range
spec:
limits:
- default:
memory: 512Mi
defaultRequest:
memory: 256Mi
type: Container
儲存為 limitranger.yaml 並執行:
kubectl apply -f limitranger.yaml -n team-1
內容解密:
此 LimitRange 設定了容器的預設記憶體限制和請求。
驗證 LimitRange 的效果:
kubectl run team-1-pod --image=nginx -n team-1
kubectl describe pod team-1-pod -n team-1
你應該會看到 Pod 的規格中設定了以下請求和限制:
Limits:
memory: 512Mi
Requests:
memory: 256Mi
叢集擴充套件(Cluster Scaling)
選擇適當的例項大小是佈署叢集時的重要決策。Kubernetes 提供了手動和自動擴充套件叢集的機制。
手動擴充套件
手動擴充套件叢集通常涉及選擇新的節點數量,並由服務將新節點新增到叢集中。可以使用節點池來新增新的例項型別到正在執行的叢集中。
自動擴充套件
Kubernetes 提供了一個 Cluster Autoscaler 外掛,允許設定叢集的最小和最大節點數量。當 Pod 處於 Pending 狀態時,Cluster Autoscaler 將新增新節點到叢集中。
應用程式擴充套件(Application Scaling)
Kubernetes 提供了多種方式來擴充套件應用程式。你可以手動更改佈署中的副本數量,也可以使用 Horizontal Pod Autoscaler(HPA)自動擴充套件工作負載。
以下是一個佈署範例:
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
spec:
replicas: 3
selector:
matchLabels:
app: frontend
template:
metadata:
name: frontend
labels:
app: frontend
spec:
containers:
- image: nginx:alpine
name: frontend
resources:
requests:
cpu: 100m
內容解密:
此佈署設定了前端應用程式的副本數量和資源請求。
Kubernetes 資源管理最佳實踐
在前面的章節中,我們探討瞭如何佈署前端服務的三個副本。接下來,我們可以使用 kubectl scale 命令來擴充套件這個佈署:
kubectl scale deployment frontend --replicas 5
這將導致前端服務的五個副本。這很好,但讓我們看看如何新增一些智慧,並根據指標自動擴充套件應用程式。
使用 HPA 進行擴充套件
Kubernetes 的 HPA(Horizontal Pod Autoscaler)允許您根據 CPU、記憶體或自定義指標來擴充套件佈署。它監視佈署並從 Kubernetes metrics-server 提取指標。它還允許您設定可用的最小和最大 Pod 數量。例如,您可以定義一個 HPA 策略,將最小 Pod 數量設定為 3,最大 Pod 數量設定為 10,當佈署達到 80% 的 CPU 使用率時進行擴充套件。設定最小和最大數量非常重要,因為您不想讓 HPA 由於應用程式錯誤或問題而無限擴充套件副本。
HPA 具有以下預設設定,用於同步指標、擴充套件和縮減副本:
horizontal-pod-autoscaler-sync-period:預設 30 秒,用於同步指標horizontal-pod-autoscaler-upscale-delay:預設 3 分鐘,兩次擴充套件操作之間的延遲horizontal-pod-autoscaler-downscale-delay:預設 5 分鐘,兩次縮減操作之間的延遲
您可以透過使用相關的 flag 來更改預設值,但需要謹慎。如果您的負載非常可變,則值得調整設定以最佳化您的特定使用案例。
設定 HPA 策略
首先,在埠 80 上公開佈署:
kubectl expose deployment frontend --port 80
接下來,設定自動擴充套件策略:
kubectl autoscale deployment frontend --cpu-percent=50 --min=1 --max=10
這將設定策略,以在 CPU 負載達到 50% 時將應用程式從最小 1 個副本擴充套件到最大 10 個副本。
#### 內容解密:
此命令建立了一個 HPA 物件,該物件會根據指定的 CPU 使用率百分比自動調整前端佈署的副本數量。 --cpu-percent=50 表示當平均 CPU 使用率超過 50% 時,HPA 將增加副本數量。 --min=1 和 --max=10 分別指定了副本數量的最小值和最大值。
讓我們生成一些負載,以便我們可以看到佈署自動擴充套件:
kubectl run -i --tty load-generator --image=busybox /bin/sh
進入命令提示符後,執行:
while true; do wget -q -O- http://frontend.default.svc.cluster.local; done
然後,在另一個終端中執行:
kubectl get hpa
您可能需要等待幾分鐘才能看到副本自動擴充套件。
使用自定義指標的 HPA
在第 4 章中,我們介紹了 metrics server 在監控 Kubernetes 系統中的作用。透過 Metrics Server API,我們還可以支援使用自定義指標來擴充套件應用程式。 Custom Metrics API 和 Metrics Aggregator 允許第三方提供商插入並擴充套件指標,然後 HPA 可以根據這些外部指標進行擴充套件。例如,您可以根據在外部儲存佇列上收集的指標進行擴充套件,而不是僅僅根據基本的 CPU 和記憶體指標。透過利用自定義指標進行自動擴充套件,您可以根據應用程式特定的指標或外部服務指標進行擴充套件。
垂直 Pod 自動擴充套件器(VPA)
VPA 與 HPA 的不同之處在於它不擴充套件副本,而是自動調整請求。前面我們討論了為 Pod 設定請求,以及它如何保證給定容器的 X 資源量。 VPA 使您免於手動調整這些請求,並自動為您縮放 Pod 請求。對於由於架構原因無法擴充套件的工作負載,這非常適合自動調整資源。例如,MySQL 資料函式庫的擴充套件方式與無狀態的 Web 前端不同。使用 MySQL,您可能希望將 Master 節點設定為根據工作負載自動擴充套件。
VPA 比 HPA 更複雜,它由三個元件組成:
- Recommender:監視當前和過去的資源消耗,並為容器的 CPU 和記憶體請求提供建議值
- Updater:檢查哪些 Pod 具有正確的資源設定,如果沒有,則殺死它們,以便它們可以使用更新的請求由控制器重新建立
- Admission Plugin:在新的 Pod 上設定正確的資源請求
#### 內容解密:
VPA 的三個元件共同工作,以確保 Pod 的資源請求得到最佳組態。 Recommender 分析資源使用情況,提供最佳請求建議。 Updater 確保 Pod 使用最新的請求組態。 Admission Plugin 保證新建立的 Pod 使用正確的資源請求。
垂直擴充套件有兩個目標: • 透過自動組態資源需求來降低維護成本。 • 提高叢集資源利用率,同時最小化容器記憶體不足或 CPU 不足的風險。
資源管理最佳實踐
• 利用 pod 反親和性將工作負載分散到多個可用區,以確保應用程式的高用性。
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
spec:
replicas: 3
selector:
matchLabels:
app: frontend
template:
metadata:
labels:
app: frontend
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- frontend
topologyKey: "kubernetes.io/hostname"
#### 內容解密:
此 YAML 組態檔案定義了一個名為 frontend 的 Deployment 物件,並使用 podAntiAffinity 將其副本分散到不同的節點上,以提高用性。 topologyKey: "kubernetes.io/hostname" 表示根據節點的主機名進行分散。
• 如果您使用的是專用硬體,例如啟用了 GPU 的節點,請確保只有需要 GPU 的工作負載被排程到這些節點上,方法是使用 taints。
kubectl taint nodes <node-name> gpu=true:NoSchedule
#### 內容解密:
此命令為指定的節點增加了一個 taint,只有具有相應 toleration 的 Pod 才可以被排程到該節點上。
• 使用 NodeCondition taints 主動避免失敗或降級的節點。 • 將 nodeSelectors 應用於您的 pod 組態,以將 pod 排程到您在叢集中佈署的專用硬體上。 • 在投入生產之前,嘗試不同的節點大小,以找到節點型別的成本和效能的最佳組合。 • 如果您正在佈署具有不同效能特徵的工作負載組合,請利用節點池在單個叢集中擁有混合節點型別。 • 確保為佈署到叢集的所有 pod 設定記憶體和 CPU 限制。 • 利用 ResourceQuotas 確保多個團隊或應用程式在叢集中獲得公平的資源份額。 • 實施 LimitRange 以為未設定限制或請求的 pod 組態設定預設限制和請求。 • 從手動叢集縮放開始,直到您瞭解 Kubernetes 上的工作負載組態檔。您可以使用自動縮放,但它伴隨著有關節點啟動時間和叢集縮小額外考慮。 • 將 HPA 用於具有可變性和意外峰值的工作負載。
網路、網路安全與服務網格
Kubernetes實際上是跨多個連線系統叢集的分散式系統管理工具。這使得系統之間的通訊方式至關重要,而網路是實作此目標的關鍵。瞭解Kubernetes如何促進其管理的分散式服務之間的通訊對於有效地應用服務間通訊至關重要。
本章重點介紹Kubernetes對網路的基本原則以及在不同情況下應用這些概念的最佳實踐。任何有關網路的討論通常都會涉及安全問題。在Kubernetes這個分散式系統的新世界中,傳統的網路安全邊界控制模型並未消失,但其實作方式和提供的功能略有變化。Kubernetes提供了一個原生的網路安全策略API,這與傳統的防火牆規則類別似。
本章的最後一部分將探討服務網格(service mesh)這個新興且令人興奮的領域。服務網格技術在Kubernetes中仍處於初期階段,可以說是個全新的領域。
Kubernetes網路原則
瞭解Kubernetes如何利用底層網路促進服務之間的通訊對於有效地規劃應用程式架構至關重要。通常,網路主題會讓大多數人感到頭痛。幸運的是,Kubernetes已經為我們制定了一些網路規則,讓我們有個良好的開端。這些規則概述了不同元件之間通訊的預期行為。讓我們更仔細地看看每條規則:
同一Pod內容器間的通訊
同一Pod內的所有容器分享相同的網路空間。這使得容器之間可以透過localhost進行通訊。這也意味著同一Pod內的容器需要使用不同的埠號。這是透過Linux名稱空間和Docker網路實作的,使用每個Pod中的一個暫停容器來託管Pod的網路。圖9-1展示了容器A如何透過localhost和埠號直接與容器B進行通訊。
Pod間的通訊
所有Pod之間需要能夠在沒有網路位址轉換(NAT)的情況下進行通訊。這意味著接收Pod看到的傳送Pod的IP位址是傳送者的實際IP位址。根據所使用的網路外掛,這一規則的實作方式有所不同。無論是在同一節點上的Pod還是不同節點上的Pod,這一規則都適用。這也擴充套件到節點能夠直接與Pod進行通訊,無需NAT。這使得根據主機的代理或系統守護程式能夠根據需要與Pod進行通訊。圖9-2展示了同一節點上和不同節點上的Pod之間的通訊過程。
服務與Pod之間的通訊
Kubernetes中的服務代表了一個持久的IP位址和埠號,每個節點上都會將所有流量轉發到對映到該服務的端點。在不同的Kubernetes版本中,實作這一功能的優先方法有所變化,但主要有兩種方法:一種是透過使用iptables,另一種是更新的IP虛擬伺服器(IPVS)。一些雲端服務提供者和更先進的實作在允許使用根據eBPF的資料平面。大多數實作在今天使用iptables實作在每個節點上啟用偽第4層負載平衡器。圖9-3展示了服務如何透過標籤選擇器與Pod繫結。
網路外掛
早期的特殊興趣小組(SIG)將網路標準引導向更具可插拔性的架構,為眾多的第三方網路專案開啟了大門,這些專案在很多情況下為Kubernetes工作負載注入了增值功能。這些網路外掛有兩種形式。最基本的是Kubenet,它是Kubernetes原生提供的預設外掛。第二種型別的外掛遵循容器網路介面(CNI)規範,這是一個通用的容器網路解決方案。
Kubenet
Kubenet是Kubernetes自帶的最基本的網路外掛。它提供了Linux橋接器cbr0,為連線到它的Pod建立虛擬乙太網對。然後,Pod從一個跨叢集節點分配的無類別域間路由(CIDR)範圍內獲得IP位址。還有一個IP偽裝標誌應該被設定,以允許目的地在Pod CIDR範圍外的流量被偽裝。這遵守了Pod間通訊的規則,因為只有目的地在Pod CIDR範圍外的流量才會進行網路位址轉換(NAT)。當資料包離開一個節點前往另一個節點時,會設定某種路由以促進將流量轉發到正確的節點。
Kubenet最佳實踐
- Kubenet允許簡單的網路堆積疊,不會佔用已經擁擠的網路上的寶貴IP位址。
- 確保Pod CIDR範圍足夠大,以處理叢集和每個叢集中Pod的潛在規模。
- 瞭解並相應地規劃路由規則,以正確允許流量到達正確節點上的Pod。
CNI外掛
核心CNI專案提供了函式庫,您可以使用這些函式庫來編寫提供基本要求的外掛,並呼叫其他外掛來執行各種功能。這種適應性導致了許多可以用於容器網路的CNI外掛,從雲端服務提供商(如Microsoft Azure原生CNI和Amazon Web Services(AWS)VPC CNI外掛)到傳統網路提供商(如Nuage CNI、Juniper Networks Contrail/Tungsten Fabric和VMware NSX)。
@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultTextAlignment center
skinparam rectangleBackgroundColor #F5F5F5
skinparam rectangleBorderColor #333333
skinparam arrowColor #333333
title CNI外掛
rectangle "localhost通訊" as node1
rectangle "無NAT通訊" as node2
rectangle "負載平衡" as node3
node1 --> node2
node2 --> node3
@enduml
圖表翻譯: 此圖示展示了Kubernetes中不同元件之間的通訊方式,包括同一Pod內的容器、不同Pod之間以及服務與Pod之間的通訊。它說明瞭Kubernetes如何利用網路原則來促進這些元件之間的通訊。
內容解密:
此圖示用於說明 Kubernetes 網路模型中的關鍵概念。首先,同一 Pod 內的容器可以透過 localhost 直接相互通訊,因為它們分享相同的網路名稱空間。其次,Pod 之間無需 NAT 即可直接通訊,無論它們位於同一節點還是不同節點。這種設計使得 Kubernetes 中的網路管理和應用佈署更加靈活高效。最後,Kubernetes 中的服務透過負載平衡將流量分發到後端的 Pod 上,實作了應用的高用性。
網路安全的未來
隨著Kubernetes的不斷發展,網路安全也變得越來越重要。Kubernetes提供了原生的網路安全策略API,使得管理員可以定義精細的安全規則,以控制Pod之間的流量。這種方法比傳統的根據邊界的安全模型更加靈活,能夠更好地適應動態的微服務架構。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: test-network-policy
namespace: default
spec:
podSelector:
matchLabels:
role: db
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
role: frontend
- ports:
- 6379
egress:
- to:
- podSelector:
matchLabels:
role: frontend
- ports:
- 80
內容解密:
此YAML檔案定義了一個名為test-network-policy的網路策略。它適用於標籤為role: db的Pod,並且同時控制入口和出口流量。入口規則允許來自標籤為role: frontend的Pod且目標埠為6379的流量。出口規則允許流向標籤為role: frontend的Pod且目標埠為80的流量。這種精細的流量控制有助於提高叢集內的安全性。