Братцы! Скорее всего вы уже знаете, что Kubernetes отказался от поддержки Docker в качестве среды выполнения контейнеров (container runtime) в будущих версиях. В релизе 1.20, вышедшем в конце 2020 года Dockershim помечен как устаревший (deprecated). В релизе 1.22, выход которого запланирован на конец 2021 года, от его поддержки планируют полностью отказаться.
Если вы используете управляемые кластеры Kubernetes (такие как GKE, EKS, AKS) это не станет для вас серьезной проблемой и скорее всего переключение будет простым. Но если вы управляете кластером самостоятельно (например, с помощью kubeadm) и используете Docker container runtime, рано или поздно, вам придется заменить ее, чтобы иметь возможность обновлять Kubernetes до последних версий.
Задача этой статьи не дать исчерпывающую информацию о причинах такого решения со стороны разработчиков Kubernetes или подробно изучить поведения конкретных container runtime в кластере Kubernetes. Вместо этого мы шаг за шагом разберемся как переключить Docker container runtime на другое решение, поддерживающее стандарт Container Runtime Interface (CRI). Если вас интересуют причины из-за которых Docker больше не рекомендован к использованию, ознакомьтесь со статьей из официального блога Kubernetes Don't Panic: Kubernetes and Docker.
Чтобы не пропустить новые статьи подписывайтесь на телеграм-канал Mops DevOps
Что проверять в первую очередь
Влияние на рабочие нагрузки, выполняемые в вашем кластере, должно быть минимальным. Единственное, о чем вам нужно позаботиться, - это используете ли вы Docker-in-Docker в любой из ваших контейнерных рабочих нагрузок, смонтировав сокет Docker /var/run/docker.sock. В этом случае вам нужно будет найти альтернативу (например, Kaniko), прежде чем переключаться с Docker на новую container runtime.
Также настоятельно рекомендуется сделать резервную копию ваших данных, прежде чем переходить к переключению среды выполнения контейнера!
Приступим к работе!
Отлично, теперь, когда вы готовы к переключению container runtime, можно начинать. В этой статье будем использовать containerd в качестве container runtime, но приведенные ниже шаги можно адаптировать к другой среде выполнения контейнера, например, CRI-O.
Мы начнем с рабочих узлов (worker nodes) и только потом выполним аналогичные действия на мастерах (control plane).
Worker nodes
Указанные ниже шаги нужно выполнить на всех рабочих узлах кластера.
1) Вначале выполним drain
и cordon
узла кластера, чтобы эвакуировать нагрузки с него и предотвратить планирование новых нагрузок во время выполнения последующих операций:
kubectl cordon <node_name>
kubectl drain <node_name>
Замечание: если на узлах кластера запущены DaemonSets, необходимо использовать флаг --ignore-daemonsets
, чтобы продолжить эвакуацию остальных pods. Не волнуйтесь kubelet эти pods автоматически пересоздаст с помощью новой container runtime, когда процедура переключения будет завершена. Если у вас есть критические сервисы, запущенные в DaemonSet, и вы не хотите, чтобы они работали во время процесса переключения, вы можете либо указать nodeSelector
в своем DaemonSet, либо полностью удалить и переустановить их в конце процесса.
2) Останавливаем сервис kubelet:
sudo systemctl stop kubelet
sudo systemctl status kubelet
3) Удаляем Docker
Я не буду подробно описывать команды, поскольку это зависит от вашего дистрибутива Linux и способа установки Docker. Просто будьте осторожны, если вы хотите полностью очистить артефакты Docker, возможно, вам придется вручную удалить некоторые файлы (например, /var/ lib/docker).
Подробную инструкцию вы найдете в документации Docker.
4) Устанавливаем countainerd используя официальное руководству для вашей версии операционной системы.
5) Выполняем Enable
и Start
сервиса containerd:
sudo systemctl enable containerd
sudo systemctl start containerd
sudo systemctl status containerd
6) Kubernetes взаимодействует с container runtime через плагин CRI . Убедитесь, что этот плагин не был отключен при установке containerd.
Проверим параметр в файле конфигурации /etc/containerd/config.toml
disabled_plugins = [""]
Если на предыдущем шаге внесены изменения в конфигурационный файл, необходимо перезагрузить сервис containerd:
sudo systemctl restart containerd
7) Отредактируем конфигурационный файл kubelet.
Добавим в конфигурационный файл /var/lib/kubelet/kubeadm-flags.env флаги для переменной KUBELET_KUBEADM_ARGS (при необходимости измените путь к container runtime):
--container-runtime=remote --container-runtime-endpoint=/run/containerd/containerd.sock
8) Запускаем сервис kubelet:
sudo systemctl start kubelet
9) Проверяем, что на узле запущена требуемая версия container runtime:
kubectl describe node <node_name>
System Info:
Machine ID: 21a5dd31f86c4
System UUID: 4227EF55-BA3BCCB57BCE
Boot ID: 77229747-9ea581ec6773
Kernel Version: 3.10.0-1127.10.1.el7.x86_64
OS Image: Red Hat Enterprise Linux Server 7.8 (Maipo)
Operating System: linux
Architecture: amd64
>>Container Runtime Version: containerd://1.4.3
Kubelet Version: v1.20.2
Kube-Proxy Version: v1.20.2
10) Выполняем Uncordon на узле, чтобы разрешить планировать на него нагрузки, и проверим статус работы pods:
kubectl uncordon <node_name>
Вот и все, как только все ваши поды будут перезапущены, вы можете перейти к настройке следующего узла кластера!
Control Plane
Процедура обновление container runtime на мастерах полностью повторяет установку на рабочих узлах кластера. Однако будьте осторожны, если ваш кластер запущен с единственным мастером.
Пока новая container runtime будет загружать образы kube-apiserver, etcd и coredns и создавать соответствующие pods, кластер будет недоступен. У вас также не должно быть возможности запускать команду kubectl.
Вот несколько советов, которые помогут вам следить за запуском container runtime и устранять потенциальные проблемы:
1) Используем journalctl, чтобы отслеживать изменения в журналах kubelet:
journalctl -u kubelet
2) Проверяем журналы containerd:
journalctl -u containerd
3) Используем утилиту crictl, чтобы убедится, что контейнеры запущены:
crictl --runtime-endpoint /run/containerd/containerd.sock ps
4) После замены container runtime убедимся, что используем требуемую версию, выполнив команду на всех узлах кластера:
kubectl describe node <master_node_name>
также можем выполнить команду, она выведет информацию сразу по всем узлам кластера
kubectl get node -o wide
Поздравляю! Кластер Kubernetes настроен без Docker, теперь проблем с обновлением на новые версии возникнуть не должно.
Телеграм-канал Mops DevOps - анонсы вебинаров и конференций, полезные статьи и видео, а также регулярные скидки на обучение!