Работа мечты в один клик 💼

💭Мечтаешь работать в Сбере, но не хочешь проходить десять кругов HR-собеседований? Теперь это проще, чем когда-либо!
💡AI-интервью за 15 минут – и ты уже на шаг ближе к своей новой работе.
Как получить оффер? 📌 Зарегистрируйся 📌 Пройди AI-интервью 📌 Получи обратную связь сразу же!
HR больше не тянут время – рекрутеры свяжутся с тобой в течение двух дней! 🚀
Реклама. ПАО СБЕРБАНК, ИНН 7707083893. Erid 2VtzquscAwp
Пишем приложение (Python + Flask)
Поскольку Python – единственный язык программирования, на котором я что-то умею писать, особого выбора у меня нет. Приложения будет запускаться как веб-сервер, слушать указанный порт и при обращении выдавать приветствие "Hello from Python". Кроме Python потребуется фреймворк Flask.
Код приложения:
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello from Python"
if __name__ == "__main__":
app.run(host='0.0.0.0')
В первых двух строчках мы подключаем Flask, а далее создаем обработку корневого запроса. Приложение неидеально, но как минимальный вариант для развертывания в кластере k8s оно сгодится. Так как k8s – это среда запуска контейнеров, для переноса приложение необходимо упаковать, например, в Docker.
Упаковываем приложение в контейнер Docker
Чтобы собрать контейнер, нужно поставить Docker на локальную машину (да, да – Капитан очевидность). Инструкция по инсталляции есть на официальном сайте – процесс довольно несложен. Далее собирать образ можно средствами Docker, я использую для этих целей утилиту buildah. Она ни разу меня не подводила, рекомендую.
Для начала создаем директорию, из которой
будем собирать контейнер. Первый файл в директории назовем, например, app.py
(его код приведен выше). Для установки зависимостей нам потребуется файл requirements.txt
. Поскольку приложение простенькое, достаточно добавить только модуль Flask:
Flask==1.0.2
Третий
файл называется Dockerfile
– без расширения. Его содержимое:
FROM python:3.9-alpine
RUN mkdir /app
WORKDIR /app
ADD . /app/
RUN pip install -r requirements.txt
EXPOSE 5000
CMD ["python", "/app/app.py"]
Разберем его построчно:
- 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:
buildah bud -f ./Dockerfile .
Запустится сборка, прогрузятся все зависимости из requirements.txt
, и в
итоге сгенерируется хеш – строка Storing signatures
, которая нам в дальнейшем
понадобится (копируем ее в буфер обмена)

Дальше необходимо запушить сборку в локальный репозиторий Docker. Выполняем следующую команду, подставляя в параметры свой хеш:
buildah push dedd9a5526d3c97231e9a0b73ca1e4a91ece0d70a7f7bff254f61f7d28d8e9fb docker-daemon:app:v0
- :app – это имя нашего контейнера (можно указать свой).
- :v0 – это tag. Обычно через него выставляется версионность для удобной навигации в репозитории.
Контейнер уже можно увидеть в списке локального репозитория Docker, выполнив следующую команду:
docker image ls

docker run --rm -d -v `pwd`:/app -p 5000:5000 app:v0

Приложение откликается, значит контейнер рабочий. Последний штрих – запушить контейнер из локального репозитория в удаленный, например, в Docker Hub. Это нужно, чтобы мы могли скачать контейнер в кластер k8s и запуститься его уже там.
Чтобы это сделать, потребуется авторизоваться на Docker Hub и создать пустой репозиторий. Детально описывать эту процедуру не буду: процесс похож на создание Git-репозитория.
docker login
<выполните авторизацию>. Делается один раз, пароль и логин запоминаются
docker tag app:v0 <ваш логин docker hub>/<ваш репозиторий>/app:v0
buildah push <image ID> <ваш логин docker hub>/<ваш репозиторий>:app
Теперь можно на любом хосте с Docker запустить контейнер и в качестве расположения указать уже не локальный репозиторий, а Docker Hub.
docker run --rm -d -v `pwd`:/app -p 5000:5000 test/learn_images:app:v0
Цель – развернуть приложение Python из контейнера, но уже в кластере k8s в нескольких репликах.
Для этого необходимо создать два объекта (подробнее мы рассматривали их в предыдущей статье):
- Deployment – развернет приложение и будет поддерживать необходимое количество реплик.
- Service – обеспечит сетевое взаимодействие внутри кластера.
Создаем Deployment для приложения в кластере k8s
Заходим по SSH на мастер-узел (ноду), проверяем работоспособность kubectl
.
Далее необходимо создать deployment.yaml
.
apiVersion: apps/v1
kind: Deployment
metadata:
name: app
labels:
app: app
spec:
replicas: 2
selector:
matchLabels:
app: app
template:
metadata:
labels:
app: app
spec:
containers:
- name: app
image: <ваш логин docker hub>/<ваш репозиторий>:app
ports:
- containerPort: 5000
protocol: TCP
name: http
resources:
limits:
cpu: 50m
memory: 20Mi
requests:
cpu: 50m
memory: 20Mi
Разбираем подробнее:
- 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
и выполняем команду для развертывания приложения:
kubectl create -f deployment.yaml
Если ошибок в файле не было, успешный исход – активное приложение в 2 репликах. Посмотреть состояние можно следующей командой:
kubectl get pod -o wide
Приложение
развернуто в двух репликах – с помощью curl можно обратиться к каждой из них по IP пода, но это плохой вариант (поды рано или поздно
переедут на другие узлы и IP поменяются). Давайте напишем еще один объект
кластера, который закроет эту проблему – Service
.
Создаем Service приложения в кластере k8s
endpoint
).Создаем еще один файл service.yaml
.
apiVersion: v1
kind: Service
metadata:
labels:
app: app
name: app
spec:
ports:
- port: 8080
protocol: TCP
targetPort: 5000
selector:
app: app
type: ClusterIP
Его главные отличительные особенности:
- ports: port – порт, по которому
Service
будет принимать трафик. - targetPort – порт для связи с приложением.
- selector: – мапим наш
Deployment
и все реплики по этой метке. - type: clusterIP – тип объекта
Service
. В нашем случае для сетевого взаимодействия внутри кластера k8s.
Запускаем процедуру создания следующей командой:
kubectl create -f service.yaml
Далее
смотрим детали Service
:
kubectl get svc -o wide

Супер! У нас есть IP, по которому можно обращаться к сервису в кластере с любого пода.
Подведем итог статьи. Мы добились следующих результатов:
- Написали приложение на Python + Flask.
- Упаковали приложение в контейнер Docker.
- Разместили контейнер в репозитории Docker hub.
- Сделали Deployment и Service в кластере k8s.
Поздравляю, вы развернули первое приложение в кластере k8s! Возможно оно простовато, но в следующих статьях мы будем доводить его до ума.
Комментарии