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

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


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


=== Создание ethernet-моста (bridge) ===
=== Создание ethernet-моста (bridge) ===
Строка 6: Строка 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''.


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


При развертывания виртуальных машин им будут присваиваться статические адреса из подсети ''10.150.0.0/24''.
При развертывания виртуальных машин им будут присваиваться статические адреса из подсети ''10.150.0.0/24''.
Строка 27: Строка 33:
  net.bridge.bridge-nf-call-iptables = 0
  net.bridge.bridge-nf-call-iptables = 0


Перечисленные переменные должны иметь нулевое значение, иначе связь между виртуальными машинами не поддерживается.
Перечисленные переменные должны иметь нулевое значение, иначе связь между виртуальными может
фильтроваться правилами ''iptables'', ''arptables''.
 
Если вывод команду пустой, подключите модуль ''br_netfilter'':
modprobe br_netfilter
и обеспечьте загрузку этого модуля после перезагрузки.
 
Если часть переменных имеет ненулевые значения, сформируйте файл ''/etc/sysctl.d/99-sysctl.conf'':
Если часть переменных имеет ненулевые значения, сформируйте файл ''/etc/sysctl.d/99-sysctl.conf'':
  #
  #
Строка 37: Строка 49:
  net.bridge.bridge-nf-call-arptables = 0
  net.bridge.bridge-nf-call-arptables = 0
и запустите команду:
и запустите команду:
  # sysctl -f /etc/sysctl.d/99-sysctl.conf
  sysctl -f /etc/sysctl.d/99-sysctl.conf


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


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


Для создания балансировщика установите пакеты:
Для создания балансировщика установите пакеты:
Строка 99: Строка 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 ====
Строка 112: Строка 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 {
Строка 132: Строка 149:
     }
     }
     virtual_ipaddress {
     virtual_ipaddress {
         10.150.0.170
         10.150.0.160
     }
     }
     track_script {
     track_script {
Строка 139: Строка 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
   
   
Строка 148: Строка 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''.


==== Запуск сервисов ====
==== Запуск сервисов ====
Строка 163: Строка 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

Ссылки