Python: Разработка Flask на Kubernetes с помощью DevSpace

Левент Огут

Kubernetes ставит перед разработчиками определенные задачи. Им нужно изучить некоторые новые концепции, как они связаны друг с другом, и, самое главное, как разрабатывать приложения с использованием кластера Kubernetes. Но чем больше времени они тратят на изучение этих тем, тем меньше времени у них остается на создание приложений. DevSpace — это швейцарский армейский нож для разработчиков, который устраняет этот пробел исключительно хорошо. Инструкции DevSpace распространяются в виде простого YAML-файла в репозитории для всей команды.

DevSpace призван облегчить жизнь разработчикам, предоставляя широкий спектр инструментов. Различные функции DevSpace позволяют разработчику не беспокоиться о среде Kubernetes. Вместо этого он позволяет разработчику вести разработку так, как он делал бы это на своей локальной машине.

Некоторые возможности DevSpace, включая, но не ограничиваясь ими:

  • Развертывание с помощью Helm, kubectl
  • Модификация Dockerfile в памяти во время выполнения
  • Инструменты разработки, такие как синхронизация файлов, агрегация журналов.
  • Пользовательские хуки — это действия, которые выполняются на основе событий.
  • Пользовательские команды, с помощью которых можно собрать сложные или длинные команды в одну подкоманду.
  • Пользовательские профили могут использоваться для изменения чего-либо в devspace.yaml и Dockerfile с помощью операций add, patch, remove и merge. Профили дают возможность использовать различные конфигурации для определенных типов развертывания, например, staging, production, testing.

Требования

Помимо доступа к кластеру Kubernetes — удаленному или локальному — нам необходимо установить три инструмента CLI, если они еще не установлены.

  • Kubectl.
  • Helm.
  • DevSpace.

Для продолжения работы вам также понадобится Python-проект на основе Flask; если у вас нет проекта, вы можете использовать представленный здесь код или обратиться к документации Flask о том, как его создать.

Разработка в DevSpace

Все действия DevSpace зависят от его конфигурационного файла devspace.yaml. Поскольку у нас нет такого файла, давайте попросим помощи у DevSpace. Запуск devspace init проанализирует текущую папку, задаст несколько вопросов и создаст минимальный файл devspace.yaml. Этот конфигурационный файл будет описывать все наши развертывания, зависимости, хуки, специальные команды и так далее.

$ devspace init
Вход в полноэкранный режим Выход из полноэкранного режима
    ____              ____                       
    |  _   _____   __/ ___| _ __   __ _  ___ ___ 
    | | | |/ _   / /___ | '_  / _` |/ __/ _ 
    | |_| |  __/ V /  ___) | |_) | (_| | (_|  __/
    |____/ ___| _/  |____/| .__/ __,_|______|
                            |_|


? How do you want to deploy this project? helm: Use Component Helm Chart [QUICKSTART] (https://devspace.sh/component-chart/docs)

? How should DevSpace build the container image for this project? Create a new Dockerfile for this project

? Select the programming language of this project python


[info]   DevSpace does *not* require pushing your images to a registry but let's assume you wanted to do that (optional)

? Which registry would you want to use to push images to? (optional, choose any) Use hub.docker.com => you are logged in as leventogut
[done] √ Great! You are authenticated with hub.docker.com              

[info]   Configuration saved in devspace.yaml - you can make adjustments as needed
[done] √ Project successfully initialized

You can now run:
- `devspace use namespace` to pick which Kubernetes namespace to work in
- `devspace dev` to start developing your project in Kubernetes
- `devspace deploy -p production` to deploy your project to Kubernetes
- `devspace -h` to get a list of available commands
Войти в полноэкранный режим Выход из полноэкранного режима

Убедитесь, что выбран правильный контекст Kubernetes.

$ kubectl config use-context docker-desktop 
Switched to context "docker-desktop".
Войти в полноэкранный режим Выход из полноэкранного режима

Также убедитесь, что выбрано правильное пространство имен.

$ devspace use namespace default
Войти в полноэкранный режим Выход из полноэкранного режима

Мы будем использовать следующий код для нашего приложения.

#!/usr/bin/env python
from flask import Flask

app = Flask(__name__)



@app.route("/")
def hello_world():
    return "<p>Hello, World!</p>"


if __name__ == '__main__':
    app.run(debug=True, use_debugger=True, use_reloader=False)

Вход в полноэкранный режим Выход из полноэкранного режима

Сохраните этот код в файл app.py в корневом каталоге проекта или используйте свой собственный проект Flask, если он у вас есть.

На этом этапе я советую вам посмотреть на devspace.yaml, чтобы получить представление о сгенерированной конфигурации.

Поскольку Flash по умолчанию использует порт 5000, нам нужно исправить это в нашем devspace.yaml в разделе dev.ports.

Теперь давайте запустим devspace dev.

$ devspace dev
Вход в полноэкранный режим Выход из полноэкранного режима
[warn]   Deploying into the 'default' namespace is usually not a good idea as this namespace cannot be deleted

[info]   Using namespace 'default'               
[info]   Using kube context 'docker-desktop'
[info]   Execute 'helm upgrade devspace-flask /Users/logut/.devspace/component-chart/component-chart-0.8.1.tgz --namespace default --values /var/folders/3h/tq577p717mdccgjpcgtcvqv80000gn/T/089143002 --install --kube-context docker-desktop'
[info]   Execute 'helm list --namespace default --output json --kube-context docker-desktop'                                   
[done] √ Deployed helm chart (Release revision: 2)                                                                             
[done] √ Successfully deployed devspace-flask with helm                                                                        

#########################################################
[info]   DevSpace UI available at: http://localhost:8090
#########################################################

[done] √ Port forwarding started on 5000:5000 (default/devspace-flask-5f785f7fdd-6rx5f-devspace)
[0:sync] Waiting for pods...
[0:sync] Starting sync...
[0:sync] Sync started on /Users/logut/dev/loft/devspace-flask <-> . (Pod: default/devspace-flask-5f785f7fdd-6rx5f-devspace)
[0:sync] Waiting for initial sync to complete
[info]   Opening 'http://localhost:8080' as soon as application will be started (timeout: 4m0s)
[info]   Opening shell to pod:container devspace-flask-5f785f7fdd-6rx5f-devspace:container-0
Installing Python Dependencies
Requirement already satisfied: click==8.0.1 in /usr/local/lib/python3.9/site-packages (from -r requirements.txt (line 1)) (8.0.1)
Requirement already satisfied: Flask==2.0.1 in /usr/local/lib/python3.9/site-packages (from -r requirements.txt (line 2)) (2.0.1)
Requirement already satisfied: itsdangerous==2.0.1 in /usr/local/lib/python3.9/site-packages (from -r requirements.txt (line 3)) (2.0.1)
Requirement already satisfied: Jinja2==3.0.1 in /usr/local/lib/python3.9/site-packages (from -r requirements.txt (line 4)) (3.0.1)
Requirement already satisfied: MarkupSafe==2.0.1 in /usr/local/lib/python3.9/site-packages (from -r requirements.txt (line 5)) (2.0.1)
Requirement already satisfied: Werkzeug==2.0.1 in /usr/local/lib/python3.9/site-packages (from -r requirements.txt (line 6)) (2.0.1)
WARNING: Running pip as root will break packages and permissions. You should install packages reliably by using venv: https://pip.pypa.io/warnings/venv
WARNING: You are using pip version 21.1.2; however, version 21.2.4 is available.
You should consider upgrading via the '/usr/local/bin/python -m pip install --upgrade pip' command.

   ____              ____
  |  _   _____   __/ ___| _ __   __ _  ___ ___
  | | | |/ _   / /___ | '_  / _` |/ __/ _ 
  | |_| |  __/ V /  ___) | |_) | (_| | (_|  __/
  |____/ ___| _/  |____/| .__/ __,_|______|
                          |_|

Welcome to your development container!

This is how you can work with it:
- Run `python main.py` to build the application
- Files will be synchronized between your local machine and this container
- Some ports will be forwarded, so you can access this container on your local machine via localhost:


 Image   ImageSelector    LabelSelector   Ports (Local:Remote)  
         imagerepo-repo1/app                   5000:5000             


root@devspace-flask-7c4bd546-nfmzf-devspace:/app#
Войдите в полноэкранный режим Выход из полноэкранного режима

Запустим наше приложение.

root@devspace-flask-7c4bd546-nfmzf-devspace:/app# python app.py
Войти в полноэкранный режим Выход из полноэкранного режима
 * Serving Flask app 'app' (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: on
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 276-822-672
Войти в полноэкранный режим Выход из полноэкранного режима

Мы выбрали опцию отладки, чтобы сервер разработки Flask перезагружался при изменении файлов кода.

Команда devspace dev выполнила несколько действий по настройке нашей среды разработки.

  • Используя Helm, она развернула наше приложение на кластере Kubernetes с помощью диаграммы компонентов.
  • Запустила перенаправление портов на порт 5000, чтобы мы могли получить доступ к приложению в том виде, в котором оно запущено локально.
  • Настроил синхронизацию локальной папки в контейнер с помощью функции sync.
  • Разобрали файл requirement.txt и установили все зависимости.
  • Используя функцию dev.replacedPods, заменил образ исходного контейнера на образ контейнера разработки.
  • Открыл оболочку в контейнере приложения. Обратите внимание, что это делается путем изменения инструкции CMD в Dockerfile, поэтому вам нужно самостоятельно запустить приложение, как показано выше.

По умолчанию DevSpace использует dev.replacedPods для разработки. Возможность замены образа позволяет разработчику использовать другой образ с той же кодовой базой. Разработчик может создать образ с установленными инструментами отладки для использования в процессе разработки.

Теперь вы можете выйти из оболочки контейнера и завершить работу DevSpace. В следующем разделе будет добавлена функциональность кэширования, чтобы мы могли увидеть изменения, которые нужно сделать в нашем devspace.yaml.

Добавление кэша (Memcached)

Давайте добавим решение для кэширования в наше приложение Flask. Это позволит нам настроить devspace.yaml. Ниже приведен сниппет, который нам нужно добавить в раздел deployments в devspace.yaml. Этот сниппет определяет развертывание с помощью helm с репозиторием Bitnami и графикой Memcached. Мы также указываем версию графика.

- name: memcached
  helm:
    componentChart: false
    chart:
      name: memcached
      version: 5.12.0
      repo: https://charts.bitnami.com/bitnami
Войти в полноэкранный режим Выйдите из полноэкранного режима

И измените раздел vars следующим образом:

vars:
- name: CACHE_MEMCACHED_SERVERS
Войти в полноэкранный режим Выйти из полноэкранного режима

Добавление значений окружения в развертывание

Чтобы добавить значения окружения в нашу капсулу развертывания приложения, нам нужно определить их в разделе deployments; вам нужно только добавить раздел env в существующий devspace.yaml.

- name: devspace-flask
  # This deployment uses `helm` but you can also define `kubectl` deployments or kustomizations
  helm:
    # We are deploying the so-called Component Chart: https://devspace.sh/component-chart/docs
    componentChart: true
    # Under `values` we can define the values for this Helm chart used during `helm install/upgrade`
    # You may also use `valuesFiles` to load values from files, e.g. valuesFiles: ["values.yaml"]
    values:
      containers:
      - image: ${IMAGE} # Use the value of our `${IMAGE}` variable here (see vars above)
        env:
          - name: CACHE_MEMCACHED_SERVERS
            value: $!{CACHE_MEMCACHED_SERVERS}
      service:
        ports:
        - port: 5000
Вход в полноэкранный режим Выход из полноэкранного режима

Поскольку вся наша конфигурация готова, теперь мы можем заполнить значения окружения для серверов кэша. Выполните следующую команду.

$ devspace list vars
Войти в полноэкранный режим Выйти из полноэкранного режима

DevSpace спросит вас, если не сможет найти значение для переменной окружения. Переменные в DevSpace могут быть получены из окружения, команд, ввода и жестко закодированных значений. Эти переменные могут быть использованы в любой части конфигурации.

? Please enter a value for CACHE_MEMCACHED_SERVERS memcached:11211

 Variable                  Value            
 CACHE_MEMCACHED_SERVERS   memcached:11211  
 IMAGE                     imagerepo-repo1/app   
Вход в полноэкранный режим Выход из полноэкранного режима

Далее нам нужно настроить наше приложение на использование кэширования.

Настройки кэширования Flask

Ниже приведены изменения, которые мы сделали, чтобы включить кэширование по пути /. Во-первых, мы импортируем модуль кэширования, также настраиваем этот модуль для кэш-серверов; как вы заметили, здесь мы используем переменную окружения, ту, которую мы указывали в предыдущих разделах; далее, настраиваем приложение для кэша; наконец, добавляем декоратор кэша в нашу функцию route.

diff --git a/app.py b/app.py
index d26f024..f840dc3 100755
--- a/app.py
+++ b/app.py
@@ -1,11 +1,16 @@
 #!/usr/bin/env python
 from flask import Flask
+from flask_caching import Cache
+import os

-app = Flask(__name__)
+cache = Cache(config={'CACHE_TYPE': 'MemcachedCache','CACHE_MEMCACHED_SERVERS': [os.environ['CACHE_MEMCACHED_SERVERS']]})

+app = Flask(__name__)
+cache.init_app(app)


 @app.route("/")
+@cache.cached(timeout=50)
 def hello_world():
     return "<p>Hello, World!</p>"


if __name__ == '__main__':
    app.run(debug=True, use_debugger=True, use_reloader=False)
Вход в полноэкранный режим Выход из полноэкранного режима

Вот версия, удобная для копирования-вставки.

#!/usr/bin/env python
from flask import Flask
from flask_caching import Cache
import os

cache = Cache(config={'CACHE_TYPE': 'MemcachedCache','CACHE_MEMCACHED_SERVERS': [os.environ['CACHE_MEMCACHED_SERVERS']]})

app = Flask(__name__)
cache.init_app(app)


@app.route("/")
@cache.cached(timeout=50)
def hello_world():
    return "<p>Hello, World!</p>"


if __name__ == '__main__':
    app.run(debug=True, use_debugger=True, use_reloader=False)

Вход в полноэкранный режим Выход из полноэкранного режима

Теперь снова запустите devspace dev, чтобы запустить нашу среду разработки.

Как только вы окажетесь в оболочке, выполните команду python app.py, чтобы запустить сервер разработки.

root@devspace-flask-7c4bd546-nfmzf-devspace:/app# python app.py
Вход в полноэкранный режим Выход из полноэкранного режима
* Serving Flask app 'app' (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: on
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 276-822-672
Войдите в полноэкранный режим Выход из полноэкранного режима

Теперь при посещении конечной точки / будут создаваться записи в кэше.

root@devspace-flask-7c4bd546-nfmzf-devspace:/app# curl http://127.0.01:5000
Войти в полноэкранный режим Выход из полноэкранного режима
<p>Hello, World!</p>
Войти в полноэкранный режим Выход из полноэкранного режима

Мы также можем видеть запросы в журналах.

127.0.0.1 - - [21/Sep/2021 11:10:13] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [21/Sep/2021 11:10:15] "GET / HTTP/1.1" 200 -
Войти в полноэкранный режим Выход из полноэкранного режима

Проверка статистики кэша

Чтобы убедиться, что наш кэш работает так, как ожидалось, давайте подключимся к нему по telnet из контейнера приложения и посмотрим статистику. Вы можете установить telnet с помощью команды apt install -y telnet.

root@devspace-flask-5f785f7fdd-6rx5f-devspace:/app# telnet memcached 11211
Вход в полноэкранный режим Выход из полноэкранного режима
Trying 10.108.20.56...
Connected to memcached.default.svc.cluster.local.
Escape character is '^]'.
stats items
STAT items:2:number 1
STAT items:2:number_hot 0
STAT items:2:number_warm 0
STAT items:2:number_cold 1
STAT items:2:age_hot 0
STAT items:2:age_warm 0
STAT items:2:age 26
STAT items:2:mem_requested 101
STAT items:2:evicted 0
STAT items:2:evicted_nonzero 0
STAT items:2:evicted_time 0
STAT items:2:outofmemory 0
STAT items:2:tailrepairs 0
STAT items:2:reclaimed 1
STAT items:2:expired_unfetched 0
STAT items:2:evicted_unfetched 0
STAT items:2:evicted_active 0
STAT items:2:crawler_reclaimed 0
STAT items:2:crawler_items_checked 0
STAT items:2:lrutail_reflocked 0
STAT items:2:moves_to_cold 3
STAT items:2:moves_to_warm 2
STAT items:2:moves_within_lru 1
STAT items:2:direct_reclaims 0
STAT items:2:hits_to_hot 2
STAT items:2:hits_to_warm 1
STAT items:2:hits_to_cold 4
STAT items:2:hits_to_temp 0
END
Войти в полноэкранный режим Выход из полноэкранного режима

Мы видим, что ответы уже кэшируются.

Мы развернули наше приложение в режиме разработки, мы добавили кэш в смесь, теперь давайте посмотрим на функцию синхронизации DevSpace. Это позволит нам продолжать разработку локально и видеть результаты в кластере Kubernetes.

Создайте новую конечную точку

Сначала отправьте пару запросов к конечной точке /ping, проверьте, что ответ 404; затем отредактируйте файл app.py и добавьте следующую функцию с декоратором route:

@app.route("/ping")
def ping():
    return "pong"
Вход в полноэкранный режим Выйти из полноэкранного режима

С помощью этого небольшого кода мы создали конечную точку, которая возвращает pong ответы на все запросы. Теперь снова отправьте несколько запросов, и ответ будет 200 с содержимым pong.

Ниже приведен результат проделанных нами выше действий:

root@devspace-flask-7c4bd546-nfmzf-devspace:/app# python app.py
 * Serving Flask app 'app' (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: on
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 276-822-672
127.0.0.1 - - [21/Sep/2021 11:29:44] "GET /ping HTTP/1.1" 404 -
127.0.0.1 - - [21/Sep/2021 11:29:49] "GET /ping HTTP/1.1" 404 -
 * Detected change in '/app/app.py', reloading
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 276-822-672
127.0.0.1 - - [21/Sep/2021 11:29:50] "GET /ping HTTP/1.1" 200 -
127.0.0.1 - - [21/Sep/2021 11:29:51] "GET /ping HTTP/1.1" 200 -
Вход в полноэкранный режим Выход из полноэкранного режима

Как вы можете видеть, до добавления кода конечная точка выдавала ошибку 404 not found; сразу после добавления кода мы видим код возврата 200 и текстовый ответ pong. Важным аспектом этой установки является то, что мы используем debug=True. Это заставляет сервер следить за локальными файлами Python и перезагружать их при изменениях. Таким образом, DevSpace обнаруживает изменения на вашей локальной машине, синхронизирует изменения с контейнером, сервер отладки обнаруживает изменения и перезагружает код. Эта операция позволяет нам разрабатывать локально и сразу же развертывать на кластере Kubernetes.

Развертывание в производство

DevSpace — это не только инструмент для разработки. Его можно использовать для развертывания в staging, production и даже в конвейерах CI/CD. С помощью функции Profiles вы можете создавать различные настройки развертывания для вашего приложения и его зависимостей. Изменения включают изменения Dockerfile, изменения devspace.yaml и так далее. Вы можете найти профиль production в вашем начальном devspace.yaml Вы можете выбрать профиль или несколько профилей, которые вы хотите использовать, следующим образом:

$ devspace deploy -p production
Войти в полноэкранный режим Выйти из полноэкранного режима

Устранение неполадок с Devspace

Журналы

По умолчанию DevSpace перебрасывает вас в оболочку контейнера приложения, чтобы вы могли выполнить любую команду и устранить ошибки. Вы также можете изменить это поведение так, чтобы журналы всех или некоторых (фильтрующих) контейнеров передавались в потоковом режиме.

Пока что откройте другой терминал и выполните следующую команду, чтобы увидеть все журналы контейнера.

$ devspace logs
Войти в полноэкранный режим Выйти из полноэкранного режима

Если вы не укажете контейнер, DevSpace спросит вас, журналы какого контейнера вы хотите получить.

? Select a container memcached-6c775fbd9d-hwbhf:memcached
[info]   Printing logs of pod:container memcached-6c775fbd9d-hwbhf:memcached
memcached 14:11:52.97 
memcached 14:11:52.97 Welcome to the Bitnami memcached container
memcached 14:11:52.97 Subscribe to project updates by watching https://github.com/bitnami/bitnami-docker-memcached
memcached 14:11:52.98 Submit issues and feature requests at https://github.com/bitnami/bitnami-docker-memcached/issues
memcached 14:11:52.98 
memcached 14:11:52.98 INFO  ==> ** Starting Memcached setup **
memcached 14:11:52.99 INFO  ==> Initializing Memcached

memcached 14:11:53.00 INFO  ==> ** Memcached setup finished! **
memcached 14:11:53.00 INFO  ==> ** Starting Memcached **
Войти в полноэкранный режим Выход из полноэкранного режима

Вход в контейнеры

Вы можете использовать DevSpace для управления развернутой средой. Одним из аспектов является быстрый вход в контейнеры. Не указывая имя контейнера, вы можете выбрать его из списка.

$ devspace enter
Вход в полноэкранный режим Выход из полноэкранного режима
? Which pod do you want to open the terminal for?  [Use arrows to move, type to filter]
> devspace-flask-7c4bd546-nfmzf-devspace:container-0
  memcached-6c775fbd9d-hwbhf:memcached
Вход в полноэкранный режим Выход из полноэкранного режима

Мы также можем указать имя контейнера напрямую с помощью флага -c. Как видите, это намного проще, чем получать случайное имя стручка и затем указывать имя контейнера; DevSpace делает это автоматически для развернутого ресурса.

$ devspace enter -c container-0
Вход в полноэкранный режим Выход из полноэкранного режима
[info]   Opening shell to pod:container devspace-flask-7c4bd546-nfmzf-devspace:container-0
root@devspace-flask-7c4bd546-nfmzf-devspace:/app#
Вход в полноэкранный режим Выход из полноэкранного режима

Выполнение команд внутри контейнера

Используя ту же подкоманду enter, мы можем выполнять команды непосредственно внутри контейнера.

$ devspace enter -c container-0 -- cat requirements.txt
Войти в полноэкранный режим Выйти из полноэкранного режима
[info]   Opening shell to pod:container devspace-flask-7c4bd546-nfmzf-devspace:container-0
click==8.0.1
Flask==2.0.1
Flask-Caching==1.10.1
itsdangerous==2.0.1
Jinja2==3.0.1
MarkupSafe==2.0.1
python-memcached==1.59
six==1.16.0
Werkzeug==2.0.1
Войти в полноэкранный режим Выход из полноэкранного режима
$ devspace enter -c memcached -- ps aux
Войти в полноэкранный режим Выход из полноэкранного режима
[info]   Opening shell to pod:container memcached-6c775fbd9d-hwbhf:memcached
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
1001         1  0.0  0.0 409280  3684 ?        Ssl  Sep20   0:44 memcached -u me
1001        58  0.0  0.0   7644  2700 pts/0    Rs+  12:40   0:00 ps aux
Войти в полноэкранный режим Выход из полноэкранного режима

В DevSpace также есть функция Commands, где вы можете создавать пользовательские команды для запуска локально или в определенном контейнере; это особенно полезно для длительных и подверженных ошибкам команд, которые вы хотите запустить.

Очистка

DevSpace предоставляет подкоманду, которая легко удаляет все развертывания и ресурсы (кроме PV/PVC), чтобы вы могли легко удалить среду разработки.

$ devspace purge
Войти в полноэкранный режим Выход из полноэкранного режима

Заключение

Мы рассмотрели и реализовали некоторые возможности DevSpace, которые помогут разработчикам. Бесшовное развертывание, простота разработки — это мощные возможности. Кроме того, возможность распространять эту конфигурацию среди команды очень проста.

Существует множество функций DevSpace, о которых мы не успели рассказать. Чтобы узнать больше, ознакомьтесь с документацией или свяжитесь с нами в Kubernetes Slack в канале #devspace.

Дальнейшее чтение

  • Документация DevSpace
  • Документация по Flask
  • Python: Разработка Django на Kubernetes с помощью DevSpace

Оцените статью
Procodings.ru
Добавить комментарий