Привет, Хабр!
Многим в начале девопс-пути доверяют только настройку CI/CD. Но потом в один прекрасный день тимлид приходит с задачей развернуть инфраструктуру для бэкенд-разработки, и возникает ступор.
Меня зовут Вадим, я девопс-инженер в Surf. Прошёл ровно этот путь: в процессе накопил много полезной информации, сформировал инструкцию и теперь делюсь ею с вами. Расскажу, с чего начать, что ставить и как ко всему подступиться.
Чек-лист актуален на начало декабря 2022 года. Мы не будем глубоко погружаться в настройку каждого отдельного сервиса: затронем только установку плюс минимальную настройку для взаимодействия компонентов.
На чём будем ставить
Для развертывания окружения будем использовать виртуальную машину, созданную при помощи VMware vSphere Hypervisor. Но вы можете использовать всё, что есть под рукой: начиная от Bare Metal и заканчивая облачными провайдерами.
Я бы советовал использовать виртуализацию:
Легко масштабировать ресурсы (конечно, если они есть).
Есть snapshot и backup: всегда можно вернуться на шаг раньше, чтобы не переделывать сначала.
Относительно бесплатно в сравнении с облаком.
Что будем использовать
Ubuntu 20.04.5 LTS — ОС, на которой будем разворачивать остальные сервисы.
Docker — программное обеспечение для автоматизации развёртывания и управления приложениями в средах с поддержкой контейнеризации, контейнеризатор приложений.
K8s — система оркестрации docker-контейнеров. Для экономии ресурсов master будем использовать как worker node. Понимаем, что это не совсем правильно, но и цели high availability у нас не стоит. Если у вас достаточно ресурсов, master и worker node можно разделить.
Metallb — реализация балансировщика сетевой нагрузки для кластеров Kubernetes на «голом железе» со стандартными протоколами маршрутизации.
ArgoCD — декларативный инструмент непрерывной доставки GitOps для Kubernetes. При помощи него будем доставлять образы в наш k8s-кластер.
Traefik — обратный прокси сервер для доступа к сервисам извне.
HashiCorp Vault — обеспечит безопасный и надёжный способ хранения и распространения секретов.
Kafka — распределённый программный брокер сообщений.
Elasticsearch — масштабируемая утилита полнотекстового поиска и аналитики. Позволяет в режиме реального времени хранить и быстро искать и анализировать большие объёмы данных.
Kibana — веб-интерфейс для Elasticsearch, чтобы взаимодействовать с данными, которые хранятся в его индексах.
Fluentd — коллектор, который берет на себя прием и парсинг всех логов. Бережно укладывает всё это добро в индексы Elasticsearch.
PostgreSQL — СУБД.
Redis — резидентная система управления базами данных класса NoSQL.
Сегодня разберём установку Ubuntu, Docker, K8s, Metallb, и Traefik. Остальные сервисы посмотрим в следующей статье.
Установка и настройка
Ubuntu Server 20.04.5 LTS
Поскольку RedHat прекратил разработку и поддержку CentOS в конце 2021 года, выбор пал на Canonical c их Ubuntu Server.
Думаю, установить Ubuntu Server проблем не составит. Посоветовал бы использовать Logical Volume Manager, чтобы при увеличении количества данных можно было просто расширить диск.
Производим первоначальную настройку:
Отключаем swap, иначе k8s выдаст ошибку при старте и не запустится:
sudo swapoff --all
Комментируем строчку с монтированием в
/etc/fstab
![Комментируем последнюю строчку Комментируем последнюю строчку](https://habrastorage.org/getpro/habr/upload_files/b35/2f3/7a2/b352f37a263880973ab9dd388ab4c9e2.png)
Удаляем swap-файл для экономии места:
sudo rm /swap.img
Добавляем SSH-ключик, не забывая назначить права:
Выключаем авторизацию по паролю после проверки работоспособности SSH-ключа (опционально, на работоспособность не влияет).
Синхронизируем список пакетов и обновляем:
sudo apt update && sudo apt upgrade
Устанавливаем вспомогательные инструменты:
sudo apt install mc vim git apt-transport-https ca-certificates curl software-properties-common
Отдельно рекомендовал бы установить k9s для удобной визуализации происходящего в кластере. Обзор утилиты
wget https://github.com/derailed/k9s/releases/download/v0.26.7/k9s_Linux_x86_64.tar.gz
sudo tar -zxvf k9s_Linux_x86_64.tar.gz -C /usr/local/bin/
Проверяем, вводим k8s:
![](https://habrastorage.org/getpro/habr/upload_files/3be/28f/07f/3be28f07fd791d91fdcc7f3b39312f25.png)
Также нам потребуется средство упаковки Helm. Его будем использовать для деплоя наших сервисов, а также парочки вспомогательных сервисов из списка выше. Для установки выполним:
curl https://baltocdn.com/helm/signing.asc | gpg --dearmor | sudo tee /usr/share/keyrings/helm.gpg > /dev/null
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/helm.gpg] https://baltocdn.com/helm/stable/debian/ all main" | sudo tee /etc/apt/sources.list.d/helm-stable-debian.list
sudo apt-get update
sudo apt-get install helm
Docker
Среда исполнения у нас Docker: приступим к его установке. Далее будет идти пересказ инструкции c официального сайта Docker. Она достаточно информативная, но для удобства перечислим основные моменты, чтобы всё было собрано в одном месте.
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu focal stable"
sudo apt update
sudo apt install -y docker-ce
Добавляем текущего пользователя в группу docker, чтобы можно было выполнять команды без sudo. Это опционально и для k8s не нужно.
sudo gpasswd -a $USER docker
sudo su - ${USER}
Проверяем командой
docker ps
![](https://habrastorage.org/getpro/habr/upload_files/085/885/c31/085885c31e807d75596de98891b26ad6.png)
Kubernetes
На этом этапе с установкой Docker закончили, приступаем к установке k8s. Можно было использовать kubespray — это набор ролей Ansible для установки и конфигурирования k8s. Но для максимального понимания происходящего мы всё сделаем руками.
Добавляем ключик и репозиторий от k8s:
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add
sudo apt-add-repository "deb http://apt.kubernetes.io/ kubernetes-xenial main"
Я буду устанавливать версию 1.23.6: на момент установки она самая свежая у моего облачного провайдера. А так как в планах ещё и Stage и Prod, желательно сопоставить версии окружений.
Смотрим список доступных пакетов:
sudo apt list -a kubeadm
И устанавливаем k8s с фиксацией версии:
sudo apt install -y kubeadm=1.23.6-00 kubelet=1.23.6-00 kubectl=1.23.6-00
Очень важный шаг на BareMetal, о котором многие забывают, — зафиксировать версию k8s, чтобы в случае планового обновления пакетов не обновить или не развалить кластер:
sudo apt-mark hold kubelet kubeadm kubectl
Создаём файл параметров конфигурации для docker-демона в формате JSON с содержимым
sudo vim /etc/docker/daemon.json
{
"exec-opts": ["native.cgroupdriver=systemd"],
"log-driver": "json-file",
"log-opts": {
"max-size": "100m"
},
"storage-driver": "overlay2"
}
Перезапускаем связанные службы:
sudo systemctl daemon-reload && sudo systemctl restart docker && sudo systemctl restart kubelet
Стартуем кластер k8s:
sudo kubeadm init --pod-network-cidr=10.244.0.0/16
![](https://habrastorage.org/getpro/habr/upload_files/329/3b1/339/3293b1339d28312bb74512c07f78efe4.png)
Инструмент командной строки Kubernetes kubectl позволяет запускать команды для кластеров Kubernetes. Чтобы kubectl заработал, копируем конфиги в домашнюю директорию пользователя с назначением прав.
Создаём директорию хранения конфиг-файла в домашней директории пользователя:
mkdir -p $HOME/.kube
Копируем админский конфиг:
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
Назначаем пользователя:
sudo chown $(id -u):$(id -g) $HOME/.kube/config
Так как кластер однонодовый, разрешаем запускать поды на мастере или используем kubeadm join *** для подключения worker node:
kubectl taint nodes --all node-role.kubernetes.io/master-
Теперь можем проверить состояние нашего кластера
kubectl get nodes
![](https://habrastorage.org/getpro/habr/upload_files/a53/0aa/c69/a530aac6914b1d8e356d6be93aa53401.png)
Как видим, состояние
NotReady
: мы ещё не настроили сетевое взаимодействие. Исправим это с помощью Flannel. Выбрали его, потому что это проверенное и готовое к production сетевое решение. Тесты производительности Flannel >>
Cоздаём файл с конфигом Flannel:
sudo mkdir /run/flannel/
sudo vim /run/flannel/subnet.env
С содержимым:
FLANNEL_NETWORK=10.244.0.0/16
FLANNEL_SUBNET=10.244.0.1/24
FLANNEL_MTU=1450
FLANNEL_IPMASQ=true
Учитываем факт выбора диапозона IP и размера MTU с действующей инфраструктурой.
Разрешаем обработку bridge-трафика iptables-правилами:
sudo sysctl net.bridge.bridge-nf-call-iptables=1
Устанавливаем в наш k8s кластер Flannel:
kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml
![](https://habrastorage.org/getpro/habr/upload_files/32b/49d/1b6/32b49d1b61cf233e95681be642ba40ed.png)
Как видим, у нас установились дополнительные компоненты, такие как namespace, serviceaccount и прочие. Теперь опять проверим состояние кластера
kubectl get nodes
![](https://habrastorage.org/getpro/habr/upload_files/35c/93c/7dd/35c93c7dd10b9d7186a4b339e1361aea.png)
Кластер k8s готов, можно приступать к другим компонентам.
Metallb
Чтобы сервисы типа LoadBalancer получили «внешний» IP, будем использовать Metallb. Для этого нужно:
Включить строгий режим ARP:
kubectl edit configmap -n kube-system kube-proxy
Меняем strictARP: false
на strictARP: true
.
![](https://habrastorage.org/getpro/habr/upload_files/14a/ef2/328/14aef23282658e4b1a3dbabee50b560c.png)
Устанавливаем в наш k8s кластер Metallb:
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.13.7/config/manifests/metallb-native.yaml
![](https://habrastorage.org/getpro/habr/upload_files/b5a/775/03f/b5a77503f8c089751e45f9586d78a4ab.png)
Также нужно выделить пул IP-адресов, которые будут назначаться сервисам. Важно не забыть удалить этот пул из основного DHCP-сервера вашей сети. Создадим файл-манифест
cheap.yml
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: cheap
namespace: metallb-system
spec:
addresses:
- 10.20.30.1/32
И применим командой kubectl apply -f cheap.yml
В этой конфигурации я выделил один адрес из нашей сети. Можно выделять целые пулы, если есть такая потребность.
Traefik
Для балансировки сетевой нагрузки используем Traefik. Заодно проверим, как отрабатывает Metallb с выдачей IP-адресов сервисам. Вот тут нам и понадобится Helm, установленный на шаге выше.
Добавляем официальный репозиторий и обновляем содержимое:
helm repo add traefik https://helm.traefik.io/traefik
helm repo update
![](https://habrastorage.org/getpro/habr/upload_files/1d6/cc5/4e7/1d6cc54e77adf86ae06bab43c4b3a755.png)
Устанавливаем в отдельный namespace:
helm install traefik traefik/traefik --namespace traefik --create-namespace
![](https://habrastorage.org/getpro/habr/upload_files/1f5/963/adb/1f5963adb9f9b35f4d18210368aacc5c.png)
Проверяем назначение ip адреса сервису:
kubectl get svc -n traefik
![](https://habrastorage.org/getpro/habr/upload_files/4f4/d7b/368/4f4d7b3682b234281c9a1569ae4d02c5.png)
На этом минимальная инсталляция кластера готова. Уже можно разворачивать простые приложения которые не используют хранение данных (PostgreSQL, Vault, PersistentVolume и так далее), но могут отдавать любой статичный web-контент (Frontend).
В следующей части добавим в наш «dev stand» дополнительные компоненты для работы приложений и задеплоим собственное приложение при помощи ArgoCD + Helm.
Недавно мы запустили телеграм-канал Surf Web Team. Рассказываем о нашем опыте и кейсах, постим материалы по web, анонсы мероприятий, выкатываем актуальные cтажировки и вакансии в Surf. Добавляйтесь!
Больше кейсов команды Surf ищите на сайте >>