Розширення діапазонів IP-адрес Service

Розширення діапазонів IP-адрес Service

СТАН ФУНКЦІОНАЛУ: GA since Kubernetes v1.33
More information about this feature

This is a stable feature in Kubernetes, and has been since version v1.33. It was first available in the v1.27 release. You can no longer disable or opt out of this feature or behavior (it is locked); if you explicitly set a value for the associated feature gate MultiCIDRServiceAllocator, Kubernetes ignores it but does not report any error.

У цьому документі описано, як розширити наявний діапазон IP-адрес Service, призначений кластеру.

Перш ніж ви розпочнете

Вам треба мати кластер Kubernetes, а також інструмент командного рядка kubectl має бути налаштований для роботи з вашим кластером. Рекомендується виконувати ці настанови у кластері, що має щонайменше два вузли, які не виконують роль вузлів управління. Якщо у вас немає кластера, ви можете створити його, за допомогою minikube або використовувати одну з цих пісочниць:

Версія вашого Kubernetes сервера має бути не старішою ніж v1.29.

Для перевірки версії введіть kubectl version.

Примітка:

Хоча цю можливість можна використовувати в раніших версіях, вона є GA й офіційно підтримується лише з v1.33.

Розширення діапазонів IP-адрес Service

Панель управління забезпечує наявність спеціального обʼєкта ServiceCIDR із загальновідомою назвою kubernetes, який визначає діапазон IP-адрес на основі значення аргументу командного рядка --service-cluster-ip-range для kube-apiserver.

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

Загальновідомий Service kubernetes, який відкриває Podʼам доступ до точки доступу kube-apiserver, обчислює першу IP-адресу зі стандартного діапазону ServiceCIDR і використовує її як свою кластерну 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 у цьому випадку використовує ClusterIP 10.96.0.1, що має відповідний обʼєкт IPAddress.

kubectl get ipaddress 10.96.0.1
NAME        PARENTREF
10.96.0.1   services/default/kubernetes

ServiceCIDRs захищені завершувачами, щоб ClusterIP у Service не лишалися без батьківського обʼєкта; завершувач вилучається лише тоді, коли існує інша підмережа з наявними IPAddresses або немає IPAddresses, що належать до цієї підмережі.

Розширення кількості доступних IP-адрес для Services

Іноді користувачам потрібно збільшити кількість адрес, доступних для Services. Раніше збільшення діапазону Service було операцією з порушенням роботи, яка також могла спричинити втрату даних. Завдяки цій новій можливості користувачам достатньо додати новий ServiceCIDR, щоб збільшити кількість доступних адрес.

Додавання нового ServiceCIDR

У кластері з діапазоном 10.96.0.0/28 для Services доступно лише 2^(32-28) - 2 = 14 IP-адрес. Service kubernetes.default створюється завжди; у цьому прикладі лишається лише 13 можливих Services.

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

Ви можете збільшити кількість IP-адрес, доступних для Services, створивши новий ServiceCIDR, який розширює наявні або додає нові діапазони IP-адрес.

cat <<EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: ServiceCIDR
metadata:
  name: newcidr1
spec:
  cidrs:
  - 10.96.0.0/24
EOF
servicecidr.networking.k8s.io/newcidr1 created

і це дозволить створювати нові Services з 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, якщо є IPAddresses, які залежать від цього ServiceCIDR.

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

Kubernetes використовує завершувач на ServiceCIDR, щоб відстежувати цю залежність.

kubectl get servicecidr newcidr1 -o yaml
apiVersion: networking.k8s.io/v1
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

Видаляючи Services з IP-адресами, які блокують видалення ServiceCIDR,

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

Політики Service CIDR у Kubernetes

Адміністратори кластера можуть застосовувати політики для контролю створення й зміни ресурсів ServiceCIDR у кластері. Це дає змогу централізовано керувати діапазонами IP-адрес, які використовуються для Services, і запобігає ненавмисним або конфліктним конфігураціям. Kubernetes надає для застосування цих правил такі механізми, як валідаційні політики допуску (Validating Admission Policies).

Запобігання несанкціонованому створенню й оновленню ServiceCIDR за допомогою валідаційної політики допуску

Іноді адміністратори кластера хочуть обмежити дозволені діапазони або повністю заборонити будь-які зміни діапазонів IP-адрес Service кластера.

Примітка:

Стандартний ServiceCIDR "kubernetes" створюється kube-apiserver для забезпечення узгодженості в кластері й потрібен для роботи кластера, тому його завжди потрібно дозволяти. Щоб ValidatingAdmissionPolicy не обмежувала стандартний ServiceCIDR, додайте таку умову:

  matchConditions:
  - name: 'exclude-default-servicecidr'
    expression: "object.metadata.name != 'kubernetes'"

як у наведених нижче прикладах.

Обмеження діапазонів Service CIDR конкретними діапазонами

Нижче наведено приклад ValidatingAdmissionPolicy, яка дозволяє створювати ServiceCIDR, лише якщо вони є піддіапазонами заданих діапазонів 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'].) Ви можете скопіювати цю політику й змінити значення allowed на відповідне для вашого кластера.

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
  name: "servicecidrs.default"
spec:
  failurePolicy: Fail
  matchConstraints:
    resourceRules:
    - apiGroups:   ["networking.k8s.io"]
      apiVersions: ["v1"]
      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-default-binding"
spec:
  policyName: "servicecidrs.default"
  validationActions: [Deny,Audit]

Щоб дізнатися більше про CEL і написати власний expression для валідації, дивіться документацію CEL.

Обмеження будь-якого використання API ServiceCIDR

Наведений нижче приклад показує, як використовувати ValidatingAdmissionPolicy та її привʼязку, щоб обмежити створення будь-яких нових діапазонів Service CIDR, окрім стандартного ServiceCIDR "kubernetes":

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
  name: "servicecidrs.deny"
spec:
  failurePolicy: Fail
  matchConstraints:
    resourceRules:
    - apiGroups:   ["networking.k8s.io"]
      apiVersions: ["v1"]
      operations:  ["CREATE", "UPDATE"]
      resources:   ["servicecidrs"]
  validations:
  # Deny changes to all ServiceCIDRs except the default one
  - expression: "object.metadata.name == 'kubernetes'"
    message: "you can only create or update the default ServiceCIDR"
  # Deny changes from all users except kube-apiserver
  - expression: "request.userInfo.username == 'system:apiserver' && 'system:masters' in request.userInfo.groups"
    message: "you can not create or update ServiceCIDR objects"
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicyBinding
metadata:
  name: "servicecidrs-deny-binding"
spec:
  policyName: "servicecidrs.deny"
  validationActions: [Deny,Audit]