Для запуска контейнеров платформа Kubernetes использует Container runtime, т. е. движок для контейнеров. Долгое время основным движком считался Docker, но им не ограничивался — Kubernetes также поддерживает такие движки, как CRI-O и containerd. Однако начиная с версии Kubernetes 1.20, было объявлено, что в будущих версиях поддержка Docker (а если быть точнее, то dockershim) будет полностью прекращена. Начиная с версии Kubernetes 1.24, Docker был полностью удален из Kubernetes. Одной из причин такого решения было то, что в Docker отсутствует поддержка интерфейса CRI (Container Runtime Interface). В качестве замены можно перейти на CRI-O, который позиционирует себя как легковесную исполняемую среду для контейнеров в Kubernetes. В данной статье мы рассмотрим миграцию с движка Docker на CRI-O.

Технические характеристики кластера

Смена движка будет произведена на 4-узловом кластере Kubernetes, который состоит из 2x master (управляющих) нод и 2x worker (рабочих) нод:

Версии используемых программных компонентов:

  • Версия Kubernetes: 1.20.4

  • Версия Docker: 24.0.2

  • Версия CRI-O: 1.23

  • Операционная система: Ubuntu 20.04.6 LTS

Перед выполнением процедуры по смене контейнерного движка необходимо сделать резервную копию образов Docker, например перенесите их реестр (Nexus, Jfrog и т. д.), так как при удалении Docker все его данные (включая такие пользовательские, как образы) будут удалены.

Одно из самых важных требований во время смены движка для контейнеров — это наличие минимум 2х master (управляющих) нод кластера. При использовании одной master ноды есть риск того, что кластер не будет запущен, так как на master ноде расположены основные компоненты системы.

Вывод узлов из кластера

Начинать будем с worker (рабочих) нод, далее перейдем к master нодам. Для данной задачи нам понадобятся такие команды:

  • kubectl cordon — используется для блокировки ноды. После выполнения данной команды новые объекты типа pod не будут развёртываться на данной ноде. 

  • kubectl drain — используется для удаления подов и их перемещения на другие узлы кластера.

1) Блокируем первую ноду с именем k8s-worker2:

kubectl cordon k8s-worker2

2) Удаляем и переносим запущенные pod’ы:

kubectl drain k8s-worker2 --ignore-daemonsets

Опция --ignore-daemonsets предназначена для игнорирования размещённых на ноде объектов использующих DaemonSet.

3) Проверяем статус ноды:

kubectl get nodes

Как видно, у ноды k8s-worker2 появился статус SchedulingDisabled, что означает, что на данном узле выключена возможность по развертыванию pod’ов.

Следующие шаги выполняем на той же ноде, которую мы переводили в статус SchedulingDisabled (в данном случае это рабочая нода с именем k8s-worker2).

4) Останавливаем сервис kubelet и проверяем его статус:

sudo systemctl stop kubelet && sudo systemctl status kubelet

Дожидаемся, когда статус ноды перейдет в NotReady. Только после этого переходим к следующим шагам.

5) Останавливаем сервис docker и проверяем его статус:

sudo systemctl stop docker && sudo systemctl status docker

6) Удаляем пакеты docker с сервера:

sudo apt purge docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y

Команда apt purge удаляет также конфигурационные файлы. 

Установка CRI-O

Следующий шаг — установка движка CRI-O. Так как пакеты CRI-O отсутствуют в репозиториях ОС, мы воспользуемся репозиториями от разработчиков операционной системы openSUSE. 

1) Создадим переменные, содержащие версию используемого дистрибутива Ubuntu (20.04) и версию CRI-O, которую мы будем использовать (в данном примере это будет версия 1.23):

OS=xUbuntu_20.04
VERSION=1.23

2) Добавляем репозиторий от разработчиков openSUSE: 

echo "deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/$OS/ /" | sudo tee /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list

3) Далее добавляем репозиторий, содержащий пакеты с CRI-O:

echo "deb http://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable:/cri-o:/$VERSION/$OS/ /" | sudo tee /etc/apt/sources.list.d/devel:kubic:libcontainers:stable:cri-o:$VERSION.list

4) Скачиваем ключ от репозитория:

curl -L https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/$OS/Release.key | sudo apt-key add –

5) Устанавливаем CRI-O и необходимые пакеты:

sudo apt update && sudo apt install cri-o cri-o-runc cri-tools -y

Настройка CRI-O

1) Для настройки crio необходимо задать cgroup драйвер — мы будем использовать systemd. Для этого в файле kubelet необходимо добавить следующую строку:

echo "KUBELET_EXTRA_ARGS=--cgroup-driver=systemd" | sudo tee /etc/default/kubelet

2) Загружаем необходимые сетевые модули из ядра ОС:

cat <<EOF | sudo tee /etc/modules-load.d/containerd.conf
overlay
br_netfilter
EOF

3) Активируем загруженные модули:

sudo modprobe overlay
sudo modprobe br_netfilter

4) Применяем настройки. Команду ниже необходимо выполнять от имени пользователя root:

cat <<EOF >  /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv4.ip_forward                 = 1
net.bridge.bridge-nf-call-ip6tables = 1
EOF

5) Перезапускаем параметры ядра:

sudo sysctl --system

 6) Прописываем адрес сокета с crio. Команду ниже необходимо выполнять от имени пользователя root:

echo "runtime-endpoint: unix:///var/run/crio/crio.sock" > /etc/crictl.yaml

7) Добавляем crio в автозагрузку и запускаем:

sudo systemctl enable crio && sudo systemctl start crio

8) Проверяем, что crio работает, выполнив команду для проверки запущенных контейнеров:

sudo crictl ps

9) Открываем для редактирования конфигурационный файл kubelet:

sudo nano /etc/default/kubelet

и прописываем следующие параметры:

KUBELET_EXTRA_ARGS=--feature-gates="AllAlpha=false" --container-runtime=remote --cgroup-driver=systemd --container-runtime-endpoint='unix:///var/run/crio/crio.sock' --runtime-request-timeout=5m

Сохраняем изменения и выходим из файла.

10) Запускаем сервис kubelet:

sudo systemctl start kubelet

11) Возвращаемся на master ноду и включаем ранее выключенный узел:

kubectl uncordon k8s-worker2

12) Проверяем, что нода запущена (статус READY):

kubectl get nodes

А также проверим, что движок с Docker был изменен на crio:

kubectl get -o wide

Далее выполняем все предыдущие шаги на остальных нодах кластера. Мастер ноды будут подниматься намного дольше, чем рабочие. После того как все ноды кластеры были переведены на новый движок, проверяем, что везде используется crio (столбец CONTAINER_RUNTIME):


НЛО прилетело и оставило здесь промокод для читателей нашего блога:

— 15% на заказ любого VDS (кроме тарифа Прогрев) — HABRFIRSTVDS

Комментарии (2)


  1. nafigat
    31.07.2023 14:41
    +1

    6) Удаляем пакеты docker с сервера:

    sudo systemctl stop docker && sudo systemctl status docker

    - содержание командной строки осталось с предыдущего пункта 5).
    Хорошо бы подправить..


    1. 1shaman Автор
      31.07.2023 14:41

      спасибо! поправлено