[Перевод] k0s: Kubernetes в одном бинарном файле
В нашей новой переводной статье даем краткий обзор на новый дистрибутив Kubernetes. Надеемся, статья окажется интересной для читателей Habr’a.
Пару дней назад друг рассказал мне о новом дистрибутиве Kubernetes от Mirantis под названием k0s. Все мы знаем и любим K8s, не так ли? Нас также покорил K3s, легкий Kubernetes, разработанный Rancher Labs и переданный CNCF некоторое время назад. Пришло время открыть для себя новый дистрибутив k0s!
После краткого знакомства с k0s мы создадим кластер из трех нод, выполнив следующие действия:
- Подготовка трех виртуальных машин (Multipass в действии)
- Установка k0s на каждой из них
- Настройка простого файла конфигурации кластера k0s
- Инициализация кластера
- Получение доступа к кластеру
- Добавление рабочих узлов
- Добавление пользователя
Что такое k0s?
k0s — это новейший дистрибутив Kubernetes. Текущий релиз — 0.8.0. Он был опубликован в декабре 2020 года, а первый коммит всего проекта произошел в июне 2020 года.
k0s поставляется как единый двоичный файл без каких-либо зависимостей от ОС. Таким образом, он определяется как дистрибутив Kubernetes с характеристиками zero-friction/zero-deps/zero-cost (легкость конфигурации / отсутствие зависимостей / бесплатный).
Последний релиз k0s:
- Поставляет сертифицированный (получивший аттестацию центра интернет-безопасности) Kubernetes 1.19
- Использует containerd как среду выполнения контейнера по умолчанию
- Поддерживает архитектуры Intel (x86–64) и ARM (ARM64)
- Использует внутрикластерный etcd
- По умолчанию использует сетевой плагин Calico (тем самым активируя сетевые политики)
- Включает контроллер доступа политик безопасности Pod
- Использует DNS с CoreDNS
- Предоставляет метрики кластера через Metrics Server
- Позволяет использовать горизонтальное автомасштабирование подов (HPA).
В будущих релизах появится много крутых функций, в том числе:
- Среда выполнения компактных виртуальных машин (очень жду возможности протестировать эту функцию)
- Обновление кластера с нулевым временем простоя
- Резервное копирование и восстановление кластера
Впечатляет, не правда ли? Далее мы рассмотрим, как использовать k0s для развертывания кластера из 3 нод.
Подготовка виртуальных машин
Для начала мы создадим три виртуальные машины, каждая из которых будет являться узлом в нашем кластере. В этой статье я пойду быстрым и легким путем и воспользуюсь прекрасным инструментом Multipass (обожаю его) для подготовки локальных виртуальных машин на MacOS.
Следующие команды создают три экземпляра Ubuntu на xhyve. Каждая виртуальная машина имеет 5 ГБ диска, 2 ГБ оперативной памяти и 2 виртуальных процессора (vCPU):
for i in 1 2 3; do
multipass launch -n node$i -c 2 -m 2G
done
Затем мы можем отобразить список виртуальных машин, чтобы убедиться, что все они работают нормально:
$ multipass list
Name State IPv4 Image
node1 Running 192.168.64.11 Ubuntu 20.04 LTS
node2 Running 192.168.64.12 Ubuntu 20.04 LTS
node3 Running 192.168.64.13 Ubuntu 20.04 LTS
Далее мы установим k0s на каждый из этих узлов.
Установка последнего релиза k0s
Последний релиз k0s можно скачать из репозитория GitHub.
У него есть удобный скрипт установки:
curl -sSLf get.k0s.sh | sudo sh
Мы используем этот скрипт, чтобы установить k0s на все наши узлы:
for i in 1 2 3; do
multipass exec node$i --bash -c "curl -sSLf get.k0s.sh | sudo sh"
done
Указанный скрипт устанавливает k0s в /user/bin/k0. Чтобы получить все доступные команды, нужно запустить двоичный файл без аргументов.
Доступные команды k0s
Можем проверить текущую версию:
$ k0s version
v0.8.0
Некоторые команды мы будем использовать и на следующих этапах.
Создание файла конфигурации
Во-первых, необходимо определить файл конфигурации, содержащий информацию, необходимую k0s для создания кластера. На node1 мы можем выполнить команду default-config, чтобы получить полную конфигурацию по умолчанию.
ubuntu@node1:~$ k0s default-config
apiVersion: k0s.k0sproject.io/v1beta1
kind: Cluster
metadata:
name: k0s
spec:
api:
address: 192.168.64.11
sans:
- 192.168.64.11
- 192.168.64.11
extraArgs: {}
controllerManager:
extraArgs: {}
scheduler:
extraArgs: {}
storage:
type: etcd
kine: null
etcd:
peerAddress: 192.168.64.11
network:
podCIDR: 10.244.0.0/16
serviceCIDR: 10.96.0.0/12
provider: calico
calico:
mode: vxlan
vxlanPort: 4789
vxlanVNI: 4096
mtu: 1450
wireguard: false
podSecurityPolicy:
defaultPolicy: 00-k0s-privileged
workerProfiles: []
extensions: null
images:
konnectivity:
image: us.gcr.io/k8s-artifacts-prod/kas-network-proxy/proxy-agent
version: v0.0.13
metricsserver:
image: gcr.io/k8s-staging-metrics-server/metrics-server
version: v0.3.7
kubeproxy:
image: k8s.gcr.io/kube-proxy
version: v1.19.4
coredns:
image: docker.io/coredns/coredns
version: 1.7.0
calico:
cni:
image: calico/cni
version: v3.16.2
flexvolume:
image: calico/pod2daemon-flexvol
version: v3.16.2
node:
image: calico/node
version: v3.16.2
kubecontrollers:
image: calico/kube-controllers
version: v3.16.2
repository: ""
telemetry:
interval: 10m0s
enabled: true
Помимо прочего, это позволяет нам определить:
- Параметры запуска сервера API, диспетчера контроллеров и планировщика
- Хранилище, которое можно использовать для сохранения информации о кластере (etcd)
- Сетевой плагин и его конфигурацию (Calico)
- Версию образов контейнеров с компонентами управления
- Некоторые дополнительные схемы управления, которые следует развернуть при запуске кластера
Мы могли бы сохранить эту конфигурацию в файл и адаптировать ее под свои нужды. Но в этой статье мы воспользуемся очень простой конфигурацией и сохраним ее в /etc/k0s/k0s.yaml.
apiVersion: k0s.k0sproject.io/v1beta1
kind: Cluster
metadata:
name: k0s
spec:
api:
address: 192.168.64.11
sans:
- 192.168.64.11
network:
podCIDR: 10.244.0.0/16
serviceCIDR: 10.96.0.0/12
Примечание: Так как мы инициализируем кластер на узле node1, этот узел будет обслуживать сервер API. IP-адрес этого узла используется в api.address и api.sans (альтернативные имена субъектов) в приведенном выше файле конфигурации. Если бы у нас были дополнительные главные узлы и балансировщик нагрузки над ними, мы бы также использовали в настройках api.sans IP-адрес каждого узла и балансировщика нагрузки (или соответствующее доменное имя).
Инициализация кластера
Сначала мы создаем systemd unit на node1 для управления k0s.
[Unit]
Description="k0s server"
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
ExecStart=/usr/bin/k0s server -c /etc/k0s/k0s.yaml --enable-worker
Restart=always
Основная команда здесь указана в ExecStart; она запускает сервер k0s с той конфигурацией, которую мы сохранили в наш файл на предыдущем этапе. Мы также указываем параметр --enable-worker, чтобы этот первый главный узел также функционировал как рабочий.
Затем мы копируем этот файл в /lib/systemd/system/k0s.service, перезагружаем systemd и запускаем недавно созданную службу.
ubuntu@node1:~$ sudo systemctl daemon-reload
ubuntu@node1:~$ sudo systemctl start k0s.service
Ради любопытства можно проверить процессы, запущенные сервером k0s:
ubuntu@node1:~$ sudo ps aux | awk ‘{print $11}’ | grep k0s
/usr/bin/k0s
/var/lib/k0s/bin/etcd
/var/lib/k0s/bin/konnectivity-server
/var/lib/k0s/bin/kube-controller-manager
/var/lib/k0s/bin/kube-scheduler
/var/lib/k0s/bin/kube-apiserver
/var/lib/k0s/bin/containerd
/var/lib/k0s/bin/kubelet
Из выходных данных выше мы видим, что все основные компоненты запущены (kube-apiserver, kube-controller-manager, kube-scheduler и т. д.), а также компоненты, общие для главных и рабочих узлов (containerd, kubelet). k0s отвечает за управление всеми этими компонентами.
Теперь мы имеем кластер из 1 ноды. На следующем этапе мы увидим, как получить к нему доступ.
Получение доступа к кластеру
Сначала нам необходимо получить файл kubeconfig, сгенерированный во время создания кластера; он был создан на node1 в /var/lib/k0s/pki/admin.conf. Этот файл нужно использовать для настройки kubectl на локальной машине.
Сначала получаем kubeconfig кластера из node1:
# Get kubeconfig file
$ multipass exec node1 cat /var/lib/k0s/pki/admin.conf > k0s.cfg
Далее заменяем внутренний IP-адрес на внешний IP-адрес node1:
# Replace IP address
$ NODE1_IP=$(multipass info node1 | grep IP | awk '{print $2}')
sed -i '' "s/localhost/$NODE1_IP/" k0s.cfg
Затем выполняем конфигурацию нашего локального клиента kubectl для связи с сервером k0s API:
export KUBECONFIG=$PWD/k0s.cfg
Наверняка одной из первых команд, которые мы запускаем при входе в новый кластер, является та, которая отображает список всех доступных узлов, — давайте попробуем:
$ kubectl get no
NAME STATUS ROLES AGE VERSION
node1 Ready 78s v1.19.4
Здесь нет ничего удивительного. Ведь node1 является не только главным, но и рабочим узлом нашего первого кластера благодаря флагу --enable-worker, который мы указали в команде запуска. Без этого флага node1 был бы только рабочим и не отображался бы в списке узлов здесь.
Добавление рабочих узлов
Чтобы добавить в кластер node2 и node3, сначала нам нужно создать токен соединения из node1 (это довольно распространенный этап, так как он используется в кластерах Docker Swarm и Kubernetes, созданных с помощью kubeadm).
$ TOKEN=$(k0s token create --role=worker)
Вышеуказанная команда генерирует длинный (очень длинный) токен. Используя его, мы можем присоединить к кластеру node2 и node3:
ubuntu@node2:~$ k0s worker $TOKEN
ubuntu@node3:~$ k0s worker $TOKEN
Примечание: В реальном кластере мы бы использовали systemd (или другой супервизор) для управления процессами k0s для рабочих узлов, как мы сделали для главного узла.
Наш трехузловой кластер запущен и работает, в чем мы можем убедиться, отобразив список узлов перечислив узлы еще раз:
$ kubectl get no
NAME STATUS ROLES AGE VERSION
node1 Ready 30m v1.19.4
node2 Ready 35s v1.19.4
node3 Ready 32s v1.19.4
Мы также можем проверить поды, работающие во всех пространствах имен:
Список подов, работающих в кластере во всех пространствах имен
Здесь следует отметить несколько моментов:
- Как обычно, мы видим поды kube-proxy, поды сетевых плагинов (на основе Calico), а также под для CoreDNS.
- Поды api-server, scheduler и controller-manager не отображаются в этом списке, поскольку они выполняются как обычные процессы, а не внутри подов.
Добавление пользователя
Версия k0s 0.8.0 содержит подкоманду user. Это позволяет создать kubeconfig для дополнительного пользователя/группы. Например, следующая команда создает для нового пользователя файл kubeconfig с названием demo, который находится внутри имитированной группы (imaginary group) с названием development.
Примечание: В Kubernetes пользователи и группы управляются администратором вне кластера, то есть в K8s нет ресурса «пользователь-не-группа».
$ sudo k0s user create demo --groups development > demo.kubeconfig
Для лучшего понимания мы извлечем сертификат клиента из этого файла kubeconfig и декодируем его из представления base64:
$ cat demo.kubeconfig | grep client-certificate-data | awk '{print $2}' | base64 --decode > demo.crt
Затем мы используем команду openssl чтобы получить содержимое сертификата:
ubuntu@node1:~$ openssl x509 -in demo.crt -noout -text
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
71:8b:a4:4d:be:76:70:8a:...:07:60:67:c1:2d:51:94
Signature Algorithm: sha256WithRSAEncryption
Issuer: CN = kubernetes-ca
Validity
Not Before: Dec 2 13:50:00 2020 GMT
Not After : Dec 2 13:50:00 2021 GMT
Subject: O = development, CN = demo
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public-Key: (2048 bit)
Modulus:
00:be:87:dd:15:46:91:98:eb:b8:38:34:77:a4:99:
da:4b:d6:ca:09:92:f3:29:28:2d:db:7a:0b:9f:91:
65:f3:11:bb:6c:88:b1:8f:46:6e:38:71:97:b7:b5:
9b:8d:32:86:1f:0b:f8:4e:57:4f:1c:5f:9f:c5:ee:
40:23:80:99:a1:77:30:a3:46:c1:5b:3e:1c:fa:5c:
- Свойство issuer — это kubernetes-ca, который является центром сертификации нашего кластера k0s.
- Subject — это O = development, CN = demo; эта часть важна, так как именно здесь появляется имя и группа пользователя. Так как сертификат подписан центром сертификации кластера, подключаемый модуль на api-server может аутентифицировать пользователя/группу по общему имени (CN) и организации (O) в теме сертификата.
Сначала мы даем команду kubectl использовать контекст, определенный в этом новом файле kubeconfig:
$ export KUBECONFIG=$PWD/demo.kubeconfig
Затем еще раз отображаем список узлов перечисляем узлы кластера:
$ kubectl get no
Error from server (Forbidden): nodes is forbidden: User "demo” cannot list resource "nodes” in API group "” at the cluster scope
Это сообщение об ошибке было ожидаемым. Даже если api-server
идентифицировал пользователя (сертификат, отправленный вместе с запросом пользователя, был подписан центром сертификации кластера), он не имеет права выполнять какие-либо действия в кластере.
Дополнительные права можно легко добавить, создав Role/ClusterRole
и привязав их к пользователю при помощи RoleBinding/ClusterRoleBinding
, но эту задачу я оставляю в качестве упражнения для читателя.
Заключение
k0s определенно стоит рассмотреть. Такой подход, когда единый двоичный файл управляет всеми процессами, очень интересен.
В данной статье представлен только краткий обзор k0s, но я обязательно буду отслеживать его развитие и посвящу будущие статьи этому новому и перспективному дистрибутиву Kubernetes. Некоторые из будущих функций кажутся действительно многообещающими, и я с нетерпением жду возможности их протестировать.