Персональна освітня сорінка
by Pavlo Shcherbukha
Це продовження записок початківця про python flask. В попреденіх серіях було про запуск flask application в контейнері і через docker-compose поєднати з супутнім сервісов. В якості супутнього сервісу було вибрано Redis DB. Але в усіх цих випадках сервіс Python запускався я продуктивному режимі. Але, не маючи режима debug в контейнері ефективно розробляти не зручно. В цьому блозі:
Як налаштувати можливість debug python-flask application, що запущено в контейнері, викорстовуючи docker-compose. Я довго це пробував зібрати до купи. Але цей метод мені здався найбільш дієвим. Тут мова піде не про програмування, а більше про devops навики. Але, якщо розробник не матиме цих навиків, то як йому на своєму laptop створити середовище розробки і ефективно працювати? Як правильно зпроектувати, які компоненти винести в параметризацію?…. Ну і ще можна знайти купу таких риторичних запитань.
Репозиторій з прикладом доступний за лінком: py-flask-app-smpl-redis-dbg Flask application. Debug додатку, що запущено в контейнері.
Flask template розроблений таким чином, що його можна запустити в development mode, як описано в Створення найпростішого скрипта для flask app та запуск applicaiton з індивідуальною назвою в DEVELOPENT mode. А бо ж flask application запускається в productive mode за WSGI сервером типу gunicorn, як описано в Python - flask запуск в контейнері від RadHat UBI8.
Збірка запуск та debug контейнера з сервісом python описана за цими лінками:
Але, воно мене не дуже влаштовує, так як запускає окремий контейнер. А мені потрібно підняти локально кілька компонентів через docker-compose, які “бачать” один одного в мережі а вже потім підключати debug.
Раптом мені попалася бібліотека від Microsoft, що забезепечує взаємодію debug протоколу python додатків та Visual Studio Code: ptvsd або ж лінк на github Python Tools for Visual Studio debug server. Також, зандобилася бібліотека debugpy , або на github debugpy - a debugger for Python.
Таким чином, мені для запуску debug потрібно:
Для запуску в *productive mode** Dockerfile виглядава таким чином:
FROM registry.fedoraproject.org/f33/python3
# Add application sources to a directory that the assemble script expects them
# and set permissions so that the container runs without root access
USER 0
COPY . /tmp/src
RUN /usr/bin/fix-permissions /tmp/src
USER 1001
# Install the dependencies
RUN python3.9 -m pip install --upgrade pip
RUN /usr/libexec/s2i/assemble
EXPOSE 8080
# Set the default command for the resulting image
CMD /usr/libexec/s2i/run
Тепер використаємо властивість Dockerfile multistage-build. Сенс використаня multistage-build в тому, що ми можемо використати кілька команд FROM з аліасом. Основний сенс цик команд в наступному:
можна з одної FROM копиіювати дані в наступну stage
можна при побудові образу вказати на якій stage зупинитися.
Ось останню особливість і використаємо. А при старті docker-compose вкажемо, яка stage мається на увазі у тезі target : Compose file version 3 reference

Ось наведено Dockerfile який в результаті отримав:
FROM registry.fedoraproject.org/f33/python3 as base
# Add application sources to a directory that the assemble script expects them
# and set permissions so that the container runs without root access
USER 0
COPY . /tmp/src
RUN /usr/bin/fix-permissions /tmp/src
USER 1001
# Install the dependencies
RUN python3.9 -m pip install --upgrade pip
RUN /usr/libexec/s2i/assemble
EXPOSE 8080
FROM base as debug
RUN pip install ptvsd debugpy
# Keeps Python from generating .pyc files in the container
ENV PYTHONDONTWRITEBYTECODE 1
# Turns off buffering for easier container logging
ENV PYTHONUNBUFFERED 1
EXPOSE 5678
FROM base as prod
# Set the default command for the resulting image
CMD /usr/libexec/s2i/run
А на pic-02 показані коротке пояснення, як stage з Dockerfile відображається на yaml з docker compose

Потрібно не забути, що при запуску в режимі debug, flask app потрібно запускати поза gunicorn, командою pyhon flask run ну з розширенням спеціальним ключами під debug. В нашому випадку:
python -m debugpy --listen 0.0.0.0:5678 --wait-for-client -m flask run -h 0.0.0.0 -p 8080
На pic-03 показана порівняльна характеристика docker-comppose - файлів для різних режимів запуску, що будуються з єдного dockerfile.

Для налаштування Visual Studio Code потрібно в файл: “.vscode/launch.json” блок для підключення:
{
"name": "Sh-FLASK-Python: Remote Attach",
"type": "python",
"request": "attach",
"port": 5678,
"host": "0.0.0.0",
"pathMappings": [
{
"localRoot": "${workspaceFolder}",
"remoteRoot": "/opt/app-root/src"
}
]
}
В полі remoteRoot потрібно вказати каталог де знаходиться програмний код вашого додатку в контейнері. Для UBI8 це /opt/app-root/src. А в приципі, можна отримати, якщо підключится до контейнера перейти в ваш каталог та виконати команду linux pwd.
Ну і тепер порібно це все запустити.
docker-compose -f docker-compose-debug.yaml up --build smplapp-srvc-redis
docker-compose -f docker-compose-prod.yaml up --build smplapp-srvc-redis
Для швидкого запуску я виніс запуск docker-compose у sh-composer-up-dev.cmd та sh-composer-up-prod.cmd
Для запуску в режимы Debug запускаємо sh-composer-up-dev.cmd.
Спершу виконується побудова образу, потім контейнер запускається і завмирає на Attachin to …… (обведено червоною рамочкою на pic-04)

В цей момент потріно переклчитися на Visual Studio Code та вирати налаштований вами в попередньому пункті режим підключення до контейнера pic-05

І от диво, сервіс стартонув у контейнері pic-06

Ну а якщо відкрити файл view.py поставити brakepoint на обробнику метода /api/health то отримаємо зупинку програми при зверенні до http://localhost:8081/api/health як на pic-07.

Якщо ж виконати запуск в продуктивному режимі, то на pic-08 видно як воно швидко стартує, та ще й в 4 потоках (там для кожного pid в лог записується).

Ну, таким чином, можна вважати що Remote Debug для Flask app , що запущено в контейнері виконано.
tags: