扩展服务 IP 范围

特性状态: Kubernetes v1.33 [stable] (默认启用:true)

本文档介绍了如何扩展分配给集群的现有 Service IP 范围。

准备工作

你需要有一个 Kubernetes 集群,并且 kubectl 命令行工具已配置为与你的集群通信。建议你在至少有两个节点且不充当控制平面主机的集群上运行本教程。如果你还没有集群,可以使用 minikube 创建一个,或者使用这些 Kubernetes 操场中的一个

你的 Kubernetes 服务器版本必须是 v1.29 或更高版本。

要检查版本,请输入 kubectl version

扩展服务 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 范围。

将 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]
上次修改时间:2025 年 4 月 22 日 上午 9:28 PST:更新 content/en/docs/tasks/network/extend-service-ip-ranges.md (d8462fb84a)