Хабрахабр

[Перевод] Настройка кластера HA Kubernetes на «голом железе» с GlusterFS & MetalLB. Часть 2/3


Часть 1/3 тут

Это вторая часть статьи о настройке кластера Kubernetes на «голом железе». Привет и с возвращением! Ну а теперь пришло время настроить дополнительную среду и утилиты, чтобы сделать кластер полезнее и максимально приближенным к рабочему состоянию. Ранее мы настраивали НА-кластер Kubernetes с помощью внешнего etcd, схемы «ведущий-ведущий» и балансировки нагрузки.

Также мы установим и настроим распределенное хранилище файлов между нашими рабочими нодами. В этой части статьи мы сосредоточимся на настройке внутреннего балансировщика нагрузки сервисов кластера — это будет MetalLB. Будем использовать GlusterFS для постоянных томов, которые доступны в Kubernetes.
После выполнения всех действий схема нашего кластера будет выглядеть следующим образом:

1. Настройка MetalLB в качестве внутреннего балансировщика нагрузки.

Несколько слов о MetalLB, непосредственно со страницы документа:

MetalLB — это реализация балансировщика нагрузки для кластеров Kubernetes на «голом железе» со стандартными протоколами маршрутизации.

Все варианты реализации Network LB, с которыми поставляется Kubernetes, — это связующий код, он обращается к различным платформам IaaS (GCP, AWS, Azure и др.). Kubernetes не предлагает реализацию сетевых балансировщиков нагрузки (служб типа LoadBalancer) для «голого железа». Если вы не работаете на платформе, поддерживаемой IaaS (GCP, AWS, Azure и др.), LoadBalancer при создании останется в состоянии «ожидания» на неопределенный срок.

Оба этих варианта имеют существенные недостатки в продакшене, что превращает BM-кластеры в граждан второго сорта в экосистеме Kubernetes. Операторы BM-серверов располагают двумя менее эффективными инструментами для ввода трафика пользователя в свои кластеры, службы «NodePort» и «externalIPs».

MetalLB стремится исправить этот дисбаланса, предлагая реализацию Network LB, которая интегрируется со стандартным сетевым оборудованием, так что внешние службы на BM-кластерах также «просто работают» на максималках.

Процесс настройки действительно прост и понятен. Таким образом, с помощью этого инструмента мы запускаем сервисы в кластере Kubernetes, используя балансировщик нагрузки, — за что огромное спасибо команде MetalLB.

168. Ранее в примере мы выбрали для нужд нашего кластера подсеть 192. 0/24. 0. Теперь возьмем некоторую часть этой подсети для будущего балансировщика нагрузки.

Входим в систему машины с настроенной утилитой kubectl и запускаем:

control# kubectl apply -f https://raw.githubusercontent.com/google/metallb/v0.7.3/manifests/metallb.yaml

Убедитесь, что все компоненты MetalLB функционируют нормально: Это развернет MetalLB в кластере, в неймспейсе metallb-system.

control# kubectl get pod --namespace=metallb-system NAME READY STATUS RESTARTS AGE controller-7cc9c87cfb-ctg7p 1/1 Running 0 5d3h speaker-82qb5 1/1 Running 0 5d3h speaker-h5jw7 1/1 Running 0 5d3h speaker-r2fcg 1/1 Running 0 5d3h

В этом примере мы используем настройку Layer 2. Теперь настроим MetalLB с помощью configmap. За информацией о других вариантах настройки обращайтесь к документации MetalLB.

Создайте файл metallb-config.yaml в любой директории внутри выбранного IP-диапазона подсети нашего кластера:

control# vi metallb-config.yaml
apiVersion: v1 kind: ConfigMap metadata: namespace: metallb-system name: config data: config: | address-pools: - name: default protocol: layer2 addresses: - 92.168.0.240-192.168.0.250

И примените эту настройку:

control# kubectl apply -f metallb-config.yaml

При необходимости проверьте и измените configmap позднее:

control# kubectl describe configmaps -n metallb-system
control# kubectl edit configmap config -n metallb-system

Проверим, как он работает, на примере службы Nginx. Теперь у нас есть собственный настроенный локальный балансировщик нагрузки.

control# vi nginx-deployment.yaml
apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment spec: selector: matchLabels: app: nginx replicas: 3 template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:latest ports: - containerPort: 80 control# vi nginx-service.yaml
apiVersion: v1 kind: Service metadata: name: nginx spec: type: LoadBalancer selector: app: nginx ports: - port: 80 name: http

Затем создайте тестовый деплой и службу Nginx:

control# kubectl apply -f nginx-deployment.yaml
control# kubectl apply -f nginx-service.yaml

А теперь — проверим результат:

control# kubectl get po NAME READY STATUS RESTARTS AGE nginx-deployment-6574bd76c-fxgxr 1/1 Running 0 19s nginx-deployment-6574bd76c-rp857 1/1 Running 0 19s nginx-deployment-6574bd76c-wgt9n 1/1 Running 0 19s
control# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE nginx LoadBalancer 10.100.226.110 192.168.0.240 80:31604/TCP 107s

Служба Nginx будет направлять трафик на все эти поды по схеме циклической балансировки. Создано 3 пода Nginx, как мы и указали в деплое ранее. И вы также можете увидеть внешний IP, полученный от нашего балансировщика нагрузки MetalLB.

168. Теперь попробуйте свернуться на IP-адрес 192. 240, и вы увидите страницу Nginx index.html. 0. Не забудьте удалить тестовое развертывание и службу Nginx.

control# kubectl delete svc nginx service "nginx" deleted
control# kubectl delete deployment nginx-deployment deployment.extensions "nginx-deployment" deleted

Хорошо, на этом с MetalLB всё, идем дальше — настроим GlusterFS для томов Kubernetes.

2. Настройка GlusterFS с Heketi на рабочих нодах.

Как вы знаете, поды — эфемерны, т.е. По факту, кластер Kubernetes невозможно юзать без томов внутри него. Все данные внутри них будут потеряны. их можно создать и удалить в любой момент. Таким образом, в реальном кластере потребуется распределенное хранилище, чтобы обеспечить обмен настройками и данными между нодами и приложениями внутри него.

В этом примере я продемонстрирую, как создается хранилище GlusterFS для любых внутренних приложений, оно — как постоянные тома. В Kubernetes тома доступны в различных вариантах, выбирайте подходящие. Ранее я использовал для этого «системную» установку GlusterFS на всех рабочих нодах Kubernetes, а затем просто создавал тома типа hostPath в каталогах GlusterFS.

Теперь у нас есть новый удобный инструмент Heketi.

Несколько слов из документации Heketi:

Инфраструктура управления томами на основе RESTful для GlusterFS.

Благодаря Heketi облачные сервисы, например OpenStack Manila, Kubernetes и OpenShift, могут динамически предоставлять тома GlusterFS с любым поддерживаемым типом надежности. Heketi предлагает интерфейс управления RESTful, который можно использовать для управления жизненным циклом томов GlusterFS. Heketi также поддерживает любое количество кластеров GlusterFS, позволяя облачным службам предлагать сетевое хранилище файлов, не ограничиваясь единственным кластером GlusterFS. Heketi автоматически определяет местоположение блоков в кластере, обеспечивая расположение блоков и их реплик в разных областях отказов.

В конце концов вы сможете создавать PersistentVolumeClaims, которые будут формироваться автоматически, и многое другое. Звучит неплохо, и, кроме того, этот инструмент приблизит наш ВМ-кластер к большим облачным кластерам Kubernetes.

В этом примере я воспользуюсь вторым методом. Можно взять дополнительные системные жесткие диски для настройки GlusterFS или просто создать несколько фиктивных блочных устройств.

Создайте фиктивные блочные устройства на всех трех рабочих нодах:

worker1-3# dd if=/dev/zero of=/home/gluster/image bs=1M count=10000

Затем используйте losttup — чтобы добавить его в эти ноды, в качестве петлевого устройства: Вы получите файл размером около 10 ГБ.

worker1-3# losetup /dev/loop0 /home/gluster/image

Обратите внимание: если у вас уже есть некое петлевое устройство 0, то вам потребуется выбрать любой другой номер.

Поэтому, чтобы предотвратить любые проблемы в будущих конфигурациях, сначала убедимся, что мы загрузили модуль ядра dm_thin_pool и установили пакет glusterfs-client на всех рабочих нодах. Я не пожалел времени и выяснил, почему Heketi не хочет работать должным образом.

worker1-3# modprobe dm_thin_pool
worker1-3# apt-get update && apt-get -y install glusterfs-client

Не забудьте создать службу systemd, которая будет автоматически запускать losetup и modprobe при каждой загрузке этих серверов. Хорошо, теперь нужно, чтобы на всех рабочих нодах присутствовали файл /home/gluster/image и устройство /dev/loop0.

worker1-3# vi /etc/systemd/system/loop_gluster.service
[Unit]
Description=Create the loopback device for GlusterFS
DefaultDependencies=false
Before=local-fs.target
After=systemd-udev-settle.service
Requires=systemd-udev-settle.service
[Service]
Type=oneshot
ExecStart=/bin/bash -c "modprobe dm_thin_pool && [ -b /dev/loop0 ] || losetup /dev/loop0 /home/gluster/image"
[Install]
WantedBy=local-fs.target

И включите ее:

worker1-3# systemctl enable /etc/systemd/system/loop_gluster.service
Created symlink /etc/systemd/system/local-fs.target.wants/loop_gluster.service → /etc/systemd/system/loop_gluster.service.

Для этого я буду использовать вот это прикольное руководство. Подготовительные работы закончены, и мы готовы деплоить GlusterFS и Heketi в наш кластер. Большинство команд запускаем с внешнего управляющего компьютера, а очень маленькие команды запускаются с любой мастер-ноды внутри кластера.

Сначала скопируем репозиторий и создадим DaemonSet GlusterFS:

control# git clone https://github.com/heketi/heketi
control# cd heketi/extras/kubernetes
control# kubectl create -f glusterfs-daemonset.json

Теперь пометим наши три рабочие ноды для GlusterFS; после нанесения меток на них будут созданы поды GlusterFS:

control# kubectl label node worker1 storagenode=glusterfs
control# kubectl label node worker2 storagenode=glusterfs
control# kubectl label node worker3 storagenode=glusterfs
control# kubectl get pod
NAME READY STATUS RESTARTS AGE
glusterfs-5dtdj 1/1 Running 0 1m6s
glusterfs-hzdll 1/1 Running 0 1m9s
glusterfs-p8r59 1/1 Running 0 2m1s

Теперь создадим учетную запись службы Heketi:

control# kubectl create -f heketi-service-account.json

Для этого создадим кластерную функцию, обязательную для нашей только что созданной учетной записи службы: Обеспечим для этой учетной записи службы возможность управлять подами gluster.

control# kubectl create clusterrolebinding heketi-gluster-admin --clusterrole=edit --serviceaccount=default:heketi-service-account

Теперь давайте создадим секретный ключ Kubernetes, который блокирует конфигурацию нашего экземпляра Heketi:

control# kubectl create secret generic heketi-config-secret --from-file=./heketi.json

Создайте первый исходный под Heketi, который мы используем для первых операций по настройке и впоследствии удалим:

control# kubectl create -f heketi-bootstrap.json
service "deploy-heketi" created
deployment "deploy-heketi" created
control# kubectl get pod
NAME READY STATUS RESTARTS AGE
deploy-heketi-1211581626-2jotm 1/1 Running 0 2m
glusterfs-5dtdj 1/1 Running 0 6m6s
glusterfs-hzdll 1/1 Running 0 6m9s
glusterfs-p8r59 1/1 Running 0 7m1s

После создания и запуска службы Bootstrap Heketi нам потребуется перейти на один из наших мастер-нодов, там мы запустим несколько команд, поскольку наш внешний управляющий нод не находится внутри нашего кластера, поэтому мы не можем получить доступ к работающим подам и внутренней сети кластера.

Сначала давайте загрузим утилиту heketi-client и скопируем ее в системную папку bin:

master1# wget https://github.com/heketi/heketi/releases/download/v8.0.0/heketi-client-v8.0.0.linux.amd64.tar.gz
master1# tar -xzvf ./heketi-client-v8.0.0.linux.amd64.tar.gz
master1# cp ./heketi-client/bin/heketi-cli /usr/local/bin/
master1# heketi-cli heketi-cli v8.0.0

Теперь найдем IP-адрес пода heketi и экспортируем его как системную переменную:

master1# kubectl --kubeconfig /etc/kubernetes/admin.conf describe pod deploy-heketi-1211581626-2jotm For me this pod have a 10.42.0.1 ip
master1# curl http://10.42.0.1:57598/hello
Handling connection for 57598
Hello from Heketi
master1# export HEKETI_CLI_SERVER=http://10.42.0.1:57598

Мы предоставляем ее через файл топологии. Теперь давайте предоставим Heketi информацию о кластере GlusterFS, которым он должен управлять. Топология — это манифест JSON со списком всех нод, дисков и кластеров, используемых GlusterFS.

Убедитесь, что hostnames/manage указывает на точное название, как в разделе kubectl get node, и что hostnames/storage — это IP-адрес нодов хранилища. ПРИМЕЧАНИЕ.

master1:~/heketi-client# vi topology.json
, "zone": 1 }, "devices": [ "/dev/loop0" ] }, { "node": { "hostnames": { "manage": [ "worker2" ], "storage": [ "192.168.0.8" ] }, "zone": 1 }, "devices": [ "/dev/loop0" ] }, { "node": { "hostnames": { "manage": [ "worker3" ], "storage": [ "192.168.0.9" ] }, "zone": 1 }, "devices": [ "/dev/loop0" ] } ] } ]
}

Затем загрузите этот файл:

master1:~/heketi-client# heketi-cli topology load --json=topology.json
Creating cluster ... ID: e83467d0074414e3f59d3350a93901ef Allowing file volumes on cluster. Allowing block volumes on cluster. Creating node worker1 ... ID: eea131d392b579a688a1c7e5a85e139c Adding device /dev/loop0 ... OK Creating node worker2 ... ID: 300ad5ff2e9476c3ba4ff69260afb234 Adding device /dev/loop0 ... OK Creating node worker3 ... ID: 94ca798385c1099c531c8ba3fcc9f061 Adding device /dev/loop0 ... OK

Название команды немного странное, но все в порядке. Далее мы используем Heketi, чтобы предоставить тома для хранения базы данных. Также создайте хранилище heketi:

master1:~/heketi-client# heketi-cli setup-openshift-heketi-storage
master1:~/heketi-client# kubectl --kubeconfig /etc/kubernetes/admin.conf create -f heketi-storage.json secret/heketi-storage-secret created
endpoints/heketi-storage-endpoints created
service/heketi-storage-endpoints created
job.batch/heketi-storage-copy-job created

Вернемся к управляющей ноде и продолжим оттуда; в первую очередь убедитесь, что последняя запущенная команда успешно выполнена: Это все команды, которые нужно запустить с мастер-ноды.

control# kubectl get pod
NAME READY STATUS RESTARTS AGE
glusterfs-5dtdj 1/1 Running 0 39h
glusterfs-hzdll 1/1 Running 0 39h
glusterfs-p8r59 1/1 Running 0 39h
heketi-storage-copy-job-txkql 0/1 Completed 0 69s

И задание heketi-storage-copy-job выполнено.

Если на данный момент на ваших рабочих нодах отсутствует установленный пакет glusterfs-client, то имеет место ошибка.

Пришло время удалить установочный файл Bootstrap Heketi и произвести небольшую очистку:

control# kubectl delete all,service,jobs,deployment,secret --selector="deploy-heketi"

На последнем этапе нам нужно создать долгосрочный экземпляр Heketi:

control# cd ./heketi/extras/kubernetes
control:~/heketi/extras/kubernetes# kubectl create -f heketi-deployment.json
secret/heketi-db-backup created
service/heketi created
deployment.extensions/heketi created
control# kubectl get pod
NAME READY STATUS RESTARTS AGE
glusterfs-5dtdj 1/1 Running 0 39h
glusterfs-hzdll 1/1 Running 0 39h
glusterfs-p8r59 1/1 Running 0 39h
heketi-b8c5f6554-knp7t 1/1 Running 0 22m

А мы почти закончили, теперь база данных Heketi сохраняется в томе GlusterFS и не сбрасывается при каждом перезапуске пода Heketi. Если на данный момент на ваших рабочих нодах отсутствует установленный пакет glusterfs-client, то имеет место ошибка.

Чтобы начать использовать кластер GlusterFS с динамическим выделением ресурсов, нам нужно создать StorageClass.

Сначала давайте найдем конечную точку хранилища Gluster, которая будет передана в StorageClass в качестве параметра (heketi-storage-endpoints):

control# kubectl get endpoints
NAME ENDPOINTS AGE
heketi 10.42.0.2:8080 2d16h
....... ... ..

Теперь создайте несколько файлов:

control# vi storage-class.yml
apiVersion: storage.k8s.io/v1beta1
kind: StorageClass
metadata: name: slow
provisioner: kubernetes.io/glusterfs
parameters: resturl: "http://10.42.0.2:8080"
control# vi test-pvc.yml
kind: PersistentVolumeClaim
apiVersion: v1
metadata: name: gluster1 annotations: volume.beta.kubernetes.io/storage-class: "slow"
spec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi

Используйте эти файлы для создания class и pvc:

control# kubectl create -f storage-class.yaml
storageclass "slow" created
control# kubectl get storageclass
NAME PROVISIONER AGE
slow kubernetes.io/glusterfs 2d8h
control# kubectl create -f test-pvc.yaml
persistentvolumeclaim "gluster1" created
control# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE gluster1 Bound pvc-27f733cd-1c77-11e9-bb07-7efe6b0e6fa5 1Gi RWO slow 2d8h

Мы также можем просмотреть том PV:

control# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-27f733cd-1c77-11e9-bb07-7efe6b0e6fa5 1Gi RWO Delete Bound default/gluster1 slow 2d8h

Теперь у нас есть динамически созданный том GlusterFS, связанный с PersistentVolumeClaim, и мы можем использовать это утверждение в любом поде.

Создайте простой под Nginx и протестируйте его:

control# vi nginx-test.yml apiVersion: v1
kind: Pod
metadata: name: nginx-pod1 labels: name: nginx-pod1
spec: containers: - name: nginx-pod1 image: gcr.io/google_containers/nginx-slim:0.8 ports: - name: web containerPort: 80 volumeMounts: - name: gluster-vol1 mountPath: /usr/share/nginx/html volumes: - name: gluster-vol1 persistentVolumeClaim: claimName: gluster1
control# kubectl create -f nginx-test.yaml
pod "nginx-pod1" created

Просмотрите под (подождите несколько минут, возможно, потребуется загрузить образ, если он еще не существует):

control# kubectl get pods NAME READY STATUS RESTARTS AGE
glusterfs-5dtdj 1/1 Running 0 4d10h
glusterfs-hzdll 1/1 Running 0 4d10h
glusterfs-p8r59 1/1 Running 0 4d10h
heketi-b8c5f6554-knp7t 1/1 Running 0 2d18h
nginx-pod1 1/1 Running 0 47h

Теперь войдите в контейнер и создайте файл index.html:

control# kubectl exec -ti nginx-pod1 /bin/sh
# cd /usr/share/nginx/html
# echo 'Hello there from GlusterFS pod !!!' > index.html
# ls
index.html
# exit

Потребуется найти внутренний IP-адрес пода и свернуться в него из любой мастер-ноды:

master1# curl 10.40.0.1
Hello there from GlusterFS pod !!!

При этом мы просто тестируем наш новый постоянный том.

Их можно запустить на своем компьютере при наличии установленного heketi-cli. Несколько полезных команд для проверки нового кластера GlusterFS: heketi-cli cluster list и heketi-cli volume list. В данном примере это нода master1.

master1# heketi-cli cluster list
Clusters:
Id:e83467d0074414e3f59d3350a93901ef [file][block]
master1# heketi-cli volume list
Id:6fdb7fef361c82154a94736c8f9aa53e Cluster:e83467d0074414e3f59d3350a93901ef Name:vol_6fdb7fef361c82154a94736c8f9aa53e
Id:c6b69bd991b960f314f679afa4ad9644 Cluster:e83467d0074414e3f59d3350a93901ef Name:heketidbstorage

На этом этапе мы успешно настроили внутренний балансировщик нагрузки с файловым хранилищем, и наш кластер теперь ближе к рабочему состоянию.

В следующей части статьи мы сосредоточимся на создании системы мониторинга кластера, а также запустим в нем тестовый проект для использования всех настроенных нами ресурсов.

Оставайтесь на связи, и всего хорошего!

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть