☸️ Первое знакомство с Kubernetes: создаем приложение для развертывания в кластере
Изучив основы и подготовив тестовый полигон, мы переходим к практической части. Сегодня разберем, как создать первое приложение на Python + Flask и развернуть его в кластере k8s.
Пишем приложение (Python + Flask)
Поскольку Python – единственный язык программирования, на котором я что-то умею писать, особого выбора у меня нет. Приложения будет запускаться как веб-сервер, слушать указанный порт и при обращении выдавать приветствие "Hello from Python". Кроме Python потребуется фреймворк Flask.
Код приложения:
В первых двух строчках мы подключаем Flask, а далее создаем обработку корневого запроса. Приложение неидеально, но как минимальный вариант для развертывания в кластере k8s оно сгодится. Так как k8s – это среда запуска контейнеров, для переноса приложение необходимо упаковать, например, в Docker.
Упаковываем приложение в контейнер Docker
Чтобы собрать контейнер, нужно поставить Docker на локальную машину (да, да – Капитан очевидность). Инструкция по инсталляции есть на официальном сайте – процесс довольно несложен. Далее собирать образ можно средствами Docker, я использую для этих целей утилиту buildah. Она ни разу меня не подводила, рекомендую.
Для начала создаем директорию, из которой
будем собирать контейнер. Первый файл в директории назовем, например, app.py
(его код приведен выше). Для установки зависимостей нам потребуется файл requirements.txt
. Поскольку приложение простенькое, достаточно добавить только модуль Flask:
Третий
файл называется Dockerfile
– без расширения. Его содержимое:
Разберем его построчно:
- FROM python:3.9-alpine – добавляем в контейнер интерпретатор Python 3.9, сборка alpine.
- RUN mkdir /app – создаем директорию
/app
внутри контейнера. - WORKDIR /app – позволяет один раз указать конкретный путь (каталог на диске), после чего большинство инструкций (например, RUN или COPY) будут выполняться в контексте этого каталога.
- ADD . /app/ – очень важная команда, если мы делаем контейнер для k8s. Дело в том что когда отрабатывает запуск контейнера, k8s думает, что нам необходима внешняя директория
/app
. Ее в кластере нет, и контейнер падает с ошибкой (не найден файл/app/app.py
). - RUN pip install -r requirements.txt – запускаем
pip
и скармливаем ему файл зависимостей. Flask скачивается и устанавливается в контейнер. - EXPOSE 5000 – пробрасываем порт 5000 для общения с нашим приложением.
- CMD ["python", "/app/app.py"] – запускаем интерпретатор Python и наше приложение
app.py
.
app.py
, requirements.txt
, Dockerfile
.Находясь в директории с файлами, выполняем команду для сборки контейнера на основе Dockerfile с помощью утилиты buildah:
Запустится сборка, прогрузятся все зависимости из requirements.txt
, и в
итоге сгенерируется хеш – строка Storing signatures
, которая нам в дальнейшем
понадобится (копируем ее в буфер обмена)
Дальше необходимо запушить сборку в локальный репозиторий Docker. Выполняем следующую команду, подставляя в параметры свой хеш:
- :app – это имя нашего контейнера (можно указать свой).
- :v0 – это tag. Обычно через него выставляется версионность для удобной навигации в репозитории.
Контейнер уже можно увидеть в списке локального репозитория Docker, выполнив следующую команду:
Приложение откликается, значит контейнер рабочий. Последний штрих – запушить контейнер из локального репозитория в удаленный, например, в Docker Hub. Это нужно, чтобы мы могли скачать контейнер в кластер k8s и запуститься его уже там.
Чтобы это сделать, потребуется авторизоваться на Docker Hub и создать пустой репозиторий. Детально описывать эту процедуру не буду: процесс похож на создание Git-репозитория.
Теперь можно на любом хосте с Docker запустить контейнер и в качестве расположения указать уже не локальный репозиторий, а Docker Hub.
Цель – развернуть приложение Python из контейнера, но уже в кластере k8s в нескольких репликах.
Для этого необходимо создать два объекта (подробнее мы рассматривали их в предыдущей статье):
- Deployment – развернет приложение и будет поддерживать необходимое количество реплик.
- Service – обеспечит сетевое взаимодействие внутри кластера.
Создаем Deployment для приложения в кластере k8s
Заходим по SSH на мастер-узел (ноду), проверяем работоспособность kubectl
.
Далее необходимо создать deployment.yaml
.
Разбираем подробнее:
- kind: Deployment – определяем, какой у нас будет объект. В данном случае
Deployment
, но может быть иService
или, скажем,Pod
. - name: app – имя нашего
Deployment
(именно так он будет отображаться в кластере k8s). - matchLabels: и app: app – метка приложения, ее уникальный идентификатор для дальнейшего мапинга с сервисом и другими объектами k8s.
- replicas: 2 – сколько экземпляров приложения необходимо создать
- containers: – этой секции описывается, откуда нам спулить контейнер (ясно дело, с Docker Hub). Порт для сетевого взаимодействия.
- resources: – интересная секция. Тут описаны минимально необходимые ресурсы для запуска (
limits
). Без этих ресурсов приложение не стартует и планировщик кластера будет искать подходящий узел, удовлетворяющую минимальным ресурсам. Запрашиваемые (requests
) – это ресурсы, которые резервируются на ноде для вашего приложения. Сверх этих ограничений приложение не получит ресурсов CPU и RAM.
Сохраняем файл deployment.yaml
и выполняем команду для развертывания приложения:
Если ошибок в файле не было, успешный исход – активное приложение в 2 репликах. Посмотреть состояние можно следующей командой:
Приложение
развернуто в двух репликах – с помощью curl можно обратиться к каждой из них по IP пода, но это плохой вариант (поды рано или поздно
переедут на другие узлы и IP поменяются). Давайте напишем еще один объект
кластера, который закроет эту проблему – Service
.
Создаем Service приложения в кластере k8s
endpoint
).Создаем еще один файл service.yaml
.
Его главные отличительные особенности:
- ports: port – порт, по которому
Service
будет принимать трафик. - targetPort – порт для связи с приложением.
- selector: – мапим наш
Deployment
и все реплики по этой метке. - type: clusterIP – тип объекта
Service
. В нашем случае для сетевого взаимодействия внутри кластера k8s.
Запускаем процедуру создания следующей командой:
Далее
смотрим детали Service
:
Супер! У нас есть IP, по которому можно обращаться к сервису в кластере с любого пода.
Подведем итог статьи. Мы добились следующих результатов:
- Написали приложение на Python + Flask.
- Упаковали приложение в контейнер Docker.
- Разместили контейнер в репозитории Docker hub.
- Сделали Deployment и Service в кластере k8s.
Поздравляю, вы развернули первое приложение в кластере k8s! Возможно оно простовато, но в следующих статьях мы будем доводить его до ума.