В статье будет рассмотрено, как собрать Docker-контейнер Node.js-приложения и затем развернуть его в Kubernetes-кластере. Также рассмотрим, как можно легко накатывать изменения в коде и инфраструктуре, а также правильную организацию раздачи asset’ов, подняв для этого перед приложением reverse proxy-сервер.
В качестве замены K8s-кластеру воспользуемся minikube, это позволит малыми затратами подготовить локальное окружения для работы с werf.
О werf
werf — утилита командной строки, помогающая в организации всего цикла доставки ваших приложений в Kubernetes. В основе ее работы лежит едины источник истины — Git-репозиторий, в котором хранится само приложение и его конфигурация. Состояние приложения определяется коммитом, в котором оно зафиксировано. werf собирает его, заливает в container registry, при необходимости дособирая несуществующие слои конечных образов, после чего разворачивает приложение в кластере, обновляя его составный части, если они изменились. Дополнительно werf умеет удалять из container registry устаревшие артефакты. Для этого применяется уникальный алгоритм, основанный на истории Git-репозитория и политиках, настроенных пользователем.
Основная фишка werf — объединение различных инструментов, используемых DevOps-/SRE-инженерами и разработчиками в свой работе, в рамках одной утилиты. Это Git, Docker, container registry, CI-система, Helm и Kubernetes. Компоненты тесно интегрированы между собой и опираются на большой опыт разработчиков утилиты в «кубернетизации» приложений.
Предварительная настройка окружения
Для начала необходимо поставить актуальную версию werf из стабильной ветки. Инструкция по установке доступна в официальной документации.
Описанные далее действия тестировались на ОС Linux (Ubuntu 20.04.03). Утилита доступна и для других ОС (Windows или macOS), ее команды идентичны, но в случае других операционных систем могут быть небольшие особенности.
Установка зависимостей
Необходимо настроить работоспособный Kubernetes-кластер. Выполним следующие шаги:
- настроим minikube — небольшой дистрибутив K8s, предназначенный для локальной установки;
- установим в него NGINX Ingress Controller — специальный компонент, отвечающий за проброс запросов извне внутрь;
- внесем изменения в /etc/hosts, чтобы обращаться к приложению в кластер по понятному имени имени, а не просто IP-адресу;
- войдем под своей учетной записью на Docker Hub;
- подготовим Secret с данными для входа в учетную запись Docker Hub;
- развернем приложение в настроенном K8s-кластере.
Установка и настройка minikube
Поставьте minikube по инструкции из официальной документации. В случае, если вы его уже когда-то устанавливали, проверьте, что стоит актуальная версия.
Создайте K8s-кластер:
# Удаляем существующий minikube-кластер, если он существует
minikube delete
# Запускаем новый minikube-кластер
minikube start --driver=docker
При каждом запуске kubectl придется явно указывать пространство имен. Это неудобно, поэтому настроим его по умолчанию (обратите внимание, что сейчас мы только настроим имя, а само пространство имен не создается, это мы сделаем далее по тексту):
kubectl config set-context minikube --namespace=werf-first-app
Если у вас нет kubectl, поставить ее можно одним из этих двух способов:
- воспользоваться входящей в состав minikube версией утилиты, для чего выполните две команды:
alias kubectl="minikube kubectl --"
echo 'alias kubectl="minikube kubectl --"' >> ~/.bash_aliases
Во втором случае при первом запуске kubectl нужная версия утилиты загрузится из репозиториев minikube и станет доступна для использования.
Проверим состояние кластера, взглянув на запущенные в нем Pod’ы:
kubectl get --all-namespaces pod
Нужно обратить внимание на содержание столбцов READY и STATUS: все Pod’ы должны находиться в статусе Running, а их количество быть равным 1/1 (важно, чтобы левое число соответствовало правому). Если видите что-то другое, то нужно немного подождать — Pod’ы запускаются не мгновенно, поэтому до изменения их статуса на активный может пройти некоторое время.
Установка NGINX Ingress Controller
Далее установим Ingress-контроллер. Он нужен для того, чтобы запросы извне кластера пробрасывались внутрь на наше приложение.
Сделать это можно следующей командой:
minikube addons enable ingress
Иногда установка занимает довольно много времени. Например, в моем случае процесс занял чуть больше четырех минут.
Если все установилось и активировалось, мы увидим соответствующее сообщение:
The 'ingress' addon is enabled
Подождем, пока он запустится, и проверим состояние кластера:
kubectl -n ingress-nginx get pod
Мы должны увидеть что-то наподобие этого:
Если статус Pod’а в нижней строке должен быть Running.
Правим /etc/hosts
Чтобы к приложению можно было обращаться по доменному имени, нужно добавить соответствующую запись в /etc/hosts.
Добавим в файл адрес werf-first-app.test. Посмотрим IP-адрес кластера, выполнив команду minikube ip. Она должна отобразить правильный IP-адрес (например, 192.168.49.2). Если вы видите что-то другое, нужно пройти предыдущие шаги заново.
Для добавления строки в hosts запустим команду:
echo "$(minikube ip) werf-first-app.test" | sudo tee -a /etc/hosts
Чтобы проверить, что все сработало как надо, проверьте содержимое /etc/hosts любым доступным способом, в конце должна добавиться строка 192.168.49.2 werf-first-app.test.
Проверим, что окружение настроено правильно. Обратимся на созданный адрес:
curl http://werf-first-app.test
Т.к. приложение пока не запущено, Ingress ответит ошибкой 404:
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx</center>
</body>
</html>
Логинимся на Docker Hub
Собираемые образы нужно где-то хранить. Очевидное решение — приватный репозиторий на Docker Hub с именем werf-first-app.
Теперь нужно авторизоваться на Docker Hub под своим аккаунтом:
docker login
Username: <ИМЯ ПОЛЬЗОВАТЕЛЯ DOCKER HUB>
Password: <ПАРОЛЬ ПОЛЬЗОВАТЕЛЯ DOCKER HUB>
В случае успешного входа отобразится сообщение Login Succeeded.
Генерация Secret для доступа к registry
Чтобы у werf был доступ к созданному container registry, необходимо подготовить Secret с параметрами для входа. Располагаться он должен в одном пространстве имен с приложением.
Создадим пространство имен приложения:
kubectl create namespace werf-first-app
В случае успешного выполнения мы увидим сообщение namespace/werf-first-app created.
Теперь сгенерируем Secret, задав ему имя registrysecret:
kubectl create secret docker-registry registrysecret
--docker-server='https://index.docker.io/v1/'
--docker-username='<ИМЯ ПОЛЬЗОВАТЕЛЯ DOCKER HUB>'
--docker-password='<ПАРОЛЬ ПОЛЬЗОВАТЕЛЯ DOCKER HUB>'
Если отобразилось secret/registrysecret created, значит Secret создан. В случае возникновения ошибки при создании Secret удалите его kubectl delete secret registrysecret, а затем создайте еще раз. К сожалению, возможности отредактировать созданный Secret нет.
В документации Kubernetes этот метод создания Secret’ов указан как стандартный.
Теперь у нас готово окружение, и можно начинать разработку и деплой приложения!