Docker — это приложение с открытым исходным кодом, которое позволяет администраторам создавать, управлять, развертывать и реплицировать приложения с помощью контейнеров. Контейнеры можно рассматривать как пакет, содержащий зависимости, необходимые приложению для запуска на уровне операционной системы. Это означает, что каждое приложение, развернутое с помощью Docker, живет в своей собственной среде, и его требования обрабатываются отдельно.
Flask — это веб-микро-фреймворк, построенный на Python. Его называют микро-фреймворком, потому что для его запуска не требуются специальные инструменты или подключаемые модули. Фреймворк Flask легкий и гибкий, но при этом высокоструктурированный, что делает его предпочтительнее других фреймворков.
Развертывание приложения Flask с помощью Docker позволит вам реплицировать приложение на разных серверах с минимальной перенастройкой.
В этом руководстве вы создадите приложение Flask и развернете его с помощью Docker. В этом руководстве также будет рассказано, как обновить приложение после развертывания.
Предварительные требования
Чтобы следовать этому руководству, вам понадобится следующее:
- Пользователь без права root с правами sudo настраивается, следуя руководству по начальной настройке сервера с Ubuntu 23.04.
- Один сервер Ubuntu 23.04 с установленным Docker;
- Установленный Nginx.
Настройка приложения Flask
Для начала вы создадите структуру каталогов, в которой будет храниться ваше приложение Flask. В этом руководстве будет создан каталог с именем TestApp
в /var/www
, но вы можете изменить команду, чтобы назвать его как угодно.
1 |
sudo mkdir /var/www/TestApp |
Перейдите во вновь созданный TestApp
каталог:
1 |
cd /var/www/TestApp |
Затем создайте базовую структуру папок для приложения Flask:
1 |
sudo mkdir -p app/static app/templates |
-p
Флаг указывает, что mkdir
будет создан каталог и все родительские каталоги, которые не существуют. В этом случае mkdir
будет создан app
родительский каталог в процессе создания каталогов static
и templates
.
В app
каталоге будут содержаться все файлы, связанные с приложением Flask, такие как его представления и схемы элементов. Представления — это код, который вы пишете для ответа на запросы к вашему приложению. Схемы элементов создают компоненты приложения и поддерживают общие шаблоны внутри приложения или в нескольких приложениях.
В static
каталоге хранятся ресурсы, такие как изображения, файлы CSS и JavaScript. В templates
каталоге вы разместите HTML-шаблоны для своего проекта.
Теперь, когда базовая структура папок завершена, создайте файлы, необходимые для запуска приложения Flask. Сначала создайте __init__.py файл внутри app каталога. Этот файл сообщает интерпретатору Python, что app каталог является пакетом и должен рассматриваться как таковой.
Выполните следующую команду для создания файла:
1 |
sudo nano app/__init__.py |
Пакеты на Python позволяют группировать модули в логические пространства имен или иерархии. Такой подход позволяет разбивать код на отдельные и управляемые блоки, которые выполняют определенные функции.
Далее вы добавите код в __init__.py
, который создаст экземпляр Flask, и импортируете логику из views.py
файла, который вы создадите после сохранения этого файла. Добавьте следующий код в свой новый файл:
/var/www/TestApp/app/__init__.py
1 2 3 |
from flask import Flask app = Flask(__name__) from app import views |
После добавления этого кода сохраните и закройте файл.
После создания __init__.py
файла вы готовы создать views.py
файл в своем app
каталоге. Этот файл будет содержать большую часть логики вашего приложения.
1 |
sudo nano app/views.py |
Затем добавьте код в свой views.py файл. Этот код вернет hello world! строку пользователям, которые посещают вашу веб-страницу:
/var/www/TestApp/app/views.py
1 2 3 4 5 |
from app import app @app.route('/') def home(): return "hello world!" |
@app.route
Строка над функцией называется декоратором. Декораторы изменяют функцию, которая следует за ней. В этом случае декоратор сообщает Flask, какой URL-адрес запустит home()
функцию. hello world
Текст, возвращаемый home
функцией, будет показан пользователю в браузере.
Теперь, когда views.py
файл на месте, вы готовы создать uwsgi.ini
файл. Этот файл будет содержать uWSGI конфигурации для нашего приложения. uWSGI — это вариант развертывания для Nginx, который является одновременно протоколом и сервером приложений; сервер приложений может обслуживать протоколы uWSGI, FastCGI и HTTP.
Чтобы создать этот файл, выполните следующую команду:
1 |
sudo nano uwsgi.ini |
Затем добавьте следующее содержимое в свой файл для настройки сервера uWSGI:
/var/www/TestApp/uwsgi.ini
1 2 3 4 |
[uwsgi] module = main callable = app master = true |
Этот код определяет модуль, из которого будет обслуживаться приложение Flask. В данном случае это main.py
файл, упомянутый здесь как main
. callable
Опция указывает uWSGI использовать app
экземпляр, экспортированный основным приложением. Опция master
позволяет вашему приложению продолжать работу, поэтому время простоя невелико даже при перезагрузке всего приложения.
Затем создайте main.py
файл, который является точкой входа в приложение. Точка входа инструктирует uWSGI о том, как взаимодействовать с приложением.
1 |
sudo nano main.py |
Далее скопируйте и вставьте в файл следующее. При этом импортируется экземпляр Flask с именем app
из пакета приложения, который был создан ранее.
/var/www/TestApp/main.py
1 |
from app import app |
Наконец, создайте requirements.txt
файл для указания зависимостей, которые pip
менеджер пакетов установит для вашего развертывания Docker:
1 |
sudo nano requirements.txt |
Добавьте следующую строку, чтобы добавить Flask в качестве зависимости:
/var/www/TestApp/requirements.txt
1 |
Flask==1.0.2 |
Здесь указывается версия Flask, которая должна быть установлена. На момент написания этого руководства, 1.0.2
это последняя версия Flask. Вы можете проверить наличие обновлений на официальном веб-сайте Flask.
Сохраните и закройте файл. Вы успешно настроили свое приложение Flask и готовы к настройке Docker.
Настройка Docker
На этом шаге вы создадите два файла, Dockerfile
и start.sh
, для создания развертывания Docker. Dockerfile
Это текстовый документ, содержащий команды, используемые для сборки образа. start.sh
Файл представляет собой сценарий оболочки, который создаст образ и контейнер из Dockerfile
.
Сначала создайте Dockerfile
.
1 |
sudo nano Dockerfile |
Затем добавьте желаемую конфигурацию в Dockerfile
. Эти команды определяют, как будет создан образ и какие дополнительные требования будут включены.
/var / www / TestApp /Dockerfile
1 2 3 4 5 6 |
FROM tiangolo/uwsgi-nginx-flask:python3.6-alpine3.7 RUN apk --update add bash nano ENV STATIC_URL /static ENV STATIC_PATH /var/www/app/static COPY ./requirements.txt /var/www/requirements.txt RUN pip install -r /var/www/requirements.txt |
В этом примере образ Docker будет создан на основе существующего образа, tiangolo/uwsgi-nginx-flask
который вы можете найти на DockerHub. Этот конкретный образ Docker является хорошим выбором по сравнению с другими, поскольку он поддерживает широкий спектр версий Python и образов ОС.
В первых двух строках указывается родительский образ, который вы будете использовать для запуска приложения и установки командного процессора bash и nano
текстового редактора. Также устанавливается git
клиент для подключения к сервисам управления версиями, таким как GitHub, GitLab и Bitbucket. ENV STATIC_URL /static
— переменная среды, специфичная для этого образа Docker. Она определяет статическую папку, из которой отправляются все ресурсы, такие как изображения, файлы CSS и файлы JavaScript.
Последние две строки скопируют requirements.txt
файл в контейнер, чтобы его можно было выполнить, а затем проанализируют requirements.txt
файл для установки указанных зависимостей.
Сохраните и закройте файл после добавления вашей конфигурации.
С вашим Dockerfile
на месте вы почти готовы написать свой start.sh
скрипт, который соберет контейнер Docker. Перед написанием start.sh
скрипта сначала убедитесь, что у вас есть открытый порт для использования в конфигурации. Чтобы проверить, свободен ли порт, выполните следующую команду:
1 |
sudo nc localhost 56733 < /dev/null; echo $? |
Если результат приведенной выше команды равен 1
, значит, порт свободен и его можно использовать. В противном случае вам нужно будет выбрать другой порт для использования в вашем start.sh
файле конфигурации.
После того, как вы нашли открытый порт для использования, создайте start.sh
скрипт:
1 |
sudo nano start.sh |
start.sh Скрипт — это сценарий оболочки, который создаст образ из Dockerfile
и контейнер из полученного образа Docker. Добавьте свою конфигурацию в новый файл.:/var/www/TestApp/start.sh
1 2 3 4 5 6 |
#!/bin/bash app="docker.test" docker build -t ${app} . docker run -d -p 56733:80 \ --name=${app} \ -v $PWD:/app ${app} |
Первая строка называется shebang. Она указывает, что это файл bash и будет выполняться в виде команд. В следующей строке указывается имя, которое вы хотите присвоить изображению и контейнеру, и сохраняется как переменная с именем app
. Следующая строка инструктирует Docker создать образ из вашего, Dockerfile
расположенного в текущем каталоге. Это создаст образ с именем docker.test
в этом примере.
Последние три строки создают новый контейнер с именем docker.test
, который отображается в порту 56733
. Наконец, он связывает текущий каталог с /var/www
каталогом контейнера.
Флаг -d
используется для запуска контейнера в режиме демона или в качестве фонового процесса. Флаг -p
используется для привязки порта на сервере к определенному порту контейнера Docker. В этом случае вы привязываете порт 56733
к порту 80
контейнера Docker. Флаг -v
указывает том Docker для монтирования в контейнере, и в этом случае вы монтируете весь каталог проекта в /var/www
папку в контейнере Docker.
Выполните start.sh
скрипт для создания образа Docker и создайте контейнер из полученного образа:
1 |
sudo bash start.sh |
После завершения запуска скрипта используйте следующую команду, чтобы составить список всех запущенных контейнеров:
1 |
sudo docker ps |
Вы получите выходные данные, показывающие контейнеры:
1 2 |
OutputCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 58b05508f4dd docker.test "/entrypoint.sh /sta…" 12 seconds ago Up 3 seconds 443/tcp, 0.0.0.0:56733->80/tcp docker.test |
Вы обнаружите, что docker.test
контейнер запущен. Теперь, когда он запущен, перейдите по IP-адресу на указанный порт в вашем браузере: http://ip-address:56733
Вы увидите страницу, похожую на следующую:
На этом шаге вы успешно развернули свое приложение Flask в Docker. Далее вы будете использовать шаблоны для отображения контента пользователям.
Отправка файлов шаблонов
Шаблоны — это файлы, которые отображают статическое и динамическое содержимое пользователям, посещающим ваше приложение. На этом шаге вы создадите HTML-шаблон для создания домашней страницы приложения.
Начните с создания home.html
файла в app/templates
каталоге:
1 |
sudo nano app/templates/home.html |
Добавьте код для вашего шаблона. Этот код создаст страницу HTML5, содержащую заголовок и некоторый текст.
/var/www/TestApp/app/templates/home.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<!doctype html> <html lang="en-us"> <head> <meta charset="utf-8"> <meta http-equiv="x-ua-compatible" content="ie=edge"> <title>Welcome home</title> </head> <body> <h1>Home Page</h1> <p>This is the home page of our application.</p> </body> </html> |
Сохраните и закройте файл после добавления шаблона.
Затем измените app/views.py
файл для обслуживания вновь созданного файла:
1 |
sudo nano app/views.py |
Сначала добавьте следующую строку в начало вашего файла, чтобы импортировать render_template
метод из Flask. Этот метод анализирует HTML-файл для отображения веб-страницы пользователю.
/var/www/TestApp/app/views.py
1 2 |
from flask import render_template ... |
В конце файла вы также добавите новый маршрут для отображения файла шаблона. Этот код указывает, что пользователям предоставляется содержимое home.html
файла всякий раз, когда они посещают /template
маршрут в вашем приложении.
/var/www/TestApp/app/views.py
1 2 3 4 5 |
... @app.route('/template') def template(): return render_template('home.html') |
Обновленный app/views.py
файл будет выглядеть следующим образом:
/var/www/TestApp/app/views.py
1 2 3 4 5 6 7 8 9 10 |
from flask import render_template from app import app @app.route('/') def home(): return "Hello world!" @app.route('/template') def template(): return render_template('home.html') |
Сохраните и закройте файл, когда закончите.
Для того, чтобы эти изменения вступили в силу, вам необходимо остановить и перезапустить контейнеры Docker. Выполните следующую команду, чтобы перестроить контейнер:
1 |
sudo docker stop docker.test && sudo docker start docker.test |
Посетите страницу вашего приложения по адресу http://your-ip-address:56733/template, чтобы увидеть, как подается новый шаблон.
В этом разделе вы создали файл шаблона Docker для обслуживания посетителей вашего приложения. На следующем шаге вы увидите, как изменения, внесенные в ваше приложение, могут вступить в силу без перезапуска контейнера Docker.
Обновление приложения
Иногда вам потребуется внести изменения в приложение, будь то установка новых требований, обновление контейнера Docker или изменения HTML и логики. В этом разделе вы настроите touch-reload
для внесения этих изменений без необходимости перезапуска контейнера Docker.
Python автозагрузка отслеживает изменения во всей файловой системе и обновляет приложение при обнаружении изменений. Автозагрузка в рабочей среде не рекомендуется, поскольку она может очень быстро стать ресурсоемкой. На этом шаге вы будете использовать touch-reload
для отслеживания изменений в определенном файле и перезагрузки при обновлении или замене файла.
Чтобы реализовать это, начните с открытия вашего uwsgi.ini
файла:
1 |
sudo nano uwsgi.ini |
Далее добавьте выделенную строку в конец файла:
/var/www/TestApp/uwsgi.ini
1 2 3 4 |
module = main callable = app master = true touch-reload = /app/uwsgi.ini |
Здесь указывается файл, который будет изменен для запуска перезагрузки всего приложения. После внесения изменений сохраните и закройте файл.
Чтобы продемонстрировать это, внесите небольшое изменение в свое приложение. Начните с открытия вашего app/views.py
файла:
1 2 |
sudo nano app/views.py |
Замените строку, возвращаемую home
функцией:
/var/www/TestApp/app/views.py
1 2 3 4 5 6 7 8 9 10 11 |
from flask import render_template from app import app @app.route('/') def home(): return "<b>There has been a change</b>" @app.route('/template') def template(): return render_template('home.html') |
Сохраните и закройте файл после внесения изменений.
Далее, если вы откроете домашнюю страницу своего приложения по адресу http://ip-address:56733, вы заметите, что изменения не отражены. Это потому, что условием перезагрузки является изменение uwsgi.ini
файла. Чтобы перезагрузить приложение, используйте touch
для активации условия:
1 |
sudo touch uwsgi.ini |
Снова загрузите домашнюю страницу приложения в своем браузере. Вы обнаружите, что приложение включило изменения:
На этом шаге вы настраиваете touch-reload
условие для обновления вашего приложения после внесения изменений.
Заключение
В этом руководстве вы создали и развернули приложение Flask в контейнере Docker. Вы также настроили touch-reload
обновление вашего приложения без необходимости перезапуска контейнера.