Привет, Друзья.
Недавно я написал простенькое приложение на Flask (Python) для Россиян, которые релоцировались в Казахстан, которое парсит официальный сайт ПС МИР, получает оттуда курс обмена валют, конвертирует в человеческих вид "Тенге за 1 рубль", записывает все показания в базу SQLite и рисует красивый график с использованием chart.js. Данный проект является open-source проектом, любой может использовать его или его части в своих проектах, а также разворачивать у себя, проект доступен на Github.
Сразу следует отметить пару человек, которые как минимум косвенно привели меня к созданию данного поста:
- https://vas3k.club/user/xandrcorr/ - подал идею и небольшой кусок кода для работы с PyQuery.
- https://vas3k.club/user/AndreiChenchik/ - подал идею о написании поста про Kubernetes в комментариях к посту о развертывании статического веб-сайта в Docker+Nginx.
Проект состоит из одного файла с расширением python с основной логикой данного проекта, файла базы данных SQLite и пары HTML шаблонов.
Так как я, а возможно и другие участники клуба хотят расширять свои познания, я экспериментирую с данным проектом.
Итак, в рамках данной статьи мы добавим gunicorn в качестве веб-сервера для нашего Flask-приложения, создадим Docker-образ и запустим контейнер в Kubernetes.
Приступим.
В данный момент используется встроенный во Flask веб-сервер, будем использовать gunicorn, установим его в venv и добавим в requirements.txt:
pip install gunicorn
# установка gunicorn в виртуальное окружение
Создадим файл Dockerfile:
FROM python:3.8
WORKDIR /app
COPY . .
RUN pip install -r requirements.txt
CMD [ "gunicorn", "--bind", "0.0.0.0:5000", "app:app" ]
#первый app - название модуля, файла, второй app - название приложения
Далее собираем образ и сразу назначаем имя образу:
docker build -t k8s-exrates .
#точка в конце указывает на текущий каталог
После успешной сборки образа Docker проверим работоспособноть нашего образа, запустим Docker-контейнер:
docker run -p 5000:5000 k8s-exrates
После нам необходимо установить Minikube:
brew install minikube
# https://kubernetes.io/ru/docs/tasks/tools/install-minikube/
Теперь запускаем Minikube:
minikube start
Запускаем Dashboard для отслеживания состояния нашего кластера, подов (контейнеров), сервисов:
minikube dashboard
Далее нам следует создать несколько файлов, первый flask_deployment.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: flask-app
spec:
replicas: 5 # реплики, есть один запустится с ошибкой, то запустится следующий
selector:
matchLabels:
app: flask-app
template:
metadata:
labels:
app: flask-app
spec:
containers:
- name: flask-app-container
image: k8s-exrates
# образ docker image, который мы сбилдили ранее
imagePullPolicy: Never
ports:
- containerPort: 5000 # порт контейнера
protocol: TCP
Затем файл flask_service.yaml:
apiVersion: v1
kind: Service
metadata:
name: flask-app-service
spec:
type: ClusterIP
ports:
- port: 5000
selector:
app: flask-app
Наконец файл flask_ingress.yaml:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: flask-app-ingress
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/ssl-redirect: "false"
spec:
rules:
- http:
paths:
- backend:
service:
name: flask-app-service
port:
number: 5000
path: /
pathType: Prefix
Теперь необходимо применить все конфигурации, это можно сделать одной командой:
kubectl apply -f flask_service.yaml -f flask_deployment.yaml -f flask_ingress.yaml
После этого необходимо загрузить сам образ Docker, который мы ранее собрали:
minikube image load k8s-exrates
#k8s-exrates - название образа
Для проверки запущены ли поды, сервисы и ингресс, можно прописать такое:
kubectl get pod
# Вывод запущенных контейнеров, реплик
NAME READY STATUS RESTARTS AGE
flask-app-5fd78976cb-h28jp 1/1 Running 0 58m
flask-app-5fd78976cb-h4mlf 1/1 Running 0 58m
flask-app-5fd78976cb-kwb2b 1/1 Running 0 58m
flask-app-5fd78976cb-wb5ct 1/1 Running 0 58m
flask-app-5fd78976cb-zsxdl 1/1 Running 0 58m
kubectl get service
# Вывод запущенных сервисов
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
flask-app-service2 ClusterIP 10.111.75.246 <none> 5000/TCP 59m
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 62m
kubectl get ingress
# Вывод запущенных правил для входящих соединений
NAME CLASS HOSTS ADDRESS PORTS AGE
flask-app-ingress2 <none> * 192.168.49.2 80 60m
Может случится так, что в ingress не будет отображаться IP-адрес, также, его не будет видно в Minikube Dashboard, для этого следует запустить пару следующих команд:
minikube addons enable ingress
minikube tunnel
В данном случае приложение будет доступно по адресу 127.0.0.1:80 (http порт)
Проверяем в браузере доступность приложения, всё работает.
Также, для проверки извне можно воспользоваться инструментов NGROK. После установки ngrok запускаем новый терминал и вводим:
ngrok http 127.0.0.1
# Вывод ссылки по которой доступно локально запущенное приложение и успешные возвраты 200 кода
ngrok (Ctrl+C to quit)
Session Status online
Account Bakhti Baymukhamedov (Plan: Free)
Version 3.0.2
Region India (in)
Latency 215.43725ms
Web Interface http://127.0.0.1:4040
Forwarding https://25b5-145-249-246-67.in.ngrok.io -> http://127.0.0.1:80
Connections ttl opn rt1 rt5 p50 p90
2 0 0.02 0.01 76.05 77.04
HTTP Requests
-------------
GET / 200 OK
GET / 200 OK
GET / 200 OK
КУБЕРНЕТЕС
Вот это хороший уровень оверинжиниринга. Ещё б сюда мониторинг впилить...
Люди делятся на 2 типа
Ну в самом деле! Это тренеровка "на кошках" как залить свое первое приложение в куб. Если вы каждые день деплоите 500 сервесив в куб - пройдите мимо (а ещё лучше подскажите как сделать лучше\проще). А для тех, кто никогда этого не делал - эта статья отличная точка входа.
Без автотестов - не пойдет!
Когда задача слишком простая, некоторые разработчики с лихвой компенсируют её сложностью реализации :)
Не слушай никого, всё реально четко и по делу =) . Миникуб в общем-то для этого и нужен.
а как же letsencrypt в ингрессе?