扩展 Service IP 范围

特性状态: Kubernetes v1.31 [beta]

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

准备开始

你必须拥有一个 Kubernetes 的集群,且必须配置 kubectl 命令行工具让其与你的集群通信。 建议运行本教程的集群至少有两个节点,且这两个节点不能作为控制平面主机。 如果你还没有集群,你可以通过 Minikube 构建一个你自己的集群,或者你可以使用下面的 Kubernetes 练习环境之一:

你的 Kubernetes 服务器版本必须不低于版本 v1.29. 要获知版本信息,请输入 kubectl version.

API

如果 Kubernetes 集群的 kube-apiserver 启用了 MultiCIDRServiceAllocator 特性门控networking.k8s.io/v1alpha1 API,集群将创建一个新的 ServiceCIDR 对象, 该对象采用 kubernetes 这个众所周知的名称并基于 kube-apiserver 的 --service-cluster-ip-range 命令行参数的值来使用 IP 地址范围。

  1. kubectl get servicecidr
  1. NAME CIDRS AGE
  2. kubernetes 10.96.0.0/28 17d

公认的 kubernetes Service 将 kube-apiserver 的端点暴露给 Pod, 计算出默认 ServiceCIDR 范围中的第一个 IP 地址,并将该 IP 地址用作其集群 IP 地址。

  1. kubectl get service kubernetes
  1. NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
  2. kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 17d

在本例中,默认 Service 使用具有对应 IPAddress 对象的 ClusterIP 10.96.0.1。

  1. kubectl get ipaddress 10.96.0.1
  1. NAME PARENTREF
  2. 10.96.0.1 services/default/kubernetes

ServiceCIDR 受到 终结器 的保护, 以避免留下孤立的 Service ClusterIP;只有在存在包含现有 IPAddress 的另一个子网或者没有属于此子网的 IPAddress 时,才会移除终结器。

扩展 Service 可用的 IP 数量

有时候用户需要增加可供 Service 使用的 IP 地址数量。 以前,增加 Service 范围是一个可能导致数据丢失的破坏性操作。 有了这个新的特性后,用户只需添加一个新的 ServiceCIDR 对象,便能增加可用地址的数量。

添加新的 ServiceCIDR

对于 Service 范围为 10.96.0.0/28 的集群,只有 2^(32-28) - 2 = 14 个可用的 IP 地址。 kubernetes.default Service 始终会被创建;在这个例子中,你只剩下了 13 个可能的 Service。

  1. for i in $(seq 1 13); do kubectl create service clusterip "test-$i" --tcp 80 -o json | jq -r .spec.clusterIP; done
  1. 10.96.0.11
  2. 10.96.0.5
  3. 10.96.0.12
  4. 10.96.0.13
  5. 10.96.0.14
  6. 10.96.0.2
  7. 10.96.0.3
  8. 10.96.0.4
  9. 10.96.0.6
  10. 10.96.0.7
  11. 10.96.0.8
  12. 10.96.0.9
  13. error: failed to create ClusterIP service: Internal error occurred: failed to allocate a serviceIP: range is full

通过创建一个扩展或新增 IP 地址范围的新 ServiceCIDR,你可以提高 Service 可用的 IP 地址数量。

  1. cat <EOF | kubectl apply -f -
  2. apiVersion: networking.k8s.io/v1alpha1
  3. kind: ServiceCIDR
  4. metadata:
  5. name: newcidr1
  6. spec:
  7. cidrs:
  8. - 10.96.0.0/24
  9. EOF
  1. servicecidr.networking.k8s.io/newcidr1 created

这将允许你创建新的 Service,其 ClusterIP 将从这个新的范围中选取。

  1. for i in $(seq 13 16); do kubectl create service clusterip "test-$i" --tcp 80 -o json | jq -r .spec.clusterIP; done
  1. 10.96.0.48
  2. 10.96.0.200
  3. 10.96.0.121
  4. 10.96.0.144

删除 ServiceCIDR

如果存在依赖于 ServiceCIDR 的 IPAddress,你将无法删除 ServiceCIDR。

  1. kubectl delete servicecidr newcidr1
  1. servicecidr.networking.k8s.io "newcidr1" deleted

Kubernetes 在 ServiceCIDR 上使用一个终结器来跟踪这种依赖关系。

  1. kubectl get servicecidr newcidr1 -o yaml
  1. apiVersion: networking.k8s.io/v1alpha1
  2. kind: ServiceCIDR
  3. metadata:
  4. creationTimestamp: "2023-10-12T15:11:07Z"
  5. deletionGracePeriodSeconds: 0
  6. deletionTimestamp: "2023-10-12T15:12:45Z"
  7. finalizers:
  8. - networking.k8s.io/service-cidr-finalizer
  9. name: newcidr1
  10. resourceVersion: "1133"
  11. uid: 5ffd8afe-c78f-4e60-ae76-cec448a8af40
  12. spec:
  13. cidrs:
  14. - 10.96.0.0/24
  15. status:
  16. conditions:
  17. - lastTransitionTime: "2023-10-12T15:12:45Z"
  18. message:
  19. There are still IPAddresses referencing the ServiceCIDR, please remove
  20. them or create a new ServiceCIDR
  21. reason: OrphanIPAddress
  22. status: "False"
  23. type: Ready

移除一些 Service,这些 Service 包含阻止删除 ServiceCIDR 的 IP 地址:

  1. for i in $(seq 13 16); do kubectl delete service "test-$i" ; done
  1. service "test-13" deleted
  2. service "test-14" deleted
  3. service "test-15" deleted
  4. service "test-16" deleted

控制平面会注意到这种移除操作。控制平面随后会移除其终结器,以便真正移除待删除的 ServiceCIDR。

  1. kubectl get servicecidr newcidr1
  1. Error from server (NotFound): servicecidrs.networking.k8s.io "newcidr1" not found