Translate

неділю, 30 квітня 2023 р.

Kubernetes. Part VII: Setup Cluster With K0s

Kubernetes - це скоріше фреймворк для побудови кластеру, тому способів його розгортання є дуже багато, хоч вони і різні за актуальністю. Останнім часом з'явилось багато managed-рішень від cloud-платформ і менших хостерів на зразок DigitalOcean чи Scaleway. Установка ж на bare-metal інсталяції часто буває складнішою, адже потрібно наперед продумати деякі додаткові аспекти.

Раніше я вже описував створення кластеру Kubernetes за допомогою Kubespray і, виходячи із комітів до його репозиторію, він і досі лишається актуальним. Але цього разу я хочу приділити час іншому проекту по розгортанню K8s - k0s.

k0s - опенсорс проект, головним розробником якого є компанія Mirantis. Код проекту написаний на мові Go і для опису кластеру k0s використовує YAML конфігураційний файл. Має наступні ключові особливості:

  • різні методи інсталяцій:  single-node, multi-node (в тому числі HA майстрів), airgap (установка в середовище із обмеженим інтернет доступом) та Docker (щось на зразок kind)
  • уміє керувати повним життєвим циклом кластеру за допомогою k0sctl: оновлення, бекап чи відновлення
  • у якості CNI із коробки підтримує Kube-Router (за замовчуванням) та Calico. Інші екстеншени також підтримуються, але це вже ручна робота, яка надалі ймовірно дасть про себе знати
  • CRI лише containerd. Історія із custom варіантами аналогічна custom CNI
  • OpenEBS представлений у якості CSI (Container Storage Interface)
  • інші, менш помітні особливості: скромніші системні вимоги, ванільний K8s тощо

На відміну від KubeSpray знання Ansible не потрібні, хоч налаштування, як не дивно, також відбуваються по ssh. Цього разу будемо будувати Kubernetes кластер високої доступності, тобто із 3-ма майстрами, а надалі додамо ще один воркер. Три майстри необхідні для того, щоб запобігти Split-brain процесу, точніше ця вимога необхідна лише для бази etcd, котра працює на майстрах.

 

1. BASIC K0S USAGE. KUBERNETES CONTROL PLANE HA CLUSTER

Cтворимо 4 віртуалки під будь-якою Linux ОС із ядром версії 3.10 або новішим:

192.168.1.11 k8s-m1
192.168.1.12 k8s-m2
192.168.1.13 k8s-m3
192.168.1.21 k8s-s1


Я користуюсь останнім LTS-релізом Ubuntu. Копіюємо ключ на кожну віртуалку для безпарольного доступу. Він має бути попередньо згенерований:

$ ssh-copy-id -i id_rsa.pub ubuntu@192.168.1.11


Видаляємо вміст /etc/machine-id на кожному вузлі, якщо він був створений із загального образу віртуальної машини:

$ :> /etc/machine-id

Після чого перевантажуємо всі майбутні вузли. Створимо конфігураційний файл, котрий буде потрібний для створення k8s-кластеру:

$ k0sctl init --controller-count 3 ubuntu@192.168.1.11 ubuntu@192.168.1.12 ubuntu@192.168.1.13 ubuntu@192.168.1.21 > k0sctl.yaml

Де control plane буде складатись із 3-x машин, а воркера лише із одного.

Вимкнемо телеметрію:

$ export DISABLE_TELEMETRY=true

Запустимо власне створення:

$ k0sctl apply --config k0sctl.yaml
...
k0sctl v0.15.0 Copyright 2022, k0sctl authors.
By continuing to use k0sctl you agree to these terms:
https://k0sproject.io/licenses/eula
INFO ==> Running phase: Connect to hosts
INFO [ssh] 192.168.1.21:22: connected             
INFO [ssh] 192.168.1.11:22: connected             
INFO [ssh] 192.168.1.13:22: connected             
INFO [ssh] 192.168.1.12:22: connected             
INFO ==> Running phase: Detect host operating systems
INFO [ssh] 192.168.1.21:22: is running Ubuntu 22.04.2 LTS
INFO [ssh] 192.168.1.11:22: is running Ubuntu 22.04.2 LTS
INFO [ssh] 192.168.1.12:22: is running Ubuntu 22.04.2 LTS
INFO [ssh] 192.168.1.13:22: is running Ubuntu 22.04.2 LTS
INFO ==> Running phase: Acquire exclusive host lock
INFO ==> Running phase: Prepare hosts    
INFO ==> Running phase: Gather host facts
INFO [ssh] 192.168.1.11:22: using k8s-m1 as hostname
INFO [ssh] 192.168.1.21:22: using k8s-s1 as hostname
INFO [ssh] 192.168.1.13:22: using k8s-m3 as hostname
INFO [ssh] 192.168.1.12:22: using k8s-m2 as hostname
INFO [ssh] 192.168.1.11:22: discovered enp0s3 as private interface
INFO [ssh] 192.168.1.21:22: discovered enp0s3 as private interface
INFO [ssh] 192.168.1.13:22: discovered enp0s3 as private interface
INFO [ssh] 192.168.1.12:22: discovered enp0s3 as private interface
INFO ==> Running phase: Validate hosts   
INFO ==> Running phase: Gather k0s facts
INFO ==> Running phase: Validate facts   
INFO ==> Running phase: Download k0s on hosts
INFO [ssh] 192.168.1.11:22: downloading k0s v1.27.1+k0s.0
INFO [ssh] 192.168.1.13:22: downloading k0s v1.27.1+k0s.0
INFO [ssh] 192.168.1.12:22: downloading k0s v1.27.1+k0s.0
INFO [ssh] 192.168.1.21:22: downloading k0s v1.27.1+k0s.0
INFO ==> Running phase: Configure k0s    
WARN [ssh] 192.168.1.11:22: generating default configuration
INFO [ssh] 192.168.1.12:22: validating configuration
INFO [ssh] 192.168.1.13:22: validating configuration
INFO [ssh] 192.168.1.11:22: validating configuration
INFO [ssh] 192.168.1.12:22: configuration was changed
INFO [ssh] 192.168.1.11:22: configuration was changed
INFO [ssh] 192.168.1.13:22: configuration was changed
INFO ==> Running phase: Initialize the k0s cluster
INFO [ssh] 192.168.1.11:22: installing k0s controller
INFO [ssh] 192.168.1.11:22: waiting for the k0s service to start
INFO [ssh] 192.168.1.11:22: waiting for kubernetes api to respond
INFO ==> Running phase: Install controllers
INFO [ssh] 192.168.1.11:22: generating token      
INFO [ssh] 192.168.1.12:22: writing join token    
INFO [ssh] 192.168.1.12:22: installing k0s controller
INFO [ssh] 192.168.1.12:22: starting service      
INFO [ssh] 192.168.1.12:22: waiting for the k0s service to start
INFO [ssh] 192.168.1.12:22: waiting for kubernetes api to respond
INFO [ssh] 192.168.1.11:22: generating token      
INFO [ssh] 192.168.1.13:22: writing join token    
INFO [ssh] 192.168.1.13:22: installing k0s controller
INFO [ssh] 192.168.1.13:22: starting service      
INFO [ssh] 192.168.1.13:22: waiting for the k0s service to start
INFO [ssh] 192.168.1.13:22: waiting for kubernetes api to respond
INFO ==> Running phase: Install workers  
INFO [ssh] 192.168.1.21:22: validating api connection to https://192.168.1.11:6443
INFO [ssh] 192.168.1.11:22: generating token      
INFO [ssh] 192.168.1.21:22: writing join token    
INFO [ssh] 192.168.1.21:22: installing k0s worker
INFO [ssh] 192.168.1.21:22: starting service      
INFO [ssh] 192.168.1.21:22: waiting for node to become ready
INFO ==> Running phase: Release exclusive host lock
INFO ==> Running phase: Disconnect from hosts
INFO ==> Finished in 2m23s               
INFO k0s cluster version 1.27.1+k0s.0 is now installed
INFO Tip: To access the cluster you can now fetch the admin kubeconfig using:
INFO      k0sctl kubeconfig 
             

Створимо локальний конфіг kubeconfig:

$ k0sctl kubeconfig --config k0sctl.yaml > k0s.config

У останніх версіях k8s control plane вузли не відображаються, адже на них не запущено kubelet:

$ kubectl get nodes --kubeconfig k0s.config
NAME     STATUS   ROLES    AGE   VERSION
k8s-s1   Ready    <none>   43m   v1.27.1+k0s

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


Або ж можна експортувати змінну KUBECONFIG і надалі не писати --kubeconfig ключа:

$ export KUBECONFIG=/path/to/k0s.config

$ kubectl cluster-info

Kubernetes control plane is running at https://192.168.1.11:6443
CoreDNS is running at https://192.168.1.11:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy

To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.


Для того, щоб control plane вузли працювали в режимі високої доступності необхідно поставити перед ними балансувальник. Інакше зв'язок воркерів буде відбуватись за адресою першого майстра, на що вказує вивід попередньої команди. Для цього створимо додатковий вузол:

192.168.1.31 k8s-m-ha

На ньому встановимо HAProxy та запишемо такий конфігураційний файл:

$ vim /etc/haproxy/haproxy.cfg

global
        ...

defaults
        ...
frontend kubeAPI
    bind :6443
    mode tcp
    default_backend kubeAPI_backend
frontend konnectivity
    bind :8132
    mode tcp
    default_backend konnectivity_backend
frontend controllerJoinAPI
    bind :9443
    mode tcp
    default_backend controllerJoinAPI_backend

backend kubeAPI_backend
    mode tcp
    server k8s-m1 192.168.1.11:6443 check check-ssl verify none
    server k8s-m2 192.168.1.12:6443 check check-ssl verify none
    server k8s-m3 192.168.1.13:6443 check check-ssl verify none
backend konnectivity_backend
    mode tcp
    server k8s-m1 192.168.1.11:8132 check check-ssl verify none
    server k8s-m2 192.168.1.12:8132 check check-ssl verify none
    server k8s-m3 192.168.1.13:8132 check check-ssl verify none
backend controllerJoinAPI_backend
    mode tcp
    server k8s-m1 192.168.1.11:9443 check check-ssl verify none
    server k8s-m2 192.168.1.12:9443 check check-ssl verify none
    server k8s-m3 192.168.1.13:9443 check check-ssl verify none

listen stats
   bind *:9000
   mode http
   stats enable
   stats uri /


Не забувайте перевантажити HAProxy. Оновимо конфігураційний файл k0sctl.yaml, куди додамо секцію із щойноствореним балансувальником. Врешті-решт він виглядатиме наступним чином (зверніть увагу на наведену жирним частину):

$ cat k0sctl.yaml

apiVersion: k0sctl.k0sproject.io/v1beta1
kind: Cluster
metadata:
  name: k0s-cluster
spec:
  hosts:
  - ssh:
      address: 192.168.1.11
      user: ubuntu
      port: 22
      keyPath: null
    role: controller
  - ssh:
      address: 192.168.1.12
      user: ubuntu
      port: 22
      keyPath: null
    role: controller
  - ssh:
      address: 192.168.1.13
      user: ubuntu
      port: 22
      keyPath: null
    role: controller
  - ssh:
      address: 192.168.1.21
      user: ubuntu
      port: 22
      keyPath: null
    role: worker
  k0s:
    version: 1.27.1+k0s.0
    dynamicConfig: false
    config:
      spec:
        api:
          externalAddress: 192.168.1.31
          sans:
          - 192.168.1.31
        telemetry:
          enabled: false


Застосуємо зміни:

$ k0sctl apply --config k0sctl.yaml


Оновимо kubeconfig, тут має з'явитись адреса балансувальника https://192.168.1.31:6443:

$ k0sctl kubeconfig --config k0sctl.yaml > k0s.config
$ export KUBECONFIG=./k0s.config

$ kubectl cluster-info
Kubernetes control plane is running at https://192.168.1.31:6443
CoreDNS is running at https://192.168.1.31:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy


To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.


Є можливість використовувати HA-модель на кшталт тій, що в Kubespray, коли на кожній worker ноді працює HAProxy, що балансує запити між майстрами. Але в цьому випадку це вливає лише на високу доступність майстрів для трафіку від воркерів, а не зовнішнього трафіку до control plane. Мабуть можна користуватись одразу двома HA-моделями, але це ймовірно ускладнить розуміння роботи і обслуговування. До того ж цей функціонал поки перебуває в експериментальному стані.

Це все, ми розглянули базовий варіант установки HA-кластера.

 

2. CALICO, ADDITIONAL WORKER NODE

Якщо запал ще не вщух, можна кастомізувати кластер. Цього разу створимо (або оновимо попередній) кластер із наступними параметрами:

  • додамо новий воркер k8s-s2
  • замінимо CNI на Calico (k0s активує за замовчуванням VXLAN інкапсуляцію пакетів)
  • режим роботи kube-proxy змінимо на IPVS (помітно продуктивніший, якщо кількість сервісів вища за 1000)

Якщо цього замало - то можна ознайомитись із додатковими можливостями кастомізації за посиланням, проект k0s доволі непогано документований.

Цього разу просто застосувати зміни буде мало, адже відбувається заміна CNI. Тому спочатку скинемо всі налаштування кластеру (це повністю очистить k8s вузли):

$ k0sctl reset --config k0sctl.yaml 

k0sctl v0.15.0 Copyright 2022, k0sctl authors.
By continuing to use k0sctl you agree to these terms:
https://k0sproject.io/licenses/eula
? Going to reset all of the hosts, which will destroy all configuration and data, Are you sure? Yes
INFO ==> Running phase: Connect to hosts
INFO [ssh] 192.168.1.11:22: connected             
INFO [ssh] 192.168.1.12:22: connected             
INFO [ssh] 192.168.1.21:22: connected             
INFO [ssh] 192.168.1.13:22: connected             
INFO [ssh] 192.168.1.22:22: connected             
INFO ==> Running phase: Detect host operating systems
INFO [ssh] 192.168.1.13:22: is running Ubuntu 22.04.2 LTS
INFO [ssh] 192.168.1.21:22: is running Ubuntu 22.04.2 LTS
INFO [ssh] 192.168.1.11:22: is running Ubuntu 22.04.2 LTS
INFO [ssh] 192.168.1.12:22: is running Ubuntu 22.04.2 LTS
INFO [ssh] 192.168.1.22:22: is running Ubuntu 22.04.2 LTS
INFO ==> Running phase: Acquire exclusive host lock
INFO ==> Running phase: Prepare hosts    
INFO ==> Running phase: Gather k0s facts
INFO [ssh] 192.168.1.12:22: is running k0s controller version 1.27.1+k0s.0
INFO [ssh] 192.168.1.13:22: is running k0s controller version 1.27.1+k0s.0
INFO [ssh] 192.168.1.11:22: is running k0s controller version 1.27.1+k0s.0
INFO [ssh] 192.168.1.21:22: is running k0s worker version 1.27.1+k0s.0
INFO [ssh] 192.168.1.11:22: checking if worker  has joined
INFO [ssh] 192.168.1.22:22: is running k0s worker version 1.27.1+k0s.0
INFO [ssh] 192.168.1.11:22: checking if worker  has joined
INFO ==> Running phase: Reset workers    
INFO [ssh] 192.168.1.22:22: reset                 
INFO [ssh] 192.168.1.21:22: reset                 
INFO ==> Running phase: Reset controllers
INFO [ssh] 192.168.1.11:22: reset                 
INFO [ssh] 192.168.1.12:22: reset                 
INFO [ssh] 192.168.1.13:22: reset                 
INFO ==> Running phase: Reset leader     
INFO [ssh] 192.168.1.11:22: reset                 
INFO ==> Running phase: Release exclusive host lock
INFO ==> Running phase: Disconnect from hosts
INFO ==> Finished in 18s           


Звісно для менше кардинальних змін reset кластеру робити не треба. Конфігураційний файл для поставлених вище цілей буде виглядати наступним чином:

$ cat k0sctl.yaml

apiVersion: k0sctl.k0sproject.io/v1beta1
kind: Cluster
metadata:
  name: k0s-cluster
spec:
  hosts:
  - ssh:
      address: 192.168.1.11
      user: ubuntu
      port: 22
      keyPath: null
    role: controller
  - ssh:
      address: 192.168.1.12
      user: ubuntu
      port: 22
      keyPath: null
    role: controller
  - ssh:
      address: 192.168.1.13
      user: ubuntu
      port: 22
      keyPath: null
    role: controller
  - ssh:
      address: 192.168.1.21
      user: ubuntu
      port: 22
      keyPath: null
    role: worker
  - ssh:
      address: 192.168.1.22
      user: ubuntu
      port: 22
      keyPath: null
    role: worker

  k0s:
    version: 1.27.1+k0s.0
    dynamicConfig: false
    config:
      spec:
        api:
          externalAddress: 192.168.1.31
          sans:
          - 192.168.1.31
        telemetry:
          enabled: false
        network:
          provider: calico
          kubeProxy:
            mode: ipvs


Де 192.168.1.22 - адреса нового вузла k8s-s2. Застосуємо новий конфігураційний файл:

$ k0sctl apply --config k0sctl.yaml

$ k0sctl kubeconfig --config k0sctl.yaml > k0s.config
$ export KUBECONFIG=./k0s.config

$ kubectl get pods -n kube-system

NAME                                       READY   STATUS    RESTARTS   AGE
calico-kube-controllers-55f8c7d5b4-rb9fv   1/1     Running   0          2m39s
calico-node-h72n5                          1/1     Running   0          2m27s
calico-node-w48mq                          1/1     Running   0          2m26s
coredns-878bb57ff-kwbmq                    1/1     Running   0          2m39s
coredns-878bb57ff-n72vj                    1/1     Running   0          2m24s
konnectivity-agent-dskzb                   1/1     Running   0          2m24s
konnectivity-agent-nzm68                   1/1     Running   0          2m23s
kube-proxy-kffbk                           1/1     Running   0          2m27s
kube-proxy-pmm2t                           1/1     Running   0          2m26s
metrics-server-7f86dff975-hxxlm            1/1     Running   0          2m34s

Посилання:
https://docs.k0sproject.io
https://reece.tech/posts/how-to-make-sure-the-kubernetes-controlplane-is-healthy/
https://medium.com/k0sproject/k0s-1-26-released-292db2c6948a

Немає коментарів:

Дописати коментар