Если вы применяли в работе предыдущие выпуски Kubernetes тот же
1.16 вы, возможно, видели странное предупреждение от kubectl
run
.
До недавнего времени этой командой можно было сгенерировать объекты для развертывания или YAML из командной строки. Начиная с Kubernetes 1.18 такая возможность была сломана весьма удивительным образом. В статье будут ответы на вопросы Почему? и Как дальше с этим жить?
Прежде чем занырнуть поглубже в эти вопросы, вспомним, что есть три основных способа создания объектов для развертывания в Kubernetes:
- Через API (как это делает например OpenFaaS)
- Путем создания вручную файла YAML. Или более приближенно к реальность копипасты в него откуда-то из разных сайтов (привет, StackOverflow)
- Запуская
kubectl run
илиkubectl run -o yaml --dry-run
Как видно я также перечислил варианты по порядку по сложности (от сложного до простого).
Сравнение вариантов
Первый случай, использование API возможно наиболее стабильный путь для развертывания, но и наиболее сложный в реализации. До недавнего времени API был относительно стабильным в extensions/v1beta, пока не перешел в apps/v1, это было достаточно большое изменение и многие проекты с открытым исходным кодом должны были переработать свой код и файлы YAML. Я не уверен, что сложнее создавать объекты в Go или YAML. С Go вы получаете возможность подсказок IDE, но нужно искать описание пакетов, где и в каком из них требуемый тип. Core? Meta? Apps? Extensions? Может быть это то, что мы упускаем при редактировании манифестов старый добрый Intellisense?
Кусочек кода из контроллера OpenFaaS для Kubernetes (aka
faas-netes)
Второй вариант создание YAML вручную. Если пользовались Twitter или смотрели по хэштегу #kubernetes, то могли видеть еще и то, что все, от новичков, уважаемых авторов и до основателей Kubernetes, ругаются на то, как трудно писать и понимать YAML.
Лично мне он нравится, и я считаю, что его легче всего применять, но я то понимаю, что к чему с жалобами. Я предполагаю, что они на самом деле жалуются на сложную и вложенную структуру схемы API Kubernetes.
apiVersion: apps/v1kind: Deploymentmetadata: name: nginx-1 labels: app: nginxspec: replicas: 1 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.14.2 ports: - containerPort: 80
Этот пример скопирован из документации к Kubernetes, а затем число реплик изменено с трех на одну. Лично мне не хотелось бы писать такое с нуля, хоть убейте.
Написание Kubernetes YAML напоминает мне задачу на собеседовании на листике с карандашом про переворачивание двойного связного списка, без ошибок и опечаток (сложно, но можно прим. переводчика).
Третий вариант до недавнего времени был весьма приятной альтернативой первому и второму вариантам:
- особенно для обучения;
- при необходимости написания коротких инструкций для демонстрации приложения;
- для создания YAML для дальнейшей настройки;
- использования в конвейерах CI\CD.
Например, для раскатки приложения в кластере с политикой перезапуска, именем, образом и портом можно сделать так:
$ kubectl run nginx-1 --image=nginx --port=80 --restart=Always
Если хотите лучше, можно смешать вариант два и три выводим YAML без его применения, после чего ковыряем его. Давайте сравним то, что выводится командой и документацией?
$ kubectl run nginx-1 --image=nginx:1.14.2 --port=80 \ --restart=Always -o yaml --dry-runapiVersion: apps/v1kind: Deploymentmetadata: creationTimestamp: null labels: run: nginx-1 name: nginx-1spec: replicas: 1 selector: matchLabels: run: nginx-1 strategy: {} template: metadata: creationTimestamp: null labels: run: nginx-1 spec: containers: - image: nginx:1.14.2 name: nginx-1 ports: - containerPort: 80 resources: {}
Еще есть пара флагов, типа --replicas
и
--serviceaccount
. Вывод не сильно отличается от
документации.
Но причина написания этой статьи вы больше не сможете так делать, поскольку эта функция удалена, начиная с Kubernetes версии 1.18 и более поздних выпусков.
Предупреждения
Я всегда был немного удивлён этой ошибкой, но в ней не было ни времени, ни другого контекста для помощи.
Как и вы, я подумал: Ну, допустим, в будущем я выучу альтернативную команду
$ kubectl run nginx-1 --image=nginx --port=80 --restart=Alwayskubectl run --generator=deployment/apps.v1 is DEPRECATED and will be removed in a future version. Use kubectl run --generator=run-pod/v1 or kubectl create instead.deployment.apps/nginx-1 created
Если вы скачаете kubectl 1.17 или более раннюю (я работаю 1.15 в этой статье), то вы все еще сможете разворачивать приложения или создавать YAML. Но как только вы обновитесь до Kubernetes 1.18 получится так:
kubectl run nginx-1 --image=nginx --port=80 --restart=Always -o yaml --dry-runW0512 14:27:13.111424 30104 helpers.go:535] --dry-run is deprecated and can be replaced with --dry-run=client.apiVersion: v1kind: Podmetadata: creationTimestamp: null labels: run: nginx-1 name: nginx-1spec: containers: - image: nginx name: nginx-1 ports: - containerPort: 80 resources: {} dnsPolicy: ClusterFirst restartPolicy: Always
Это Pod не то же самое что Deployment. К счастью все еще можно указать service account и порт, но работать напрямую с подами не стоит, особенно на боевых серверах, поскольку они эфемерны, могут переехать на другой узел, быть убиты и не имеют (по умолчанию) стабильного имени или ip-адреса. Deployments и Services решают эту проблему.
Работать с подами можно, для одноразовых задач типа запуска curl для проверки api, или же для добавления сообщений в Kafka.
Мы с этим столкнулись в проекте inlets-operator, когда пользователь пожаловался, что примеры из документации не работают.
Мы хотели простейшую инструкцию для документации и для вспомогательного сообщения helm chart, которая помогла бы пользователям понять, как пользоваться проектом. Вы создаете Deployment, затем открываете доступ извне через LoadBalancer, мы создаем VM в вашем любимом облаке, создаем обратный туннель, так что вы в результате имеете полностью внедренный белый ip-адрес.
Наша старая документация выглядела так:
kubectl run nginx-1 --image=nginx --port=80 --restart=Alwayskubectl expose deployment nginx-1 --port=80 --type=LoadBalancer
Новая так:
export DEPLOYMENT=nginx-1(cat<<EOFapiVersion: apps/v1kind: Deploymentmetadata: name: $DEPLOYMENT labels: app: nginxspec: replicas: 1 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.14.2 ports: - containerPort: 80EOF) | kubectl apply -f -kubectl expose deployment nginx-1 --port=80 --type=LoadBalancer
Просьба к разработчикам Kubernetes, пожалуйста не
отбирайте у нас команду kubectl expose
;-)
Жду с нетерпением сохранения текстов такого же объема во всех моих руководствах, а также начинаю привыкать писать простыни для Deployment. Я был настолько недоволен полученным руководством, что поместил его в отдельный файл, который надо будет скачать всем желающим для проверки перед запуском кластера:
$ kubectl apply -f https://raw.githubusercontent.com/inlets/inlets-operator/master/contrib/nginx-sample-deployment.yaml
Люди, никогда не делайте kubectl apply -f
файлов из
интернета без их предварительной проверки.
Что делать?
Оказывается, нет никакой полноценной альтернативы.
Некоторые считают, что новая команда это kubectl create
deployment
.
Самые внимательные уже заметили, что все важные опции отсутствуют, к примеру--port
,--serviceaccount
,--replicas
и--restart-policy
.
kubectl create deployment --helpCreate a deployment with the specified name.Aliases:deployment, deployExamples: # Create a new deployment named my-dep that runs the busybox image. kubectl create deployment my-dep --image=busyboxOptions: --allow-missing-template-keys=true: If true, ignore any errors in templates when a field or map key is missing inthe template. Only applies to golang and jsonpath output formats. --dry-run='none': Must be "none", "server", or "client". If client strategy, only print the object that would besent, without sending it. If server strategy, submit server-side request without persisting the resource. --image=[]: Image name to run. -o, --output='': Output format. One of:json|yaml|name|go-template|go-template-file|template|templatefile|jsonpath|jsonpath-file. --save-config=false: If true, the configuration of current object will be saved in its annotation. Otherwise, theannotation will be unchanged. This flag is useful when you want to perform kubectl apply on this object in the future. --template='': Template string or path to template file to use when -o=go-template, -o=go-template-file. Thetemplate format is golang templates [http://golang.org/pkg/text/template/#pkg-overview]. --validate=true: If true, use a schema to validate the input before sending itUsage: kubectl create deployment NAME --image=image [--dry-run=server|client|none] [options]Use "kubectl options" for a list of global command-line options (applies to all commands).
Так что наш изначальный пример не будет больше работать с
kubectl create
, а также не может быть применен иначе,
как блок YAML. Если нужен динамический порт есть вариант с
шаблонами на bash, что однако не кроссплатформенно.
Лучшее что можно сделать с новой командой это очередной поиск по StackOverflow или документации Kubernetes каждый раз для простого Deployment. Почему? Потому что вложенные схемы на YAML сложно запоминать.
$ kubectl create deployment nginx-1 --image=nginx -o yaml --dry-runW0512 14:38:18.296270 30135 helpers.go:535] --dry-run is deprecated and can be replaced with --dry-run=client.apiVersion: apps/v1kind: Deploymentmetadata: creationTimestamp: null labels: app: nginx-1 name: nginx-1spec: replicas: 1 selector: matchLabels: app: nginx-1 strategy: {} template: metadata: creationTimestamp: null labels: app: nginx-1 spec: containers: - image: nginx name: nginx resources: {}
Обратите внимание, что нет порта, restartPolicy и других вещей.
Какие выводы?
Хотел бы я ошибаться, но чаще всего благими намерениями вымощена дорога в ад, а решение проблем с техническим долгом может привести к ухудшению положения пользователей, несмотря на то, что намерения изначально были ради улучшения.
Pull request
68132 внес все это, желая приблизить поведение kubectl
run
к docker run
. Вообще неплохая задумка.
Я надеялся, что разработчики Kubernetes рассмотрят вопрос о
добавлении различных отсутствующих флагов и опций в новую команду
kubectl create deployment
, однако первому же человеку,
пожелавшему такое, сказали: хочешь пиши свой PR.
Вас это тоже затронуло? Пишите в Twitter, или комментируйте запрос, в котором будут изменения.
Трудно сделать что-то лучше, особенно если это ломает пользовательский опыт, однако это у вас, авторов Kubernetes, получилось. И вышло просто идеально.
Полный список изменений в 1.18.
Статья переведена и подготовлена для Хабра сотрудниками обучающего центра Слёрм интенсивы, видеокурсы и корпоративное обучение от практикующих специалистов (Kubernetes, DevOps, Docker, Ansible, Ceph, SRE)