Тестирование контейнерной ОС на основе кодовой базы openEuler / OpenScaler

В этой статье мы обсудим новый специализированный дистрибутив на основе кодовой базы openEuler / openScaler оптимизированный под запуск контейнеров – NestOS.

Сейчас принято подобные ОС называть cloud-based, так как основное их применение — использование в качестве узлов для запуска контейнеров в кластерах kubernetes. Из отличительных особенностей данного дистрибутива стоит отметить его минималистичность. Так, размер iso образа NestOS составляет чуть более 700 Мб, а установленная система занимает меньше 10 Гб.

При этом, в этот базовый образ NestOS (речь идёт про версию, основанную на стабильной OpenEuler 22.03 LTS SP1) уже включены 3 системы контейнеризации – привычные всем docker (версии 18.09) и podman (версии 3.4.4), а также собственную систему контейнеризации iSulad (версии 2.0.17) о которой мы уже писали в одной из наших прошлых статей. Поэтому, достаточно активировать нужную систему контейнеризации и узел уже будет готов для запуска контейнеров.

Давайте немного остановимся на особенностях NestOS.

В этой ОС нет привычных многим пакетных менеджеров, позволяющих на ходу добавлять и удалять пакеты. NestOS использует для управления программным обеспечением наработки проекта ostree, который позволяет производить атомарные операции по обновлению (или откату обновлений) всего древа файловой системы ОС. Подобный подход получил название «git for operating system binaries», и для управлениями образами используется утилита rpm-ostree. То есть система обновляется путём накатывания образов системы, позволяя всегда (в случае непредвиденных обстоятельств) откатиться на предыдущий образ. По умолчанию этих образов 2 (текущий и предыдущий), но можно «запинить» (сделать pin) для образа, чтобы сохранить его и защитить от удаления. Побочным эффектом такого подхода является то, что после установки пакетов в систему при помощи утилиты rpm-ostree они записываются в новый образ и не появляются сразу в системе. Чтобы воспользоваться установленным ПО необходимо перезагрузить систему.

Так же следует отметить, что файловая система NestOS организована таким образом, что для записи пользователю доступны только каталоги /etc и /var. При этом, чтобы не ломать совместимость, все привычные (для записи) пользователям каталоги организованы путём создания символьных ссылок внутрь /var:

# ls -l /
total 17
lrwxrwxrwx. 3 root root 7 Dec 29 2022 bin -> usr/bin
drwxr-xr-x. 7 root root 1024 May 19 07:39 boot
drwxr-xr-x 20 root root 3300 May 19 10:49 dev
drwxr-xr-x 91 root root 8192 May 19 10:49 etc
lrwxrwxrwx. 3 root root 8 Dec 29 2022 home -> var/home
lrwxrwxrwx. 3 root root 7 Dec 29 2022 lib -> usr/lib
lrwxrwxrwx. 3 root root 9 Dec 29 2022 lib64 -> usr/lib64
lrwxrwxrwx. 3 root root 9 Dec 29 2022 media -> run/media
lrwxrwxrwx. 3 root root 7 Dec 29 2022 mnt -> var/mnt
lrwxrwxrwx. 3 root root 7 Dec 29 2022 opt -> var/opt
lrwxrwxrwx. 3 root root 14 Dec 29 2022 ostree -> sysroot/ostree
dr-xr-xr-x 277 root root 0 May 19 10:49 proc
lrwxrwxrwx. 3 root root 12 Dec 29 2022 root -> var/roothome
drwxr-xr-x 44 root root 1260 Jul 3 07:44 run
lrwxrwxrwx. 3 root root 8 Dec 29 2022 sbin -> usr/sbin
lrwxrwxrwx. 3 root root 7 Dec 29 2022 srv -> var/srv
dr-xr-xr-x 13 root root 0 May 19 10:49 sys
drwxr-xr-x. 4 root root 66 Dec 29 2022 sysroot
drwxrwxrwt 6 root root 120 Jul 3 08:13 tmp
drwxr-xr-x. 12 root root 155 Jan 1 1970 usr
drwxr-xr-x. 24 root root 4096 May 19 08:40 var

Таким образом достигается неизменяемость системы, которая позволяет быть уверенным, что бинарные файлы запуска программ не изменены и не могут быть случайно удалены.

Теперь давайте перейдём к практической части.

В нашей демо лаборатории мы протестировали развёртывание kubernetes кластера с использованием узлов, на которых была установлена NestOS 22.03 LTS SP1.

Для этого мы создали 5 виртуальных машин. Все виртуальные машины имеют следующую конфигурацию: 8vCPU, 16GB RAM, диск 40 Гб.

  • k8s-nestos-m1 – мастер №1 (172.17.3.31)

  • k8s-nestos-m1 – мастер №2 (172.17.3.32)

  • k8s-nestos-m1 – мастер №3 (172.17.3.33)

  • k8s-nestos-w1 – worker №1 (172.17.3.41)

  • k8s-nestos-w2 – worker №2 (172.17.3.42)

Машины, у которых hostname оканчивается на -mX — это master узлы, -wX — это рабочие узлы.

Дополнительно используются адреса:

– 172.17.3.100 – кластерный адрес API k8s (работает через keepalived)

Заметим, что виртуальные машины мы создаём в сети, где уже развёрнут DHCP сервер.

Установка NestOS

Для установки качаем iso образ 22.03 SP1 с сайта https://nestos.openeuler.org, подключаем этот образ к созданным виртуальным машинам и загружаем с него наши виртуальные машины.


Выбираем для загрузки NestOS (Live) и попадаем в консоль, где сразу можно стать root (используя команду sudo -i)


Для установки системы используется утилита nestos-installer, которая использует созданный заранее файл с профилем установки.

Для создания этого профиля подойдёт любой Linux сервер с установленным docker.

На нашем стенде мы даём эти команды на первом сервере, на остальных серверах используем готовый конфиг, скопированный с первого сервера.

Главное – получить на выходе transpiled_config.ign который надо скопировать на остальные узлы с загруженным nestos live.

systemctl start docker
docker pull hub.oepkgs.net/nestos/butane:0.14.0

Замечание: да, в загруженном NestOS Live мы используем docker, после установки мы уже будем использовать в качестве движка контейнеризации iSulad.

Подготавливаем файл ~/config.bu, в который мы помещаем хэш пароля для пользователя core (подготавливаем его при помощи openssl hash) и заместо key1 и key2 помещаем публичные ssh ключи администраторов.

variant: nestos
version: 1.1.0
passwd:
users:
– name: core
password_hash: “<хэш>”
ssh_authorized_keys:
“<ssh-rsa key1>”
“<ssh-rsa key2>”

даём команду преобразования конфига:

docker run –interactive –rm hub.oepkgs.net/nestos/butane:0.14.0 –pretty –strict < config.bu > transpiled_config.ign

После этого производим установку NestOS на диск /dev/sda сервера и перезагружаем сервер:

nestos-installer install /dev/sda –ignition-file transpiled_config.ign
systemctl reboot

На остальных серверах достаточно просто переписать на них конфиг transpiled_config.ign и просто выполняем команды:

nestos-installer install /dev/sda –ignition-file transpiled_config.ign
systemctl reboot

Установка kubernetes

Для развёртывания кластера kubernetes нам надо будет преднастроить узлы, добавить репозиторий с пакетами kubernetes, поставить необходимые пакеты и собрать кластер.

Заметим, что в данном примере мы будем устанавливать kubernetes с контейнерным движком iSulad.

На сервера, которые предназначены для работы master необходимо установить keepalived и настроить общий адрес 172.17.3.100. Но в момент установки нужно выключить keepalived на всех мастерах, кроме первого. После установки всех мастеров, сервис keepalived можно будет включить на всех master узлах. Установка и настройка keepalived выходит за рамки этой статьи.

Рассмотрим все эти шаги подробнее.

Для начала на каждой созданной виртуальной машине мы настраиваем:

– статический ip адрес и hostname

– прописываем все узлы будущего кластера kubernetes в /etc/hosts

– отключаем SELinux (к сожалению, это требование в документации к NestOS)

/etc/sysconfig/selinux
SELINUX=disabled

– прописываем необходимые sysctl:

/etc/sysctl.conf
net.bridge.bridge-nf-call-iptables=1
net.bridge.bridge-nf-call-ip6tables=1
net.ipv4.ip_forward=1

прописываем модуль br_netfilter в автозагрузку

/etc/modules-load.d/br_netfilter.conf
br_netfilter

Добавляем в /etc/yum.repos.d/openEuler.repo репозиторий (https://docs.openeuler.org/en/docs/22.03_LTS_SP1/docs/NestOS/usage.html#downloading-the-components)

[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg

  • Устанавливаем пакеты kubernetes (добавляем их в образ rpm-ostree)

rpm-ostree install kubectl-1.25.9-0.x86_64 kubeadm-1.25.9-0.x86_64 kubelet-1.25.9-0.x86_64

Заметим, что после завершения работы этой команды установленные пакеты в системе не появятся, такова особенность rpm-ostree. Для завершения установки (чтобы увидеть пакеты в системе) необходимо перезагрузить сервер. Мы сделаем это чуть позднее.

– Конфиг isulad приводим к виду:

# cat /etc/isulad/daemon.json
{
“group”: “isula”,
“default-runtime”: “lcr”,
“graph”: “/var/lib/isulad”,
“state”: “/var/run/isulad”,
“engine”: “lcr”,
“log-level”: “ERROR”,
“pidfile”: “/var/run/isulad.pid”,
“log-opts”: {
“log-file-mode”: “0600”,
“log-path”: “/var/lib/isulad”,
“max-file”: “1”,
“max-size”: “30KB”
},
“log-driver”: “stdout”,
“container-log”: {
“driver”: “json-file”
},
“hook-spec”: “/etc/default/isulad/hooks/default.json”,
“start-timeout”: “2m”,
“storage-driver”: “overlay2”,
“storage-opts”: [
“overlay2.override_kernel_check=true”
],
“registry-mirrors”: [
“docker.io”
],
“insecure-registries”: [
“<если у нас есть локальный репозиторий образов — можно добавить сюда>:5000”,
“rnd-dockerhub.huawei.com”,
“k8s.gcr.io”,
“quay.io”
],
“pod-sandbox-image”: “registry.aliyuncs.com/google_containers/pause:3.5”,
“native.umask”: “secure”,
“network-plugin”: “cni”,
“cni-bin-dir”: “/opt/cni/bin”,
“cni-conf-dir”: “/etc/cni/net.d”,
“image-layer-check”: false,
“use-decrypted-key”: true,
“insecure-skip-verify-enforce”: false
}

Перезагружаем сервер:

systemctl reboot

После перезагрузки активируем службы:

systemctl enable –now isulad
systemctl enable kubelet

На первом мастере даём команду инициализации кластера:

kubeadm init –image-repository registry.aliyuncs.com/google_containers –apiserver-advertise-address=172.17.3.31 –cri-socket=/var/run/isulad.sock –service-cidr=10.10.0.0/16 –pod-network-cidr=10.122.0.0/16 –upload-certs –control-plane-endpoint “172.17.3.100:6443” –ignore-preflight-errors=all

Так как у нас файловая система /usr доступна только для чтения, то (прямо в момент инициализации кластера kubernetes) необходимо зайти в каталог манифестов /etc/kubernetes/manifests и исправить в файле kube-controller-manager.yaml пути для диска flexvolume-dir с /usr на /opt (/opt/libexec/kubernetes/kubelet-plugins/volume/exec).

При успешном выполнении команды инициализации кластера kubernetes в выводе будут команды для добавления оставшихся мастеров и узлов worker.

Даём эти команды join на оставшихся узлах (не забывая добавлять в команду —cri-socket=/var/run/isulad.sock), чтобы у нас использовался контейнерный движок iSulad.

После всего устанавливаем в кластер выбранный вами сетевой плагин (CNI). Для каждого плагина CNI необходимо смотреть соответствующую документацию.

Проверка после перезагрузки

команда статуса возвращает нам всегда ok

$ kubectl get cs
Warning: v1 ComponentStatus is deprecated in v1.19+
NAME STATUS MESSAGE ERROR
scheduler Healthy ok
controller-manager Healthy ok
etcd-0 Healthy {“health”:“true”,“reason”:“”}

команда вывода списка узлов показывает их все в статусе ready

$ kubectl get no
NAME STATUS ROLES AGE VERSION
k8s-nestos-m1 Ready control-plane 49m v1.25.9
k8s-nestos-m2 Ready control-plane 47m v1.25.9
k8s-nestos-m3 Ready control-plane 44m v1.25.9
k8s-nestos-w1 Ready <none> 35m v1.25.9
k8s-nestos-w2 Ready <none> 31m v1.25.9

Итоги тестирования

NestOS — является удобной ОС для развёртывания кластера kubernetes. Использование профиля установки transpiled_config.ign позволяет гибко регулировать настройки, которые необходимо внести на этапе установки узла. При этом скрипт установки nestos-installer позволяет создавать свои собственные ISO с внесёнными изменениями, которые необходимы для вашей конкретной инсталляции. Подробнее об этом можно почитать тут: https://docs.openeuler.org/en/docs/22.03_LTS/docs/NestOS/usage.html#generating-a-customized-nestos-iso-file

Доступные только на чтение основные каталоги файловой системы позволяют повысить информационную безопасность системы и защититься от ошибочных действий администратора системы, а гибкая система обновлений позволяет быстро и удобно обновлять систему, при этом обеспечивая быстрый откат изменений.