*Автор выбрал Tech Education Fund для получения пожертвования в рамках программы Write for DOnations.*

Введение

Docker — это приложение с открытым исходным кодом, позволяющее администраторам создавать, развертывать и воспроизводить приложения с помощью контейнеров. Контейнеры — это пакеты, в которых содержатся все зависимости, необходимые для запуска приложения на уровне операционной системы. Это означает, что каждое приложение, развернутое с помощью Docker, имеет собственную среду, и его требования обрабатываются отдельно.

Flask — это веб-микроструктура, построенная на базе Python. Она называется микроструктурой, потому что не требует для работы специальных инструментов или плагинов. Микроструктура Flask отличается компактностью, гибкостью и высоким уровнем структурирования, за счет чего она более предпочтительна по сравнению с другими программными структурами.

Развертывание приложения Flask с помощью Docker позволит вам воспроизводить приложение на разных серверах с минимальными изменениями конфигурации.

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

Предварительные требования

docker illustration for: Предварительные требования

Для выполнения этого руководства вам потребуется следующее:

Шаг 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, которы вы создадите после сохранения этого файла. Добавьте в новый файл следующий код:

				
					
[label /var/www/TestApp/__init__.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! строка для пользователей, посещающих вашу веб-страницу:

				
					
[label /var/www/TestApp/app/views.py]

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:

				
					
[label /var/www/TestApp/uwsgi.ini]

[uwsgi]

module = main

callable = app

master = true

				
			

Этот код определяет модуль, из которого будет обслуживаться приложение Flask. В данном случае это файл main.py, который здесь указывается как main. Опция callable указывает uWSGI использовать экземпляр app, экспортированный основным приложением. Параметр master позволяет вашему приложению продолжать работать, и поэтому даже при перезагрузке всего приложения время простоя будет минимальным.

Теперь создайте файл main.py, который будет главной точкой входа в приложение. Точка входа сообщает uWSGI, как следует взаимодействовать с приложением.

				
					
sudo nano main.py

				
			

Далее скопируйте и вставьте в файл следующий код. Этот код импортирует экземпляр Flask под названием app из пакета приложения, созданного на предыдущих шагах.

				
					
[label /var/www/TestApp/main.py]

from app import app

				
			

Наконец, создайте файл requirements.txt, чтобы указать, какие зависимости диспетчер пакетов pip установит в вашу среду Docker:

				
					
sudo nano requirements.txt

				
			

Добавьте следующую строку для добавления Flask в качестве зависимости:

				
					
[label /var/www/TestApp/app/requirements.txt]

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 желаемую конфигурацию. Эти команды указывают, как будет построен образ, и какие дополнительные требования будут в него включены.

				
					
[label /var/www/TestApp/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. Добавьте свою конфигурацию в новый файл:

				
					
[label /var/www/TestApp/start.sh]

#!/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

				
			

В результате будет выведен список контейнеров:

				
					
[secondary_label Output]

CONTAINER 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, содержащую заголовок и текст.

				
					
[label /var/www/TestApp/app/templates/home.html]



&lt;!doctype html&gt;



&lt;html lang="en-us"&gt;   

  &lt;head&gt;

    &lt;meta charset="utf-8"&gt;

    &lt;meta http-equiv="x-ua-compatible" content="ie=edge"&gt;

    &lt;title&gt;Welcome home&lt;/title&gt;

  &lt;/head&gt;



  &lt;body&gt;

    &lt;h1&gt;Home Page&lt;/h1&gt;

    &lt;p&gt;This is the home page of our application.&lt;/p&gt;

  &lt;/body&gt;

&lt;/html&gt;

				
			

После добавления шаблона сохраните и закройте файл.

Теперь измените файл app/views.py, чтобы обслуживать созданный файл:

				
					
sudo nano app/views.py

				
			

Вначале добавьте в начале файла следующую строку для импорта метода render_template из Flask. Этот метод проводит синтаксический анализ файла HTML для рендеринга веб-страницы для пользователя.

				
					
[label /var/www/TestApp/app/views.py]

from flask import render_template

...

				
			

В конце файла вы добавите новый маршрут для рендеринга файла шаблона. Данный код указывает, что пользователям выводится содержимое файла home.html всегда, когда они посещают маршрут /template в вашем приложении.

				
					
[label /var/www/TestApp/app/views.py]

...



@app.route('/template')

def template():

    return render_template('home.html')

				
			

Обновленный файл app/views.py будет выглядеть примерно следующим образом:

				
					
[label /var/www/TestApp/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 &lt;^&gt;docker.test&lt;^&gt; &amp;&amp; sudo docker start &lt;^&gt;docker.test&lt;^&gt;

				
			

Откройте свое приложение по адресу http://<^>your-ip-address<^>:56733/template, чтобы увидеть, как выводится новый шаблон.

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

Шаг 4 — Обновление приложения

Иногда в приложение бывает нужно внести изменения. Это может быть установка новых требований, обновление контейнера Docker или внесение изменений в код HTML и логику. В этом разделе вы настроите команду touch-reload для внесения этих зменений без перезапуска контейнера Docker.

Функция *автоматической перезагрузки* Python отслеживает изменения во всей файловой системе и обновляет приложение при обнаружении изменений. Автоматическая перезагрузка не рекомендуется в производственной среди, поскольку она может очень быстро увеличить нагрузку на ресурсы системы. На этом шаге вы используете команду touch-reload для отслеживания изменений определенного файла и перезагрузке контейнера в случае обновления или замены файла.

Для реализации этой функции откройте файл uwsgi.ini:

				
					
sudo nano uwsgi.ini

				
			

Добавьте в конец файла выделенную строку:

				
					
[label /var/www/TestApp/uwsgi.ini]

module = main

callable = app

master = true

&lt;^&gt;touch-reload = /app/uwsgi.ini&lt;^&gt;

				
			

Эта строка указывает файл, изменение которого запускает перезагрузку приложения. После внесения изменений сохраните и закройте файл.

Чтобы продемонстрировать это, внесите в ваше приложение небольшое изменение. Для начала откройте файл app/views.py:

				
					
sudo nano app/views.py

				
			

Замените строку, возвращаемую функцией home:

				
					
[label  /var/www/TestApp/app/views.py]

from flask import render_template

from app import app



@app.route('/')

def home():

    return "&lt;^&gt;&lt;b&gt;There has been a change&lt;/b&gt;&lt;^&gt;"



@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, ознакомьтесь с официальной документацией.