Найти тему
Типичный программист

Собираем в Kubernetes приложение на Node.js с помощью werf

Оглавление

В статье будет рассмотрено, как собрать 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, поставить ее можно одним из этих двух способов:

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’ов указан как стандартный.

Теперь у нас готово окружение, и можно начинать разработку и деплой приложения!