Создание кластера Kubernetes на VPS с помощью Kubespray
14
14751
20 ноября 2020 9:37
20/11/2020
Visitors have accessed this post 14751 times.
Автор — Андрей Трошин
k8s, Kubernetes
Не для кого не секрет, что сегодня этот оркестратор у всех на слуху. Из каждого IT-утюга доносится «k8s, кластер, CI\CD» и всякие другие неприличные и малопонятные слова. Давайте разберемся и попробуем собрать кластер Kubernetes на VPS.
Варианты установки
- Стандартный репозиторий OS
- Kubespray
В качестве хост-системы будем использовать CentOS 7 на всех узлах нашего k8s кластера (если у вас другая хост-система — ищите информацию на официальном сайте Kubernetes). В нашем случае выбираем вариант установки с помощью Kubespray. Kubespray — это набор Ansible ролей для установки и конфигурации Kubernetes. В свою очередь, Ansible — это инструмент для автоматизации настройки и развертывания программного обеспечения.
Подготовка
В дальнейшем мы будем использовать кластер для публикации разных сервисов и поэтому установка будет на VPS. Но мануал по установке будет также успешно работать, если вы захотите поднять k8s у себя на виртуальных машинах.
Что нам потребуется
- Master node (OS CentOS 7: 1vCPU, RAM 2Gb, HDD 10Gb)
- Worker node (OS CentOS 7: 1vCPU, RAM 2Gb, HDD 10Gb)
- Worker node (OS CentOS 7: 1vCPU, RAM 2GB, HDD 10Gb)
- Ingress node (OS CentOS 7: 2vCPU, RAM 8Gb, HDD 10Gb)
Эта конфигурация — это учебный вариант. С таким количеством узлов кластера в продуктиве, конечно же, запускаться не стоит. С другой стороны, это уже не minikube, а разнесенный по узлам кластер, хоть и маленький 🙂
Делаем k8s
Итак, у нас в распоряжении 4 узла кластера и для дальнейших действий на всех узлах необходимо сделать следующее:
- Отключить Swap
- Отключить Firewall
- Сгенерировать и скопировать ssh-ключи (необходимо для того, что бы Ansible ходил по хостам и делал свои дела)
Поехали.
Отключаем SWAP.
swapoff -a
Отключаем Firewall.
firewall-cmd --state
systemctl stop firewalld
systemctl disable firewalld
Заходим на master ноду по ssh и генерируем ssh-ключ, копируем его на все хосты кластера (включая master хост, на котором был сгенерирован ключ). По очереди подставляем IP каждого узла кластера на место remote_host.
ssh-keygen
ssh-copy-id root@remote_host
Продолжим подготавливать master. Для дальнейшей работы потребуется pip и собственно git.
curl "https://bootstrap.pypa.io/get-pip.py" -o "get-pip.py"
python get-pip.py
yum install git
С подготовительной частью мы закончили. Возвращаемся на master ноду и дальнейшие операции до конца установки кластера будем совершать с нее. Скачиваем репозиторий к себе на хост и переходим в директорию kubespray.
git clone https://github.com/kubernetes-sigs/kubespray.git
cd kubespray
Далее устанавливаем python-библиотеку requests и другие зависимости из файла requirements.txt.
pip install --ignore-installed requests==2.23.0
pip install -r requirements.txt
В результате у нас получилось следующее:
- На master ноде установили Ansible.
- Мы сгенерировали и скопировали ssh-ключ на все узлы кластера.
- Установили все необходимые зависимости.
Приступаем к конфигурации Kubespray. Для того чтобы Kubespray понимал, на какие узлы ему устанавливать k8s, необходимо создать директорию. В ней мы опишем конфигурацию будущего кластера. Копируем /inventory/sample/ в новую директорию и переименовываем, в моем случае — в root/, и в ней открываем файл inventory.ini.
[root@master-1 inventory]# ll
total 12
drwxr-xr-x. 2 root root 4096 Nov 5 15:08 local
drwxr-xr-x. 3 root root 4096 Nov 5 15:18 root
drwxr-xr-x. 3 root root 4096 Nov 5 15:18 sample
[root@master-1 inventory]# cd root/
[root@master-1 root]# ll
total 8
drwxr-xr-x. 4 root root 4096 Nov 5 15:08 group_vars
-rw-r--r--. 1 root root 994 Nov 5 15:08 inventory.ini
[root@master-1 root]#
Типичный inventory.ini:
# ## Configure 'ip' variable to bind kubernetes services on a
# ## different ip than the default iface
# ## We should set etcd_member_name for etcd cluster. The node that is not a etcd member do not need to set the value, or can set the empty string value.
[all]
# node1 ansible_host=95.54.0.12 # ip=10.3.0.1 etcd_member_name=etcd1
# node2 ansible_host=95.54.0.13 # ip=10.3.0.2 etcd_member_name=etcd2
# node3 ansible_host=95.54.0.14 # ip=10.3.0.3 etcd_member_name=etcd3
# node4 ansible_host=95.54.0.15 # ip=10.3.0.4 etcd_member_name=etcd4
# node5 ansible_host=95.54.0.16 # ip=10.3.0.5 etcd_member_name=etcd5
# node6 ansible_host=95.54.0.17 # ip=10.3.0.6 etcd_member_name=etcd6
# ## configure a bastion host if your nodes are not directly reachable
# bastion ansible_host=x.x.x.x ansible_user=some_user
[kube-master]
# node1
# node2
[etcd]
# node1
# node2
# node3
[kube-node]
# node2
# node3
# node4
# node5
# node6
[calico-rr]
[k8s-cluster:children]
kube-master
kube-node
calico-rr
Конфигурация не сложная, и на первый взгляд понятно, что в секции [all] идет присвоение IP-адресов ко всем нодам. В остальных секциях идет компановка кластера. Ниже приведен пример inventory.ini c моими IP-адресами (у вас они могут отличаться).
# ## Configure 'ip' variable to bind kubernetes services on a
# ## different ip than the default iface
# ## We should set etcd_member_name for etcd cluster. The node that is not a etcd member do not need to set the value, or can set the empty string value.
[all]
master-1.root.local.io ansible_host=192.168.0.5 ip=192.168.0.5
ingress-1.root.local.io ansible_host=192.168.0.4 ip=192.168.0.4
node-1.root.local.io ansible_host=192.168.0.6 ip=192.168.0.6
node-2.root.local.io ansible_host=192.168.0.3 ip=192.168.0.3
# ## configure a bastion host if your nodes are not directly reachable
# bastion ansible_host=x.x.x.x ansible_user=some_user
[kube-master]
master-1.root.local.io
[etcd]
master-1.root.local.io
[kube-node]
node-1.root.local.io
node-2.root.local.io
ingress-1.root.local.io
[kube-ingress-1]
ingress-1.root.local.io
[k8s-cluster:children]
kube-node
kube-master
Разберем, что следует из такой конфигурации:
- Наш кластер состоит из 4 узлов.
- Одна master-нода с компонентами Сontrol Plane.
- Одна нода с Ingress для маршрутизации трафика и две Worker ноды, на которых будут запускаться наши сервисы.
- Control Plane (API server, etcd, Sheduler, Controle manager) собран на одной ноде. Это очень нехорошо и обычно в секции [kube-master] более одного узла, а в секции [etcd] — более трех узлов. Почему 3 узла в etcd? Потому что quorum собирается не меньше, чем в 3 узла и с нечетным общим количеством узлов в etcd. Но в нашем учебном случае такой вариант оптимальный.
Сохраняем изменения в inventory.ini и идем в директорию group_vars/. Создаем там файл kube-ingress.yml с содержимым:
node_labels:
node-role.kubernetes.io/ingress: ""
node_taints:
- "node-role.kubernetes.io/ingress=:NoSchedule"
Это для корректной настройки Ingress контроллера. Далее редактируем файл k8s-cluster/addons.yml. Добавляем helm, сбор метрик для мониторинга и функционал Nginx ingress controller:
- helm_enabled: true
- metrics_server_enabled: true
- Убираем комментирование с Nginx ingress controller deployment
ingress_nginx_enabled: true
ingress_nginx_host_network: false
ingress_publish_status_address: ""
ingress_nginx_nodeselector:
kubernetes.io/os: "linux"
ingress_nginx_tolerations:
- key: "node-role.kubernetes.io/master"
operator: "Equal"
value: ""
effect: "NoSchedule"
ingress_nginx_namespace: "ingress-nginx"
ingress_nginx_insecure_port: 80
ingress_nginx_secure_port: 443
ingress_nginx_configmap:
map-hash-bucket-size: "128"
ssl-protocols: "SSLv2"
ingress_nginx_configmap_tcp_services:
9000: "default/example-go:8080"
ingress_nginx_configmap_udp_services:
53: "kube-system/coredns:53"
ingress_nginx_extra_args:
- --default-ssl-certificate=default/foo-tls
Также редактируем k8s-cluster/k8s-cluster.yml. Меняем network plugin на flannel и имя нашего кластера на root.local:
- kube_network_plugin: flannel
- cluster_name: root.local
Немножко подправим k8s-cluster/k8s-net-flannel.yml. Тут обычный regexp на сеть нашего провайдера VPS. У меня она 192.168.0.0/24. У вас может отличаться. Исправляем:
- flannel_interface_regexp: ‘192\.168\.0\.\d{1,9}’
Готово! Конфигурация закончена. Мы в рамках пяти конфигурационных файлов, смогли описать все необходимое для сборки. Вспомним:
- inventory.ini — назначаем IP-адреса и компонуем кластер.
- kube-ingress.yml — определяем Ingress.
- addons.yml — включаем в сборку необходимые компоненты. Добавляем helm, сбор метрик для мониторинга и функционал Nginx ingress controller.
- k8s-cluster.yml — выбираем network plugin и задаем имя нашему кластеру.
- k8s-net-flannel.yml — настраиваем network plugin.
Теперь осталоcь запустить playbook Ansible, который соберет кластер, и дождаться его выполнения. Переходим в корень директории kubespray и выполняем в терминале команду:
ansible-playbook -u root -i inventory/root/inventory.ini cluster.yml -b --diff
Разберем параметры. Запускаем ansible-playbook от имени root с инвентарем inventary.ini. Дальше Ansible начнет свою работу по настройке кластера. Обычно это занимает от 10 до 20 минут. Если в это время у вас вдруг отвалиться соединение ssh или еще какая беда случится и прервется сборка, то ее можно запустить повторно и это не вызовет ошибок. В итоге, должно получиться как на скрине ниже.
Кластер собран и готов к работе. Проверяем состав нод командой kubectl get nodes.
[root@master-1 kubespray]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
ingress-1.root.local.io Ready <none> 2d1h v1.19.3
master-1.root.local.io Ready master 2d1h v1.19.3
node-1.root.local.io Ready <none> 2d1h v1.19.3
node-2.root.local.io Ready <none> 2d1h v1.19.3
Видим, что кластер имеет одну мастер-ноду, две рабочие ноды и ингресс.
Но тут, если посмотреть в ROLE, можно заметить, что нашему Ingress-1 не назначена роль ingress. Исправляем kubectl label node ingress-1.root.local.io node-role.
kubernetes.io/ingress=ay]# kubectl label node ingress-1.root.local.io node-role.
node/ingress-1.root.local.io labeled
[root@master-1 kubespray]#
И повторно смотрим, чтобы назначилась нужная нам роль. Для расширенного просмотра информации по нодам можно использовать команду kubectl get nodes -owide.
[root@master-1 kubespray]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
ingress-1.root.local.io Ready ingress 2d1h v1.19.3
master-1.root.local.io Ready master 2d1h v1.19.3
node-1.root.local.io Ready <none> 2d1h v1.19.3
node-2.root.local.io Ready <none> 2d1h v1.19.3
[root@master-1 kubespray]#
Поздравляю! У вас получилось собрать k8s кластер и теперь можно развернуть в нем простенькое приложение. Но это уже тема следующих статей.
От редакции
Если вам интересно посещать бесплатные онлайн-мероприятия по DevOps, Kubernetes, Docker, GitlabCI и др. и задавать вопросы в режиме реального времени, подключайтесь к каналу DevOps by REBRAIN.
*Анонсы мероприятий каждую неделю
Практикумы для специалистов по инфраструктуре и разработчиков — https://rebrainme.com.
Наш Youtube-канал — https://www.youtube.com/channel/UC6uIx64IFKMVmj12gKtSgBQ.
Агентство Fevlake, проектируем и поддерживаем IT-инфраструктуры с 2012 года — https://fevlake.com.
Cпасибо за статью. 2 обслуживающему персоналу — по какой причине код не влазит в форму, например выдача метки .
2 автор, этот вариант развернет ингресс на всех нодах , а нужен ли он нам везде, в том числе и на мастерах….. Я бы предложил поиграться с лейблом kubernetes.io/os: , точнее вместо него завести другой, соответствующий узко ингрессу.
2 сервис — функционал редактирования коммента скоро добавить? И спасибо автору за статью, ждем обещанного продолжения