Готовим Flask приложение для Docker + Kubernetes

 Публичный пост
28 августа 2022  939

Привет, Друзья.

Недавно я написал простенькое приложение на Flask (Python) для Россиян, которые релоцировались в Казахстан, которое парсит официальный сайт ПС МИР, получает оттуда курс обмена валют, конвертирует в человеческих вид "Тенге за 1 рубль", записывает все показания в базу SQLite и рисует красивый график с использованием chart.js. Данный проект является open-source проектом, любой может использовать его или его части в своих проектах, а также разворачивать у себя, проект доступен на Github.

Сразу следует отметить пару человек, которые как минимум косвенно привели меня к созданию данного поста:

  1. https://vas3k.club/user/xandrcorr/ - подал идею и небольшой кусок кода для работы с PyQuery.
  2. 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
Связанные посты
9 комментариев 👇

КУБЕРНЕТЕС

  Развернуть 1 комментарий
Mark Aliev Бекенд Разработчик 28 августа 2022

Вот это хороший уровень оверинжиниринга. Ещё б сюда мониторинг впилить...

  Развернуть 1 комментарий

кубернетес это конечно весело, но для такого проекта перебор

бесплатный серверлесс (для наблюдателя) способ:

  1. делаем скрипт на чем удобно, который скачивает инфу и сохраняет в файл
  2. делаем статический сайт, который рисует графики (например) из локального файла
  3. на гитхабе по крону запускаем скрипт и обновленный файл комиттим прямо в репозиторий
  4. заправляем это дело vercelом
  5. профит!

один из примеров:

  Развернуть 1 комментарий

Без автотестов - не пойдет!

  Развернуть 1 комментарий
Илья Гусев 🌱🌿☘️🍀🌵🌴🌲🌳 28 августа 2022

а как же letsencrypt в ингрессе?

  Развернуть 1 комментарий

И прямо руками все деплоить? нужен gitops и argocd :)

  Развернуть 1 комментарий

Не слушай никого, всё реально четко и по делу =) . Миникуб в общем-то для этого и нужен.

  Развернуть 1 комментарий

Когда задача слишком простая, некоторые разработчики с лихвой компенсируют её сложностью реализации :)

  Развернуть 1 комментарий

Люди делятся на 2 типа

  1. Это оверинжиниринг
  2. Слишком сложно

Ну в самом деле! Это тренеровка "на кошках" как залить свое первое приложение в куб. Если вы каждые день деплоите 500 сервесив в куб - пройдите мимо (а ещё лучше подскажите как сделать лучше\проще). А для тех, кто никогда этого не делал - эта статья отличная точка входа.

  Развернуть 1 комментарий

😎

Автор поста открыл его для большого интернета, но комментирование и движухи доступны только участникам Клуба

Что вообще здесь происходит?


Войти  или  Вступить в Клуб