Обнаружение устареваний API Kubernetes с помощью pluto

API Kubernetes постоянно меняется. С этими изменениями приходят устаревания и возможные удаления частей API. Чтобы иметь возможность поддерживать актуальную версию кластера Kubernetes, мы должны определить устаревшие API и обновить их. Это может стать утомительным в больших кластерах с сотнями ресурсов, но такие инструменты, как pluto, могут помочь.

Что означает устаревание API в Kubernetes?

Операции, управляющие жизненным циклом всех ресурсов Kubernetes, предоставляются через конечные точки RESTful API сервером Kubernetes API. Другими словами, Kubernetes API — это фронтенд плоскости управления Kubernetes.

API ресурсов связаны с такими URI, как

Некоторые ресурсы также объединены в основную группу (или группу наследия). Они доступны через специальную конечную точку API /api/{version} (см. группы API). Например, стручки являются частью основной группы. Запрос на список всех стручков в данном пространстве имен my-namespace отображается в следующий HTTP GET запрос.

GET /api/v1/namespaces/my-namespace/pods

(Для справки см. документацию API для ресурса Pod).

Проблема устаревания API Kubernetes

Kubernetes определяет политику обесценивания, которая определяет, что означает, если части API становятся обесцененными. По сути, обесценивание означает, что связанные с ним конечные точки сервера API Kubernetes помечаются для удаления и впоследствии удаляются. Поскольку сервер API управляет жизненным циклом ресурса, использование ресурса с удаленной версией API предотвратит развертывание этого ресурса. Следовательно, если мы не обновим версии API наших ресурсов, мы либо застрянем с устаревшей версией Kubernetes, либо обновление до новой версии Kubernetes предотвратит развертывание определенных ресурсов. Оба эти состояния нежелательны, поскольку мы либо

  1. продолжать использовать нестабильную версию Kubernetes, либо
  2. наше развертывание Kubernetes будет неполным.

Развертывание ресурсов с удаленными версиями API

Чтобы получить более ясную картину, давайте рассмотрим вторую проблему и посмотрим, как Kubernetes реагирует, если мы попытаемся развернуть ресурс с использованием удаленной версии API. Для этого мы запустим локальный кластер Kubernetes с k3d.

$ k3d cluster create
INFO[0000] Prep: Network
INFO[0004] Created network 'k3d-k3s-default'
INFO[0004] Created image volume k3d-k3s-default-images
INFO[0004] Starting new tools node...
INFO[0005] Pulling image 'ghcr.io/k3d-io/k3d-tools:5.4.3'
INFO[0007] Starting Node 'k3d-k3s-default-tools'
INFO[0007] Creating node 'k3d-k3s-default-server-0'
INFO[0009] Pulling image 'docker.io/rancher/k3s:v1.23.6-k3s1'
INFO[0027] Creating LoadBalancer 'k3d-k3s-default-serverlb'
INFO[0028] Pulling image 'ghcr.io/k3d-io/k3d-proxy:5.4.3'
INFO[0030] Using the k3d-tools node to gather environment information
INFO[0030] Starting new tools node...
INFO[0030] Starting Node 'k3d-k3s-default-tools'
INFO[0033] Starting cluster 'k3s-default'
INFO[0033] Starting servers...
INFO[0033] Starting Node 'k3d-k3s-default-server-0'
INFO[0040] All agents already running.
INFO[0040] Starting helpers...
INFO[0040] Starting Node 'k3d-k3s-default-serverlb'
INFO[0049] Injecting records for hostAliases (incl. host.k3d.internal) and for 3 network members into CoreDNS configmap...
INFO[0051] Cluster 'k3s-default' created successfully!
INFO[0051] You can now use it like this:
kubectl cluster-info
Входим в полноэкранный режим Выйти из полноэкранного режима

Затем переключаем контекст Kubernetes, например, с помощью kubectx.

$ kubectx k3d-k3s-default
Switched to context "k3d-k3s-default".
Войти в полноэкранный режим Выйти из полноэкранного режима

Теперь посмотрим, какая версия сервера Kubernetes API запущена, выполнив команду kubectl version.

$ kubectl version
WARNING: This version information is deprecated and will be replaced with the output from kubectl version --short.  Use --output=yaml|json to get the full version.
Client Version: version.Info{Major:"1", Minor:"24", GitVersion:"v1.24.2", GitCommit:"f66044f4361b9f1f96f0053dd46cb7dce5e990a8", GitTreeState:"clean", BuildDate:"2022-06-15T14:22:29Z", GoVersion:"go1.18.3", Compiler:"gc", Platform:"darwin/amd64"}
Kustomize Version: v4.5.4
Server Version: version.Info{Major:"1", Minor:"23", GitVersion:"v1.23.6+k3s1", GitCommit:"418c3fa858b69b12b9cefbcff0526f666a6236b9", GitTreeState:"clean", BuildDate:"2022-04-28T22:16:18Z", GoVersion:"go1.17.5", Compiler:"gc", Platform:"linux/amd64"}
Войти в полноэкранный режим Выйти из полноэкранного режима

Как мы видим из вывода Server Version:, наш кластер k3d работает под управлением Kubernetes v1.23.

Взглянув на руководство по устареванию API, мы видим, что две версии API Ingress, extensions/v1beta1 и networking.k8s.io/v1beta1, были удалены в версии 1.22 Kubernetes. Поэтому давайте попробуем развернуть ресурс Ingress с этой версией API и посмотрим, что произойдет. Ниже приведен пример манифеста, который я бессовестно украл из раздела The Ingress Resource официальной документации Kubernetes и поместил его в файл ingress-pre-1.22.yaml.

# ingress-pre-1.22.yaml
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: minimal-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx-example
  rules:
  - http:
      paths:
      - path: /testpath
        pathType: Prefix
        backend:
          service:
            name: test
            port:
              number: 80
Вход в полноэкранный режим Выход из полноэкранного режима

А затем давайте попробуем развернуть его на нашем кластере Kubernetes версии 1.23.

$ kubectl apply -f ingress-pre-1.22.yaml
error: resource mapping not found for name: "minimal-ingress" namespace: "" from "ingress-pre-1.22.yaml": no matches for kind "Ingress" in version "networking.k8s.io/v1beta1"
ensure CRDs are installed first
Вход в полноэкранный режим Выход из полноэкранного режима

Как мы видим, API возвращает ошибку, указывая, что networking.k8s.io/v1beta1 больше не включает тип Ingress. Однако если мы изменим версию API на networking.k8s.io/v1,

# ingress-1.22.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: minimal-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx-example
  rules:
  - http:
      paths:
      - path: /testpath
        pathType: Prefix
        backend:
          service:
            name: test
            port:
              number: 80
Вход в полноэкранный режим Выйти из полноэкранного режима

наш Ingress будет создан без проблем.

$ kubectl apply -f ingress-1.22.yaml
ingress.networking.k8s.io/minimal-ingress created
Войти в полноэкранный режим Выход из полноэкранного режима

Определение устаревания API с помощью pluto

В более реалистичном сценарии у нас уже есть ресурсы, развернутые на нашем кластере, и мы хотим поддерживать их версии API в актуальном состоянии, чтобы мы могли безопасно обновить версию нашего кластера.

Поэтому возникает вопрос, как обнаружить ресурсы с устаревшими и скоро удаляемыми версиями API? Один из ответов на этот вопрос заключается в том, чтобы обратиться к руководству по устареванию, упомянутому ранее, и проверить, какие версии API ресурсов будут удалены в предстоящем обновлении Kubernetes. Важно отметить, однако, что если мы пропустим несколько версий, нам придется повторить эту проверку для всех версий между текущей и целевой версиями Kubernetes.

В больших кластерах с десятками типов ресурсов и версий это может стать утомительным и чреватым ошибками. К счастью, существуют такие инструменты, как pluto от FairwindOps, которые помогают нам обнаружить устаревшие и скоро удаляемые версии API ресурсов.

Например, давайте развернем наш ресурс Ingress на кластере Kubernetes с версией сервера API более ранней, чем v1.22 (например, v1.19). Создать кластер k3d с неактуальной версией API Kubernetes можно, передав опцию --image в k3d, указав образ k3s для желаемой версии Kubernetes (например, v1.19.16-k3s1, полный список образов доступен на Dockerhub):

$ k3d cluster delete
INFO[0000] Deleting cluster 'k3s-default'
INFO[0002] Deleting cluster network 'k3d-k3s-default'
INFO[0005] Deleting 2 attached volumes...
WARN[0005] Failed to delete volume 'k3d-k3s-default-images' of cluster 'k3s-default': failed to find volume 'k3d-k3s-default-images': Error: No such volume: k3d-k3s-default-images -> Try to delete it manually
INFO[0005] Removing cluster details from default kubeconfig...
INFO[0005] Removing standalone kubeconfig file (if there is one)...
INFO[0005] Successfully deleted cluster k3s-default!
$ k3d cluster create --image rancher/k3s:v1.19.16-k3s1
INFO[0000] Prep: Network
INFO[0003] Created network 'k3d-k3s-default'
INFO[0003] Created image volume k3d-k3s-default-images
INFO[0003] Starting new tools node...
INFO[0003] Starting Node 'k3d-k3s-default-tools'
INFO[0006] Creating node 'k3d-k3s-default-server-0'
INFO[0009] Pulling image 'rancher/k3s:v1.19.16-k3s1'
INFO[0018] Creating LoadBalancer 'k3d-k3s-default-serverlb'
INFO[0018] Using the k3d-tools node to gather environment information
INFO[0018] Starting new tools node...
INFO[0018] Starting Node 'k3d-k3s-default-tools'
INFO[0021] Starting cluster 'k3s-default'
INFO[0021] Starting servers...
INFO[0021] Starting Node 'k3d-k3s-default-server-0'
INFO[0028] All agents already running.
INFO[0028] Starting helpers...
INFO[0028] Starting Node 'k3d-k3s-default-serverlb'
INFO[0037] Injecting records for hostAliases (incl. host.k3d.internal) and for 3 network members into CoreDNS configmap...
INFO[0039] Cluster 'k3s-default' created successfully!
INFO[0039] You can now use it like this:
kubectl cluster-info
Вход в полноэкранный режим Выход из полноэкранного режима

Мы снова подтверждаем, что на сервере API работает Kubernetes v1.19 с помощью kubectl version.

$ kubectl version
WARNING: This version information is deprecated and will be replaced with the output from kubectl version --short.  Use --output=yaml|json to get the full version.
Client Version: version.Info{Major:"1", Minor:"24", GitVersion:"v1.24.2", GitCommit:"f66044f4361b9f1f96f0053dd46cb7dce5e990a8", GitTreeState:"clean", BuildDate:"2022-06-15T14:22:29Z", GoVersion:"go1.18.3", Compiler:"gc", Platform:"darwin/amd64"}
Kustomize Version: v4.5.4
Server Version: version.Info{Major:"1", Minor:"19", GitVersion:"v1.19.16+k3s1", GitCommit:"da16869555775cf17d4d97ffaf8a13b70bc738c2", GitTreeState:"clean", BuildDate:"2021-11-04T00:55:24Z", GoVersion:"go1.15.14", Compiler:"gc", Platform:"linux/amd64"}
WARNING: version difference between client (1.24) and server (1.19) exceeds the supported minor version skew of +/-1
Войти в полноэкранный режим Выйти из полноэкранного режима

Теперь применим наш Ingress с манифестом, в котором снова указана устаревшая версия API.

$ kubectl apply -f ingress-pre-1.22.yaml
Warning: networking.k8s.io/v1beta1 Ingress is deprecated in v1.19+, unavailable in v1.22+; use networking.k8s.io/v1 Ingress
ingress.networking.k8s.io/minimal-ingress created
Войти в полноэкранный режим Выход из полноэкранного режима

Как мы видим, мы уже получили полезное предупреждение об устаревании, которое рекомендует использовать networking.k8s.io/v1 вместо networking.k8s.io/v1beta1. Пока мы предполагаем, однако, что наши ресурсы уже развернуты на работающем кластере, и мы хотим обнаружить эти ресурсы (без повторного применения).

Вот здесь-то и пригодятся такие инструменты, как pluto для обнаружения использования устаревшей версии API ресурса.

Pluto доступен на различных платформах и через различные менеджеры пакетов. Здесь мы будем использовать binenv.

$ binenv install pluto
2022-07-21T19:47:18+02:00 WRN version for "pluto" not specified; using "5.8.0"
fetching pluto version 5.8.0 100% |█████████████████████████████████████████████████████████████████████████████████████████████████████████████████| (11/11 MB, 9.578 MB/s)
2022-07-21T19:47:22+02:00 INF "pluto" (5.8.0) installed
Вход в полноэкранный режим Выход из полноэкранного режима

Есть несколько способов передать манифесты ресурсов в pluto для обнаружения устаревших версий API: например, через сканирование каталога или прямой ввод. Кроме того, существует удобная интеграция с Helm, которая проверяет наши релизы на наличие устаревших версий.

Сканирование каталога

Использование сканирования каталога требует, чтобы мы знали, где найти манифесты Kubernetes для нашего кластера. В нашем случае это довольно просто, поскольку у нас есть только два простых манифеста, и оба они находятся в текущем каталоге. Следующая команда заставляет pluto выполнить сканирование каталога и обнаружить нашу устаревшую версию api.

$ pluto detect-files --directory . --target-versions k8s=v1.22.0
NAME              KIND      VERSION                     REPLACEMENT            REMOVED   DEPRECATED
minimal-ingress   Ingress   networking.k8s.io/v1beta1   networking.k8s.io/v1   true      true
Войти в полноэкранный режим Выйти из полноэкранного режима

Обратите внимание, что мы можем указать целевую версию (версии) с помощью опции --target-versions. Если бы мы выбрали Kubernetes v1.15.0, pluto вернул бы пустой список, поскольку версия нашего CRD API была устаревшей только в версии v1.16.0.

$ pluto detect-files --directory . --target-versions k8s=v1.15.0
No output to display
Вход в полноэкранный режим Выход из полноэкранного режима

Прямой ввод

Используя прямой ввод, мы можем просто передать манифест ресурсов непосредственно в pluto. Это особенно полезно, если мы хотим просканировать ресурсы, уже развернутые на кластере (а просматривать манифесты слишком сложно). Поскольку наш CRD уже развернут, мы можем получить манифест ресурсов с помощью kubectl get и передать его в pluto.

$ kubectl get ingress minimal-ingress -o yaml | pluto detect -
Warning: extensions/v1beta1 Ingress is deprecated in v1.14+, unavailable in v1.22+; use networking.k8s.io/v1 Ingress
NAME              KIND      VERSION              REPLACEMENT            REMOVED   DEPRECATED
minimal-ingress   Ingress   extensions/v1beta1   networking.k8s.io/v1   true      true
Вход в полноэкранный режим Выход из полноэкранного режима

ℹ️ Вы могли заметить, что pluto сообщает об устаревшей версии API как extensions/v1beta1 вместо networking.k8s.io/v1beta1. Это происходит потому, что сервер API в версии 1.19., очевидно, нормализует networking.k8s.io/v1beta1 до extensions/v1beta1. Манифест развернутого Ingress, возвращаемый командой kubectl get ingress minimal-ingress -o yaml, имеет версию API extensions/v1beta1.

Релизы Helm

Если мы развертываем наши ресурсы с помощью Helm, Pluto также предоставляет подкоманду detect-helm, которая проверяет наши релизы на наличие устаревших версий API.

Резюме

API Kubernetes постоянно развивается. Чтобы поддерживать наш кластер в актуальном состоянии, нам постоянно приходится следить за устаревшими и скоро удаляемыми версиями API ресурсов. Ручные проверки возможны благодаря руководству Kubernetes deprecation guide, но они могут стать очень утомительными и привести к ошибкам. Такие инструменты, как pluto, позволяют нам автоматизировать проверки на устаревание API и упростить работу по поддержанию актуальных версий API ресурсов.

Оцените статью
devanswers.ru
Добавить комментарий