[Перевод] k0s: Kubernetes в одном бинарном файле

В нашей новой переводной статье даем краткий обзор на новый дистрибутив Kubernetes. Надеемся, статья окажется интересной для читателей Habr’a.


Пару дней назад друг рассказал мне о новом дистрибутиве Kubernetes от Mirantis под названием k0s. Все мы знаем и любим K8s, не так ли? Нас также покорил K3s, легкий Kubernetes, разработанный Rancher Labs и переданный CNCF некоторое время назад. Пришло время открыть для себя новый дистрибутив k0s!
qhs0qxrxoapdmhlzasdpyet4ze0.jpeg

После краткого знакомства с 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. Чтобы получить все доступные команды, нужно запустить двоичный файл без аргументов.

exzmdfcrtntrqaudhjklgwrlb2s.png
Доступные команды 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


Мы также можем проверить поды, работающие во всех пространствах имен:

i_jke9icy5psrsgz_2dg85jgnak.png
Список подов, работающих в кластере во всех пространствах имен

Здесь следует отметить несколько моментов:

  • Как обычно, мы видим поды 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. Некоторые из будущих функций кажутся действительно многообещающими, и я с нетерпением жду возможности их протестировать.

© Habrahabr.ru