Восстановление master-узла, если kubelet не может загрузить компоненты управляющего слоя
Подобная ситуация может возникнуть, если в кластере с одним master-узлом были удалены образы
компонентов управляющего слоя (например, удалена директория /var/lib/containerd
). В этом случае kubelet при рестарте не сможет скачать образы компонентов управляющего слоя, поскольку на master-узле нет параметров авторизации в registry.deckhouse.io
.
containerd
Для восстановления работоспособности master-узла выполните следующие шаги:
-
В любом рабочем кластере под управлением Deckhouse выполните следующую команду:
1d8 k -n d8-system get secrets deckhouse-registry -o json | 2jq -r '.data.".dockerconfigjson"' | base64 -d | 3jq -r '.auths."registry.deckhouse.io".auth'
- Скопируйте вывод команды и присвойте его переменной
AUTH
на повреждённом master-узле. -
Загрузите образы компонентов управляющего слоя на повреждённом master-узле:
1for image in $(grep "image:" /etc/kubernetes/manifests/* | awk '{print $3}'); do 2 crictl pull --auth $AUTH $image 3done
- После того как образы будут загружены, перезапустите kubelet.
Изменение CRI для NodeGroup
Возможен переход CRI только с Containerd
на NotManaged
и обратно.
Чтобы сменить CRI, задайте для параметра cri.type значение Containerd
или NotManaged
.
Пример YAML-манифеста NodeGroup:
1apiVersion: deckhouse.io/v1
2kind: NodeGroup
3metadata:
4 name: worker
5spec:
6 nodeType: Static
7 cri:
8 type: Containerd
Также эту операцию можно выполнить с помощью патча:
-
Для
Containerd
:1d8 k patch nodegroup <имя NodeGroup> --type merge -p '{"spec":{"cri":{"type":"Containerd"}}}'
-
Для
NotManaged
:1d8 k patch nodegroup <имя NodeGroup> --type merge -p '{"spec":{"cri":{"type":"NotManaged"}}}'
При смене cri.type
для объектов NodeGroup, созданных с помощью dhctl
, измените CRI в dhctl config edit provider-cluster-configuration
и настройках объекта NodeGroup.
После настройки нового CRI для NodeGroup модуль node-manager
выполняет drain на каждом узле и устанавливает на них новый CRI. Обновление узла
сопровождается простоем (disruption). В зависимости от настройки disruption
для NodeGroup модуль node-manager
либо автоматически разрешает обновление
узлов, либо требует ручного подтверждения.
Изменение CRI для всего кластера
Возможен переход CRI только с Containerd
на NotManaged
и обратно.
Необходимо с помощью утилиты dhctl
отредактировать параметр defaultCRI
в конфиге cluster-configuration
.
Также возможно выполнить эту операцию с помощью патча. Пример:
-
Для
Containerd
:1data="$(d8 k -n kube-system get secret d8-cluster-configuration -o json | jq -r '.data."cluster-configuration.yaml"' | base64 -d | sed "s/NotManaged/Containerd/" | base64 -w0)" 2d8 k -n kube-system patch secret d8-cluster-configuration -p '{"data":{"cluster-configuration.yaml":"'${data}'"}}'
-
Для
NotManaged
:1data="$(d8 k -n kube-system get secret d8-cluster-configuration -o json | jq -r '.data."cluster-configuration.yaml"' | base64 -d | sed "s/Containerd/NotManaged/" | base64 -w0)" 2d8 k -n kube-system patch secret d8-cluster-configuration -p '{"data":{"cluster-configuration.yaml":"'${data}'"}}'
Если необходимо какую-то NodeGroup оставить на другом CRI, перед изменением defaultCRI
необходимо установить CRI для этой NodeGroup,
следуя соответствующей инструкции.
Изменение defaultCRI
влечет за собой изменение CRI на всех узлах, включая master-узлы.
Если master-узел один, данная операция является опасной и может привести к полной неработоспособности кластера.
Предпочтительный вариант — сделать multimaster и поменять тип CRI.
При изменении CRI в кластере для master-узлов необходимо выполнить дополнительные шаги:
-
Deckhouse обновляет узлы в master NodeGroup по одному, поэтому необходимо определить, какой узел на данный момент обновляется:
1d8 k get nodes -l node-role.kubernetes.io/control-plane="" -o json | jq '.items[] | select(.metadata.annotations."update.node.deckhouse.io/approved"=="") | .metadata.name' -r
-
Подтвердить disruption для master-узла, полученного на предыдущем шаге:
1d8 k annotate node <имя master-узла> update.node.deckhouse.io/disruption-approved=
-
Дождаться перехода обновленного master-узла в
Ready
. Выполнить итерацию для следующего master’а.
Как использовать containerd с поддержкой Nvidia GPU?
-
Создайте отдельную NodeGroup для GPU-узлов:
1apiVersion: deckhouse.io/v1 2kind: NodeGroup 3metadata: 4 name: gpu 5spec: 6 chaos: 7 mode: Disabled 8 disruptions: 9 approvalMode: Automatic 10 nodeType: CloudStatic
-
Далее необходимо создать NodeGroupConfiguration для NodeGroup
gpu
для конфигурации containerd:1apiVersion: deckhouse.io/v1alpha1 2kind: NodeGroupConfiguration 3metadata: 4 name: containerd-additional-config.sh 5spec: 6 bundles: 7 - '*' 8 content: | 9 # Copyright 2023 Flant JSC 10 # 11 # Licensed under the Apache License, Version 2.0 (the "License"); 12 # you may not use this file except in compliance with the License. 13 # You may obtain a copy of the License at 14 # 15 # http://www.apache.org/licenses/LICENSE-2.0 16 # 17 # Unless required by applicable law or agreed to in writing, software 18 # distributed under the License is distributed on an "AS IS" BASIS, 19 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20 # See the License for the specific language governing permissions and 21 # limitations under the License. 22 mkdir -p /etc/containerd/conf.d 23 bb-sync-file /etc/containerd/conf.d/nvidia_gpu.toml - << "EOF" 24 [plugins] 25 [plugins."io.containerd.grpc.v1.cri"] 26 [plugins."io.containerd.grpc.v1.cri".containerd] 27 default_runtime_name = "nvidia" 28 [plugins."io.containerd.grpc.v1.cri".containerd.runtimes] 29 [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc] 30 [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.nvidia] 31 privileged_without_host_devices = false 32 runtime_engine = "" 33 runtime_root = "" 34 runtime_type = "io.containerd.runc.v2" 35 [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.nvidia.options] 36 BinaryName = "/usr/bin/nvidia-container-runtime" 37 SystemdCgroup = false 38 EOF 39 nodeGroups: 40 - gpu 41 weight: 31
- Добавьте NodeGroupConfiguration для установки драйверов Nvidia для NodeGroup
gpu
: - Выполните бутстрап и перезагрузите узел.
Ubuntu
1apiVersion: deckhouse.io/v1alpha1
2kind: NodeGroupConfiguration
3metadata:
4 name: install-cuda.sh
5spec:
6 bundles:
7 - ubuntu-lts
8 content: |
9 # Copyright 2023 Flant JSC
10 #
11 # Licensed under the Apache License, Version 2.0 (the "License");
12 # you may not use this file except in compliance with the License.
13 # You may obtain a copy of the License at
14 #
15 # http://www.apache.org/licenses/LICENSE-2.0
16 #
17 # Unless required by applicable law or agreed to in writing, software
18 # distributed under the License is distributed on an "AS IS" BASIS,
19 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 # See the License for the specific language governing permissions and
21 # limitations under the License.
22 if [ ! -f "/etc/apt/sources.list.d/nvidia-container-toolkit.list" ]; then
23 distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
24 curl -s -L https://nvidia.github.io/libnvidia-container/gpgkey | sudo apt-key add -
25 curl -s -L https://nvidia.github.io/libnvidia-container/$distribution/libnvidia-container.list | sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
26 fi
27 bb-apt-install nvidia-container-toolkit nvidia-driver-535-server
28 nvidia-ctk config --set nvidia-container-runtime.log-level=error --in-place
29 nodeGroups:
30 - gpu
31 weight: 30
CentOS
1apiVersion: deckhouse.io/v1alpha1
2kind: NodeGroupConfiguration
3metadata:
4 name: install-cuda.sh
5spec:
6 bundles:
7 - centos
8 content: |
9 # Copyright 2023 Flant JSC
10 #
11 # Licensed under the Apache License, Version 2.0 (the "License");
12 # you may not use this file except in compliance with the License.
13 # You may obtain a copy of the License at
14 #
15 # http://www.apache.org/licenses/LICENSE-2.0
16 #
17 # Unless required by applicable law or agreed to in writing, software
18 # distributed under the License is distributed on an "AS IS" BASIS,
19 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 # See the License for the specific language governing permissions and
21 # limitations under the License.
22 if [ ! -f "/etc/yum.repos.d/nvidia-container-toolkit.repo" ]; then
23 distribution=$(. /etc/os-release;echo $ID$VERSION_ID) \
24 curl -s -L https://nvidia.github.io/libnvidia-container/$distribution/libnvidia-container.repo | sudo tee /etc/yum.repos.d/nvidia-container-toolkit.repo
25 fi
26 bb-dnf-install nvidia-container-toolkit nvidia-driver
27 nvidia-ctk config --set nvidia-container-runtime.log-level=error --in-place
28 nodeGroups:
29 - gpu
30 weight: 30
Как проверить, что все прошло успешно?
Создайте в кластере Job
под именем nvidia-cuda-test
:
1apiVersion: batch/v1
2kind: Job
3metadata:
4 name: nvidia-cuda-test
5 namespace: default
6spec:
7 completions: 1
8 template:
9 spec:
10 restartPolicy: Never
11 nodeSelector:
12 node.deckhouse.io/group: gpu
13 containers:
14 - name: nvidia-cuda-test
15 image: nvidia/cuda:11.6.2-base-ubuntu20.04
16 imagePullPolicy: "IfNotPresent"
17 command:
18 - nvidia-smi
Посмотрите логи, выполнив следующую команду:
1d8 k logs job/nvidia-cuda-test
Пример вывода команды:
1Tue Jan 24 11:36:18 2023
2+-----------------------------------------------------------------------------+
3| NVIDIA-SMI 525.60.13 Driver Version: 525.60.13 CUDA Version: 12.0 |
4|-------------------------------+----------------------+----------------------+
5| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
6| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
7| | | MIG M. |
8|===============================+======================+======================|
9| 0 Tesla T4 Off | 00000000:8B:00.0 Off | 0 |
10| N/A 45C P0 25W / 70W | 0MiB / 15360MiB | 0% Default |
11| | | N/A |
12+-------------------------------+----------------------+----------------------+
13+-----------------------------------------------------------------------------+
14| Processes: |
15| GPU GI CI PID Type Process name GPU Memory |
16| ID ID Usage |
17|=============================================================================|
18| No running processes found |
19+-----------------------------------------------------------------------------+
Создайте в кластере Job
под именем gpu-operator-test
:
1apiVersion: batch/v1
2kind: Job
3metadata:
4 name: gpu-operator-test
5 namespace: default
6spec:
7 completions: 1
8 template:
9 spec:
10 restartPolicy: Never
11 nodeSelector:
12 node.deckhouse.io/group: gpu
13 containers:
14 - name: gpu-operator-test
15 image: nvidia/samples:vectoradd-cuda10.2
16 imagePullPolicy: "IfNotPresent"
Посмотрите логи, выполнив следующую команду:
1d8 k logs job/gpu-operator-test
Пример вывода команды:
1[Vector addition of 50000 elements]
2Copy input data from the host memory to the CUDA device
3CUDA kernel launch with 196 blocks of 256 threads
4Copy output data from the CUDA device to the host memory
5Test PASSED
6Done
Как добавить несколько статических узлов в кластер вручную?
Используйте существующий или создайте новый ресурс NodeGroup.
Пример ресурса NodeGroup с именем worker
:
1apiVersion: deckhouse.io/v1
2kind: NodeGroup
3metadata:
4 name: worker
5spec:
6 nodeType: Static
Автоматизировать процесс добавления узлов можно с помощью любой платформы автоматизации. Далее приведен пример для Ansible.
-
Получите один из адресов Kubernetes API-сервера. Обратите внимание, что IP-адрес должен быть доступен с узлов, которые добавляются в кластер:
1d8 k -n default get ep kubernetes -o json | jq '.subsets[0].addresses[0].ip + ":" + (.subsets[0].ports[0].port | tostring)' -r
Проверьте версию Kubernetes. Если версия больше 1.25, создайте токен
node-group
:1d8 k create token node-group --namespace d8-cloud-instance-manager --duration 1h
Сохраните полученный токен и добавьте в поле
token
в Ansible playbook на дальнейших шагах. -
Если версия Kubernetes меньше 1.25, получите Kubernetes API-токен для специального ServiceAccount, которым управляет Deckhouse:
1d8 k -n d8-cloud-instance-manager get $(d8 k -n d8-cloud-instance-manager get secret -o name | grep node-group-token) \ 2 -o json | jq '.data.token' -r | base64 -d && echo ""
-
Создайте Ansible playbook и замените значения
vars
данными, полученными на предыдущих шагах:1- hosts: all 2 become: yes 3 gather_facts: no 4 vars: 5 kube_apiserver: <KUBE_APISERVER> 6 token: <TOKEN> 7 tasks: 8 - name: # Проверка, что на узле уже был выполнен бутстрап. 9 stat: 10 path: /var/lib/bashible 11 register: bootstrapped 12 - name: # Получение секрета бутстрапа. 13 uri: 14 url: "https:///api/v1/namespaces/d8-cloud-instance-manager/secrets/manual-bootstrap-for-" 15 return_content: yes 16 method: GET 17 status_code: 200 18 body_format: json 19 headers: 20 Authorization: "Bearer " 21 validate_certs: no 22 register: bootstrap_secret 23 when: bootstrapped.stat.exists == False 24 - name: Run bootstrap.sh 25 shell: "" 26 args: 27 executable: /bin/bash 28 ignore_errors: yes 29 when: bootstrapped.stat.exists == False 30 - name: wait 31 wait_for_connection: 32 delay: 30 33 when: bootstrapped.stat.exists == False
-
Определите дополнительную переменную
node_group
. Значение переменной должно совпадать с именем NodeGroup, которой будет принадлежать узел. Переменную можно передать различными способами, например с использованием inventory-файла:1[system] 2system-0 3system-1 4[system:vars] 5node_group=system 6[worker] 7worker-0 8worker-1 9[worker:vars] 10node_group=worker
-
Выполните playbook с использованием inventory-файла.
Как заставить werf игнорировать состояние Ready в группе узлов?
werf проверяет состояние Ready
у ресурсов и в случае его наличия дожидается, пока значение станет True
.
Создание (обновление) ресурса NodeGroup в кластере может потребовать значительного времени на развертывание необходимого количества узлов. Развертывание такого ресурса в кластере с помощью werf (например, в рамках процесса CI/CD) может завершиться в случае превышения времени ожидания готовности ресурса.
Чтобы заставить werf игнорировать состояние NodeGroup, добавьте к NodeGroup следующие аннотации:
1metadata:
2 annotations:
3 werf.io/fail-mode: IgnoreAndContinueDeployProcess
4 werf.io/track-termination-mode: NonBlocking