Compare languages | Managing nodes: FAQ

How do I add a master nodes to a cloud cluster (single-master to a multi-master)?

Как добавить master-узлы в облачном кластере (single-master в multi-master)?

See the control-plane-manager module FAQ…

Инструкция в FAQ модуля control-plane-manager…

How do I reduce the number of master nodes in a cloud cluster (multi-master to single-master)?

Как уменьшить число master-узлов в облачном кластере (multi-master в single-master)?

See the control-plane-manager module FAQ…

Инструкция в FAQ модуля control-plane-manager…

Static nodes

Статические узлы

You can add a static node to the cluster manually (an example) or by using Cluster API Provider Static.

Добавить статический узел в кластер можно вручную (пример) или с помощью Cluster API Provider Static.

How do I add a static node to a cluster (Cluster API Provider Static)?

Как добавить статический узел в кластер (Cluster API Provider Static)?

To add a static node to a cluster (bare metal server or virtual machine), follow these steps:

Чтобы добавить статический узел в кластер (сервер bare metal или виртуальную машину), выполните следующие шаги:

  1. Prepare the required resources — servers/virtual machines, install specific OS packages, add mount points, configure the network, etc.
  2. Create the SSHCredentials resource.
  3. Create the StaticInstance resource.
  4. Create the NodeGroup resource with the Static nodeType, specify the desired number of nodes in the group and, if necessary, the filter for StaticInstance.
  1. Подготовьте необходимые ресурсы — серверы/виртуальные машины, установите специфические пакеты ОС, добавьте точки монтирования, настройте сетевую связанность и т.п.
  2. Создайте ресурс SSHCredentials.
  3. Создайте ресурс StaticInstance.
  4. Создайте ресурс NodeGroup с nodeType Static, указав желаемое количество узлов в группе и, при необходимости, фильтр выбора StaticInstance.

An example of adding a static node.

Пример добавления статического узла.

How do I add a batch of static nodes to a cluster manually?

Как добавить несколько статических узлов в кластер вручную?

Use an existing one or create a new NodeGroup custom resource (example of the NodeGroup called worker). The nodeType parameter for static nodes in the NodeGroup must be Static or CloudStatic.

Используйте существующий или создайте новый custom resource NodeGroup (пример NodeGroup с именем worker).

You can automate the bootstrap process with any automation platform you prefer. The following is an example for Ansible.

Автоматизировать процесс добавления узлов можно с помощью любой платформы автоматизации. Далее приведен пример для Ansible.

  1. Pick up one of Kubernetes API Server endpoints. Note that this IP must be accessible from nodes that are being added to the cluster:
  1. Получите один из адресов Kubernetes API-сервера. Обратите внимание, что IP-адрес должен быть доступен с узлов, которые добавляются в кластер:

shell kubectl -n default get ep kubernetes -o json | jq ‘.subsets[0].addresses[0].ip + “:” + (.subsets[0].ports[0].port | tostring)’ -r

shell kubectl -n default get ep kubernetes -o json | jq ‘.subsets[0].addresses[0].ip + “:” + (.subsets[0].ports[0].port | tostring)’ -r

Check the K8s version. If the version >= 1.25, create node-group token:

Проверьте версию K8s. Если версия >= 1.25, создайте токен node-group:

shell kubectl create token node-group –namespace d8-cloud-instance-manager –duration 1h

shell kubectl create token node-group –namespace d8-cloud-instance-manager –duration 1h

Save the token you got and add it to the token: field of the Ansible playbook in the next steps.

Сохраните полученный токен, и добавьте в поле token: playbook’а Ansible на дальнейших шагах.

  1. If the Kubernetes version is smaller than 1.25, get a Kubernetes API token for a special ServiceAccount that Deckhouse manages:
  1. Если версия Kubernetes меньше 1.25, получите Kubernetes API-токен для специального ServiceAccount’а, которым управляет Deckhouse:

shell kubectl -n d8-cloud-instance-manager get $(kubectl -n d8-cloud-instance-manager get secret -o name | grep node-group-token)
-o json | jq ‘.data.token’ -r | base64 -d && echo “”

shell kubectl -n d8-cloud-instance-manager get $(kubectl -n d8-cloud-instance-manager get secret -o name | grep node-group-token)
-o json | jq ‘.data.token’ -r | base64 -d && echo “”

  1. Create Ansible playbook with vars replaced with values from previous steps:
  1. Создайте Ansible playbook с vars, которые заменены на полученные на предыдущих шагах значения:

yaml

  • hosts: all become: yes gather_facts: no vars: kube_apiserver: token: tasks:
  • name: Check if node is already bootsrapped stat: path: /var/lib/bashible register: bootstrapped
  • name: Get bootstrap secret uri: url: “https://{{ kube_apiserver }}/api/v1/namespaces/d8-cloud-instance-manager/secrets/manual-bootstrap-for-{{ node_group }}” return_content: yes method: GET status_code: 200 body_format: json headers: Authorization: “Bearer {{ token }}” validate_certs: no register: bootstrap_secret when: bootstrapped.stat.exists == False
  • name: Run bootstrap.sh shell: “{{ bootstrap_secret.json.data[‘bootstrap.sh’] | b64decode }}” args: executable: /bin/bash ignore_errors: yes when: bootstrapped.stat.exists == False
  • name: wait wait_for_connection: delay: 30 when: bootstrapped.stat.exists == False

yaml

  • hosts: all become: yes gather_facts: no vars: kube_apiserver: token: tasks:
  • name: Check if node is already bootsrapped stat: path: /var/lib/bashible register: bootstrapped
  • name: Get bootstrap secret uri: url: “https://{{ kube_apiserver }}/api/v1/namespaces/d8-cloud-instance-manager/secrets/manual-bootstrap-for-{{ node_group }}” return_content: yes method: GET status_code: 200 body_format: json headers: Authorization: “Bearer {{ token }}” validate_certs: no register: bootstrap_secret when: bootstrapped.stat.exists == False
  • name: Run bootstrap.sh shell: “{{ bootstrap_secret.json.data[‘bootstrap.sh’] | b64decode }}” args: executable: /bin/bash ignore_errors: yes when: bootstrapped.stat.exists == False
  • name: wait wait_for_connection: delay: 30 when: bootstrapped.stat.exists == False
  1. Specify one more node_group variable. This variable must be the same as the name of NodeGroup to which node will belong. Variable can be passed in different ways, for example, by using an inventory file.:
  1. Определите дополнительную переменную node_group. Значение переменной должно совпадать с именем NodeGroup, которой будет принадлежать узел. Переменную можно передать различными способами, например с использованием inventory-файла:

text [system] system-0 system-1

text [system] system-0 system-1

[system:vars] node_group=system

[system:vars] node_group=system

[worker] worker-0 worker-1

[worker] worker-0 worker-1

[worker:vars] node_group=worker

[worker:vars] node_group=worker

  1. Run the playbook with the inventory file.
  1. Выполните playbook с использованием inventory-файла.

How do I clean up a static node manually?

Как вручную очистить статический узел?

This method is valid for both manually configured nodes (using the bootstrap script) and nodes configured using CAPS.

To decommission a node from the cluster and clean up the server (VM), run the following command on the node:

Инструкция справедлива как для узла, настроенного вручную (с помощью bootstrap-скрипта), так и для узла, настроенного с помощью CAPS.

shell bash /var/lib/bashible/cleanup_static_node.sh –yes-i-am-sane-and-i-understand-what-i-am-doing

Чтобы вывести из кластера узел и очистить сервер (ВМ), выполните следующую команду на узле:

Can I delete a StaticInstance?

shell bash /var/lib/bashible/cleanup_static_node.sh –yes-i-am-sane-and-i-understand-what-i-am-doing

A StaticInstance that is in the Pending state can be deleted with no adverse effects.

Можно ли удалить StaticInstance?

To delete a StaticInstance in any state other than Pending (Runnig, Cleaning, Bootstraping), you need to:

  1. Add the label "node.deckhouse.io/allow-bootstrap": "false" to the StaticInstance.
  2. Wait until the StaticInstance status becomes Pending.
  3. Delete the StaticInstance.
  4. Decrease the NodeGroup.spec.staticInstances.count field by 1.

StaticInstance, находящийся в состоянии Pending можно удалять без каких-либо проблем.

How do I change the IP address of a StaticInstance?

Чтобы удалить StaticInstance находящийся в любом состоянии, отличном от Pending (Running, Cleaning, Bootstraping):

  1. Добавьте лейбл "node.deckhouse.io/allow-bootstrap": "false" в StaticInstance.
  2. Дождитесь, пока StaticInstance перейдет в статус Pending.
  3. Удалите StaticInstance.
  4. Уменьшите значение параметра NodeGroup.spec.staticInstances.count на 1.

You cannot change the IP address in the StaticInstance resource. If an incorrect address is specified in StaticInstance, you have to delete the StaticInstance and create a new one.

Как изменить IP-адрес StaticInstance?

How do I migrate a manually configured static node under CAPS control?

Изменить IP-адрес в ресурсе StaticInstance нельзя. Если в StaticInstance указан ошибочный адрес, то нужно удалить StaticInstance и создать новый.

You need to clean up the node, then hand over the node under CAPS control.

Как мигрировать статический узел настроенный вручную под управление CAPS?

How do I change the NodeGroup of a static node?

Необходимо выполнить очистку узла, затем добавить узел под управление CAPS.

Note that if a node is under CAPS control, you cannot change the NodeGroup membership of such a node. The only alternative is to delete StaticInstance and create a new one.

Как изменить NodeGroup у статического узла?

To switch an existing manually created static node to another NodeGroup, you need to change its group label:

shell kubectl label node –overwrite node.deckhouse.io/group= kubectl label node node-role.kubernetes.io/-

Если узел находится под управлением CAPS, то изменить принадлежность к NodeGroup у такого узла нельзя. Единственный вариант — удалить StaticInstance и создать новый.

Applying the changes will take some time.

Чтобы перенести существующий статический узел созданный вручную из одной NodeGroup в другую, необходимо изменить у узла лейбл группы:

How to clean up a node for adding to the cluster?

shell kubectl label node –overwrite node.deckhouse.io/group= kubectl label node node-role.kubernetes.io/-

This is only needed if you have to move a static node from one cluster to another. Be aware these operations remove local storage data. If you just need to change a NodeGroup, follow this instruction.

Применение изменений потребует некоторого времени.

Note! Evict resources from the node and remove the node from LINSTOR/DRBD using the instruction if the node you are cleaning up has LINSTOR/DRBD storage pools.

Как зачистить узел для последующего ввода в кластер?

  1. Delete the node from the Kubernetes cluster:

Это необходимо только в том случае, если нужно переместить статический узел из одного кластера в другой. Имейте в виду, что эти операции удаляют данные локального хранилища. Если необходимо просто изменить NodeGroup, следуйте этой инструкции.

shell kubectl drain --ignore-daemonsets --delete-local-data kubectl delete node

Внимание! Если на зачищаемом узле есть пулы хранения LINSTOR/DRBD, то предварительно выгоните ресурсы с узла и удалите узел LINSTOR/DRBD, следуя инструкции.

  1. Run cleanup script on the node:
  1. Удалите узел из кластера Kubernetes:

shell bash /var/lib/bashible/cleanup_static_node.sh –yes-i-am-sane-and-i-understand-what-i-am-doing

shell kubectl drain --ignore-daemonsets --delete-local-data kubectl delete node

  1. Run the bootstrap.sh script after reboot of the node.
  1. Запустите на узле скрипт очистки:

How do I know if something went wrong?

shell bash /var/lib/bashible/cleanup_static_node.sh –yes-i-am-sane-and-i-understand-what-i-am-doing

If a node in a nodeGroup is not updated (the value of UPTODATE when executing the kubectl get nodegroup command is less than the value of NODES) or you assume some other problems that may be related to the node-manager module, then you need to look at the logs of the bashible service. The bashible service runs on each node managed by the node-manager module.

  1. После перезагрузки узла запустите скрипт bootstrap.sh.

To view the logs of the bashible service on a specific node, run the following command:

Как понять, что что-то пошло не так?

shell journalctl -fu bashible

Если узел в NodeGroup не обновляется (значение UPTODATE при выполнении команды kubectl get nodegroup меньше значения NODES) или вы предполагаете какие-то другие проблемы, которые могут быть связаны с модулем node-manager, нужно посмотреть логи сервиса bashible. Сервис bashible запускается на каждом узле, управляемом модулем node-manager.

Example of output when the bashible service has performed all necessary actions:

Чтобы посмотреть логи сервиса bashible, выполните на узле следующую команду:

console May 25 04:39:16 kube-master-0 systemd[1]: Started Bashible service. May 25 04:39:16 kube-master-0 bashible.sh[1976339]: Configuration is in sync, nothing to do. May 25 04:39:16 kube-master-0 systemd[1]: bashible.service: Succeeded.

shell journalctl -fu bashible

How do I know what is running on a node while it is being created?

Пример вывода, когда все необходимые действия выполнены:

You can analyze cloud-init to find out what’s happening on a node during the bootstrapping process:

console May 25 04:39:16 kube-master-0 systemd[1]: Started Bashible service. May 25 04:39:16 kube-master-0 bashible.sh[1976339]: Configuration is in sync, nothing to do. May 25 04:39:16 kube-master-0 systemd[1]: bashible.service: Succeeded.

  1. Find the node that is currently bootstrapping:

Как посмотреть, что в данный момент выполняется на узле при его создании?

shell kubectl get instances | grep Pending

Если необходимо узнать, что происходит на узле (к примеру, он долго создается), можно посмотреть логи cloud-init. Для этого выполните следующие шаги:

  1. Найдите узел, который сейчас бутстрапится:

An example:

shell kubectl get instances | grep Pending

shell $ kubectl get instances | grep Pending dev-worker-2a6158ff-6764d-nrtbj Pending 46s

Пример:

  1. Get information about connection parameters for viewing logs:

shell $ kubectl get instances | grep Pending dev-worker-2a6158ff-6764d-nrtbj Pending 46s

shell kubectl get instances dev-worker-2a6158ff-6764d-nrtbj -o yaml | grep ‘bootstrapStatus’ -B0 -A2

  1. Получите информацию о параметрах подключения для просмотра логов:

An example:

shell kubectl get instances dev-worker-2a6158ff-6764d-nrtbj -o yaml | grep ‘bootstrapStatus’ -B0 -A2

shell $ kubectl get instances dev-worker-2a6158ff-6764d-nrtbj -o yaml | grep ‘bootstrapStatus’ -B0 -A2 bootstrapStatus: description: Use ‘nc 192.168.199.178 8000’ to get bootstrap logs. logsEndpoint: 192.168.199.178:8000

Пример:

  1. Run the command you got (nc 192.168.199.115 8000 according to the example above) to see cloud-init logs and determine the cause of the problem on the node.

shell $ kubectl get instances dev-worker-2a6158ff-6764d-nrtbj -o yaml | grep ‘bootstrapStatus’ -B0 -A2 bootstrapStatus: description: Use ‘nc 192.168.199.178 8000’ to get bootstrap logs. logsEndpoint: 192.168.199.178:8000

The logs of the initial node configuration are located at /var/log/cloud-init-output.log.

  1. Выполните полученную команду (в примере выше — nc 192.168.199.178 8000), чтобы увидеть логи cloud-init и на чем зависла настройка узла.

How do I update kernel on nodes?

Логи первоначальной настройки узла находятся в /var/log/cloud-init-output.log.

Debian-based distros

Как обновить ядро на узлах?

Create a Node Group Configuration resource by specifying the desired kernel version in the desired_version variable of the shell script (the resource’s spec.content parameter):

Для дистрибутивов, основанных на Debian

yaml apiVersion: deckhouse.io/v1alpha1 kind: NodeGroupConfiguration metadata: name: install-kernel.sh spec: bundles:

  • ‘*’ nodeGroups:
  • ‘*’ weight: 32 content: | Copyright 2022 Flant JSC # Licensed under the Apache License, Version 2.0 (the “License”); you may not use this file except in compliance with the License. You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

Создайте ресурс NodeGroupConfiguration, указав в переменной desired_version shell-скрипта (параметр spec.content ресурса) желаемую версию ядра:

desired_version=”5.15.0-53-generic”

yaml apiVersion: deckhouse.io/v1alpha1 kind: NodeGroupConfiguration metadata: name: install-kernel.sh spec: bundles:

  • ‘*’ nodeGroups:
  • ‘*’ weight: 32 content: | Copyright 2022 Flant JSC # Licensed under the Apache License, Version 2.0 (the “License”); you may not use this file except in compliance with the License. You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

bb-event-on ‘bb-package-installed’ ‘post-install’ post-install() { bb-log-info “Setting reboot flag due to kernel was updated” bb-flag-set reboot }

desired_version=”5.15.0-53-generic”

version_in_use=”$(uname -r)”

bb-event-on ‘bb-package-installed’ ‘post-install’ post-install() { bb-log-info “Setting reboot flag due to kernel was updated” bb-flag-set reboot }

if [[ “$version_in_use” == “$desired_version” ]]; then exit 0 fi

version_in_use=”$(uname -r)”

bb-deckhouse-get-disruptive-update-approval bb-apt-install “linux-image-${desired_version}”

if [[ “$version_in_use” == “$desired_version” ]]; then exit 0 fi

CentOS-based distros

bb-deckhouse-get-disruptive-update-approval bb-apt-install “linux-image-${desired_version}”

Create a Node Group Configuration resource by specifying the desired kernel version in the desired_version variable of the shell script (the resource’s spec.content parameter):

Для дистрибутивов, основанных на CentOS

yaml apiVersion: deckhouse.io/v1alpha1 kind: NodeGroupConfiguration metadata: name: install-kernel.sh spec: bundles:

  • ‘*’ nodeGroups:
  • ‘*’ weight: 32 content: | Copyright 2022 Flant JSC # Licensed under the Apache License, Version 2.0 (the “License”); you may not use this file except in compliance with the License. You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

Создайте ресурс NodeGroupConfiguration, указав в переменной desired_version shell-скрипта (параметр spec.content ресурса) желаемую версию ядра:

desired_version=”3.10.0-1160.42.2.el7.x86_64”

yaml apiVersion: deckhouse.io/v1alpha1 kind: NodeGroupConfiguration metadata: name: install-kernel.sh spec: bundles:

  • ‘*’ nodeGroups:
  • ‘*’ weight: 32 content: | Copyright 2022 Flant JSC # Licensed under the Apache License, Version 2.0 (the “License”); you may not use this file except in compliance with the License. You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

bb-event-on ‘bb-package-installed’ ‘post-install’ post-install() { bb-log-info “Setting reboot flag due to kernel was updated” bb-flag-set reboot }

desired_version=”3.10.0-1160.42.2.el7.x86_64”

version_in_use=”$(uname -r)”

bb-event-on ‘bb-package-installed’ ‘post-install’ post-install() { bb-log-info “Setting reboot flag due to kernel was updated” bb-flag-set reboot }

if [[ “$version_in_use” == “$desired_version” ]]; then exit 0 fi

version_in_use=”$(uname -r)”

bb-deckhouse-get-disruptive-update-approval bb-yum-install “kernel-${desired_version}”

if [[ “$version_in_use” == “$desired_version” ]]; then exit 0 fi

NodeGroup parameters and their result

bb-deckhouse-get-disruptive-update-approval bb-yum-install “kernel-${desired_version}”

The NodeGroup parameter Disruption update Node provisioning Kubelet restart
chaos - - -
cloudInstances.classReference - + -
cloudInstances.maxSurgePerZone - - -
cri.containerd.maxConcurrentDownloads - - +
cri.type - (NotManaged) / + (other) - -
disruptions - - -
kubelet.maxPods - - +
kubelet.rootDir - - +
kubernetesVersion - - +
nodeTemplate - - -
static - - +
update.maxConcurrent - - -

Какие параметры NodeGroup к чему приводят?

Refer to the description of the NodeGroup custom resource for more information about the parameters.

Параметр NG Disruption update Перезаказ узлов Рестарт kubelet
chaos - - -
cloudInstances.classReference - + -
cloudInstances.maxSurgePerZone - - -
cri.containerd.maxConcurrentDownloads - - +
cri.type - (NotManaged) / + (other) - -
disruptions - - -
kubelet.maxPods - - +
kubelet.rootDir - - +
kubernetesVersion - - +
nodeTemplate - - -
static - - +
update.maxConcurrent - - -

Changing the InstanceClass or instancePrefix parameter in the Deckhouse configuration won’t result in a RollingUpdate. Deckhouse will create new MachineDeployments and delete the old ones. The number of machinedeployments ordered at the same time is determined by the cloud Instances.maxSurgePerZone parameter.

Подробно о всех параметрах можно прочитать в описании custom resource NodeGroup.

During the disruption update, an evict of the pods from the node is performed. If any pod failes to evict, the evict is repeated every 20 seconds until a global timeout of 5 minutes is reached. After that, the pods that failed to evict are removed.

В случае изменения параметров InstanceClass или instancePrefix в конфигурации Deckhouse не будет происходить RollingUpdate. Deckhouse создаст новые MachineDeployment, а старые удалит. Количество заказываемых одновременно MachineDeployment определяется параметром cloudInstances.maxSurgePerZone.

How do I redeploy ephemeral machines in the cloud with a new configuration?

При disruption update выполняется evict подов с узла. Если какие-либо поды не удалось evict’нуть, evict повторяется каждые 20 секунд до достижения глобального таймаута в 5 минут. После этого поды, которые не удалось evict’нуть, удаляются.

If the Deckhouse configuration is changed (both in the node-manager module and in any of the cloud providers), the VMs will not be redeployed. The redeployment is performed only in response to changing InstanceClass or NodeGroup objects.

Как пересоздать эфемерные машины в облаке с новой конфигурацией?

To force the redeployment of all Machines, you need to add/modify the manual-rollout-id annotation to the NodeGroup: kubectl annotate NodeGroup name_ng "manual-rollout-id=$(uuidgen)" --overwrite.

При изменении конфигурации Deckhouse (как в модуле node-manager, так и в любом из облачных провайдеров) виртуальные машины не будут перезаказаны. Пересоздание происходит только после изменения ресурсов InstanceClass или NodeGroup.

How do I allocate nodes to specific loads?

Чтобы принудительно пересоздать все узлы, связанные с ресурсом Machines, следует добавить/изменить аннотацию manual-rollout-id в NodeGroup: kubectl annotate NodeGroup имя_ng "manual-rollout-id=$(uuidgen)" --overwrite.

Note! You cannot use the deckhouse.io domain in labels and taints keys of the NodeGroup. It is reserved for Deckhouse components. Please, use the dedicated or dedicated.client.com keys.

Как выделить узлы под специфические нагрузки?

There are two ways to solve this problem:

Внимание! Запрещено использование домена deckhouse.io в ключах labels и taints у NodeGroup. Он зарезервирован для компонентов Deckhouse. Следует отдавать предпочтение в пользу ключей dedicated или dedicated.client.com.

  1. You can set labels to NodeGroup’s spec.nodeTemplate.labels, to use them in the Pod’s spec.nodeSelector or spec.affinity.nodeAffinity parameters. In this case, you select nodes that the scheduler will use for running the target application.
  2. You cat set taints to NodeGroup’s spec.nodeTemplate.taints and then remove them via the Pod’s spec.tolerations parameter. In this case, you disallow running applications on these nodes unless those applications are explicitly allowed.

Для решений данной задачи существуют два механизма:

Deckhouse tolerates the dedicated by default, so we recommend using the dedicated key with any value for taints on your dedicated nodes.️ To use custom keys for taints (e.g., dedicated.client.com), you must add the key’s value to the modules.placement.customTolerationKeys parameters. This way, deckhouse can deploy system components (e.g., cni-flannel) to these dedicated nodes.

  1. Установка меток в NodeGroup spec.nodeTemplate.labels для последующего использования их в Pod spec.nodeSelector или spec.affinity.nodeAffinity. Указывает, какие именно узлы будут выбраны планировщиком для запуска целевого приложения.
  2. Установка ограничений в NodeGroup spec.nodeTemplate.taints с дальнейшим снятием их в Pod spec.tolerations. Запрещает исполнение не разрешенных явно приложений на этих узлах.

How to allocate nodes to system components?

Deckhouse по умолчанию tolerate’ит ключ dedicated, поэтому рекомендуется использовать ключ dedicated с любым value для taint’ов на ваших выделенных узлах.️ Если необходимо использовать произвольные ключи для taints (например, dedicated.client.com), значение ключа нужно добавить в параметр modules.placement.customTolerationKeys. Таким образом мы разрешим системным компонентам (например, cni-flannel) выезжать на эти выделенные узлы.

Frontend

Подробности в статье на Habr.

For Ingress controllers, use the NodeGroup with the following configuration:

Как выделить узлы под системные компоненты?

yaml nodeTemplate: labels: node-role.deckhouse.io/frontend: “” taints:

  • effect: NoExecute key: dedicated.deckhouse.io value: frontend

Фронтенд

System components

Для Ingress-контроллеров используйте NodeGroup со следующей конфигурацией:

NodeGroup for components of Deckhouse subsystems will look as follows:

yaml nodeTemplate: labels: node-role.deckhouse.io/frontend: “” taints:

  • effect: NoExecute key: dedicated.deckhouse.io value: frontend

yaml nodeTemplate: labels: node-role.deckhouse.io/system: “” taints:

  • effect: NoExecute key: dedicated.deckhouse.io value: system

Системные

How do I speed up node provisioning on the cloud when scaling applications horizontally?

NodeGroup для компонентов подсистем Deckhouse будут с такими параметрами:

The most efficient way is to have some extra nodes “ready”. In this case, you can run new application replicas on them almost instantaneously. The obvious disadvantage of this approach is the additional maintenance costs related to these nodes.

yaml nodeTemplate: labels: node-role.deckhouse.io/system: “” taints:

  • effect: NoExecute key: dedicated.deckhouse.io value: system

Here is how you should configure the target NodeGroup:

Как ускорить заказ узлов в облаке при горизонтальном масштабировании приложений?

  1. Specify the number of “ready” nodes (or a percentage of the maximum number of nodes in the group) using the cloudInstances.standby paramter.
  2. If there are additional service components (not maintained by Deckhouse, such as filebeat DaemonSet) for these nodes, you need to specify their combined resource consumption via the standbyHolder.notHeldResources parameter.
  3. This feature requires that at least one group node is already running in the cluster. In other words, there must be either a single replica of the application, or the cloudInstances.minPerZone parameter must be set to 1.

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

An example:

Необходимые настройки целевой NodeGroup будут следующие:

yaml cloudInstances: maxPerZone: 10 minPerZone: 1 standby: 10% standbyHolder: notHeldResources: cpu: 300m memory: 2Gi

  1. Указать абсолютное количество подогретых узлов (или процент от максимального количества узлов в этой группе) в параметре cloudInstances.standby.
  2. При наличии дополнительных служебных компонентов (не обслуживаемых Deckhouse, например DaemonSet filebeat) для этих узлов — задать их суммарное потребление ресурсов в параметре standbyHolder.notHeldResources.
  3. Для работы этой функции требуется, чтобы как минимум один узел из группы уже был запущен в кластере. Иными словами, либо должна быть доступна одна реплика приложения, либо количество узлов для этой группы cloudInstances.minPerZone должно быть 1.

How do I disable machine-controller-manager in the case of potentially cluster-damaging changes?

Пример:

Note! Use this switch only if you know what you are doing and clearly understand the consequences.

yaml cloudInstances: maxPerZone: 10 minPerZone: 1 standby: 10% standbyHolder: notHeldResources: cpu: 300m memory: 2Gi

Set the mcmEmergencyBrake parameter to true:

Как выключить machine-controller-manager в случае выполнения потенциально деструктивных изменений в кластере?

yaml mcmEmergencyBrake: true

Внимание! Использовать эту настройку допустимо только тогда, когда вы четко понимаете, зачем это необходимо.

How do I restore the master node if kubelet cannot load the control plane components?

Установить параметр:

Such a situation may occur if images of the control plane components on the master were deleted in a cluster that has a single master node (e.g., the directory /var/lib/containerd was deleted). In this case, kubelet cannot pull images of the control plane components when restarted since the master node lacks authorization parameters required for accessing registry.deckhouse.io.

yaml mcmEmergencyBrake: true

Below is an instruction on how you can restore the master node.

Как восстановить master-узел, если kubelet не может загрузить компоненты control plane?

containerd

Подобная ситуация может возникнуть, если в кластере с одним master-узлом на нем были удалены образы компонентов control plane (например, удалена директория /var/lib/containerd). В этом случае kubelet при рестарте не сможет скачать образы компонентов control plane, поскольку на master-узле нет параметров авторизации в registry.deckhouse.io.

Execute the following command to restore the master node in any cluster running under Deckhouse:

Ниже инструкция по восстановлению master-узла.

shell kubectl -n d8-system get secrets deckhouse-registry -o json | jq -r ‘.data.”.dockerconfigjson”’ | base64 -d | jq -r ‘.auths.”registry.deckhouse.io”.auth’

containerd

Copy the command’s output and use it for setting the AUTH variable on the corrupted master. Next, you need to pull images of control plane components to the corrupted master:

Для восстановления работоспособности master-узла нужно в любом рабочем кластере под управлением Deckhouse выполнить команду:

shell for image in $(grep “image:” /etc/kubernetes/manifests/* | awk ‘{print $3}’); do crictl pull –auth $AUTH $image done

shell kubectl -n d8-system get secrets deckhouse-registry -o json | jq -r ‘.data.”.dockerconfigjson”’ | base64 -d | jq -r ‘.auths.”registry.deckhouse.io”.auth’

You need to restart kubelet after pulling the images.

Вывод команды нужно скопировать и присвоить переменной AUTH на поврежденном master-узле. Далее на поврежденном master-узле нужно загрузить образы компонентов control-plane:

How to change CRI for NodeGroup?

shell for image in $(grep “image:” /etc/kubernetes/manifests/* | awk ‘{print $3}’); do crictl pull –auth $AUTH $image done

Note! CRI can only be switched from Containerd to NotManaged and back (the cri.type parameter).

После загрузки образов необходимо перезапустить kubelet.

Set NodeGroup cri.type to Containerd or NotManaged.

Как изменить CRI для NodeGroup?

NodeGroup YAML example:

Внимание! Возможен переход только с Containerd на NotManaged и обратно (параметр cri.type).

yaml apiVersion: deckhouse.io/v1 kind: NodeGroup metadata: name: worker spec: nodeType: Static cri: type: Containerd

Установить параметр cri.type в Containerd или в NotManaged.

Also, this operation can be done with patch:

Пример YAML-манифеста NodeGroup:

  • For Containerd:

yaml apiVersion: deckhouse.io/v1 kind: NodeGroup metadata: name: worker spec: nodeType: Static cri: type: Containerd

shell kubectl patch nodegroup --type merge -p '{"spec":{"cri":{"type":"Containerd"}}}'

Также эту операцию можно выполнить с помощью патча:

  • For NotManaged:
  • Для Containerd:

shell kubectl patch nodegroup --type merge -p '{"spec":{"cri":{"type":"NotManaged"}}}'

shell kubectl patch nodegroup <имя NodeGroup=""> --type merge -p '{"spec":{"cri":{"type":"Containerd"}}}'

Note! While changing cri.type for NodeGroups, created using dhctl, you must change it in dhctl config edit provider-cluster-configuration and in NodeGroup object.

  • Для NotManaged:

After setting up a new CRI for NodeGroup, the node-manager module drains nodes one by one and installs a new CRI on them. Node update is accompanied by downtime (disruption). Depending on the disruption setting for NodeGroup, the node-manager module either automatically allows node updates or requires manual confirmation.

shell kubectl patch nodegroup <имя NodeGroup=""> --type merge -p '{"spec":{"cri":{"type":"NotManaged"}}}'

How to change CRI for the whole cluster?

Внимание! При смене cri.type для NodeGroup, созданных с помощью dhctl, нужно менять ее в dhctl config edit provider-cluster-configuration и настройках объекта NodeGroup.

Note! CRI can only be switched from Containerd to NotManaged and back (the cri.type parameter).

После настройки нового CRI для NodeGroup модуль node-manager по одному drain’ит узлы и устанавливает на них новый CRI. Обновление узла сопровождается простоем (disruption). В зависимости от настройки disruption для NodeGroup модуль node-manager либо автоматически разрешает обновление узлов, либо требует ручного подтверждения.

It is necessary to use the dhctl utility to edit the defaultCRI parameter in the cluster-configuration config.

Как изменить CRI для всего кластера?

Also, this operation can be done with the following patch:

  • For Containerd:

Внимание! Возможен переход только с Containerd на NotManaged и обратно (параметр cri.type).

shell data=”$(kubectl -n kube-system get secret d8-cluster-configuration -o json | jq -r ‘.data.”cluster-configuration.yaml”’ | base64 -d | sed “s/NotManaged/Containerd/” | base64 -w0)” kubectl -n kube-system patch secret d8-cluster-configuration -p “{"data":{"cluster-configuration.yaml":"$data"}}”

Необходимо с помощью утилиты dhctl отредактировать параметр defaultCRI в конфиге cluster-configuration.

  • For NotManaged:

Также возможно выполнить эту операцию с помощью kubectl patch. Пример:

  • Для Containerd:

shell data=”$(kubectl -n kube-system get secret d8-cluster-configuration -o json | jq -r ‘.data.”cluster-configuration.yaml”’ | base64 -d | sed “s/Containerd/NotManaged/” | base64 -w0)” kubectl -n kube-system patch secret d8-cluster-configuration -p “{"data":{"cluster-configuration.yaml":"$data"}}”

shell data=”$(kubectl -n kube-system get secret d8-cluster-configuration -o json | jq -r ‘.data.”cluster-configuration.yaml”’ | base64 -d | sed “s/NotManaged/Containerd/” | base64 -w0)” kubectl -n kube-system patch secret d8-cluster-configuration -p “{"data":{"cluster-configuration.yaml":"$data"}}”

If it is necessary to leave some NodeGroup on another CRI, then before changing the defaultCRI it is necessary to set CRI for this NodeGroup, as described here.

  • Для NotManaged:

Note! Changing defaultCRI entails changing CRI on all nodes, including master nodes. If there is only one master node, this operation is dangerous and can lead to a complete failure of the cluster! The preferred option is to make a multi-master and change the CRI type!

shell data=”$(kubectl -n kube-system get secret d8-cluster-configuration -o json | jq -r ‘.data.”cluster-configuration.yaml”’ | base64 -d | sed “s/Containerd/NotManaged/” | base64 -w0)” kubectl -n kube-system patch secret d8-cluster-configuration -p “{"data":{"cluster-configuration.yaml":"$data"}}”

When changing the CRI in the cluster, additional steps are required for the master nodes:

Если необходимо какую-то NodeGroup оставить на другом CRI, перед изменением defaultCRI необходимо установить CRI для этой NodeGroup, как описано здесь.

  1. Deckhouse updates nodes in master NodeGroup one by one, so you need to discover which node is updating right now:

Внимание! Изменение defaultCRI влечет за собой изменение CRI на всех узлах, включая master-узлы. Если master-узел один, данная операция является опасной и может привести к полной неработоспособности кластера! Предпочтительный вариант — сделать multimaster и поменять тип CRI!

shell kubectl get nodes -l node-role.kubernetes.io/control-plane=”” -o json | jq ‘.items[] | select(.metadata.annotations.”update.node.deckhouse.io/approved”==””) | .metadata.name’ -r

При изменении CRI в кластере для master-узлов необходимо выполнить дополнительные шаги:

  1. Confirm the disruption of the master node that was discovered in the previous step:
  1. Deckhouse обновляет узлы в master NodeGroup по одному, поэтому необходимо определить, какой узел на данный момент обновляется:

shell kubectl annotate node update.node.deckhouse.io/disruption-approved=

shell kubectl get nodes -l node-role.kubernetes.io/control-plane=”” -o json | jq ‘.items[] | select(.metadata.annotations.”update.node.deckhouse.io/approved”==””) | .metadata.name’ -r

  1. Wait for the updated master node to switch to Ready state. Repeat steps for the next master node.
  1. Подтвердить disruption для master-узла, полученного на предыдущем шаге:

How to add node configuration step?

shell kubectl annotate node <имя master-узла=""> update.node.deckhouse.io/disruption-approved=

Additional node configuration steps are set via the NodeGroupConfiguration custom resource.

  1. Дождаться перехода обновленного master-узла в Ready. Выполнить итерацию для следующего master’а.

How to use containerd with Nvidia GPU support?

Как добавить шаг для конфигурации узлов?

Create NodeGroup for GPU-nodes.

Дополнительные шаги для конфигурации узлов задаются с помощью custom resource NodeGroupConfiguration.

yaml apiVersion: deckhouse.io/v1 kind: NodeGroup metadata: name: gpu spec: chaos: mode: Disabled disruptions: approvalMode: Automatic nodeType: CloudStatic

Как использовать containerd с поддержкой Nvidia GPU?

Create NodeGroupConfiguration for containerd configuration of NodeGroup gpu:

Необходимо создать отдельную NodeGroup для GPU-нод.

yaml apiVersion: deckhouse.io/v1alpha1 kind: NodeGroupConfiguration metadata: name: containerd-additional-config.sh spec: bundles:

  • ‘*’ content: | Copyright 2023 Flant JSC # Licensed under the Apache License, Version 2.0 (the “License”); you may not use this file except in compliance with the License. You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

yaml apiVersion: deckhouse.io/v1 kind: NodeGroup metadata: name: gpu spec: chaos: mode: Disabled disruptions: approvalMode: Automatic nodeType: CloudStatic

mkdir -p /etc/containerd/conf.d bb-sync-file /etc/containerd/conf.d/nvidia_gpu.toml - « “EOF” [plugins] [plugins.”io.containerd.grpc.v1.cri”] [plugins.”io.containerd.grpc.v1.cri”.containerd] default_runtime_name = “nvidia” [plugins.”io.containerd.grpc.v1.cri”.containerd.runtimes] [plugins.”io.containerd.grpc.v1.cri”.containerd.runtimes.runc] [plugins.”io.containerd.grpc.v1.cri”.containerd.runtimes.nvidia] privileged_without_host_devices = false runtime_engine = “” runtime_root = “” runtime_type = “io.containerd.runc.v1” [plugins.”io.containerd.grpc.v1.cri”.containerd.runtimes.nvidia.options] BinaryName = “/usr/bin/nvidia-container-runtime” SystemdCgroup = false EOF nodeGroups:

  • gpu weight: 49

Далее необходимо создать NodeGroupConfiguration для NodeGroup gpu для конфигурации containerd:

Create NodeGroupConfiguration for Nvidia drivers setup on NodeGroup gpu.

yaml apiVersion: deckhouse.io/v1alpha1 kind: NodeGroupConfiguration metadata: name: containerd-additional-config.sh spec: bundles:

  • ‘*’ content: | Copyright 2023 Flant JSC # Licensed under the Apache License, Version 2.0 (the “License”); you may not use this file except in compliance with the License. You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

Ubuntu

mkdir -p /etc/containerd/conf.d bb-sync-file /etc/containerd/conf.d/nvidia_gpu.toml - « “EOF” [plugins] [plugins.”io.containerd.grpc.v1.cri”] [plugins.”io.containerd.grpc.v1.cri”.containerd] default_runtime_name = “nvidia” [plugins.”io.containerd.grpc.v1.cri”.containerd.runtimes] [plugins.”io.containerd.grpc.v1.cri”.containerd.runtimes.runc] [plugins.”io.containerd.grpc.v1.cri”.containerd.runtimes.nvidia] privileged_without_host_devices = false runtime_engine = “” runtime_root = “” runtime_type = “io.containerd.runc.v1” [plugins.”io.containerd.grpc.v1.cri”.containerd.runtimes.nvidia.options] BinaryName = “/usr/bin/nvidia-container-runtime” SystemdCgroup = false EOF nodeGroups:

  • gpu weight: 49

yaml apiVersion: deckhouse.io/v1alpha1 kind: NodeGroupConfiguration metadata: name: install-cuda.sh spec: bundles:

  • ubuntu-lts content: | Copyright 2023 Flant JSC # Licensed under the Apache License, Version 2.0 (the “License”); you may not use this file except in compliance with the License. You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

Далее необходимо добавить NodeGroupConfiguration для установки драйверов Nvidia для NodeGroup gpu.

distribution=$(. /etc/os-release;echo $ID$VERSION_ID) curl -s -L https://nvidia.github.io/libnvidia-container/gpgkey | sudo apt-key add - curl -s -L https://nvidia.github.io/libnvidia-container/$distribution/libnvidia-container.list | sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list apt-get update apt-get install -y nvidia-container-toolkit nvidia-driver-525-server nodeGroups:

  • gpu weight: 30

Ubuntu

Centos

yaml apiVersion: deckhouse.io/v1alpha1 kind: NodeGroupConfiguration metadata: name: install-cuda.sh spec: bundles:

  • ubuntu-lts content: | Copyright 2023 Flant JSC # Licensed under the Apache License, Version 2.0 (the “License”); you may not use this file except in compliance with the License. You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

yaml apiVersion: deckhouse.io/v1alpha1 kind: NodeGroupConfiguration metadata: name: install-cuda.sh spec: bundles:

  • centos content: | Copyright 2023 Flant JSC # Licensed under the Apache License, Version 2.0 (the “License”); you may not use this file except in compliance with the License. You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

distribution=$(. /etc/os-release;echo $ID$VERSION_ID) curl -s -L https://nvidia.github.io/libnvidia-container/gpgkey | sudo apt-key add - curl -s -L https://nvidia.github.io/libnvidia-container/$distribution/libnvidia-container.list | sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list apt-get update apt-get install -y nvidia-container-toolkit nvidia-driver-525-server nodeGroups:

  • gpu weight: 30

distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
curl -s -L https://nvidia.github.io/libnvidia-container/$distribution/libnvidia-container.repo | sudo tee /etc/yum.repos.d/nvidia-container-toolkit.repo yum install -y nvidia-container-toolkit nvidia-driver nodeGroups:

  • gpu weight: 30

Centos

Bootstrap and reboot node.

yaml apiVersion: deckhouse.io/v1alpha1 kind: NodeGroupConfiguration metadata: name: install-cuda.sh spec: bundles:

  • centos content: | Copyright 2023 Flant JSC # Licensed under the Apache License, Version 2.0 (the “License”); you may not use this file except in compliance with the License. You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

How to check if it was successful?

distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
curl -s -L https://nvidia.github.io/libnvidia-container/$distribution/libnvidia-container.repo | sudo tee /etc/yum.repos.d/nvidia-container-toolkit.repo yum install -y nvidia-container-toolkit nvidia-driver nodeGroups:

  • gpu weight: 30

Deploy the Job:

После этого выполните бутстрап и ребут узла.

yaml apiVersion: batch/v1 kind: Job metadata: name: nvidia-cuda-test namespace: default spec: completions: 1 template: spec: restartPolicy: Never nodeSelector: node.deckhouse.io/group: gpu containers:

  • name: nvidia-cuda-test image: nvidia/cuda:11.6.2-base-ubuntu20.04 imagePullPolicy: “IfNotPresent” command:
  • nvidia-smi

Как проверить, что все прошло успешно?

And check the logs:

Создайте в кластере Job:

shell $ kubectl logs job/nvidia-cuda-test Tue Jan 24 11:36:18 2023 +—————————————————————————–+ | NVIDIA-SMI 525.60.13 Driver Version: 525.60.13 CUDA Version: 12.0 | |——————————-+———————-+———————-+ | GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC | | Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. | | | | MIG M. | |===============================+======================+======================| | 0 Tesla T4 Off | 00000000:8B:00.0 Off | 0 | | N/A 45C P0 25W / 70W | 0MiB / 15360MiB | 0% Default | | | | N/A | +——————————-+———————-+———————-+

yaml apiVersion: batch/v1 kind: Job metadata: name: nvidia-cuda-test namespace: default spec: completions: 1 template: spec: restartPolicy: Never nodeSelector: node.deckhouse.io/group: gpu containers:

  • name: nvidia-cuda-test image: nvidia/cuda:11.6.2-base-ubuntu20.04 imagePullPolicy: “IfNotPresent” command:
  • nvidia-smi

+—————————————————————————–+ | Processes: | | GPU GI CI PID Type Process name GPU Memory | | ID ID Usage | |=============================================================================| | No running processes found | +—————————————————————————–+

И посмотрите логи:

Deploy the Job:

shell $ kubectl logs job/nvidia-cuda-test Tue Jan 24 11:36:18 2023 +—————————————————————————–+ | NVIDIA-SMI 525.60.13 Driver Version: 525.60.13 CUDA Version: 12.0 | |——————————-+———————-+———————-+ | GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC | | Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. | | | | MIG M. | |===============================+======================+======================| | 0 Tesla T4 Off | 00000000:8B:00.0 Off | 0 | | N/A 45C P0 25W / 70W | 0MiB / 15360MiB | 0% Default | | | | N/A | +——————————-+———————-+———————-+

yaml apiVersion: batch/v1 kind: Job metadata: name: gpu-operator-test namespace: default spec: completions: 1 template: spec: restartPolicy: Never nodeSelector: node.deckhouse.io/group: gpu containers:

  • name: gpu-operator-test image: nvidia/samples:vectoradd-cuda10.2 imagePullPolicy: “IfNotPresent”

+—————————————————————————–+ | Processes: | | GPU GI CI PID Type Process name GPU Memory | | ID ID Usage | |=============================================================================| | No running processes found | +—————————————————————————–+

And check the logs:

Создайте в кластере Job:

shell $ kubectl logs job/gpu-operator-test [Vector addition of 50000 elements] Copy input data from the host memory to the CUDA device CUDA kernel launch with 196 blocks of 256 threads Copy output data from the CUDA device to the host memory Test PASSED Done

yaml apiVersion: batch/v1 kind: Job metadata: name: gpu-operator-test namespace: default spec: completions: 1 template: spec: restartPolicy: Never nodeSelector: node.deckhouse.io/group: gpu containers:

  • name: gpu-operator-test image: nvidia/samples:vectoradd-cuda10.2 imagePullPolicy: “IfNotPresent”

How to deploy custom containerd configuration?

И посмотрите логи:

Bashible on nodes merges main deckhouse containerd config with configs from /etc/containerd/conf.d/*.toml.

shell $ kubectl logs job/gpu-operator-test [Vector addition of 50000 elements] Copy input data from the host memory to the CUDA device CUDA kernel launch with 196 blocks of 256 threads Copy output data from the CUDA device to the host memory Test PASSED Done

How to add additional registry auth?

Как развернуть кастомный конфиг containerd?

Deploy NodeGroupConfiguration script:

Bashible на узлах мержит основной конфиг containerd для Deckhouse с конфигами из /etc/containerd/conf.d/*.toml.

yaml

apiVersion: deckhouse.io/v1alpha1 kind: NodeGroupConfiguration metadata: name: containerd-additional-config.sh spec: bundles:

  • ‘*’ content: | Copyright 2023 Flant JSC # Licensed under the Apache License, Version 2.0 (the “License”); you may not use this file except in compliance with the License. You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

Как добавить авторизацию в дополнительный registry?

mkdir -p /etc/containerd/conf.d bb-sync-file /etc/containerd/conf.d/additional_registry.toml - « “EOF” [plugins] [plugins.”io.containerd.grpc.v1.cri”] [plugins.”io.containerd.grpc.v1.cri”.registry] [plugins.”io.containerd.grpc.v1.cri”.registry.mirrors] [plugins.”io.containerd.grpc.v1.cri”.registry.mirrors.”docker.io”] endpoint = [“https://registry-1.docker.io”] [plugins.”io.containerd.grpc.v1.cri”.registry.mirrors.”artifactory.proxy”] endpoint = [“https://artifactory.proxy”] [plugins.”io.containerd.grpc.v1.cri”.registry.configs] [plugins.”io.containerd.grpc.v1.cri”.registry.configs.”artifactory.proxy”.auth] auth = “AAAABBBCCCDDD==” EOF nodeGroups:

  • “*” weight: 49

Разверните скрипт NodeGroupConfiguration:

How to use NodeGroup’s priority feature

yaml

apiVersion: deckhouse.io/v1alpha1 kind: NodeGroupConfiguration metadata: name: containerd-additional-config.sh spec: bundles:

  • ‘*’ content: | Copyright 2023 Flant JSC # Licensed under the Apache License, Version 2.0 (the “License”); you may not use this file except in compliance with the License. You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

The priority field of the NodeGroup CustomResource allows you to define the order in which nodes will be provisioned in the cluster. For example, cluster-autoscaler can first provision spot-nodes and switch to regular ones when they run out. Or it can provision larger nodes when there are plenty of resources in the cluster and then switch to smaller nodes once cluster resources run out.

mkdir -p /etc/containerd/conf.d bb-sync-file /etc/containerd/conf.d/additional_registry.toml - « “EOF” [plugins] [plugins.”io.containerd.grpc.v1.cri”] [plugins.”io.containerd.grpc.v1.cri”.registry] [plugins.”io.containerd.grpc.v1.cri”.registry.mirrors] [plugins.”io.containerd.grpc.v1.cri”.registry.mirrors.”docker.io”] endpoint = [“https://registry-1.docker.io”] [plugins.”io.containerd.grpc.v1.cri”.registry.mirrors.”artifactory.proxy”] endpoint = [“https://artifactory.proxy”] [plugins.”io.containerd.grpc.v1.cri”.registry.configs] [plugins.”io.containerd.grpc.v1.cri”.registry.configs.”artifactory.proxy”.auth] auth = “AAAABBBCCCDDD==” EOF nodeGroups:

  • “*” weight: 49

Here is an example of creating two NodeGroups using spot-node nodes:

Как использовать NodeGroup с приоритетом?

yaml

apiVersion: deckhouse.io/v1 kind: NodeGroup metadata: name: worker-spot spec: cloudInstances: classReference: kind: AWSInstanceClass name: worker-spot maxPerZone: 5 minPerZone: 0 priority: 50 nodeType: CloudEphemeral — apiVersion: deckhouse.io/v1 kind: NodeGroup metadata: name: worker spec: cloudInstances: classReference: kind: AWSInstanceClass name: worker maxPerZone: 5 minPerZone: 0 priority: 30 nodeType: CloudEphemeral

С помощью параметра priority custom resource’а NodeGroup можно задавать порядок заказа узлов в кластере. Например, можно сделать так, чтобы сначала заказывались узлы типа spot-node, а если они закончились — обычные узлы. Или чтобы при наличии ресурсов в облаке заказывались узлы большего размера, а при их исчерпании — узлы меньшего размера.

In the above example, cluster-autoscaler will first try to provision a spot-node. If it fails to add such a node to the cluster within 15 minutes, the worker-spot NodeGroup will be paused (for 20 minutes), and cluster-autoscaler will start provisioning nodes from the worker NodeGroup. If, after 30 minutes, another node needs to be deployed in the cluster, cluster-autoscaler will first attempt to provision a node from the worker-spot NodeGroup before provisioning one from the worker NodeGroup.

Пример создания двух NodeGroup с использованием узлов типа spot-node:

Once the worker-spot NodeGroup reaches its maximum (5 nodes in the example above), the nodes will be provisioned from the worker NodeGroup.

yaml

apiVersion: deckhouse.io/v1 kind: NodeGroup metadata: name: worker-spot spec: cloudInstances: classReference: kind: AWSInstanceClass name: worker-spot maxPerZone: 5 minPerZone: 0 priority: 50 nodeType: CloudEphemeral — apiVersion: deckhouse.io/v1 kind: NodeGroup metadata: name: worker spec: cloudInstances: classReference: kind: AWSInstanceClass name: worker maxPerZone: 5 minPerZone: 0 priority: 30 nodeType: CloudEphemeral

Note that node templates (labels/taints) for worker and worker-spot NodeGroups must be the same (or at least suitable for the load that triggers the cluster scaling process).

В приведенном выше примере cluster-autoscaler сначала попытается заказать узел типа spot-node. Если в течение 15 минут его не получится добавить в кластер, NodeGroup worker-spot будет поставлена на паузу (на 20 минут) и cluster-autoscaler начнет заказывать узлы из NodeGroup worker. Если через 30 минут в кластере возникнет необходимость развернуть еще один узел, cluster-autoscaler сначала попытается заказать узел из NodeGroup worker-spot и только потом — из NodeGroup worker.

How to interpret Node Group states?

После того как NodeGroup worker-spot достигнет своего максимума (5 узлов в примере выше), узлы будут заказываться из NodeGroup worker.

Ready — the node group contains the minimum required number of scheduled nodes with the status Ready for all zones.

Шаблоны узлов (labels/taints) для NodeGroup worker и worker-spot должны быть одинаковыми или как минимум подходить для той нагрузки, которая запускает процесс увеличения кластера.

Example 1. A group of nodes in the Ready state:

Как интерпретировать состояние группы узлов?

yaml apiVersion: deckhouse.io/v1 kind: NodeGroup metadata: name: ng1 spec: nodeType: CloudEphemeral cloudInstances: maxPerZone: 5 minPerZone: 1 status: conditions:

  • status: “True” type: Ready — apiVersion: v1 kind: Node metadata: name: node1 labels: node.deckhouse.io/group: ng1 status: conditions:
  • status: “True” type: Ready

Ready — группа узлов содержит минимально необходимое число запланированных узлов с состоянием Ready для всех зон.

Example 2. A group of nodes in the Not Ready state:

Пример 1. Группа узлов в состоянии Ready:

yaml apiVersion: deckhouse.io/v1 kind: NodeGroup metadata: name: ng1 spec: nodeType: CloudEphemeral cloudInstances: maxPerZone: 5 minPerZone: 2 status: conditions:

  • status: “False” type: Ready — apiVersion: v1 kind: Node metadata: name: node1 labels: node.deckhouse.io/group: ng1 status: conditions:
  • status: “True” type: Ready

yaml apiVersion: deckhouse.io/v1 kind: NodeGroup metadata: name: ng1 spec: nodeType: CloudEphemeral cloudInstances: maxPerZone: 5 minPerZone: 1 status: conditions:

  • status: “True” type: Ready — apiVersion: v1 kind: Node metadata: name: node1 labels: node.deckhouse.io/group: ng1 status: conditions:
  • status: “True” type: Ready

Updating — a node group contains at least one node in which there is an annotation with the prefix update.node.deckhouse.io (for example, update.node.deckhouse.io/waiting-for-approval).

Пример 2. Группа узлов в состоянии Not Ready:

WaitingForDisruptiveApproval - a node group contains at least one node that has an annotation update.node.deckhouse.io/disruption-required and there is no annotation update.node.deckhouse.io/disruption-approved.

yaml apiVersion: deckhouse.io/v1 kind: NodeGroup metadata: name: ng1 spec: nodeType: CloudEphemeral cloudInstances: maxPerZone: 5 minPerZone: 2 status: conditions:

  • status: “False” type: Ready — apiVersion: v1 kind: Node metadata: name: node1 labels: node.deckhouse.io/group: ng1 status: conditions:
  • status: “True” type: Ready

Scaling — calculated only for node groups with the type CloudEphemeral. The state True can be in two cases:

Updating — группа узлов содержит как минимум один узел, в котором присутствует аннотация с префиксом update.node.deckhouse.io (например, update.node.deckhouse.io/waiting-for-approval).

  1. When the number of nodes is less than the desired number of nodes in the group, i.e. when it is necessary to increase the number of nodes in the group.
  2. When a node is marked for deletion or the number of nodes is greater than the desired number of nodes, i.e. when it is necessary to reduce the number of nodes in the group.

WaitingForDisruptiveApproval — группа узлов содержит как минимум один узел, в котором присутствует аннотация update.node.deckhouse.io/disruption-required и отсутствует аннотация update.node.deckhouse.io/disruption-approved.

The desired number of nodes is the sum of all replicas in the node group.

Scaling — рассчитывается только для групп узлов с типом CloudEphemeral. Состояние True может быть в двух случаях:

Example. The desired number of nodes is 2:

  1. Когда число узлов меньше желаемого числа узлов в группе, то есть когда нужно увеличить число узлов в группе.
  2. Когда какой-то узел помечается к удалению или число узлов больше желаемого числа узлов, то есть когда нужно уменьшить число узлов в группе.

yaml apiVersion: deckhouse.io/v1 kind: NodeGroup metadata: name: ng1 spec: nodeType: CloudEphemeral cloudInstances: maxPerZone: 5 minPerZone: 2 status: … desired: 2 …

Желаемое число узлов — это сумма всех реплик, входящих в группу узлов.

Error — contains the last error that occurred when creating a node in a node group.

Пример. Желаемое число узлов равно 2:

How do I make werf ignore the Ready conditions in a node group?

yaml apiVersion: deckhouse.io/v1 kind: NodeGroup metadata: name: ng1 spec: nodeType: CloudEphemeral cloudInstances: maxPerZone: 5 minPerZone: 2 status: … desired: 2 …

werf checks the Ready status of resources and, if available, waits for the value to become True.

Error — содержит последнюю ошибку, возникшую при создании узла в группе узлов.

Creating (updating) a nodeGroup resource in a cluster can take a significant amount of time to create the required number of nodes. When deploying such a resource in a cluster using werf (e.g., as part of a CI/CD process), deployment may terminate when resource readiness timeout is exceeded. To make werf ignore the nodeGroup status, the following nodeGroup annotations must be added:

Как заставить werf игнорировать состояние Ready в группе узлов?

yaml metadata: annotations: werf.io/fail-mode: IgnoreAndContinueDeployProcess werf.io/track-termination-mode: NonBlocking

werf проверяет состояние Ready у ресурсов и в случае его наличия дожидается, пока значение станет True.

What is an Instance resource?

Создание (обновление) ресурса nodeGroup в кластере может потребовать значительного времени на развертывание необходимого количества узлов. При развертывании такого ресурса в кластере с помощью werf (например, в рамках процесса CI/CD) развертывание может завершиться по превышении времени ожидания готовности ресурса. Чтобы заставить werf игнорировать состояние nodeGroup, необходимо добавить к nodeGroup следующие аннотации:

An Instance resource contains a description of an implementation-independent ephemeral machine resource. For example, machines created by MachineControllerManager or Cluster API Provider Static will have a corresponding Instance resource.

yaml metadata: annotations: werf.io/fail-mode: IgnoreAndContinueDeployProcess werf.io/track-termination-mode: NonBlocking

The object does not contain a specification. The status contains:

  1. A link to the InstanceClass if it exists for this implementation;
  2. A link to the Kubernetes Node object;
  3. Current machine status;
  4. Information on how to view machine creation logs (at the machine creation stage).

Что такое ресурс Instance?

When a machine is created/deleted, the Instance object is created/deleted accordingly. You cannot create an Instance resource yourself, but you can delete it. In this case, the machine will be removed from the cluster (the removal process depends on implementation details.

Ресурс Instance содержит описание объекта эфемерной машины, без учета ее конкретной реализации. Например, машины созданные MachineControllerManager или Cluster API Provider Static будут иметь соответcтвующий ресурс Instance.

Объект не содержит спецификации. Статус содержит:

  1. Ссылку на InstanceClass, если он существует для данной реализации.
  2. Ссылку на объект Node Kubernetes.
  3. Текущий статус машины.
  4. Информацию о том, как посмотреть логи создания машины (появляется на этапе создания машины).
 

При создании/удалении машины создается/удаляется соответствующий объект Instance. Самостоятельно ресурс Instance создать нельзя, но можно удалить. В таком случае машина будет удалена из кластера (процесс удаления зависит от деталей реализации).