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

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


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


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


Для выделения 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''.


При создании виртуальных машин в пункте конфигурирования сетевого интерфейса  
В дальнейшем при создании виртуальных машин в пункте конфигурирования сетевого интерфейса  
укажите:
укажите:
* Создать на базе: Устройство моста
* Создать на базе: Устройство моста
* Название устройства: br0
* Название устройства: br0
* Состояние связи: активно
* Состояние связи: активно
[[Файл:Vmnetconfig.png|мини]]
[[Файл:Vmnetconfig.png]]
 
 
 
 


При развертывания виртуальных машин им будут присваиваться статические адреса из подсети ''10.150.0.0/24''.
При развертывания виртуальных машин им будут присваиваться статические адреса из подсети ''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-системе поднять балансировщик, распределяющий входящие запросы между мастер-узлами кластера.
Для работы высоко-доступного (Highly Available) kubernetes-кластера необходимо на всех трех узлах поднять балансировщик, распределяющий входящие запросы между мастер-узлами кластера.
Для поддержки отказоустойчивости самого балансировщика создают несколько HOST-систем на которых запускают балансировщики  
Для поддержки отказоустойчивости самого балансировщика на  HOST-системах  запускаются балансировщики.
разделяющий один общий виртуальный адрес. В данном примере мы будем использовать один балансировщик, располагающийся в HOST-системе.
Одному их балансировщику присваивается виртуальный адрес ''10.150.0.160''.
При выходе из строя или потери доступности основного балансировщика виртуальный адрес присваивается
другому доступному балансировщику.  


Для создания балансировщика установите пакеты:
Для создания балансировщика установите пакеты:
Строка 81: Строка 113:
     option ssl-hello-chk
     option ssl-hello-chk
     balance    roundrobin
     balance    roundrobin
         server master01 10.150.0.159:6443 check
         server master01 10.150.0.161:6443 check
         server master02 10.150.0.158:6443 check
         server master02 10.150.0.162:6443 check
        server master03 10.150.0.163:6443 check


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


В секции ''balance roundrobin'' укажите список имен, IP-адресов и портов 6443 API-интерфейсов мастер-узлов.
''haproxy'' будет принимать входящие соединения на порту ''8443'' и передавать их на один из
перечисленных ''master-серверов'' на порт ''6443''.


==== Конфигурирование keepalived ====
==== Конфигурирование keepalived ====
Строка 94: Строка 129:
  ! Configuration File for keepalived
  ! Configuration File for keepalived
  global_defs {
  global_defs {
     router_id LVS_DEVEL
     router_id LVS_K8S
  }
  }
  vrrp_script check_apiserver {
  vrrp_script check_apiserver {
Строка 114: Строка 149:
     }
     }
     virtual_ipaddress {
     virtual_ipaddress {
         10.150.0.170
         10.150.0.160
     }
     }
     track_script {
     track_script {
Строка 121: Строка 156:
  }
  }


Скрипт ''/etc/keepalived/check_apiserver.sh'' проверят доступность балансировщика 'haproxy':
На одном из узлов установите параметр ''state'' в значение ''MASTER'' и параметр ''priority'' в значение ''101''.
На остальных параметр ''state'' в значение ''BACKUP'' и параметр ''priority'' в значение ''100''.
 
Скрипт ''/etc/keepalived/check_apiserver.sh'' проверяет доступность балансировщика ''haproxy'':
  #!/bin/sh
  #!/bin/sh
   
   
Строка 130: Строка 168:
   
   
  APISERVER_DEST_PORT=8443
  APISERVER_DEST_PORT=8443
  APISERVER_VIP=10.150.0.4
  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}/"
  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
  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}/"
     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
  fi
Параметр ''APISERVER_DEST_PORT'' задает порт балансировщиков ''haproxy'', параметр ''APISERVER_VIP'' виртуальный адрес,
через который будут взаимодействовать ''master'' (''control plane'') узлы кластера ''k8s''.
Скрипт проверяет работоспособность ''haproxy'' на локальной машине.
А если в настоящее время виртуальный адрес принадлежит текущему узлу, то и работоспособность ''haproxy'' через виртуальный адрес. 


Добавьте флаг на выполнение скрипта:
Добавьте флаг на выполнение скрипта:
  chmod a+x /etc/keepalived/check_apiserver.sh
  chmod a+x /etc/keepalived/check_apiserver.sh


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


==== Запуск сервисов ====
==== Запуск сервисов ====
Строка 145: Строка 190:
Для запуска сервисов наберите команды:
Для запуска сервисов наберите команды:
  systemctl enable haproxy --now
  systemctl enable haproxy --now
  systemctl enable keepalived --now
  systemctl enable keepalived --now


Так как ''master-узлы'' ''k8s'' еще не подняты ''haproxy'' выведет на консоль сообщение
haproxy[nnnn]: backend apiserver has no server available!
<!--
Проверьте доступность ''haproxy'':
Проверьте доступность ''haproxy'':
  /etc/keepalived/check_apiserver.sh; echo $?
  /etc/keepalived/check_apiserver.sh; echo $?


Должен отобразиться код завершения ''0''.
Должен отобразиться код завершения ''0''.
-->
== Конфигурирование и запуск кластера ==
=== Получение образов ветки kubetnetes ===
Скачать образ можно [http://altcos.altlinux.org/?arch=x86_64&repo=sisyphus&ref=k8s тут]
=== Описание базовых 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"
Скрипт принимает три параметра:
# Тип узла - ''master'' или ''worker''.
# Номер узла (''1'', ''2'', ''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''.
<!--
Загрузите необходимые ''docker''-образы на ''worker''-узлы ''worker01'', ''worker02'', ''worker03'':
ssh worker01 sudo loadDockerArchiveImages.sh
ssh worker02 sudo loadDockerArchiveImages.sh
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'ов происходит менее минуты.


=== Конфигурирование и запуск кластера ===
После подключения проверьте на одном из ''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


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


====  Конфигурирование и запуск рабочих (worker) узлов ====
* [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]

Текущая версия от 17: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

Ссылки