擴充套件服務 IP 範圍
Kubernetes v1.33 [stable]
(預設啟用:true)本文件介紹瞭如何擴充套件分配給叢集的現有 Service IP 範圍。
準備工作
你需要有一個 Kubernetes 叢集,並且 kubectl 命令列工具已配置為與你的叢集通訊。建議你在至少有兩個節點且不充當控制平面主機的叢集上執行本教程。如果你還沒有叢集,可以使用 minikube 建立一個,或者使用這些 Kubernetes 操場中的一個
你的 Kubernetes 伺服器版本必須是 v1.29 或更高版本。要檢查版本,請輸入 kubectl version
。
注意
雖然你可以在早期版本中使用此功能,但此功能自 v1.33 版本才正式釋出並得到官方支援。擴充套件服務 IP 範圍
啟用了 MultiCIDRServiceAllocator
特性門控 且 networking.k8s.io/v1beta1
API 組處於活動狀態的 Kubernetes 叢集,將建立一個名為 kubernetes
的 ServiceCIDR 物件,並指定基於 kube-apiserver 的 --service-cluster-ip-range
命令列引數值的 IP 地址範圍。
kubectl get servicecidr
NAME CIDRS AGE
kubernetes 10.96.0.0/28 17d
著名的 kubernetes
Service 將 kube-apiserver 端點暴露給 Pods,它從預設 ServiceCIDR 範圍計算出第一個 IP 地址,並將其用作其叢集 IP 地址。
kubectl get service kubernetes
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 17d
在這種情況下,預設 Service 使用叢集 IP 10.96.0.1,它具有相應的 IPAddress 物件。
kubectl get ipaddress 10.96.0.1
NAME PARENTREF
10.96.0.1 services/default/kubernetes
ServiceCIDR 受 終結器 保護,以避免留下孤立的 Service ClusterIP;終結器僅在存在另一個包含現有 IPAddress 的子網或沒有屬於該子網的 IPAddress 時才會被移除。
擴充套件 Service 的可用 IP 數量
有時使用者需要增加 Service 可用的地址數量,以前,增加 Service 範圍是一個破壞性操作,也可能導致資料丟失。有了這個新功能,使用者只需新增一個新的 ServiceCIDR 即可增加可用地址的數量。
新增新的 ServiceCIDR
在一個 Service 範圍為 10.96.0.0/28 的叢集中,只有 2^(32-28) - 2 = 14 個 IP 地址可用。kubernetes.default
Service 總是被建立;對於這個例子,你只剩下 13 個可能的 Service。
for i in $(seq 1 13); do kubectl create service clusterip "test-$i" --tcp 80 -o json | jq -r .spec.clusterIP; done
10.96.0.11
10.96.0.5
10.96.0.12
10.96.0.13
10.96.0.14
10.96.0.2
10.96.0.3
10.96.0.4
10.96.0.6
10.96.0.7
10.96.0.8
10.96.0.9
error: failed to create ClusterIP service: Internal error occurred: failed to allocate a serviceIP: range is full
你可以透過建立一個新的 ServiceCIDR 來擴充套件或新增新的 IP 地址範圍,從而增加 Service 可用的 IP 地址數量。
cat <EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1beta1
kind: ServiceCIDR
metadata:
name: newcidr1
spec:
cidrs:
- 10.96.0.0/24
EOF
servicecidr.networking.k8s.io/newcidr1 created
這將允許你建立新的 Service,其 ClusterIP 將從這個新範圍中選取。
for i in $(seq 13 16); do kubectl create service clusterip "test-$i" --tcp 80 -o json | jq -r .spec.clusterIP; done
10.96.0.48
10.96.0.200
10.96.0.121
10.96.0.144
刪除 ServiceCIDR
如果存在依賴於 ServiceCIDR 的 IPAddress,則不能刪除 ServiceCIDR。
kubectl delete servicecidr newcidr1
servicecidr.networking.k8s.io "newcidr1" deleted
Kubernetes 在 ServiceCIDR 上使用終結器來跟蹤這種依賴關係。
kubectl get servicecidr newcidr1 -o yaml
apiVersion: networking.k8s.io/v1beta1
kind: ServiceCIDR
metadata:
creationTimestamp: "2023-10-12T15:11:07Z"
deletionGracePeriodSeconds: 0
deletionTimestamp: "2023-10-12T15:12:45Z"
finalizers:
- networking.k8s.io/service-cidr-finalizer
name: newcidr1
resourceVersion: "1133"
uid: 5ffd8afe-c78f-4e60-ae76-cec448a8af40
spec:
cidrs:
- 10.96.0.0/24
status:
conditions:
- lastTransitionTime: "2023-10-12T15:12:45Z"
message: There are still IPAddresses referencing the ServiceCIDR, please remove
them or create a new ServiceCIDR
reason: OrphanIPAddress
status: "False"
type: Ready
透過移除包含阻止刪除 ServiceCIDR 的 IP 地址的 Service
for i in $(seq 13 16); do kubectl delete service "test-$i" ; done
service "test-13" deleted
service "test-14" deleted
service "test-15" deleted
service "test-16" deleted
控制平面會注意到移除操作。然後控制平面會移除其終結器,從而使待刪除的 ServiceCIDR 實際上被移除。
kubectl get servicecidr newcidr1
Error from server (NotFound): servicecidrs.networking.k8s.io "newcidr1" not found
Kubernetes Service CIDR 策略
叢集管理員可以實施策略來控制叢集內 ServiceCIDR 資源的建立和修改。這允許對用於 Service 的 IP 地址範圍進行集中管理,並有助於防止意外或衝突的配置。Kubernetes 提供了像 Validating Admission Policies 這樣的機制來強制執行這些規則。
使用驗證准入策略防止未經授權的 ServiceCIDR 建立/更新
有時叢集管理員可能希望限制允許的範圍,或者完全拒絕更改叢集 Service IP 範圍。
注意
預設的 "kubernetes" ServiceCIDR 由 kube-apiserver 建立,以提供叢集一致性,並且是叢集正常工作所必需的,因此必須始終允許。你可以透過新增以下子句來確保你的 ValidatingAdmissionPolicy
不會限制預設的 ServiceCIDR:
matchConditions:
- name: 'exclude-default-servicecidr'
expression: "object.metadata.name != 'kubernetes'"
如下面的例子所示。
將 Service CIDR 範圍限制在特定範圍內
以下是一個 ValidatingAdmissionPolicy
的示例,它只允許建立給定 allowed
範圍子範圍的 ServiceCIDR。(因此,示例策略將允許 cidrs: ['10.96.1.0/24']
或 cidrs: ['2001:db8:0:0:ffff::/80', '10.96.0.0/20']
的 ServiceCIDR,但不會允許 cidrs: ['172.20.0.0/16']
的 ServiceCIDR。)你可以複製此策略並更改 allowed
的值,以適應你的叢集。
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
name: "servicecidrs.default"
spec:
failurePolicy: Fail
matchConstraints:
resourceRules:
- apiGroups: ["networking.k8s.io"]
apiVersions: ["v1","v1beta1"]
operations: ["CREATE", "UPDATE"]
resources: ["servicecidrs"]
matchConditions:
- name: 'exclude-default-servicecidr'
expression: "object.metadata.name != 'kubernetes'"
variables:
- name: allowed
expression: "['10.96.0.0/16','2001:db8::/64']"
validations:
- expression: "object.spec.cidrs.all(newCIDR, variables.allowed.exists(allowedCIDR, cidr(allowedCIDR).containsCIDR(newCIDR)))"
# For all CIDRs (newCIDR) listed in the spec.cidrs of the submitted ServiceCIDR
# object, check if there exists at least one CIDR (allowedCIDR) in the `allowed`
# list of the VAP such that the allowedCIDR fully contains the newCIDR.
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicyBinding
metadata:
name: "servicecidrs-binding"
spec:
policyName: "servicecidrs.default"
validationActions: [Deny,Audit]
查閱 CEL 文件 以瞭解更多關於 CEL 的資訊,如果你想編寫自己的驗證 expression
。
限制 ServiceCIDR API 的任何用法
以下示例演示瞭如何使用 ValidatingAdmissionPolicy
及其繫結來限制建立任何新的 Service CIDR 範圍,但預設的 "kubernetes" ServiceCIDR 除外。
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
name: "servicecidrs.deny"
spec:
failurePolicy: Fail
matchConstraints:
resourceRules:
- apiGroups: ["networking.k8s.io"]
apiVersions: ["v1","v1beta1"]
operations: ["CREATE", "UPDATE"]
resources: ["servicecidrs"]
validations:
- expression: "object.metadata.name == 'kubernetes'"
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicyBinding
metadata:
name: "servicecidrs-deny-binding"
spec:
policyName: "servicecidrs.deny"
validationActions: [Deny,Audit]