ALT Container OS подветка K8S. Создание HA кластера: различия между версиями
Kaf (обсуждение | вклад) |
Нет описания правки |
||
(не показано 100 промежуточных версий 2 участников) | |||
Строка 1: | Строка 1: | ||
[[Категория:Руководства]] | |||
[[Файл:K8s cluster.png]] | |||
== Настройка узлов == | |||
=== Создание ethernet-моста (bridge) === | === Создание ethernet-моста (bridge) === | ||
Строка 6: | Строка 9: | ||
Для выделения IP-адресов узлов кластера в рамках IP-адресов локальной сети необходимо в интерфейсе создания сетевых интерфейсов | Для выделения IP-адресов узлов кластера в рамках IP-адресов локальной сети необходимо в интерфейсе создания сетевых интерфейсов | ||
создать в HOST-системе создать мост (например ''br0'') и связать с ним основной ethernet-интерфейс локальной сети. | создать в HOST-системе создать мост (например ''br0'') и связать с ним основной ethernet-интерфейс локальной сети. | ||
[[Файл: | [[Файл: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 | |||
=== Конфигурирование балансировшика === | === Конфигурирование балансировшика === | ||
Для работы высоко-доступного (Highly Available) kubernetes-кластера необходимо | Для работы высоко-доступного (Highly Available) kubernetes-кластера необходимо на всех трех узлах поднять балансировщик, распределяющий входящие запросы между мастер-узлами кластера. | ||
Для поддержки отказоустойчивости самого балансировщика | Для поддержки отказоустойчивости самого балансировщика на HOST-системах запускаются балансировщики. | ||
Одному их балансировщику присваивается виртуальный адрес ''10.150.0.160''. | |||
При выходе из строя или потери доступности основного балансировщика виртуальный адрес присваивается | |||
другому доступному балансировщику. | |||
Для создания балансировщика установите пакеты: | Для создания балансировщика установите пакеты: | ||
Строка 99: | Строка 113: | ||
option ssl-hello-chk | option ssl-hello-chk | ||
balance roundrobin | balance roundrobin | ||
server master01 10.150.0. | server master01 10.150.0.161:6443 check | ||
server master02 10.150.0. | 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 ==== | ||
Строка 112: | Строка 129: | ||
! Configuration File for keepalived | ! Configuration File for keepalived | ||
global_defs { | global_defs { | ||
router_id | router_id LVS_K8S | ||
} | } | ||
vrrp_script check_apiserver { | vrrp_script check_apiserver { | ||
Строка 132: | Строка 149: | ||
} | } | ||
virtual_ipaddress { | virtual_ipaddress { | ||
10.150.0. | 10.150.0.160 | ||
} | } | ||
track_script { | track_script { | ||
Строка 139: | Строка 156: | ||
} | } | ||
Скрипт ''/etc/keepalived/check_apiserver.sh'' | На одном из узлов установите параметр ''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. | 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 | ||
При работающем | При работающем балансировщике и хотя бы одному доступному порту ''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 | |||
== | == Ссылки == | ||
* [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
Настройка узлов
Создание ethernet-моста (bridge)
Для выделения IP-адресов узлов кластера в рамках IP-адресов локальной сети необходимо в интерфейсе создания сетевых интерфейсов создать в HOST-системе создать мост (например br0) и связать с ним основной ethernet-интерфейс локальной сети. В нашем примере примем IP-адрес HOST-системы - 10.150.0.4/24 в подсети 10.150.0.0/24.
В дальнейшем при создании виртуальных машин в пункте конфигурирования сетевого интерфейса укажите:
- Создать на базе: Устройство моста
- Название устройства: br0
- Состояние связи: активно
При развертывания виртуальных машин им будут присваиваться статические адреса из подсети 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"
Скрипт принимает три параметра:
- Тип узла - 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. Запишите в переменную 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