Tutorial
Создание и развертывание приложения Flask с использованием Docker в Ubuntu 18.04
Автор выбрал Tech Education Fund для получения пожертвования в рамках программы Write for DOnations.
Введение
Docker — это приложение с открытым исходным кодом, позволяющее администраторам создавать, развертывать и воспроизводить приложения с помощью контейнеров. Контейнеры — это пакеты, в которых содержатся все зависимости, необходимые для запуска приложения на уровне операционной системы. Это означает, что каждое приложение, развернутое с помощью Docker, имеет собственную среду, и его требования обрабатываются отдельно.
Flask — это веб-микроструктура, построенная на базе Python. Она называется микроструктурой, потому что не требует для работы специальных инструментов или плагинов. Микроструктура Flask отличается компактностью, гибкостью и высоким уровнем структурирования, за счет чего она более предпочтительна по сравнению с другими программными структурами.
Развертывание приложения Flask с помощью Docker позволит вам воспроизводить приложение на разных серверах с минимальными изменениями конфигурации.
В этом обучающем модуле вы создадите приложение Flask и выполните его развертывание с помощью Docker. Также в этом обучающем модуле мы расскажем, как обновить приложение после развертывания.
Предварительные требования
Для выполнения этого руководства вам потребуется следующее:
- Пользователь без прав root с привилегиями sudo, настроенный в соответствии с указаниями обучающего модуля «Начальная настройка сервера на базе Ubuntu 18.04».
- Один сервер Ubuntu 18.04 с установленным программным обеспечением Docker, которое настроено в соответствии с указаниями этого обучающего модуля или с помощью моментально развертываемого образа Docker от DigitalOcean.
- Веб-сервер Nginx, установленный в соответствии с указаниями по первому шагу в обучающем модуле «Установка Nginx на сервере Ubuntu 18.04».
Шаг 1 — Настройка приложения Flask
Вначале вы создадите структуру каталогов, где будет размещено ваше приложение Flask. В этом обучающем модуле мы создадим каталог TestApp
в каталоге /var/www
, но вы можете изменить команду и использовать любое другое название.
- sudo mkdir /var/www/TestApp
Перейдите в созданный каталог TestApp
:
- cd /var/www/TestApp
Создайте базовую структуру папок для приложения Flask:
- sudo mkdir -p app/static app/templates
Флаг -p
означает, что команда mkdir
создаст каталог и все его родительские каталоги, которых еще не существует. В данном случае команда mkdir
создаст родительский каталог app
в процессе создания каталогов static
и templates
.
В каталоге app
будут находиться все файлы, связанные с приложением Flask, в том числе views и blueprints. Views — это создаваемый вами код, обеспечивающий ответы на запросы вашего приложения. Blueprints создает компоненты приложения и поддерживает стандартные шаблоны внутри приложения или для нескольких разных приложений.
В каталоге static
хранятся различные ресурсы, в том числе файлы изображений, CSS и JavaScript. В каталоге templates
хранятся шаблоны HTML для вашего проекта.
Теперь базовая структура папок готова, и вы можете создать все файлы, необходимые для запуска приложения Flask. Вначале создайте файл __init__.py
в каталоге app
. Этот файл сообщает интерпретатору Python, что каталог app
является пакетом, и его следует рассматривать именно как пакет.
Запустите следующую команду для создания файла:
- sudo nano app/__init__.py
Пакеты в Python позволяют группировать модули в логические пространства имен или иерархии. Этот подход позволяет разбивать код на отдельные управляемые блоки, которые выполняют конкретные функции.
Затем вы добавитье в файл __init__.py
код, который создаст экземпляр Flask и импортирует логику из файла views.py
, которы вы создадите после сохранения этого файла. Добавьте в новый файл следующий код:
from flask import Flask
app = Flask(__name__)
from app import views
После добавления этого кода сохраните и закройте файл.
После создания файла __init__.py
вы будете готовы создать файл views.py
в каталоге app
. В этом файле будет содержаться большая часть логики вашего приложения.
- sudo nano app/views.py
Затем добавьте код в файл views.py
. Этот код будет возвращать фразу hello world!
строка для пользователей, посещающих вашу веб-страницу:
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.
Для создания этого файла запустите следующую команду:
- sudo nano uwsgi.ini
Затем добавьте в файл следующее содержание для настройки сервера uWSGI:
[uwsgi]
module = main
callable = app
master = true
Этот код определяет модуль, из которого будет обслуживаться приложение Flask. В данном случае это файл main.py
, который здесь указывается как main
. Опция callable
указывает uWSGI использовать экземпляр app
, экспортированный основным приложением. Параметр master
позволяет вашему приложению продолжать работать, и поэтому даже при перезагрузке всего приложения время простоя будет минимальным.
Теперь создайте файл main.py
, который будет главной точкой входа в приложение. Точка входа сообщает uWSGI, как следует взаимодействовать с приложением.
- sudo nano main.py
Далее скопируйте и вставьте в файл следующий код. Этот код импортирует экземпляр Flask под названием app
из пакета приложения, созданного на предыдущих шагах.
from app import app
Наконец, создайте файл requirements.txt
, чтобы указать, какие зависимости диспетчер пакетов pip
установит в вашу среду Docker:
- sudo nano requirements.txt
Добавьте следующую строку для добавления Flask в качестве зависимости:
Flask==1.0.2
В нем указывается устанавливаемая версия Flask. На момент составления настоящего обучающего модуля последней версией Flask была версия 1.0.2
. Вы можете проверить обновления Flask на официальном сайте.
Сохраните и закройте файл. Вы успешно настроили свое приложение Flask и готовы к настройке Docker.
Шаг 2 — Настройка Docker
На этом шаге вы создадите два файла для развертывания Docker, Dockerfile
и start.sh
. Dockerfile
— это текстовый документ, содержащий команды, используемые для сборки образа. Файл start.sh
— это скрипт оболочки, который построит образ и создаст контейнер из файла Dockerfile
.
Вначале создайте файл Dockerfile
.
- sudo nano Dockerfile
Далее добавьте в файл Dockerfile
желаемую конфигурацию. Эти команды указывают, как будет построен образ, и какие дополнительные требования будут в него включены.
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 и образов ОСs.
В первых двух строках указывается родительский образ, который вы будете использовать для запуска приложений и установки процессора команд bash и текстового редактора nano
. Также он устанавливает клиент git
для связи со службами хостинга контроля версий, такими как GitHub, GitLab и Bitbucket. ENV STATIC_URL /static
— переменная среды, используемая для конкретного образа Docker. Она определяет статичную папку, где хранятся все ресурсы, включая образы, файлы CSS и файлы JavaScript.
Последние две строки копируют в контейнер файл requirements.txt
, чтобы его можно было выполнить, а затем выполняют синтаксический анализ файла requirements.txt
для установки указанных зависимостей.
Сохраните и закройте файл после добавления вашей конфигурации.
Теперь вы установили файл Dockerfile
и уже почти готовы написать скрипт start.sh
, который построит для вас контейнер Docker. Прежде чем создавать скрипт start.sh
, убедитесь, что у вас имеется открытый порт для использования в конфигурации. Чтобы проверить, свободен ли порт, запустите следующую команду:
- sudo nc localhost 56733 < /dev/null; echo $?
Если вывод команды больше 1
, это означает, что порт свободен и готов к использованию. В противном случае, вам нужно будет выбрать другой порт для использования в файле конфигурации start.sh
.
Когда вы найдете открытый порт для использования, создайте скрипт start.sh
:
- sudo nano start.sh
Скрипт start.sh
— это скрипт оболочки, создающий образ из файла Dockerfile
и создающий контейнер на основе полученного образа Docker. Добавьте свою конфигурацию в новый файл:
#!/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
directory в контейнере.
Флаг -d
используется для запуска контейнера в режиме демона или в качестве фонового процесса. Флаг -p
используется для привязки порта на сервере к конкретному порту контейнера Docker. В данном случае вы привязываете порт 56733
к порту 80
контейнера Docker. Флаг -v
указывает, какой том Docker следует монтировать на контейнер. В данном случае вы монтируете весь каталог проекта в папку /var/www
в контейнере Docker.
Запустите скрипт start.sh
для создания образа Docker и построения контейнера на основе этого образа:
- sudo bash start.sh
После завершения выполнения скрипта используйте следующую команду для вывода списка всех запущенных контейнеров:
- sudo docker ps
В результате будет выведен список контейнеров:
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. Теперь вы используете шаблоны, чтобы показать пользователям контент.
Шаг 3 — Работа с файлами шаблонов
Шаблоны — это файлы, показывающие статичный и динамический контент пользователям вашего приложения. На этом шаге вы создадите шаблон HTML для создания главной страницы приложения.
Вначале создайте файл home.html
в каталоге app/templates
:
- sudo nano app/templates/home.html
Добавьте код для вашего шаблона. Этот код создаст страницу HTML5, содержащую заголовок и текст.
<!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
, чтобы обслуживать созданный файл:
- sudo nano app/views.py
Вначале добавьте в начале файла следующую строку для импорта метода render_template
из Flask. Этот метод проводит синтаксический анализ файла HTML для рендеринга веб-страницы для пользователя.
from flask import render_template
...
В конце файла вы добавите новый маршрут для рендеринга файла шаблона. Данный код указывает, что пользователям выводится содержимое файла home.html
всегда, когда они посещают маршрут /template
в вашем приложении.
...
@app.route('/template')
def template():
return render_template('home.html')
Обновленный файл app/views.py
будет выглядеть примерно следующим образом:
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. Запустите следующую команду для повторного построения контейнера:
- sudo docker stop docker.test && sudo docker start docker.test
Откройте свое приложение по адресу http://your-ip-address:56733/template
, чтобы увидеть, как выводится новый шаблон.
Вы создали файл шаблона Docker, который будет выводиться посетителям вашего приложения. На следующем шаге вы увидите. как вносимые вами в приложение изменения могут вступить в силу без необходимости перезапуска контейнера Docker.
Шаг 4 — Обновление приложения
Иногда в приложение бывает нужно внести изменения. Это может быть установка новых требований, обновление контейнера Docker или внесение изменений в код HTML и логику. В этом разделе вы настроите команду touch-reload
для внесения этих зменений без перезапуска контейнера Docker.
Функция автоматической перезагрузки Python отслеживает изменения во всей файловой системе и обновляет приложение при обнаружении изменений. Автоматическая перезагрузка не рекомендуется в производственной среди, поскольку она может очень быстро увеличить нагрузку на ресурсы системы. На этом шаге вы используете команду touch-reload
для отслеживания изменений определенного файла и перезагрузке контейнера в случае обновления или замены файла.
Для реализации этой функции откройте файл uwsgi.ini
:
- sudo nano uwsgi.ini
Добавьте в конец файла выделенную строку:
module = main
callable = app
master = true
touch-reload = /app/uwsgi.ini
Эта строка указывает файл, изменение которого запускает перезагрузку приложения. После внесения изменений сохраните и закройте файл.
Чтобы продемонстрировать это, внесите в ваше приложение небольшое изменение. Для начала откройте файл app/views.py
:
- sudo nano app/views.py
Замените строку, возвращаемую функцией home
:
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
для активации условия:
- sudo touch uwsgi.ini
Еще раз перезагрузите главную страницу приложения в браузере. Вы увидите, что в приложение включены изменения:
На этом шаге вы выберете условие команды touch-reload
, с которым приложение будет обновляться после внесения изменений.
Заключение
В этом обучающем модуле вы создали и развернули приложение Flask в контейнере Docker. Также вы настроили команду touch-reload
для обновления приложения без необходимости перезапуска контейнера.
Новое приложение в Docker можно будет легко масштабировать. Чтобы узнать больше об использовании Docker, ознакомьтесь с официальной документацией.