Управление ресурсами
Итак, вы развернули приложение и настроили доступ к нему с помощью сервиса. Что дальше? Kubernetes предоставляет ряд инструментов, помогающих управлять развертыванием приложений, включая их масштабирование и обновление. Среди особенностей, которые мы обсудим более подробно, — конфигурационные файлы и лейблы.
Организация конфигураций ресурсов
Многие приложения требуют создания нескольких ресурсов типа Deployment и Service. Управление ими можно упростить, сгруппировав в один YAML-файл (со строкой "---" в качестве разделителя). Например:
apiVersion: v1
kind: Service
metadata:
name: my-nginx-svc
labels:
app: nginx
spec:
type: LoadBalancer
ports:
- port: 80
selector:
app: nginx
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
Можно создавать сразу несколько ресурсов:
kubectl apply -f https://k8s.io/examples/application/nginx-app.yaml
service/my-nginx-svc created
deployment.apps/my-nginx created
Ресурсы будут создаваться в порядке, в котором они описаны в файле. Таким образом, первым лучше всего описать сервис — это позволит планировщику распределять Pod'ы этого сервиса по мере их создания контроллером (контроллерами), например, Deployment'ом.
kubectl apply
также может принимать сразу несколько аргументов -f
:
kubectl apply -f https://k8s.io/examples/application/nginx/nginx-svc.yaml -f https://k8s.io/examples/application/nginx/nginx-deployment.yaml
Кроме того, можно указывать директории вместо отдельных файлов или в дополнение ним:
kubectl apply -f https://k8s.io/examples/application/nginx/
kubectl
прочитает все файлы с расширениями .yaml
, .yml
или .json
.
Рекомендуется размещать ресурсы, имеющие отношение к одному микросервису или уровню приложения, в одном файле, а также группировать все файлы, связанные с приложением, в одной директории. Если уровни вашего приложения связываются друг с другом через DNS, можно развернуть все компоненты стека совместно.
Также в качестве источника конфигурации можно указать URL — это удобно при создании/настройке с использованием конфигурационных файлов, размещенных на GitHub:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/website/main/content/en/examples/application/nginx/nginx-deployment.yaml
deployment.apps/my-nginx created
Пакетные операции в kubectl
Создание ресурсов — не единственная операция, которую kubectl
может выполнять в рамках одной команды. Этот инструмент также способен извлекать имена ресурсов из конфигурационных файлов для выполнения других операций, в частности, для удаления созданных ресурсов:
kubectl delete -f https://k8s.io/examples/application/nginx-app.yaml
deployment.apps "my-nginx" deleted
service "my-nginx-svc" deleted
В случае двух ресурсов их можно перечислить в командной строке, используя синтаксис вида resource/name:
kubectl delete deployments/my-nginx services/my-nginx-svc
При большем количестве ресурсов удобнее указать селектор (запрос по лейблу) с помощью -l
или --selector
, который отфильтрует ресурсы по их лейблам:
kubectl delete deployment,services -l app=nginx
deployment.apps "my-nginx" deleted
service "my-nginx-svc" deleted
Поскольку kubectl
выводит имена ресурсов в том же синтаксисе, что и получает, можно выстраивать цепочки операций с помощью $()
или xargs
:
kubectl get $(kubectl create -f docs/concepts/cluster-administration/nginx/ -o name | grep service)
kubectl create -f docs/concepts/cluster-administration/nginx/ -o name | grep service | xargs -i kubectl get {}
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
my-nginx-svc LoadBalancer 10.0.0.208 <pending> 80/TCP 0s
Приведенные выше команды сначала создают ресурсы в разделе examples/application/nginx/
, выводят о них информацию в формате -o name
(то есть в виде пары resource/name). Затем в результатах производится поиск по "service" (grep
), и информация о найденных ресурсах выводится с помощью kubectl get
.
Если ресурсы хранятся в нескольких поддиректориях в пределах одной директории, можно рекурсивно выполнять операции и в этих поддиректориях, указав --recursive
или -R
наряду с флагом --filename
, -f
.
Предположим, что существует директория project/k8s/development
, в которой хранятся все манифесты, необходимые для dev-окружения, организованные по типу ресурсов:
project/k8s/development
├── configmap
│ └── my-configmap.yaml
├── deployment
│ └── my-deployment.yaml
└── pvc
└── my-pvc.yaml
По умолчанию при выполнении массовых операций над project/k8s/development
команда остановится на первом уровне, не обрабатывая поддиректории. К примеру, попытка создать ресурсы, описанные в этой директории, приведет к ошибке:
kubectl apply -f project/k8s/development
error: you must provide one or more resources by argument or filename (.json|.yaml|.yml|stdin)
Вместо этого следует указать флаг --recursive
или -R
с флагом --filename
, -f
:
kubectl apply -f project/k8s/development --recursive
configmap/my-config created
deployment.apps/my-deployment created
persistentvolumeclaim/my-pvc created
Флаг --recursive
работает с любыми операциями, принимающими флаг --filename
, -f
, например: kubectl {create, get, delete, describe, rollout}
и т.д.
Флаг --recursive
также работает для нескольких аргументов -f
:
kubectl apply -f project/k8s/namespaces -f project/k8s/development --recursive
namespace/development created
namespace/staging created
configmap/my-config created
deployment.apps/my-deployment created
persistentvolumeclaim/my-pvc created
В разделе Инструмент командной строки kubectl доступна дополнительная информация о kubectl
.
Эффективное использование лейблов
Во всех примерах, рассмотренных до этого момента, к ресурсам прикреплялся лишь один лейбл. Однако существуют сценарии, когда необходимо использовать несколько лейблов, чтобы отличить наборы ресурсов друг от друга.
Например, разные приложения могут использовать разные значения для лейбла app
, а в случае многоуровневого приложения вроде гостевой книги лейблы могут указывать на соответствующий уровень. Например, у фронтенда могут быть следующие лейблы:
labels:
app: guestbook
tier: frontend
в то время как у master'а и slave'а Redis будут лейблы tier
и, возможно, даже дополнительный лейбл role
:
labels:
app: guestbook
tier: backend
role: master
и
labels:
app: guestbook
tier: backend
role: slave
Лейблы позволяют группировать ресурсы по любому параметру с соответствующим лейблом:
kubectl apply -f examples/guestbook/all-in-one/guestbook-all-in-one.yaml
kubectl get pods -Lapp -Ltier -Lrole
NAME READY STATUS RESTARTS AGE APP TIER ROLE
guestbook-fe-4nlpb 1/1 Running 0 1m guestbook frontend <none>
guestbook-fe-ght6d 1/1 Running 0 1m guestbook frontend <none>
guestbook-fe-jpy62 1/1 Running 0 1m guestbook frontend <none>
guestbook-redis-master-5pg3b 1/1 Running 0 1m guestbook backend master
guestbook-redis-slave-2q2yf 1/1 Running 0 1m guestbook backend slave
guestbook-redis-slave-qgazl 1/1 Running 0 1m guestbook backend slave
my-nginx-divi2 1/1 Running 0 29m nginx <none> <none>
my-nginx-o0ef1 1/1 Running 0 29m nginx <none> <none>
kubectl get pods -lapp=guestbook,role=slave
NAME READY STATUS RESTARTS AGE
guestbook-redis-slave-2q2yf 1/1 Running 0 3m
guestbook-redis-slave-qgazl 1/1 Running 0 3m
Канареечные развертывания
Еще один сценарий, в котором применение нескольких лейблов как нельзя кстати, — дифференциация развертываний отдельных релизов или конфигураций одного и того же компонента. Как правило, новая версия приложения (указанная с помощью тега образа в шаблоне Pod'а) запускается в так называемом канареечном (canary) развертывании параллельно с предыдущей версией. Далее на нее направляется часть реального production-трафика.
В примере ниже лейбл track
помогает различить релизы.
У основного, стабильного релиза он будет иметь значение stable
:
name: frontend
replicas: 3
...
labels:
app: guestbook
tier: frontend
track: stable
...
image: gb-frontend:v3
У нового релиза фронтенда гостевой книги значение этого лейбла будет другим (canary
), чтобы два набора Pod'ов не пересекались:
name: frontend-canary
replicas: 1
...
labels:
app: guestbook
tier: frontend
track: canary
...
image: gb-frontend:v4
Чтобы охватить оба набора реплик, сервис фронтенда следует настроить на выбор общего подмножества их лейблов (т.е. опустить лейбл track
). В результате трафик будет поступать на обе версии приложения:
selector:
app: guestbook
tier: frontend
При этом число стабильных и канареечных реплик можно менять, регулируя долю production-трафика, которую будет получать каждая версия приложения (три к одному в нашем случае). Убедившись в стабильности новой версии, можно поменять значение ее лейбла track
с canary
на stable
.
Более подробный пример доступен в руководстве по развертыванию Ghost.
Обновление лейблов
Иногда возникает необходимость поменять лейблы у существующих Pod'ов и других ресурсов перед созданием новых. Сделать это можно с помощью команды kubectl label
. Например, чтобы промаркировать все Pod'ы NGINX как имеющие отношение к фронтенду, выполните следующую команду:
kubectl label pods -l app=nginx tier=fe
pod/my-nginx-2035384211-j5fhi labeled
pod/my-nginx-2035384211-u2c7e labeled
pod/my-nginx-2035384211-u3t6x labeled
Сначала она выберет все Pod'ы с лейблом app=nginx
, а затем пометит их лейблом tier=fe
. Чтобы просмотреть список этих Pod'ов, выполните:
kubectl get pods -l app=nginx -L tier
NAME READY STATUS RESTARTS AGE TIER
my-nginx-2035384211-j5fhi 1/1 Running 0 23m fe
my-nginx-2035384211-u2c7e 1/1 Running 0 23m fe
my-nginx-2035384211-u3t6x 1/1 Running 0 23m fe
Будут выведены все Pod'ы app=nginx
с дополнительным столбцом tier
(задается с помощью -L
или --label-columns
).
Дополнительную информацию можно найти в разделах Лейблы и kubectl label.
Обновление аннотаций
Иногда возникает потребность навесить на ресурсы аннотации. Аннотации — это произвольные неидентифицирующие метаданные для извлечения клиентами API (инструментами, библиотеками и т.п.). Добавить аннотацию можно с помощью команды kubectl annotate
. Например:
kubectl annotate pods my-nginx-v4-9gw19 description='my frontend running nginx'
kubectl get pods my-nginx-v4-9gw19 -o yaml
apiVersion: v1
kind: pod
metadata:
annotations:
description: my frontend running nginx
...
Для получения дополнительной информации обратитесь к разделу Аннотации и описанию команды kubectl annotate.
Масштабирование приложения
Для масштабирования приложения можно воспользоваться инструментом kubectl
. Например, следующая команда уменьшит число реплик с 3 до 1:
kubectl scale deployment/my-nginx --replicas=1
deployment.apps/my-nginx scaled
После ее применения количество Pod'ов под управлением соответствующего объекта Deployment сократится до одного:
kubectl get pods -l app=nginx
NAME READY STATUS RESTARTS AGE
my-nginx-2035384211-j5fhi 1/1 Running 0 30m
Чтобы система автоматически выбирала необходимое количество реплик NGINX в диапазоне от 1 до 3, выполните следующую команду:
kubectl autoscale deployment/my-nginx --min=1 --max=3
horizontalpodautoscaler.autoscaling/my-nginx autoscaled
Теперь количество реплик NGINX будет автоматически увеличиваться и уменьшаться по мере необходимости.
Для получения дополнительной информации см. разделы kubectl scale, kubectl autoscale и horizontal pod autoscaler.
Обновление ресурсов "на месте"
Иногда возникает необходимость внести мелкие обновления в созданные ресурсы, не требующие их пересоздания.
kubectl apply
Хранить конфигурационные файлы рекомендуемтся в системе контроля версий (см. конфигурация как код). В этом случае их можно будет поддерживать и версионировать вместе с кодом ресурсов, которые те конфигурируют. Далее с помощью команды kubectl apply
изменения, внесенные в конфигурацию, можно применить к кластеру.
Она сравнит новую версию конфигурации с предыдущей и применит внесенные изменения, не меняя параметры, установленные автоматически, не затронутые новой редакцией конфигурации.
kubectl apply -f https://k8s.io/examples/application/nginx/nginx-deployment.yaml
deployment.apps/my-nginx configured
Обратите внимание, что kubectl apply
добавляет к ресурсу аннотацию, помогающую отслеживать изменения в конфигурации с момента предыдущего вызова. При вызове kubectl apply
проводит трехстороннее сравнение (three-way diff) предыдущей конфигурации, ее текущей и новой версий, которое определяет, какие правки следует внести в ресурс.
На данный момент ресурсы в Kubernetes создаются без данной аннотации, поэтому при первом вызове kubectl apply
проведет двустороннее сравнение входных данных и текущей конфигурации ресурса. Кроме того, она не cможет определить, какие свойства, заданные при создании ресурса, требуют удаления (соответственно, не будет их удалять).
При всех последующих вызовах kubectl apply
и других команд, меняющих конфигурацию, таких как kubectl replace
и kubectl edit
, аннотация будет обновляться. В результате kubectl apply
сможет проводить трехстороннее сравнение (three-way diff), определяя, какие свойства требуют удаления, и удалять их.
kubectl edit
Ресурсы также можно обновлять с помощью команды kubectl edit
:
kubectl edit deployment/my-nginx
По сути, kubectl edit
объединяет в себе логику нескольких команд, упрощая жизнь пользователям: сначала она получает (get
) ресурс, вызывает текстовый редактор, а затем применяет (apply
) обновленную конфигурацию:
kubectl get deployment my-nginx -o yaml > /tmp/nginx.yaml
vi /tmp/nginx.yaml
# внесите правки и сохраните файл
kubectl apply -f /tmp/nginx.yaml
deployment.apps/my-nginx configured
rm /tmp/nginx.yaml
Обратите внимание, что задать предпочитаемый текстовый редактор можно с помощью переменных окружения EDITOR
или KUBE_EDITOR
.
За дополнительной информацией обратитесь к разделу kubectl edit.
kubectl patch
Команда kubectl patch
обновляет объекты API "на месте". Она поддерживает форматы JSON patch, JSON merge patch и strategic merge patch. См. разделы Обновление объектов API "на месте" с помощью kubectl patch и kubectl patch.
Обновления, требующие перерыва в работе
Иногда может понадобиться обновить поля ресурса, которые нельзя изменить после инициализации, или возникнет необходимость немедленно внести рекурсивные изменения, например, "починить" сбойные Pod'ы, созданные Deployment'ом. Для этого можно воспользоваться командой replace --force
, которая удалит и пересоздаст ресурс. Вот как можно внести правки в исходный файл конфигурации в нашем примере:
kubectl replace -f https://k8s.io/examples/application/nginx/nginx-deployment.yaml --force
deployment.apps/my-nginx deleted
deployment.apps/my-nginx replaced
Обновление приложения без перерыва в работе
В какой-то момент возникнет необходимость обновить развернутое приложение. Обычно это делают, указывая новый образ или тег образа, как в приведенном выше сценарии канареечного развертывания. kubectl
поддерживает несколько видов обновлений, каждый из которых подходит для разных сценариев.
Ниже будет рассказано, как создавать и обновлять приложения с помощью объектов Deployment.
Предположим, что в кластере используется версия NGINX 1.14.2:
kubectl create deployment my-nginx --image=nginx:1.14.2
deployment.apps/my-nginx created
с тремя репликами (чтобы старые и новые ревизии могли сосуществовать):
kubectl scale deployment my-nginx --current-replicas=1 --replicas=3
deployment.apps/my-nginx scaled
Чтобы перейти на версию 1.16.1, измените значение параметра .spec.template.spec.containers[0].image
с nginx:1.14.2
на nginx:1.16.1
:
kubectl edit deployment/my-nginx
Вот и все! Deployment декларативно обновит развернутое приложение NGINX "за кулисами". При этом Kubernetes проследит, чтобы число недоступных реплик в каждый момент времени не превышало определенного значения, а также за тем, чтобы количество новых реплик не превышало определенного предела, установленного для желаемого числа Pod'ов. Более подробную информацию об этом можно получить в разделе Deployment.
Что дальше
- Узнайте о том, как использовать
kubectl
для интроспекции и отладки приложений. - Ознакомьтесь с Лучшими практиками и советами по конфигурированию.