ALT Container OS подветка K8S. Создание HA кластера: различия между версиями

Материал из ALT Linux Wiki
Нет описания правки
 
(не показано 65 промежуточных версий 2 участников)
Строка 1: Строка 1:
== Создание высоко-доступного (Highly Available) kubernetes-кластера с несколькими мастерами (control plane) в среде libvirt ==
[[Категория:Руководства]]


[[Файл:K8s cluster.png]]
[[Файл:K8s cluster.png]]
== Настройка узлов ==


=== Создание ethernet-моста (bridge) ===
=== Создание ethernet-моста (bridge) ===
Строка 7: Строка 9:
Для выделения IP-адресов узлов кластера в рамках IP-адресов локальной сети необходимо в интерфейсе создания сетевых интерфейсов
Для выделения IP-адресов узлов кластера в рамках IP-адресов локальной сети необходимо в интерфейсе создания сетевых интерфейсов
создать в HOST-системе создать мост (например ''br0'') и связать с ним основной ethernet-интерфейс локальной сети.
создать в HOST-системе создать мост (например ''br0'') и связать с ним основной ethernet-интерфейс локальной сети.
[[Файл:Ifaceconfig.png]]
[[Файл:Vmnetconfig1.png]]
 
В нашем примере примем IP-адрес HOST-системы - ''10.150.0.4/24'' в подсети ''10.150.0.0/24''.
В нашем примере примем IP-адрес HOST-системы - ''10.150.0.4/24'' в подсети ''10.150.0.0/24''.


Строка 17: Строка 18:
* Состояние связи: активно
* Состояние связи: активно
[[Файл:Vmnetconfig.png]]
[[Файл:Vmnetconfig.png]]


При развертывания виртуальных машин им будут присваиваться статические адреса из подсети ''10.150.0.0/24''.
При развертывания виртуальных машин им будут присваиваться статические адреса из подсети ''10.150.0.0/24''.
Строка 23: Строка 28:


Проверьте в sysctl настройку переменных ядра :
Проверьте в sysctl настройку переменных ядра :
  sysctl -a | grep net.bridge.bridge-nf-call
  # sysctl -a | grep net.bridge.bridge-nf-call
  net.bridge.bridge-nf-call-arptables = 0
  net.bridge.bridge-nf-call-arptables = 0
  net.bridge.bridge-nf-call-ip6tables = 0
  net.bridge.bridge-nf-call-ip6tables = 0
  net.bridge.bridge-nf-call-iptables = 0
  net.bridge.bridge-nf-call-iptables = 0


Перечисленные переменные должны иметь нулевое значение, иначе связь между виртуальными машинами не поддерживается.
Перечисленные переменные должны иметь нулевое значение, иначе связь между виртуальными может
фильтроваться правилами ''iptables'', ''arptables''.


Если вывод команду пустой, подключите модуль ''br_netfilter'':
Если вывод команду пустой, подключите модуль ''br_netfilter'':
Строка 48: Строка 54:


Для работы высоко-доступного (Highly Available) kubernetes-кластера необходимо на всех трех узлах поднять балансировщик, распределяющий входящие запросы между мастер-узлами кластера.
Для работы высоко-доступного (Highly Available) kubernetes-кластера необходимо на всех трех узлах поднять балансировщик, распределяющий входящие запросы между мастер-узлами кластера.
Для поддержки отказоустойчивости самого балансировщика создают несколько HOST-систем на которых запускают балансировщики  
Для поддержки отказоустойчивости самого балансировщика на  HOST-системах  запускаются балансировщики.
разделяющий один общий виртуальный адрес. В данном примере мы будем использовать один балансировщик, располагающийся в HOST-системе.
Одному их балансировщику присваивается виртуальный адрес ''10.150.0.160''.
При выходе из строя или потери доступности основного балансировщика виртуальный адрес присваивается
другому доступному балансировщику.  


Для создания балансировщика установите пакеты:
Для создания балансировщика установите пакеты:
Строка 111: Строка 119:
В секции ''balance roundrobin'' укажите список имен, IP-адресов и портов 6443 API-интерфейсов мастер-узлов.
В секции ''balance roundrobin'' укажите список имен, IP-адресов и портов 6443 API-интерфейсов мастер-узлов.


HAPROXY будет принимать входящие соединения на порту ''8443'' и передавать их на один из перечисленных master-серверов на порт ''6443''.
''haproxy'' будет принимать входящие соединения на порту ''8443'' и передавать их на один из  
перечисленных ''master-серверов'' на порт ''6443''.


==== Конфигурирование keepalived ====
==== Конфигурирование keepalived ====
Строка 150: Строка 159:
На остальных параметр ''state'' в значение ''BACKUP'' и параметр ''priority'' в значение ''100''.
На остальных параметр ''state'' в значение ''BACKUP'' и параметр ''priority'' в значение ''100''.


Скрипт ''/etc/keepalived/check_apiserver.sh'' проверят доступность балансировщика 'haproxy':
Скрипт ''/etc/keepalived/check_apiserver.sh'' проверяет доступность балансировщика ''haproxy'':
  #!/bin/sh
  #!/bin/sh
   
   
Строка 174: Строка 183:
  chmod a+x /etc/keepalived/check_apiserver.sh
  chmod a+x /etc/keepalived/check_apiserver.sh


При работающем балансировщики скрипт должен завершаться с кодом ''0''.
При работающем балансировщике и хотя бы одному доступному порту ''6443'' на ''master-узлах'' скрипт
должен завершаться с кодом ''0''.


==== Запуск сервисов ====
==== Запуск сервисов ====
Строка 182: Строка 192:
  systemctl enable keepalived --now
  systemctl enable keepalived --now


Так как master-узлы k8s еще не подняты ''haproxy'' выведет на консоль сообщение
Так как ''master-узлы'' ''k8s'' еще не подняты ''haproxy'' выведет на консоль сообщение
  haproxy[nnnn]: backend apiserver has no server available!
  haproxy[nnnn]: backend apiserver has no server available!
<!--
<!--
Строка 191: Строка 201:
-->
-->


=== Конфигурирование и запуск кластера ===
== Конфигурирование и запуск кластера ==
 
=== Получение образов ветки kubetnetes ===
 
Скачать образ можно [http://altcos.altlinux.org/?arch=x86_64&repo=sisyphus&ref=k8s тут]


==== Описание базовых butane YML-файлов ====
=== Описание базовых butane YML-файлов ===


На основе базовых butane YML-файлов программой ''butane'' создаются ignition-файлы, используемые для создания
На основе базовых butane YML-файлов программой ''butane'' создаются ignition-файлы, используемые для создания
Строка 223: Строка 237:
  mkpasswd --method=yescrypt
  mkpasswd --method=yescrypt


В поле ''ssh_authorized_keys'' массив открытых ключей пользователей для которых необходим беспарольный доступ к пользователю altcos виртуалной машины.
В поле ''ssh_authorized_keys'' - массив открытых ключей пользователей для которых необходим беспарольный доступ к пользователю altcos виртуалной машины.


В файл ''/etc/sudoers.d/altcos'' записывается строка, обеспечивающая беспарольный доступ пользователя ''altcos'' к ''sudo''.
В файл ''/etc/sudoers.d/altcos'' записывается строка, обеспечивающая беспарольный доступ пользователя ''altcos'' к ''sudo''.
Строка 250: Строка 264:
  version: 1.3.0
  version: 1.3.0
  storage:
  storage:
  disks:
  disks:
    - device: /dev/sdb # создадим на диске /dev/sdb партицию /dev/sdb1
    - device: /dev/sdb # создадим на диске /dev/sdb партицию /dev/sdb1
      wipe_table: true
      wipe_table: true
      partitions:
      partitions:
        - number: 1
        - number: 1
          label: docker
          label: docker
  filesystems:
  filesystems:
    - device: /dev/sdb1 # создадим в партиции /dev/sdb1 файловую систему BTRFS
    - device: /dev/sdb1 # создадим в партиции /dev/sdb1 файловую систему BTRFS
      format: btrfs
      format: btrfs
      wipe_filesystem: true
      wipe_filesystem: true
      label: docker
      label: docker
      with_mount_unit: false
      with_mount_unit: false
  directories:
  directories:
    - path: /var/mnt/docker # создадим каталог монтирования тома
    - path: /var/mnt/docker # создадим каталог монтирования тома
      overwrite: true
      overwrite: true
  files:
  files:
    - path: /etc/fstab # добавим строку монтирования btrfs-тома на каталог /var/mnt/docker
    - path: /etc/fstab # добавим строку монтирования btrfs-тома на каталог /var/mnt/docker
      append:
      append:
        - inline: |
        - inline: |
            LABEL=docker /var/mnt/docker btrfs defaults 0 2
            LABEL=docker /var/mnt/docker btrfs defaults 0 2
    # заменим в конфигурации dockerd-демона:
            /var/mnt/docker/docker/ /var/lib/docker none bind 0 0
    # тип storage-driver с overlay2 на btrfs
            /var/mnt/docker/containers/ /var/lib/containers/ none bind 0 0
    # изменим каталог размещения данных docker-демона  с /var/lib/docker на /var/mnt/docker/docker/
    # заменим в конфигурации dockerd-демона:
     - path: /etc/docker/daemon.json
    # тип storage-driver с overlay2 на btrfs
    - path: /etc/docker/daemon.json
      overwrite: true
      contents:
        inline: |
          {
          "init-path": "/usr/bin/tini",
          "userland-proxy-path": "/usr/bin/docker-proxy",
          "default-runtime": "docker-runc",
          "live-restore": false,
          "log-driver": "journald",
          "runtimes": {
            "docker-runc": {
              "path": "/usr/bin/runc"
            }
          },
          "default-ulimits": {
            "nofile": {
            "Name": "nofile",
            "Hard": 64000,
            "Soft": 64000
            }
          },
          "data-root": "/var/lib/docker/",
          "storage-driver": "btrfs"
          }
    # заменим в конфигурации CRI-O тип driver с overlay на btrfs
    - path: /etc/crio/crio.conf.d/00-btrfs.conf
      overwrite: true
      contents:
        inline: |
          [crio]
          root = "/var/lib/containers/storage"
          runroot = "/var/run/containers/storage"
          storage_driver = "btrfs"
          storage_option = []
          [crio.runtime]
          conmon = "/usr/bin/conmon"
          [crio.network]
          plugin_dirs = [
            "/usr/libexec/cni",
            "/opt/cni/bin/"
          ]
    # заменим в конфигурации podman тип driver с overlay2 на btrfs
    - path: /etc/containers/storage.conf
      overwrite: true
      contents:
        inline: |
          [storage]
          driver = "btrfs"
          runroot = "/var/run/containers/storage"
          graphroot = "/var/lib/containers/storage"
          [storage.options]
          additionalimagestores = [
          ]
          [storage.options.overlay]
          mountopt = "nodev,metacopy=on"
    # исключим определение flannel-подсети в CRIO
     - path: /etc/cni/net.d/100-crio-bridge.conf
       overwrite: true
       overwrite: true
       contents:
       contents:
         inline: |
         inline: |
           {
           {"type": "bridge"}
          "init-path": "/usr/bin/tini",
 
          "userland-proxy-path": "/usr/bin/docker-proxy",
 
          "default-runtime": "docker-runc",
В текущей версии пакета ''cri-o-1.22.1-alt1.x86_64'' файл конфигурации ''/etc/cni/net.d/100-crio-bridge.conf'' задает
          "live-restore": false,
адрес подсети для интерфейса ''cni0''. Для корректной работы сетевого плугина ''flannel'' необходимо исключить определение
          "log-driver": "journald",
подсети, так как ''flannel'' самостоятельно на основе полученной конфигурации сети конфигурирует IP-адрес интерфейса ''cni0''.
          "runtimes": {
 
            "docker-runc": {
Plugin ''flannel'' конфигурирования cni-интерфайса в образе ''rancher/mirrored-flannelcni-flannel-cni-plugin'' располагается в каталоге ''/opt/cni/bin/''. В обычной Linux-системе при запуске POD'а это ''plugin'' копируется в каталог ''/usr/libexec/cni''
              "path": "/usr/bin/runc"
откуда он загружается plugin'ом ''CRI'' (''Container Runtime Interface''). В ''ALTCOS'' каталог ''/usr'' смонтирован в режиме
            }
'''только не чтение''' и копирование не производится.
          },
Для решения этой проблемы в подключаемых узлах добавляется файл конфигурации
          "default-ulimits": {
''/etc/crio/crio.conf.d/00-btrfs.conf''. 
            "nofile": {
Он настраивает `cri-o` на использование файловой системы btrfs и
            "Name": "nofile",
в параметре ''plugin_dirs'' для подключения ''plugins'' кроме стандартного каталога ''/usr/libexec/cni'' использует каталог ''/opt/cni/bin/''.
            "Hard": 64000,
            "Soft": 64000
            }
          },
          "data-root": "/var/mnt/docker/docker/",
          "storage-driver": "btrfs"
          }
    # заменим в конфигурации CRI-O, podman:
    # тип driver с overlay2 на btrfs
    # изменим каталог размещения данных docker-демона  с /var/lib/containers/storage на /var/mnt/docker/containers/storage
    - path: /etc/containers/storage.conf
      overwrite: true
      contents:
        inline: |
          [storage]
          driver = "btrfs"
          runroot = "/var/run/containers/storage"
          graphroot = "/var/mnt/docker/containers/storage"
          [storage.options]
          additionalimagestores = [
          ]
          [storage.options.overlay]
          mountopt = "nodev,metacopy=on"


===== Файл initk8s.yml описания сервиса инициализации кластера k8s =====
===== Файл initk8s.yml описания сервиса инициализации кластера k8s с сетью flannel =====


Файл описывает сервис ''initk8s'' инициализации кластера   
Файл описывает сервис ''initk8s'' инициализации кластера   
Строка 337: Строка 385:
         ExecStart=kubeadm init --cri-socket=/var/run/crio/crio.sock \
         ExecStart=kubeadm init --cri-socket=/var/run/crio/crio.sock \
                           --pod-network-cidr=10.244.0.0/16 \
                           --pod-network-cidr=10.244.0.0/16 \
                          --ignore-preflight-errors=SystemVerification \
                          --kubernetes-version=v1.20.12 \
                           --control-plane-endpoint 10.150.0.160:8443 \
                           --control-plane-endpoint 10.150.0.160:8443 \
                           --upload-certs
                           --upload-certs
        ExecStartPost=kubectl apply -f /usr/share/k8s/flannel/kube-flannel.yml
        #ExecStartPost=kubectl taint nodes master01 node-role.kubernetes.io/master-
         [Install]
         [Install]
         WantedBy=multi-user.target
         WantedBy=multi-user.target
   
   
Если вы разворачиваете кластер в локальной сети без доступа или с низкоскоростным доступом в Интернет,
Если вы разворачиваете кластер в локальной сети без доступа или с низкоскоростным доступом в Интернет,
то необходимо:
то необходимо оставить вызов скрипта ''loadDockerArchiveImages.sh'' разворачивания архивов ''docker-образов'', хранящихся в ostree-образе.
* оставить вызов скрипта ''loadDockerArchiveImages.sh'' разворачивания архивов ''docker-образов'', хранящихся в ostree-образе;
* указать версию 'kubernetes' в параметре '' kubernetes-version'' (версию можно узнать вызвав команду <tt>rpm -qa --dbpath /lib/rpm/  | grep kubernetes</tt> или <tt>kubectl version</tt>);


Если Вы планируете загрузить ''docker-образы'' из Интернет, то <tt>ExecStartPre</tt> и <tt>--kubernetes-version=</tt> можно удалить.
Если Вы планируете загрузить ''docker-образы'' из Интернет, то строку ''ExecStartPre'' можно удалить.


В отличие от варианта разворачивания кластера с одним master-узлом в команду <tt>kubeadm init</tt> добалены параметры:
В отличие от варианта разворачивания кластера с одним ''master-узлом'' в команду ''kubeadm init'' добавлены параметры:
* ''control-plane-endpoint'' в котором указан URL основного ''haproxy''-сервера, работающего на виртуальном адресе ''10.150.0.160'' и предоставляющий доступ на порту ''8443''.
* ''control-plane-endpoint'' в котором указан URL основного ''haproxy''-сервера, работающего на виртуальном адресе ''10.150.0.160'' и предоставляющий доступ на порту ''8443''.
* ''upload-certs'', обеспечивающий загрузку сгенерированных сертификатов и раздачу их другим master-узлам.
* ''upload-certs'', обеспечивающий загрузку сгенерированных сертификатов и раздачу их другим ''master-узлам''.
 
Сетевой драйвер ''flannel'' обеспечивает выделение адресов для POD'ов и роутинг в рамках подсети ''10.244.0.0/16''.
Данная подсеть при инициализации кластера указывается параметром ''pod-network-cidr''.
 
 
При подключении узла к кластеру сетевой драйвер ''flannel'' запрашивает у планировщика подсетку ``10.244.x.0/24''
и согласно полученной подсетке он
* создает интерфейс flannel.x и присваевает ему адрес ``10.244.x.0/32''
* при создании первого POD'а конфирурирует интерфейс ''cni0'' с адресом ''10.244.x.1/32''.
Все создаваемые на этом узле POD'ы получают IP-адреса ''10.244.x.2-255/32''.


===== Файл k8senv.yml создание profile инициализации kubernetes-среды =====
===== Файл k8senv.yml создание profile инициализации kubernetes-среды =====
Строка 381: Строка 437:
             fi
             fi
           fi
           fi
Файл обеспечивает создание профайла ''/etc/profile.d/kube.sh''.
Файл обеспечивает создание профайла ''/etc/profile.d/kube.sh''.
Для привелигированного пользователя (''sudo -i bash'') в среду добавляется  
Для привелигированного пользователя (''sudo -i bash'') в среду добавляется  
переменная ''KUBECONFIG''.
переменная ''KUBECONFIG''.
Для непривилигиванного формирование каталога ''.kube''.
Для непривилигиванного пользователя обеспечивается формирование каталога ''.kube''.


===== Файл mastersUsers.yml описания открытых ключей мастер-узлов кластера =====
===== Файл mastersUsers.yml описания открытых ключей мастер-узлов кластера =====


Данный файл обеспечивает под пользователем ''altcos'' беспарольный доступ с ''master''-узлов на 'worker'-узлы.
Данный файл обеспечивает для пользователя ''altcos'' беспарольный доступ с ''master''-узлов на 'worker'-узлы.
Структура файла следующая:
Структура файла следующая:
  variant: fcos
  variant: fcos
Строка 400: Строка 455:
         - ssh-rsa ... altcos@master02
         - ssh-rsa ... altcos@master02
         - ssh-rsa ... altcos@master03   
         - ssh-rsa ... altcos@master03   
В него помещаются открытые ключи пользователей ''altcos'' ''master''-узлов.
В него помещаются открытые ключи пользователей ''altcos'' ''master''-узлов кластера.


====  Конфигурирование и запуск мастер-узлов ====
===  Конфигурирование и запуск мастер-узлов ===


===== Создание butane-YML файлов описания конфигурации master-узлов =====
==== Создание butane-YML файлов описания конфигурации master-узлов ====


YML-файл для первого узла ''master01'':
YML-файл ''master_01.yml'' для первого узла ''master01'':
  variant: fcos
  variant: fcos
  version: 1.3.0
  version: 1.3.0
Строка 415: Строка 470:
       - local: hosts.ign
       - local: hosts.ign
       - local: btrfs.ign
       - local: btrfs.ign
       - local: k8senv.ign
       - local: k8senv.ign
       - local: initk8s.ign
       - local: initk8s.ign
  storage:
  storage:
Строка 435: Строка 490:
           Gateway=10.150.0.1
           Gateway=10.150.0.1
           DNS=10.150.0.1
           DNS=10.150.0.1
В элементе ''ignition.config.merge'' описываются ignition-файлы сгенерированные командой ''butane'' из вышеперечисленных YML_файлов.
В элементе ''ignition.config.merge'' описываются ignition-файлы сгенерированные командой ''butane'' из вышеперечисленных YML-файлов.


В файле ''/etc/hostname'' указывается имя узла ''master01''.
В файле ''/etc/hostname'' указывается имя узла ''master01''.
В файле ''/etc/systemd/network/20-wired.network'' описываются адрес ''Address'' узла, шлюз ''Gateway'' и ''DNS'' для узла.
В файле ''/etc/systemd/network/20-wired.network'' описываются адрес ''Address'' узла, шлюз ''Gateway'' и ''DNS'' для узла кластера.


Остальные YML-файлы конфигурации master-узлов ''master_02.yml'', ''master_03.yml'' описываются схожим образом за исключением:
Остальные YML-файлы конфигурации ''master''-узлов ''master_02.yml'', ''master_03.yml'' описываются схожим образом за исключением:
*  файл описания сервиса ''local: initk8s.ign'' можно не подключать, так как инициализация кластера производится с узла ''master01'';
*  файл описания сервиса ''local: initk8s.ign'' не подключается, так как инициализация кластера производится на узле ''master01'';
* в файле  ''/etc/hostname'' указываются имена узлов ''master01'' и ''master02'' соответственно;
* в файле  ''/etc/hostname'' указываются имена узлов ''master02'' и ''master03'' соответственно;
* в файле '/etc/systemd/network/20-wired.network'' в поле ''Address'' указываются IP-адреса master-узлов ''10.150.0.162'' и ''10.150.0.163'' соответственно.
* в файле '/etc/systemd/network/20-wired.network'' в поле ''Address'' указываются IP-адреса master-узлов ''10.150.0.162'' и ''10.150.0.163'' соответственно.


===== Скрипт createNode.sh запуска master и worker узлов =====
Пример YML-файл ''master_02.yml'' для первого узла ''master02'':
variant: fcos
version: 1.3.0
ignition:
  config:
    merge:
      - local: users.ign
      - local: hosts.ign
      - local: btrfs.ign
      - local: k8senv.ign 
storage:
  files:
    - path: /etc/hostname
      overwrite: true
      contents:
        inline:
          master02
    - path: /etc/systemd/network/20-wired.network
      overwrite: true
      contents:
        inline: |
          [Match]
          Name=eth0
          [Network]
          DHCP=no
          Address=10.150.0.162/24
          Gateway=10.150.0.1
          DNS=10.150.0.1
 
==== Скрипт createNode.sh запуска master и worker узлов ====


Исходный код скрипта:
Исходный код скрипта:
  #!/bin/sh
  #!/bin/sh
  case $1 in  
  case $1 in  
  master | worker) type=$1;;
  master) Mem=4096;break;;
  worker) Mem=6144;break;;
   *) echo "Тип нод может быть только master или worker"; exit 1;
   *) echo "Тип нод может быть только master или worker"; exit 1;
  esac
  esac
Строка 468: Строка 554:
  sdbDisk=${prefix}_sdb.qcow2
  sdbDisk=${prefix}_sdb.qcow2
  ignFile=$PWD/${prefix}.ign
  ignFile=$PWD/${prefix}.ign
  ylmfiles="users k8senv btrfs hosts initmaster $prefix mastersUsers"
  ymlfiles="users k8senv btrfs hosts initk8s mastersUsers $prefix"
  for ymlfile in $ylmfiles
  for ymlfile in $ymlfiles
  do
  do
   if ! butane -d . -p $ymlfile.yml > $ymlfile.ign
   if ! butane -d . -p $ymlfile.yml > $ymlfile.ign
Строка 480: Строка 566:
  virt-install --name $prefix \
  virt-install --name $prefix \
   --vcpus 2 \
   --vcpus 2 \
   --ram 2048 \
   --ram $Mem \
   --os-variant altlinux1.0 \
   --os-variant altlinux1.0 \
   --import \
   --import \
Строка 491: Строка 577:
# Тип узла - ''master'' или ''worker''.
# Тип узла - ''master'' или ''worker''.
# Номер узла (''1'', ''2'', ''3'', ...).
# Номер узла (''1'', ''2'', ''3'', ...).
# Тропа до файла 'qcow2'-образа.
# Тропа до файла ''qcow2''-образа.


Скрипт на основе типа виртуальной машины и ее номера формирует ''prefix'' ''${type}_${N}'' который используется
Скрипт на основе типа виртуальной машины и ее номера формирует ''prefix'' ''${type}_${N}'' (например ''master_01'') который используется
для определения:
для определения:
* имен основных ''yml'' и  ''ignitio'' файлов;
* имен основных ''yml'' и  ''ignition'' файлов;
* имен основного (''/dev/sda'') и дополнительного ''btrfs'' (''/dev/sdb'') имен qcow2-файлов дисков;
* имен основного (''/dev/sda'') и дополнительного ''btrfs'' (''/dev/sdb'') qcow2-файла дисков;
* имен виртуальных машин.
* имен виртуальных машин.


Далее производятся следующие действия:
Далее производятся следующие действия:
* Указанный 3-м параметром файл-образ копируется в файл загрузочного qcow2-образа.
* Указанный 3-м параметром файл-образ копируется в файл загрузочного qcow2-образа.
* Команда ''qemu-img create ...'' создает образ btrfs-диска указанного размера.
* Команда ''qemu-img create ...'' создает образ ''btrfs-диска'' указанного размера.
* Команда ''virt-install --name $prefix ...'' создает виртуальную машину, передавая ''ignition'' файл конфигурации ''${prefix}.ign''.
* Команда ''virt-install --name $prefix ...'' создает виртуальную машину, передавая ''ignition'' файл конфигурации ''${prefix}.ign''.


===== Запуск виртуальных машин master-узлов =====
==== Запуск виртуальных машин master-узлов ====


В HOST-системах '''NODE3 10.140.0.3''', '''NODE4 10.140.0.4''', '''NODE5 10.140.0.5''' запустите виртуальные машины
В HOST-системах '''NODE3 10.140.0.3''', '''NODE4 10.140.0.4''', '''NODE5 10.140.0.5''' запустите виртуальные машины
командами:
командами:
* NODE3:
* NODE3:
  createNode.sh master 1 images/k8s.20211125.0.0.qcow2
  createNode.sh master 1 images/k8s.qcow2
* NODE4:
* NODE4:
  createNode.sh master 2 images/k8s.20211125.0.0.qcow2
  createNode.sh master 2 images/k8s.qcow2
* NODE5:
* NODE5:
  createNode.sh master 3 images/k8s.20211125.0.0.qcow2
  createNode.sh master 3 images/k8s.qcow2


===== Генерация ssh-ключей и их использование =====
==== Генерация ssh-ключей и их использование ====


Дождитесь запуска виртуальных машин (несколько минут) и зайдите под пользователем ''altcos'' на них:
Дождитесь запуска виртуальных машин (несколько минут) и зайдите под пользователем ''altcos'' на них:
Строка 541: Строка 627:
Добавьте открытый ключи из файла ''~altcos/.ssh/id_rsa.pub'' в файл  ''mastersUsers.yml'' описания открытых ключей мастер-узлов кластера.
Добавьте открытый ключи из файла ''~altcos/.ssh/id_rsa.pub'' в файл  ''mastersUsers.yml'' описания открытых ключей мастер-узлов кластера.


===== Иниализация кластер на первом узле master01  =====
==== Иниализация кластера на первом узле master01  ====


На узле ''master01'' (''10.150.0.161'') запустите сервис ''initk8s'':
На узле ''master01'' (''10.150.0.161'') запустите сервис ''initk8s'':
Строка 547: Строка 633:


Инициализация кластера производится несколько минут.
Инициализация кластера производится несколько минут.
После окончания проверьте наличие одного узла в кластере:
kubectl get nodes
NAME      STATUS  ROLES                  AGE    VERSION
master01  Ready    control-plane,master  1m  v1.20.8


===== Подключение остальных master-узлов =====
==== Подключение остальных master-узлов ====
   
   
На узле ''master01'' (''10.150.0.161'') запустите сервис ''initk8s'':
На узле ''master01'' (''10.150.0.161'') запустите сервис ''initk8s'':
  journalctl -u initk8s
  journalctl -u initk8s
Найдите в логах строки:
Найдите в логах строки подключения ''master-узлов'':
  kubeadm join 10.150.0.160:8443 --token ... \
  kubeadm join 10.150.0.160:8443 --token ... \
   --discovery-token-ca-cert-hash sha256:... \
   --discovery-token-ca-cert-hash sha256:... \
Строка 559: Строка 649:
  joinmaster='kubeadm join ...'
  joinmaster='kubeadm join ...'


Подключите дополнительные master-узлы командами:
Загрузите необходимые ''docker-образы'' на  узлах ''master02'', ''master03'':
ssh master02 sudo loadDockerArchiveImages.sh
ssh master03 sudo loadDockerArchiveImages.sh
 
Подключите дополнительные ''master-узлы'' командами:
  ssh master02 sudo $joinmaster
  ssh master02 sudo $joinmaster
  ssh master03 sudo $joinmaster
  ssh master03 sudo $joinmaster
Строка 572: Строка 666:
  master03  Ready    control-plane,master  178m  v1.20.8
  master03  Ready    control-plane,master  178m  v1.20.8


====  Конфигурирование и запуск рабочих (worker) узлов ====
===  Конфигурирование и запуск рабочих (worker) узлов ===


===== Создание butane-YML файлов описания конфигурации worker-узлов =====
==== Создание butane-YML файлов описания конфигурации worker-узлов ====


YML-файл для первого узла ''worker01'':
YML-файл для первого узла ''worker01'':
Строка 607: Строка 701:
   
   
Отличие он конфигурации master-файлов:
Отличие он конфигурации master-файлов:
- отсутствует подключение ''ignition''-файлов ''k8senv.ign'',  ''initk8s.ign'';
* отсутствует подключение ''ignition''-файлов ''k8senv.ign'',  ''initk8s.ign'';
- подключается файл ''mastersUsers.ign'' описания открытых ключей мастер-узлов кластера.
* подключается файл ''mastersUsers.ign'' описания открытых ключей мастер-узлов кластера.


Аналогичным образом конфигурируются файлы для ''worker02'', ''worker03''.
Аналогичным образом конфигурируются файлы для ''worker02'', ''worker03''.


===== Запуск виртуальных машин worker-узлов =====
==== Запуск виртуальных машин worker-узлов ====


В HOST-системах '''NODE3 10.140.0.3''', '''NODE4 10.140.0.4''', '''NODE5 10.140.0.5''' запустите виртуальные ''worker''-машины
В HOST-системах '''NODE3 10.140.0.3''', '''NODE4 10.140.0.4''', '''NODE5 10.140.0.5''' запустите виртуальные ''worker''-машины
командами:
командами:
* NODE3:
* NODE3:
  createNode.sh worker 1 images/k8s.20211125.0.0.qcow2
  createNode.sh worker 1 images/k8s.qcow2
* NODE4:
* NODE4:
  createNode.sh worker 2 images/k8s.20211125.0.0.qcow2
  createNode.sh worker 2 images/k8s.qcow2
* NODE5:
* NODE5:
  createNode.sh worker 3 images/k8s.20211125.0.0.qcow2
  createNode.sh worker 3 images/k8s.qcow2


===== Подключение worker-узлов =====
==== Подключение worker-узлов ====


На узле ''master01'' (''10.150.0.161'') запустите сервис ''initk8s'':
Зайдите на один из ''master''-узлов. например на ''master01''.
journalctl -u initk8s
<!--
Найдите в логах строки:
Загрузите необходимые ''docker''-образы на ''worker''-узлы ''worker01'', ''worker02'', ''worker03'':
kubeadm join 10.150.0.160:8443 --token ... \
    --discovery-token-ca-cert-hash sha256:...
добавьте к ним параметр ''--cri-socket=/var/run/crio/crio.sock'' и запишите полученную команду в переменную
joinworker='kubeadm join ...'


Подключите дополнительные master-узлы командами:
ssh worker01 sudo loadDockerArchiveImages.sh
  ssh master02 sudo $joinworker
  ssh worker02 sudo loadDockerArchiveImages.sh
  ssh master03 sudo $joinworker
  ssh worker03 sudo loadDockerArchiveImages.sh
-->
Запишите в переменную ''joinworker'' строку подключения:
joinworker="`kubeadm token create --print-join-command` --cri-socket=/var/run/crio/crio.sock"


Подключите дополнительные ''worker''-узлы командами:
ssh worker01 sudo $joinworker
ssh worker02 sudo $joinworker
ssh worker03 sudo $joinworker
Подключение worker'ов происходит менее минуты.
Подключение worker'ов происходит менее минуты.


После подключения проверьте список узлов кластера:
После подключения проверьте на одном из ''master''-узлов список узлов кластера:
   kubectl get nodes
   kubectl get nodes
  NAME      STATUS  ROLES                  AGE    VERSION
  NAME      STATUS  ROLES                  AGE    VERSION
Строка 648: Строка 745:
  worker02  Ready    <none>                185m  v1.20.8
  worker02  Ready    <none>                185m  v1.20.8
  worker03  Ready    <none>                189m  v1.20.8
  worker03  Ready    <none>                189m  v1.20.8
== Ссылки ==
* [https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/high-availability/ Creating Highly Available clusters with kubeadm];
* [https://github.com/kubernetes/kubeadm/blob/main/docs/ha-considerations.md High Availability Considerations];
* [https://www.altlinux.org/Keepalived Keepalived]

Текущая версия от 14:03, 25 декабря 2023


K8s cluster.png

Настройка узлов

Создание ethernet-моста (bridge)

Для выделения IP-адресов узлов кластера в рамках IP-адресов локальной сети необходимо в интерфейсе создания сетевых интерфейсов создать в HOST-системе создать мост (например br0) и связать с ним основной ethernet-интерфейс локальной сети. Vmnetconfig1.png В нашем примере примем IP-адрес HOST-системы - 10.150.0.4/24 в подсети 10.150.0.0/24.

В дальнейшем при создании виртуальных машин в пункте конфигурирования сетевого интерфейса укажите:

  • Создать на базе: Устройство моста
  • Название устройства: br0
  • Состояние связи: активно

Vmnetconfig.png



При развертывания виртуальных машин им будут присваиваться статические адреса из подсети 10.150.0.0/24.

Конфигурирование параметров ядра

Проверьте в sysctl настройку переменных ядра :

# sysctl -a | grep net.bridge.bridge-nf-call
net.bridge.bridge-nf-call-arptables = 0
net.bridge.bridge-nf-call-ip6tables = 0
net.bridge.bridge-nf-call-iptables = 0

Перечисленные переменные должны иметь нулевое значение, иначе связь между виртуальными может фильтроваться правилами iptables, arptables.

Если вывод команду пустой, подключите модуль br_netfilter:

modprobe br_netfilter

и обеспечьте загрузку этого модуля после перезагрузки.

Если часть переменных имеет ненулевые значения, сформируйте файл /etc/sysctl.d/99-sysctl.conf:

#
# Configure kernel parameters at boot.
# See sysctl.d(5) for more details.
#
net.bridge.bridge-nf-call-ip6tables = 0
net.bridge.bridge-nf-call-iptables = 0
net.bridge.bridge-nf-call-arptables = 0

и запустите команду:

sysctl -f /etc/sysctl.d/99-sysctl.conf

Конфигурирование балансировшика

Для работы высоко-доступного (Highly Available) kubernetes-кластера необходимо на всех трех узлах поднять балансировщик, распределяющий входящие запросы между мастер-узлами кластера. Для поддержки отказоустойчивости самого балансировщика на HOST-системах запускаются балансировщики. Одному их балансировщику присваивается виртуальный адрес 10.150.0.160. При выходе из строя или потери доступности основного балансировщика виртуальный адрес присваивается другому доступному балансировщику.

Для создания балансировщика установите пакеты:

apt-get install haproxy keepalived

Конфигурирование haproxy

Создайте файл конфигурации haproxy /etc/haproxy/haproxy.cfg:

# /etc/haproxy/haproxy.cfg
#---------------------------------------------------------------------
# Global settings
#---------------------------------------------------------------------
global
    log /dev/log local0
    log /dev/log local1 notice
    daemon

#---------------------------------------------------------------------
# common defaults that all the 'listen' and 'backend' sections will
# use if not designated in their block
#---------------------------------------------------------------------
defaults
    mode                    http
    log                     global
    option                  httplog
    option                  dontlognull
    option http-server-close
    option forwardfor       except 127.0.0.0/8
    option                  redispatch
    retries                 1
    timeout http-request    10s
    timeout queue           20s
    timeout connect         5s
    timeout client          20s
    timeout server          20s
    timeout http-keep-alive 10s
    timeout check           10s

#---------------------------------------------------------------------
# apiserver frontend which proxys to the control plane nodes
#---------------------------------------------------------------------
frontend apiserver
    bind *:8443
    mode tcp
    option tcplog
    default_backend apiserver
    
#---------------------------------------------------------------------
# round robin balancing for apiserver
#---------------------------------------------------------------------
backend apiserver
    option httpchk GET /healthz
    http-check expect status 200
    mode tcp
    option ssl-hello-chk
    balance     roundrobin
        server master01 10.150.0.161:6443 check
        server master02 10.150.0.162:6443 check
        server master03 10.150.0.163:6443 check

В секции balance roundrobin укажите список имен, IP-адресов и портов 6443 API-интерфейсов мастер-узлов.

haproxy будет принимать входящие соединения на порту 8443 и передавать их на один из перечисленных master-серверов на порт 6443.

Конфигурирование keepalived

Создайте файл конфигурации 'keepalived' /etc/keepalived/keepalived.conf:

! /etc/keepalived/keepalived.conf
! Configuration File for keepalived
global_defs {
    router_id LVS_K8S
}
vrrp_script check_apiserver {
  script "/etc/keepalived/check_apiserver.sh"
  interval 3
  weight -2
  fall 10
  rise 2
}

vrrp_instance VI_1 {
    state MASTER
    interface br0
    virtual_router_id  51
    priority 101
    authentication {
        auth_type PASS
        auth_pass 42
    }
    virtual_ipaddress {
        10.150.0.160 
    }
    track_script {
        check_apiserver
    }
}

На одном из узлов установите параметр state в значение MASTER и параметр priority в значение 101. На остальных параметр state в значение BACKUP и параметр priority в значение 100.

Скрипт /etc/keepalived/check_apiserver.sh проверяет доступность балансировщика haproxy:

#!/bin/sh

errorExit() {
    echo "*** $*" 1>&2
    exit 1
}

APISERVER_DEST_PORT=8443
APISERVER_VIP=10.150.0.160
curl --silent --max-time 2 --insecure https://localhost:${APISERVER_DEST_PORT}/ -o /dev/null || errorExit "Error GET https://localhost:${APISERVER_DEST_PORT}/"
if ip addr | grep -q ${APISERVER_VIP}; then
    curl --silent --max-time 2 --insecure https://${APISERVER_VIP}:${APISERVER_DEST_PORT}/ -o /dev/null || errorExit "Error GET https://${APISERVER_VIP}:${APISERVER_DEST_PORT}/"
fi

Параметр APISERVER_DEST_PORT задает порт балансировщиков haproxy, параметр APISERVER_VIP виртуальный адрес, через который будут взаимодействовать master (control plane) узлы кластера k8s.

Скрипт проверяет работоспособность haproxy на локальной машине. А если в настоящее время виртуальный адрес принадлежит текущему узлу, то и работоспособность haproxy через виртуальный адрес.

Добавьте флаг на выполнение скрипта:

chmod a+x /etc/keepalived/check_apiserver.sh

При работающем балансировщике и хотя бы одному доступному порту 6443 на master-узлах скрипт должен завершаться с кодом 0.

Запуск сервисов

Для запуска сервисов наберите команды:

systemctl enable haproxy --now
systemctl enable keepalived --now

Так как master-узлы k8s еще не подняты haproxy выведет на консоль сообщение

haproxy[nnnn]: backend apiserver has no server available!

Конфигурирование и запуск кластера

Получение образов ветки kubetnetes

Скачать образ можно тут

Описание базовых butane YML-файлов

На основе базовых butane YML-файлов программой butane создаются ignition-файлы, используемые для создания конечных 'master_NN.ign', 'worker_NN.jgn' ignition-файлов для разворачивания master и worker узлов кластера.

Файл users.yml описания пользователя altcos

yml описания пользователя altcos имеет следующую структуру:

variant: fcos
version: 1.3.0
passwd:
  users:
    - name: altcos
      groups:
        - wheel
        - docker
      password_hash: ...
      ssh_authorized_keys:
        - ssh-rsa ... 
        - ssh-rsa ... 
storage:
  files:
    - path: /etc/sudoers.d/altcos
      contents:
        inline: |
          altcos ALL=NOPASSWD: ALL

В поле password_hash помещается хеш-пароля, сгенерированный командой

mkpasswd --method=yescrypt

В поле ssh_authorized_keys - массив открытых ключей пользователей для которых необходим беспарольный доступ к пользователю altcos виртуалной машины.

В файл /etc/sudoers.d/altcos записывается строка, обеспечивающая беспарольный доступ пользователя altcos к sudo.

Файл hosts.yml описания имен и IP-адресов узлов

Файл hosts.yml содержит строки привязки имен и IP-адресов виртуальных машин в файле /etc/hosts:

variant: fcos
version: 1.3.0

storage:
  files:
    - path: /etc/hosts
      append:
        - inline: |
            10.150.0.161 master01
            10.150.0.162 master02
            10.150.0.163 master03
            10.150.0.171 worker01
            10.150.0.172 worker02
            10.150.0.173 worker03
Файл btrfs.yml инициализации btrfs тома
variant: fcos
version: 1.3.0
storage:
 disks:
   - device: /dev/sdb # создадим на диске /dev/sdb партицию /dev/sdb1
     wipe_table: true
     partitions:
       - number: 1
         label: docker
 filesystems:
   - device: /dev/sdb1 # создадим в партиции /dev/sdb1 файловую систему BTRFS
     format: btrfs
     wipe_filesystem: true
     label: docker
     with_mount_unit: false
 directories:
   - path: /var/mnt/docker # создадим каталог монтирования тома
     overwrite: true
 files:
   - path: /etc/fstab # добавим строку монтирования btrfs-тома на каталог /var/mnt/docker
     append:
       - inline: |
           LABEL=docker /var/mnt/docker btrfs defaults 0 2
           /var/mnt/docker/docker/ /var/lib/docker none bind 0 0
           /var/mnt/docker/containers/ /var/lib/containers/ none bind 0 0
   # заменим в конфигурации dockerd-демона:
   # тип storage-driver с overlay2 на btrfs
   - path: /etc/docker/daemon.json
     overwrite: true
     contents:
       inline: |
         {
         "init-path": "/usr/bin/tini",
         "userland-proxy-path": "/usr/bin/docker-proxy",
         "default-runtime": "docker-runc",
         "live-restore": false,
         "log-driver": "journald",
         "runtimes": {
           "docker-runc": {
             "path": "/usr/bin/runc"
           }
         },
         "default-ulimits": {
           "nofile": {
           "Name": "nofile",
           "Hard": 64000,
           "Soft": 64000
           }
         },
         "data-root": "/var/lib/docker/",
         "storage-driver": "btrfs"
         }
   # заменим в конфигурации CRI-O тип driver с overlay на btrfs
   - path: /etc/crio/crio.conf.d/00-btrfs.conf
     overwrite: true
     contents:
       inline: |
         [crio]
         root = "/var/lib/containers/storage"
         runroot = "/var/run/containers/storage"
         storage_driver = "btrfs"
         storage_option = []
         [crio.runtime]
         conmon = "/usr/bin/conmon"
         [crio.network]
         plugin_dirs = [
           "/usr/libexec/cni",
           "/opt/cni/bin/"
         ]
   # заменим в конфигурации podman тип driver с overlay2 на btrfs
   - path: /etc/containers/storage.conf
     overwrite: true
     contents:
       inline: |
         [storage]
         driver = "btrfs"
         runroot = "/var/run/containers/storage"
         graphroot = "/var/lib/containers/storage"
         [storage.options]
         additionalimagestores = [
         ]
         [storage.options.overlay]
         mountopt = "nodev,metacopy=on"
    # исключим определение flannel-подсети в CRIO 
    - path: /etc/cni/net.d/100-crio-bridge.conf
      overwrite: true
      contents:
        inline: |
          {"type": "bridge"}


В текущей версии пакета cri-o-1.22.1-alt1.x86_64 файл конфигурации /etc/cni/net.d/100-crio-bridge.conf задает адрес подсети для интерфейса cni0. Для корректной работы сетевого плугина flannel необходимо исключить определение подсети, так как flannel самостоятельно на основе полученной конфигурации сети конфигурирует IP-адрес интерфейса cni0.

Plugin flannel конфигурирования cni-интерфайса в образе rancher/mirrored-flannelcni-flannel-cni-plugin располагается в каталоге /opt/cni/bin/. В обычной Linux-системе при запуске POD'а это plugin копируется в каталог /usr/libexec/cni откуда он загружается plugin'ом CRI (Container Runtime Interface). В ALTCOS каталог /usr смонтирован в режиме только не чтение и копирование не производится. Для решения этой проблемы в подключаемых узлах добавляется файл конфигурации /etc/crio/crio.conf.d/00-btrfs.conf. Он настраивает `cri-o` на использование файловой системы btrfs и в параметре plugin_dirs для подключения plugins кроме стандартного каталога /usr/libexec/cni использует каталог /opt/cni/bin/.

Файл initk8s.yml описания сервиса инициализации кластера k8s с сетью flannel

Файл описывает сервис initk8s инициализации кластера и может быть включен только в YML-файл 1-го master-узла кластера master01.

variant: fcos
version: 1.3.0
systemd:
  units:
    - name: initk8s.service
      enabled: false
      contents: |
        [Unit]
        Description=Start up kubernetes in master mode
        After=crio.service kube-proxy.service kubelet.service systemd-networkd.service systemd-resolved.service
        [Service]
        Type=oneshot
        RemainAfterExit=yes
        Environment="KUBECONFIG=/etc/kubernetes/admin.conf"
        ExecStartPre=loadDockerArchiveImages.sh
        ExecStart=kubeadm init --cri-socket=/var/run/crio/crio.sock \
                          --pod-network-cidr=10.244.0.0/16 \
                          --control-plane-endpoint 10.150.0.160:8443 \
                          --upload-certs
        ExecStartPost=kubectl apply -f /usr/share/k8s/flannel/kube-flannel.yml
        #ExecStartPost=kubectl taint nodes master01 node-role.kubernetes.io/master-
        [Install]
        WantedBy=multi-user.target

Если вы разворачиваете кластер в локальной сети без доступа или с низкоскоростным доступом в Интернет, то необходимо оставить вызов скрипта loadDockerArchiveImages.sh разворачивания архивов docker-образов, хранящихся в ostree-образе.

Если Вы планируете загрузить docker-образы из Интернет, то строку ExecStartPre можно удалить.

В отличие от варианта разворачивания кластера с одним master-узлом в команду kubeadm init добавлены параметры:

  • control-plane-endpoint в котором указан URL основного haproxy-сервера, работающего на виртуальном адресе 10.150.0.160 и предоставляющий доступ на порту 8443.
  • upload-certs, обеспечивающий загрузку сгенерированных сертификатов и раздачу их другим master-узлам.

Сетевой драйвер flannel обеспечивает выделение адресов для POD'ов и роутинг в рамках подсети 10.244.0.0/16. Данная подсеть при инициализации кластера указывается параметром pod-network-cidr.


При подключении узла к кластеру сетевой драйвер flannel запрашивает у планировщика подсетку ``10.244.x.0/24 и согласно полученной подсетке он

  • создает интерфейс flannel.x и присваевает ему адрес ``10.244.x.0/32
  • при создании первого POD'а конфирурирует интерфейс cni0 с адресом 10.244.x.1/32.

Все создаваемые на этом узле POD'ы получают IP-адреса 10.244.x.2-255/32.

Файл k8senv.yml создание profile инициализации kubernetes-среды
variant: fcos
version: 1.3.0
storage:
  files:
    - path: /etc/profile.d/kube.sh
      mode: 0755
      contents:
        inline: |
          # Set  kube environment
          if [ `id -u ` = 0 ]
          then
            export KUBECONFIG=/etc/kubernetes/admin.conf
          else
            if [ -f /etc/kubernetes/admin.conf ]
            then
              if [ ! -d ~/.kube ]
              then
                mkdir -p ~/.kube
                sudo cp -i /etc/kubernetes/admin.conf ~/.kube/config
                sudo chown $(id -u):$(id -g) ~/.kube/config
                kubectl completion bash >> ~/.bashrc
              fi
            fi
          fi

Файл обеспечивает создание профайла /etc/profile.d/kube.sh. Для привелигированного пользователя (sudo -i bash) в среду добавляется переменная KUBECONFIG. Для непривилигиванного пользователя обеспечивается формирование каталога .kube.

Файл mastersUsers.yml описания открытых ключей мастер-узлов кластера

Данный файл обеспечивает для пользователя altcos беспарольный доступ с master-узлов на 'worker'-узлы. Структура файла следующая:

variant: fcos
version: 1.3.0
passwd:
  users:
    - name: altcos
      ssh_authorized_keys:
        - ssh-rsa ... altcos@master01 
        - ssh-rsa ... altcos@master02
        - ssh-rsa ... altcos@master03  

В него помещаются открытые ключи пользователей altcos master-узлов кластера.

Конфигурирование и запуск мастер-узлов

Создание butane-YML файлов описания конфигурации master-узлов

YML-файл master_01.yml для первого узла master01:

variant: fcos
version: 1.3.0
ignition:
  config:
    merge:
      - local: users.ign
      - local: hosts.ign
      - local: btrfs.ign
      - local: k8senv.ign
      - local: initk8s.ign
storage:
  files:
    - path: /etc/hostname
      overwrite: true
      contents:
        inline:
          master01
    - path: /etc/systemd/network/20-wired.network
      overwrite: true
      contents:
        inline: |
          [Match]
          Name=eth0
          [Network]
          DHCP=no
          Address=10.150.0.161/24
          Gateway=10.150.0.1
          DNS=10.150.0.1

В элементе ignition.config.merge описываются ignition-файлы сгенерированные командой butane из вышеперечисленных YML-файлов.

В файле /etc/hostname указывается имя узла master01. В файле /etc/systemd/network/20-wired.network описываются адрес Address узла, шлюз Gateway и DNS для узла кластера.

Остальные YML-файлы конфигурации master-узлов master_02.yml, master_03.yml описываются схожим образом за исключением:

  • файл описания сервиса local: initk8s.ign не подключается, так как инициализация кластера производится на узле master01;
  • в файле /etc/hostname указываются имена узлов master02 и master03 соответственно;
  • в файле '/etc/systemd/network/20-wired.network в поле Address указываются IP-адреса master-узлов 10.150.0.162 и 10.150.0.163 соответственно.

Пример YML-файл master_02.yml для первого узла master02:

variant: fcos
version: 1.3.0

ignition:
  config:
    merge:
      - local: users.ign
      - local: hosts.ign
      - local: btrfs.ign
      - local: k8senv.ign  
storage:
  files:
    - path: /etc/hostname
      overwrite: true
      contents:
        inline:
          master02
    - path: /etc/systemd/network/20-wired.network
      overwrite: true
      contents:
        inline: |
          [Match]
          Name=eth0
          [Network]
          DHCP=no
          Address=10.150.0.162/24
          Gateway=10.150.0.1
          DNS=10.150.0.1

Скрипт createNode.sh запуска master и worker узлов

Исходный код скрипта:

#!/bin/sh
case $1 in 
 master) Mem=4096;break;;
 worker) Mem=6144;break;;
  *) echo "Тип нод может быть только master или worker"; exit 1;
esac
N=`printf "%02d" $2 2>/dev/null` 
if [ $N = '00' ]
then
  echo "Номер ноды должен быть числовым и больше нуля"; exit 1;
fi
if [ ! -f $3 ]
then
  echo "Образ $3 не существует";exit 1;
fi
IMAGE=$3
prefix=${type}_${N}
diskSize=30G
sdaDisk=${prefix}_sda.qcow2
sdbDisk=${prefix}_sdb.qcow2
ignFile=$PWD/${prefix}.ign
ymlfiles="users k8senv btrfs hosts initk8s mastersUsers $prefix"
for ymlfile in $ymlfiles 
do
  if ! butane -d . -p $ymlfile.yml > $ymlfile.ign
  then
    exit 1;
  fi
done
cp $IMAGE $sdaDisk
qemu-img create -f qcow2 $sdbDisk $diskSize
virt-install --name $prefix \
  --vcpus 2 \
  --ram $Mem \
  --os-variant altlinux1.0 \
  --import \
  --disk $sdaDisk \
  --disk $sdbDisk \
  --vnc \
  --qemu-commandline="-fw_cfg name=opt/com.coreos/config,file=$ignFile"

Скрипт принимает три параметра:

  1. Тип узла - master или worker.
  2. Номер узла (1, 2, 3, ...).
  3. Тропа до файла qcow2-образа.

Скрипт на основе типа виртуальной машины и ее номера формирует prefix ${type}_${N} (например master_01) который используется для определения:

  • имен основных yml и ignition файлов;
  • имен основного (/dev/sda) и дополнительного btrfs (/dev/sdb) qcow2-файла дисков;
  • имен виртуальных машин.

Далее производятся следующие действия:

  • Указанный 3-м параметром файл-образ копируется в файл загрузочного qcow2-образа.
  • Команда qemu-img create ... создает образ btrfs-диска указанного размера.
  • Команда virt-install --name $prefix ... создает виртуальную машину, передавая ignition файл конфигурации ${prefix}.ign.

Запуск виртуальных машин master-узлов

В HOST-системах NODE3 10.140.0.3, NODE4 10.140.0.4, NODE5 10.140.0.5 запустите виртуальные машины командами:

  • NODE3:
createNode.sh master 1 images/k8s.qcow2
  • NODE4:
createNode.sh master 2 images/k8s.qcow2
  • NODE5:
createNode.sh master 3 images/k8s.qcow2

Генерация ssh-ключей и их использование

Дождитесь запуска виртуальных машин (несколько минут) и зайдите под пользователем altcos на них:

  • NODE3:
ssh altcos@10.150.0.161
  • NODE4:
ssh altcos@10.150.0.162
  • NODE5:
ssh altcos@10.150.0.163

Сгенерируйте ssh-ключи командой:

ssh-keygen

Передайте открытые ключи на остальные master-узлы:

  • master01 (10.150.0.161):
ssh-copy-id master02
ssh-copy-id master03
  • master02 (10.150.0.162):
ssh-copy-id master01
ssh-copy-id master03
  • master03 (10.150.0.163):
ssh-copy-id master01
ssh-copy-id master02

Добавьте открытый ключи из файла ~altcos/.ssh/id_rsa.pub в файл mastersUsers.yml описания открытых ключей мастер-узлов кластера.

Иниализация кластера на первом узле master01

На узле master01 (10.150.0.161) запустите сервис initk8s:

sudo systemctl start initk8s

Инициализация кластера производится несколько минут. После окончания проверьте наличие одного узла в кластере:

kubectl get nodes
NAME       STATUS   ROLES                  AGE    VERSION
master01   Ready    control-plane,master   1m   v1.20.8

Подключение остальных master-узлов

На узле master01 (10.150.0.161) запустите сервис initk8s:

journalctl -u initk8s

Найдите в логах строки подключения master-узлов:

kubeadm join 10.150.0.160:8443 --token ... \
  --discovery-token-ca-cert-hash sha256:... \
  --control-plane --certificate-key ...

добавьте к ним параметр --cri-socket=/var/run/crio/crio.sock и запишите полученную команду в переменную

joinmaster='kubeadm join ...'

Загрузите необходимые docker-образы на узлах master02, master03:

ssh master02 sudo loadDockerArchiveImages.sh
ssh master03 sudo loadDockerArchiveImages.sh

Подключите дополнительные master-узлы командами:

ssh master02 sudo $joinmaster
ssh master03 sudo $joinmaster

Подключение master'ов происходит за пару минут.

После подключения проверьте список узлов кластера:

 kubectl get nodes
NAME       STATUS   ROLES                  AGE    VERSION
master01   Ready    control-plane,master   3h9m   v1.20.8
master02   Ready    control-plane,master   179m   v1.20.8
master03   Ready    control-plane,master   178m   v1.20.8

Конфигурирование и запуск рабочих (worker) узлов

Создание butane-YML файлов описания конфигурации worker-узлов

YML-файл для первого узла worker01:

variant: fcos
version: 1.3.0

ignition:
  config:
    merge:
      - local: users.ign
      - local: btrfs.ign
      - local: hosts.ign
      - local: mastersUsers.ign  
storage:
  files:
    - path: /etc/hostname
      overwrite: true
      contents:
        inline:
          worker01
    - path: /etc/systemd/network/20-wired.network
      overwrite: true
      contents:
        inline: |
          [Match]
          Name=eth0
          [Network]
          DHCP=no
          Address=10.150.0.171/24
          Gateway=10.150.0.1
          DNS=10.150.0.1

Отличие он конфигурации master-файлов:

  • отсутствует подключение ignition-файлов k8senv.ign, initk8s.ign;
  • подключается файл mastersUsers.ign описания открытых ключей мастер-узлов кластера.

Аналогичным образом конфигурируются файлы для worker02, worker03.

Запуск виртуальных машин worker-узлов

В HOST-системах NODE3 10.140.0.3, NODE4 10.140.0.4, NODE5 10.140.0.5 запустите виртуальные worker-машины командами:

  • NODE3:
createNode.sh worker 1 images/k8s.qcow2
  • NODE4:
createNode.sh worker 2 images/k8s.qcow2
  • NODE5:
createNode.sh worker 3 images/k8s.qcow2

Подключение worker-узлов

Зайдите на один из master-узлов. например на master01. Запишите в переменную joinworker строку подключения:

joinworker="`kubeadm token create --print-join-command` --cri-socket=/var/run/crio/crio.sock"

Подключите дополнительные worker-узлы командами:

ssh worker01 sudo $joinworker
ssh worker02 sudo $joinworker
ssh worker03 sudo $joinworker

Подключение worker'ов происходит менее минуты.

После подключения проверьте на одном из master-узлов список узлов кластера:

 kubectl get nodes
NAME       STATUS   ROLES                  AGE    VERSION
master01   Ready    control-plane,master   3h9m   v1.20.8
master02   Ready    control-plane,master   179m   v1.20.8
master03   Ready    control-plane,master   178m   v1.20.8
worker01   Ready    <none>                 180m   v1.20.8
worker02   Ready    <none>                 185m   v1.20.8
worker03   Ready    <none>                 189m   v1.20.8

Ссылки