Как настроить колбу с MongoDB и Docker

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

Вступление

Разработка веб-приложений может стать сложной и трудоемкой при создании и поддержке ряда различных технологий. Принимая во внимание более легкие варианты, разработанные для уменьшения сложности и времени на производство для вашего приложения, можно получить более гибкое и масштабируемое решение. Как микро-веб-фреймворк, построенный наPython,Flask предоставляет разработчикам расширяемый способ расширения своих приложений с помощью расширений, которые можно интегрировать в проекты. Чтобы сохранить масштабируемость технического стека разработчика,MongoDB - это база данных NoSQL, предназначенная для масштабирования и работы с частыми изменениями. Разработчики могут использоватьDocker, чтобы упростить процесс упаковки и развертывания своих приложений.

Docker Compose еще больше упростил среду разработки, позволив вам определять свою инфраструктуру, включая службы приложений, сетевые тома и привязки монтирования, в одном файле. Использование Docker Compose упрощает использование нескольких командdocker container run. Он позволяет вам определять все ваши сервисы в одном файле Compose, и с помощью одной команды вы создаете и запускаете все сервисы из вашей конфигурации. Это обеспечивает контроль версий во всей вашей контейнерной инфраструктуре. Docker Compose использует имя проекта для изоляции сред друг от друга, что позволяет запускать несколько сред на одном хосте.

В этом руководстве вы создадите, упакуйте и запустите свое веб-приложение с Flask, Nginx и MongoDB внутри Dockercontainers. Вы определите всю конфигурацию стека в файлеdocker-compose.yml вместе с файлами конфигурации для Python, MongoDB и Nginx. Flask требуется веб-сервер для обслуживания HTTP-запросов, поэтому вы также будете использоватьGunicorn, который является HTTP-сервером Python WSGI, для обслуживания приложения. Nginx действует как обратный прокси-сервер, который перенаправляет запросы в Gunicorn для обработки.

Предпосылки

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

  • Пользователь без полномочий root с привилегиямиsudo, настроенными в соответствии с шагами из руководстваInitial Server Setup.

  • Докер устанавливается в соответствии с инструкциями из Шага 1 и Шага 2How To Install and Use Docker.

  • Docker Compose установлен в соответствии с инструкциями из шага 1How To Install Docker Compose.

[[step-1 -—- writing-the-stack-configuration-in-docker-compose]] == Шаг 1. Написание конфигурации стека в Docker Compose

Сборка приложений в Docker позволяет легко создавать версии инфраструктуры в зависимости от изменений конфигурации, которые вы вносите в Docker Compose. Инфраструктура может быть определена в одном файле и построена с помощью одной команды. На этом шаге вы настроите файлdocker-compose.yml для запуска вашего приложения Flask.

Файлdocker-compose.yml позволяет вам определять инфраструктуру вашего приложения как отдельные службы. Сервисы могут быть связаны друг с другом, и к каждой из них может быть прикрепленvolume для постоянного хранения. Тома хранятся в части файловой системы хоста, управляемой Docker (/var/lib/docker/volumes/ в Linux).

Тома - это лучший способ сохранить данные в Docker, поскольку данные в томах можно экспортировать или совместно использовать с другими приложениями. Для получения дополнительной информации о совместном использовании данных в Docker вы можете обратиться кHow To Share Data Between the Docker Container and the Host.

Для начала создайте каталог для приложения в домашнем каталоге на вашем сервере:

mkdir flaskapp

Перейдите во вновь созданный каталог:

cd flaskapp

Затем создайте файлdocker-compose.yml:

nano docker-compose.yml

Файлdocker-compose.yml начинается с номера версии, которая определяетDocker Compose file version. Версия файла Docker Compose3 нацелена на версию Docker Engine1.13.0+, что является предварительным условием для этой настройки. Вы также добавите тегservices, который определите на следующем шаге:

docker-compose.yml

version: '3'
services:

Теперь вы определитеflask как первую службу в вашем файлеdocker-compose.yml. Добавьте следующий код для определения службы Flask:

docker-compose.yml

. . .
  flask:
    build:
      context: app
      dockerfile: Dockerfile
    container_name: flask
    image: digitalocean.com/flask-python:3.6
    restart: unless-stopped
    environment:
      APP_ENV: "prod"
      APP_DEBUG: "False"
      APP_PORT: 5000
      MONGODB_DATABASE: flaskdb
      MONGODB_USERNAME: flaskuser
      MONGODB_PASSWORD: your_mongodb_password
      MONGODB_HOSTNAME: mongodb
    volumes:
      - appdata:/var/www
    depends_on:
      - mongodb
    networks:
      - frontend
      - backend

Свойствоbuild определяетcontext сборки. В этом случае папкаapp, которая будет содержатьDockerfile.

Вы используете свойствоcontainer_name, чтобы определить имя для каждого контейнера. Свойствоimage указывает имя образа и то, как образ Docker будет помечен. Свойствоrestart определяет, как следует перезапустить контейнер - в вашем случае этоunless-stopped. Это означает, что ваши контейнеры будут остановлены только при остановке / перезапуске Docker Engine или когда вы явно остановите контейнеры. Преимущество использования свойстваunless-stopped заключается в том, что контейнеры запускаются автоматически после перезапуска Docker Engine или возникновения любой ошибки.

Свойствоenvironment содержит переменные среды, которые передаются в контейнер. Вам необходимо предоставить надежный пароль для переменной средыMONGODB_PASSWORD. Свойствоvolumes определяет тома, которые использует служба. В вашем случае томappdata смонтирован внутри контейнера в каталоге/var/www. Свойствоdepends_on определяет службу, от которой зависит правильная работа Flask. В этом случае службаflask будет зависеть отmongodb, поскольку службаmongodb действует как база данных для вашего приложения. depends_on гарантирует, что службаflask запускается, только если запущена службаmongodb.

Свойствоnetworks указываетfrontend иbackend в качестве сетей, к которым службаflask будет иметь доступ.

Определив службуflask, вы готовы добавить конфигурацию MongoDB в файл. В этом примере вы будете использовать официальный образ4.0.8 версииmongo. Добавьте следующий код в ваш файлdocker-compose.yml послеflask service:

docker-compose.yml

. . .
  mongodb:
    image: mongo:4.0.8
    container_name: mongodb
    restart: unless-stopped
    command: mongod --auth
    environment:
      MONGO_INITDB_ROOT_USERNAME: mongodbuser
      MONGO_INITDB_ROOT_PASSWORD: your_mongodb_root_password
      MONGO_INITDB_DATABASE: flaskdb
      MONGODB_DATA_DIR: /data/db
      MONDODB_LOG_DIR: /dev/null
    volumes:
      - mongodbdata:/data/db
    networks:
      - backend

container_name для этой службы -mongodb с политикой перезапускаunless-stopped. Вы используете свойствоcommand, чтобы определить команду, которая будет выполняться при запуске контейнера. Командаmongod --auth отключит вход в оболочку MongoDB без учетных данных, что защитит MongoDB, потребовав аутентификации.

Переменные средыMONGO_INITDB_ROOT_USERNAME иMONGO_INITDB_ROOT_PASSWORD создают пользователя root с заданными учетными данными, поэтому не забудьте заменить местозаполнитель надежным паролем.

По умолчанию MongoDB хранит свои данные в/data/db, поэтому данные в папке/data/db будут записаны в названный томmongodbdata для сохранения. В результате вы не потеряете свои базы данных в случае перезапуска. СлужбаmongoDB не предоставляет никаких портов, поэтому служба будет доступна только через сетьbackend.

Далее вы определите веб-сервер для вашего приложения. Добавьте следующий код в файлdocker-compose.yml для настройки Nginx:

docker-compose.yml

. . .
  webserver:
    build:
      context: nginx
      dockerfile: Dockerfile
    image: digitalocean.com/webserver:latest
    container_name: webserver
    restart: unless-stopped
    environment:
      APP_ENV: "prod"
      APP_NAME: "webserver"
      APP_DEBUG: "false"
      SERVICE_NAME: "webserver"
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - nginxdata:/var/log/nginx
    depends_on:
      - flask
    networks:
      - frontend

Здесь вы определилиcontext изbuild, который является папкойnginx, содержащейDockerfile. С помощью свойстваimage вы указываете изображение, используемое для тегирования и запуска контейнера. Свойствоports настроит общедоступный сервис Nginx через:80 и:443, аvolumes монтирует томnginxdata внутри контейнера в/var/log/nginx каталог.

Вы определили службу, в которой работает веб-серверdepends_on, какflask. Наконец, свойствоnetworks определяет, что служба веб-сервера сети будет иметь доступ кfrontend.

Затем вы создадитеbridge networks, чтобы контейнеры могли взаимодействовать друг с другом. Добавьте следующие строки в конец вашего файла:

docker-compose.yml

. . .
networks:
  frontend:
    driver: bridge
  backend:
    driver: bridge

Вы определили две сети -frontend иbackend - для подключения сервисов. Интерфейсные службы, такие как Nginx, будут подключаться к сетиfrontend, поскольку она должна быть общедоступной. Внутренние службы, такие как MongoDB, будут подключаться к сетиbackend, чтобы предотвратить несанкционированный доступ к службе.

Далее вы будете использовать тома для сохранения базы данных, приложений и файлов конфигурации. Поскольку ваше приложение будет использовать базы данных и файлы, необходимо сохранить внесенные в них изменения. Тома управляются Docker и хранятся в файловой системе. Добавьте этот код в файлdocker-compose.yml для настройки томов:

docker-compose.yml

. . .
volumes:
  mongodbdata:
    driver: local
  appdata:
    driver: local
  nginxdata:
    driver: local

В разделеvolumes объявляются тома, которые приложение будет использовать для хранения данных. Здесь вы определили томаmongodbdata,appdata иnginxdata для сохранения ваших баз данных MongoDB, данных приложения Flask и журналов веб-сервера Nginx соответственно. Все эти тома используют драйверlocal для локального хранения данных. Тома используются для сохранения этих данных, чтобы такие данные, как базы данных MongoDB и журналы веб-сервера Nginx, могли быть потеряны после перезапуска контейнеров.

Ваш полный файлdocker-compose.yml будет выглядеть так:

docker-compose.yml

version: '3'
services:

  flask:
    build:
      context: app
      dockerfile: Dockerfile
    container_name: flask
    image: digitalocean.com/flask-python:3.6
    restart: unless-stopped
    environment:
      APP_ENV: "prod"
      APP_DEBUG: "False"
      APP_PORT: 5000
      MONGODB_DATABASE: flaskdb
      MONGODB_USERNAME: flaskuser
      MONGODB_PASSWORD: your_mongodb_password
      MONGODB_HOSTNAME: mongodb
    volumes:
      - appdata:/var/www
    depends_on:
      - mongodb
    networks:
      - frontend
      - backend

  mongodb:
    image: mongo:4.0.8
    container_name: mongodb
    restart: unless-stopped
    command: mongod --auth
    environment:
      MONGO_INITDB_ROOT_USERNAME: mongodbuser
      MONGO_INITDB_ROOT_PASSWORD: your_mongodb_root_password
      MONGO_INITDB_DATABASE: flaskdb
      MONGODB_DATA_DIR: /data/db
      MONDODB_LOG_DIR: /dev/null
    volumes:
      - mongodbdata:/data/db
    networks:
      - backend

  webserver:
    build:
      context: nginx
      dockerfile: Dockerfile
    image: digitalocean.com/webserver:latest
    container_name: webserver
    restart: unless-stopped
    environment:
      APP_ENV: "prod"
      APP_NAME: "webserver"
      APP_DEBUG: "true"
      SERVICE_NAME: "webserver"
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - nginxdata:/var/log/nginx
    depends_on:
      - flask
    networks:
      - frontend

networks:
  frontend:
    driver: bridge
  backend:
    driver: bridge

volumes:
  mongodbdata:
    driver: local
  appdata:
    driver: local
  nginxdata:
    driver: local

Сохраните файл и выйдите из редактора после проверки вашей конфигурации.

Вы определили конфигурацию Docker для всего стека приложений в файлеdocker-compose.yml. Теперь вы перешли к написанию Dockerfiles для Flask и веб-сервера.

[[step-2 -—- writing-the-flask-and-web-server-dockerfiles]] == Шаг 2. Написание файлов Dockerfiles для Flask и веб-сервера

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

На этом этапе вы напишите файлы Docker для служб Flask и веб-сервера. Для начала создайте каталогapp для вашего приложения Flask:

mkdir app

Затем создайтеDockerfile для вашего приложения Flask в каталогеapp:

nano app/Dockerfile

Добавьте следующий код в файл, чтобы настроить контейнер Flask:

app/Dockerfile

FROM python:3.6.8-alpine3.9

LABEL MAINTAINER="FirstName LastName "

ENV GROUP_ID=1000 \
    USER_ID=1000

WORKDIR /var/www/

В этомDockerfile вы создаете образ поверх3.6.8-alpine3.9 image, основанный на Alpine 3.9 с предустановленным Python 3.6.8.

ДирективаENV используется для определения переменных среды для нашей группы и идентификатора пользователя.
Linux Standard Base (LSB) указывает, чтоUIDs and GIDs 0-99 статически выделяются системой. Предполагается, чтоUIDs 100-999 динамически выделяются для системных пользователей и групп. Предполагается, чтоUIDs 1000-59999 динамически выделяются для учетных записей пользователей. Помня об этом, вы можете безопасно назначить UID и GID1000, кроме того, вы можете изменить UID / GID, обновивGROUP_ID иUSER_ID в соответствии с вашими требованиями.

ДирективаWORKDIR определяет рабочий каталог для контейнера. Обязательно замените полеLABEL MAINTAINER своим именем и адресом электронной почты.

Добавьте следующий блок кода, чтобы скопировать приложение Flask в контейнер и установить необходимые зависимости:

app/Dockerfile

. . .
ADD ./requirements.txt /var/www/requirements.txt
RUN pip install -r requirements.txt
ADD . /var/www/
RUN pip install gunicorn

Следующий код будет использовать директивуADD для копирования файлов из локального каталогаapp в каталог/var/www в контейнере. Затем Dockerfile будет использовать директивуRUN для установки Gunicorn и пакетов, указанных в файлеrequirements.txt, который вы создадите позже в этом руководстве.

Следующий блок кода добавляет нового пользователя и группу и инициализирует приложение:

app/Dockerfile

. . .
RUN addgroup -g $GROUP_ID www
RUN adduser -D -u $USER_ID -G www www -s /bin/sh

USER www

EXPOSE 5000

CMD [ "gunicorn", "-w", "4", "--bind", "0.0.0.0:5000", "wsgi"]

По умолчанию контейнеры Docker запускаются от имени пользователяroot. Пользовательroot имеет доступ ко всему в системе, поэтому последствия нарушения безопасности могут быть катастрофическими. Чтобы снизить этот риск безопасности, будет создан новый пользователь и группа, которые будут иметь доступ только к каталогу/var/www.

Этот код сначала использует командуaddgroup для создания новой группы с именемwww. Флаг-g устанавливает идентификатор группы для переменнойENV GROUP_ID=1000, которая определена ранее вDockerfile.

Строкиadduser -D -u $USER_ID -G www www -s /bin/sh создают пользователяwww с идентификатором пользователя1000, как определено переменнойENV. Флаг-s создает домашний каталог пользователя, если он не существует, и устанавливает оболочку входа по умолчанию на/bin/sh. Флаг-G используется для установки начальной группы входа пользователя вwww, которая была создана предыдущей командой.

КомандаUSER определяет, что программы, запущенные в контейнере, будут использовать пользователяwww. Gunicorn будет прослушивать:5000, поэтому вы откроете этот порт с помощью командыEXPOSE.

Наконец, строкаCMD [ "gunicorn", "-w", "4", "--bind", "0.0.0.0:5000", "wsgi"] запускает команду для запуска сервера Gunicorn с четырьмя рабочими, прослушивающими порт5000. Обычно это число должно составлять от 2 до 4 воркеров на ядро ​​сервера, документация Gunicorn рекомендует(2 x $num_cores) + 1 в качестве начального числа воркеров.

Ваш завершенныйDockerfile будет выглядеть следующим образом:

app/Dockerfile

FROM python:3.6.8-alpine3.9

LABEL MAINTAINER="FirstName LastName "

ENV GROUP_ID=1000 \
    USER_ID=1000

WORKDIR /var/www/

ADD . /var/www/
RUN pip install -r requirements.txt
RUN pip install gunicorn

RUN addgroup -g $GROUP_ID www
RUN adduser -D -u $USER_ID -G www www -s /bin/sh

USER www

EXPOSE 5000

CMD [ "gunicorn", "-w", "4", "--bind", "0.0.0.0:5000", "wsgi"]

Сохраните файл и выйдите из текстового редактора.

Затем создайте новый каталог для хранения вашей конфигурации Nginx:

mkdir nginx

Затем создайтеDockerfile для вашего веб-сервера Nginx в каталогеnginx:

nano nginx/Dockerfile

Добавьте следующий код в файл, чтобы создать файл Docker, который будет создавать образ для вашего контейнера Nginx:

nginx/Dockerfile

FROM digitalocean.com/alpine:latest

LABEL MAINTAINER="FirstName LastName "

RUN apk --update add nginx && \
    ln -sf /dev/stdout /var/log/nginx/access.log && \
    ln -sf /dev/stderr /var/log/nginx/error.log && \
    mkdir /etc/nginx/sites-enabled/ && \
    mkdir -p /run/nginx && \
    rm -rf /etc/nginx/conf.d/default.conf && \
    rm -rf /var/cache/apk/*

COPY conf.d/app.conf /etc/nginx/conf.d/app.conf

EXPOSE 80 443
CMD ["nginx", "-g", "daemon off;"]

Этот NginxDockerfile использует базовый образalpine, который представляет собой крошечный дистрибутив Linux с минимальной поверхностью для атак, созданной для обеспечения безопасности.

В директивеRUN вы устанавливаетеnginx, а также создаете символические ссылки для публикации ошибки и доступа к журналам стандартной ошибки (/dev/stderr) и выходным данным (/dev/stdout). Публикация ошибок в стандартную ошибку и вывод является наилучшей практикой, поскольку контейнеры эфемерны, при этом журналы отправляются в журналы докера, и оттуда вы можете перенаправлять свои журналы в службу журналирования, например, в стек Elastic, для сохранения. После этого выполняются команды для удаленияdefault.conf и/var/cache/apk/*, чтобы уменьшить размер результирующего изображения. Выполнение всех этих команд за одинRUN уменьшает количество слоев в изображении, что также уменьшает размер результирующего изображения.

ДирективаCOPY копирует конфигурацию веб-сервераapp.conf внутри контейнера. ДирективаEXPOSE гарантирует, что контейнеры прослушивают порты:80 и:443, поскольку ваше приложение будет работать на:80 с:443 в качестве защищенного порта.

Наконец, директиваCMD определяет команду для запуска сервера Nginx.

Сохраните файл и выйдите из текстового редактора.

Теперь, когдаDockerfile готов, вы готовы настроить обратный прокси Nginx для маршрутизации трафика в приложение Flask.

[[step-3 -—- configuring-the-nginx-reverse-proxy]] == Шаг 3 - Настройка обратного прокси Nginx

На этом шаге вы настроите Nginx как обратный прокси-сервер для пересылки запросов в Gunicorn на:5000. Обратный прокси-сервер используется для направления клиентских запросов на соответствующий внутренний сервер. Он обеспечивает дополнительный уровень абстракции и контроля для обеспечения бесперебойной передачи сетевого трафика между клиентами и серверами.

Начните с создания каталогаnginx/conf.d:

mkdir nginx/conf.d

Чтобы настроить Nginx, вам необходимо создать файлapp.conf со следующей конфигурацией в папкеnginx/conf.d/. Файлapp.conf содержит конфигурацию, необходимую обратному прокси-серверу для пересылки запросов в Gunicorn.

nano nginx/conf.d/app.conf

Поместите следующее содержимое в файлapp.conf:

nginx/conf.d/app.conf

upstream app_server {
    server flask:5000;
}

server {
    listen 80;
    server_name _;
    error_log  /var/log/nginx/error.log;
    access_log /var/log/nginx/access.log;
    client_max_body_size 64M;

    location / {
        try_files $uri @proxy_to_app;
    }

    location @proxy_to_app {
        gzip_static on;

        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Host $http_host;
        proxy_buffering off;
        proxy_redirect off;
        proxy_pass http://app_server;
    }
}

Сначала будет определенupstream server, который обычно используется для указания веб-сервера или сервера приложений для маршрутизации или балансировки нагрузки.

Ваш вышестоящий сервер,app_server, определяет адрес сервера с помощью директивыserver, которая идентифицируется именем контейнераflask:5000.

Конфигурация веб-сервера Nginx определяется в блокеserver. Директиваlisten определяет номер порта, на котором ваш сервер будет прослушивать входящие запросы. Директивыerror_log иaccess_log определяют файлы для записи журналов. Директиваproxy_pass используется для настройки вышестоящего сервера для пересылки запросов наhttp://app_server.

Сохраните и закройте файл.

С настроенным веб-сервером Nginx вы можете перейти к созданию API дел Flask.

[[step-4 -—- created-the-flask-to-do-api]] == Шаг 4. Создание API-интерфейса Flask To-do

Теперь, когда вы создали свою среду, вы готовы создать приложение. На этом шаге вы напишите приложение API to-do, которое будет сохранять и отображать заметки о делах, отправленные из запроса POST.

Начните с создания файлаrequirements.txt в каталогеapp:

nano app/requirements.txt

Этот файл используется для установки зависимостей для вашего приложения. Реализация этого руководства будет использоватьFlask,Flask-PyMongo иrequests. Добавьте в файлrequirements.txt следующее:

app/requirements.txt

Flask==1.0.2
Flask-PyMongo==2.2.0
requests==2.20.1

Сохраните файл и выйдите из редактора после ввода требований.

Затем создайте файлapp.py, содержащий код приложения Flask в каталогеapp:

nano app/app.py

В вашем новом файлеapp.py введите код для импорта зависимостей:

app/app.py

import os
from flask import Flask, request, jsonify
from flask_pymongo import PyMongo

Пакетos используется для импорта переменных среды. Из библиотекиflask вы импортировали объектыFlask,request иjsonify для создания экземпляра приложения, обработки запросов и отправки ответов JSON соответственно. Изflask_pymongo вы импортировали объектPyMongo для взаимодействия с MongoDB.

Затем добавьте код, необходимый для подключения к MongoDB:

app/app.py

. . .
application = Flask(__name__)

application.config["MONGO_URI"] = 'mongodb://' + os.environ['MONGODB_USERNAME'] + ':' + os.environ['MONGODB_PASSWORD'] + '@' + os.environ['MONGODB_HOSTNAME'] + ':27017/' + os.environ['MONGODB_DATABASE']

mongo = PyMongo(application)
db = mongo.db

Flask(__name__) загружает объект приложения в переменнуюapplication. Затем код создает строку подключения MongoDB из переменных среды, используяos.environ. Передача объектаapplication в методPyMongo() даст вам объектmongo, который, в свою очередь, даст вам объектdb изmongo.db.

Теперь вы добавите код для создания индексного сообщения:

app/app.py

. . .
@application.route('/')
def index():
    return jsonify(
        status=True,
        message='Welcome to the Dockerized Flask MongoDB app!'
    )

@application.route('/') определяет маршрут GET/ вашего API. Здесь ваша функцияindex() возвращает строку JSON с использованием методаjsonify.

Затем добавьте маршрут/todo в список всех дел:

app/app.py

. . .
@application.route('/todo')
def todo():
    _todos = db.todo.find()

    item = {}
    data = []
    for todo in _todos:
        item = {
            'id': str(todo['_id']),
            'todo': todo['todo']
        }
        data.append(item)

    return jsonify(
        status=True,
        data=data
    )

@application.route('/todo') определяет GET-маршрут/todo вашего API, который возвращает задачи в базе данных. Методdb.todo.find() возвращает все задачи в базе данных. Затем вы перебираете_todos, чтобы построитьitem, который включает толькоid иtodo из объектов, добавляющих их в массивdata, и, наконец, возвращает их как JSON.

Затем добавьте код для создания задачи:

app/app.py

. . .
@application.route('/todo', methods=['POST'])
def createTodo():
    data = request.get_json(force=True)
    item = {
        'todo': data['todo']
    }
    db.todo.insert_one(item)

    return jsonify(
        status=True,
        message='To-do saved successfully!'
    ), 201

@application.route('/todo') определяет POST-маршрут/todo вашего API, который создает заметку о делах в базе данных. request.get_json(force=True) получает JSON, который вы отправляете на маршрут, аitem используется для создания JSON, который будет сохранен в списке дел. db.todo.insert_one(item) используется для вставки одного элемента в базу данных. После сохранения задачи в базе данных вы возвращаете ответ JSON с кодом состояния201 CREATED.

Теперь вы добавляете код для запуска приложения:

app/app.py

. . .
if __name__ == "__main__":
    ENVIRONMENT_DEBUG = os.environ.get("APP_DEBUG", True)
    ENVIRONMENT_PORT = os.environ.get("APP_PORT", 5000)
    application.run(host='0.0.0.0', port=ENVIRONMENT_PORT, debug=ENVIRONMENT_DEBUG)

Условие__name__ == "__main__" используется для проверки того, является ли глобальная переменная__name__ в модуле точкой входа в вашу программу,"__main__", а затем запускает приложение. Если__name__ равно"__main__", тогда код внутри блокаif выполнит приложение, используя эту командуapplication.run(host='0.0.0.0', port=ENVIRONMENT_PORT, debug=ENVIRONMENT_DEBUG).

Затем мы получаем значения дляENVIRONMENT_DEBUG иENVIRONMENT_PORT из переменных среды, используяos.environ.get(), используя ключ в качестве первого параметра и значение по умолчанию в качестве второго параметра. application.run() устанавливает значенияhost,port иdebug для приложения.

Готовый файлapp.py будет выглядеть так:

app/app.py

import os
from flask import Flask, request, jsonify
from flask_pymongo import PyMongo

application = Flask(__name__)

application.config["MONGO_URI"] = 'mongodb://' + os.environ['MONGODB_USERNAME'] + ':' + os.environ['MONGODB_PASSWORD'] + '@' + os.environ['MONGODB_HOSTNAME'] + ':27017/' + os.environ['MONGODB_DATABASE']

mongo = PyMongo(application)
db = mongo.db

@application.route('/')
def index():
    return jsonify(
        status=True,
        message='Welcome to the Dockerized Flask MongoDB app!'
    )

@application.route('/todo')
def todo():
    _todos = db.todo.find()

    item = {}
    data = []
    for todo in _todos:
        item = {
            'id': str(todo['_id']),
            'todo': todo['todo']
        }
        data.append(item)

    return jsonify(
        status=True,
        data=data
    )

@application.route('/todo', methods=['POST'])
def createTodo():
    data = request.get_json(force=True)
    item = {
        'todo': data['todo']
    }
    db.todo.insert_one(item)

    return jsonify(
        status=True,
        message='To-do saved successfully!'
    ), 201

if __name__ == "__main__":
    ENVIRONMENT_DEBUG = os.environ.get("APP_DEBUG", True)
    ENVIRONMENT_PORT = os.environ.get("APP_PORT", 5000)
    application.run(host='0.0.0.0', port=ENVIRONMENT_PORT, debug=ENVIRONMENT_DEBUG)

Сохраните файл и выйдите из редактора.

Затем создайте файлwsgi.py в каталогеapp.

nano app/wsgi.py

Файлwsgi.py создает объект приложения (или вызываемый объект), чтобы сервер мог его использовать. Каждый раз, когда приходит запрос, сервер использует этот объект приложения для запуска обработчиков запросов приложения при разборе URL-адреса.

Поместите следующее содержимое в файлwsgi.py, сохраните файл и выйдите из текстового редактора:

app/wsgi.py

from app import application

if __name__ == "__main__":
  application.run()

Этот файлwsgi.py импортирует объект приложения из файлаapp.py и создает объект приложения для сервера Gunicorn.

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

[[step-5 -—- building-and-running-the-container]] == Шаг 5 - Создание и запуск контейнеров

Теперь, когда вы определили все службы в файлеdocker-compose.yml и их конфигурации, вы можете запускать контейнеры.

Поскольку службы определены в одном файле, необходимо запустить одну команду, чтобы запустить контейнеры, создать тома и настроить сети. Эта команда также создает образ для вашего приложения Flask и веб-сервера Nginx. Выполните следующую команду, чтобы построить контейнеры:

docker-compose up -d

При первом запуске команды она загрузит все необходимые образы Docker, что может занять некоторое время. После того, как изображения будут загружены и сохранены на вашем локальном компьютере,docker-compose создаст ваши контейнеры. Флаг-d демонизирует процесс, что позволяет ему работать в фоновом режиме.

Используйте следующую команду, чтобы вывести список запущенных контейнеров после завершения процесса сборки:

docker ps

Вы увидите вывод, похожий на следующий:

OutputCONTAINER ID        IMAGE                           COMMAND                  CREATED             STATUS              PORTS                                      NAMES
f20e9a7fd2b9        digitalocean.com/webserver:latest   "nginx -g 'daemon of…"   2 weeks ago         Up 2 weeks          0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp   webserver
3d53ea054517        digitalocean.com/flask-python:3.6   "gunicorn -w 4 --bin…"   2 weeks ago         Up 2 weeks          5000/tcp                                   flask
96f5a91fc0db        mongo:4.0.8                     "docker-entrypoint.s…"   2 weeks ago         Up 2 weeks          27017/tcp                                  mongodb

CONTAINER ID - это уникальный идентификатор, который используется для доступа к контейнерам. IMAGE определяет имя изображения для данного контейнера. ПолеNAMES - это имя службы, под которой создаются контейнеры, аналогичноCONTAINER ID, которые могут использоваться для доступа к контейнерам. Наконец,STATUS предоставляет информацию о состоянии контейнера, запущен ли он, перезапускается или остановлен.

Вы использовали командуdocker-compose для создания контейнеров из файлов конфигурации. На следующем шаге вы создадите пользователя MongoDB для своего приложения.

[[step-6 -—- create-a-user-for-your-mongodb-database]] == Шаг 6. Создание пользователя для вашей базы данных MongoDB

По умолчанию MongoDB позволяет пользователям входить в систему без учетных данных и предоставляет неограниченные привилегии. На этом этапе вы защитите свою базу данных MongoDB, создав для нее отдельного пользователя.

Для этого вам потребуются имя пользователя root и пароль, которые вы установили в переменных окружения файлаdocker-compose.ymlMONGO_INITDB_ROOT_USERNAME иMONGO_INITDB_ROOT_PASSWORD для службыmongodb. В целом, лучше избегать использования учетной записи администратора root при взаимодействии с базой данных. Вместо этого вы создадите отдельного пользователя базы данных для вашего приложения Flask, а также новую базу данных, к которой у приложения Flask будет разрешен доступ.

Чтобы создать нового пользователя, сначала запустите интерактивную оболочку в контейнереmongodb:

docker exec -it mongodb bash

Вы используете командуdocker exec для запуска команды внутри работающего контейнера вместе с флагом-it для запуска интерактивной оболочки внутри контейнера.

Оказавшись внутри контейнера, войдите в административную учетную запись MongoDBroot:

mongo -u mongodbuser -p

Вам будет предложено ввести пароль, который вы ввели в качестве значения переменнойMONGO_INITDB_ROOT_PASSWORD в файлеdocker-compose.yml. Пароль можно изменить, установив новое значение дляMONGO_INITDB_ROOT_PASSWORD в службеmongodb, и в этом случае вам придется повторно запустить командуdocker-compose up -d.

Запустите командуshow dbs;, чтобы вывести список всех баз данных:

show dbs;

Вы увидите следующий вывод:

Outputadmin    0.000GB
config   0.000GB
local    0.000GB
5 rows in set (0.00 sec)

База данныхadmin - это специальная база данных, которая предоставляет пользователям административные права. Если у пользователя есть доступ для чтения к базе данныхadmin, он будет иметь права на чтение и запись для всех остальных баз данных. Поскольку в выходных данных отображается база данныхadmin, пользователь имеет доступ к этой базе данных и, следовательно, может читать и писать во все другие базы данных.

Сохранение первой заметки о деле автоматически приведет кcreate the MongoDB database. MongoDB позволяет переключиться на несуществующую базу данных с помощью командыuse database. Он создает базу данных, когда документ сохраняется в коллекции. Поэтому база данных здесь не создается; это произойдет, когда вы сохраните свою первую заметку о делах в базе данных из API. Выполните командуuse, чтобы переключиться на базу данныхflaskdb:

use flaskdb

Затем создайте нового пользователя, которому будет разрешен доступ к этой базе данных:

db.createUser({user: 'flaskuser', pwd: 'your password', roles: [{role: 'readWrite', db: 'flaskdb'}]})
exit

Эта команда создает пользователя с именемflaskuser с доступомreadWrite к базе данныхflaskdb. Обязательно используйте надежный пароль в полеpwd. user иpwd здесь - это значения, которые вы определили в файлеdocker-compose.yml в разделе переменных среды для службыflask.

Войдите в аутентифицированную базу данных с помощью следующей команды:

mongo -u flaskuser -p your password --authenticationDatabase flaskdb

Теперь, когда вы добавили пользователя, выйдите из базы данных.

exit

И, наконец, выйдите из контейнера:

exit

Теперь вы настроили выделенную базу данных и учетную запись пользователя для своего приложения Flask. Компоненты базы данных готовы, так что теперь вы можете перейти к запуску приложения Flask to-do.

[[step-7 -—- running-the-flask-to-do-app]] == Шаг 7. Запуск приложения Flask To-do

Теперь, когда ваши службы настроены и работают, вы можете протестировать свое приложение, перейдя кhttp://your_server_ip в браузере. Кроме того, вы можете запуститьcurl, чтобы увидеть ответ JSON от Flask:

curl -i http://your_server_ip

Вы получите следующий ответ:

Output{"message":"Welcome to the Dockerized Flask MongoDB app!","status":true}

Конфигурация для приложения Flask передается в приложение из файлаdocker-compose.yml. Конфигурация подключения к базе данных задается с использованием переменныхMONGODB_*, определенных в разделеenvironment службыflask.

Чтобы проверить все, создайте заметку о делах, используя Flask API. Вы можете сделать это с помощью запроса curlPOST к маршруту/todo:

curl -i -H "Content-Type: application/json" -X POST -d '{"todo": "Dockerize Flask application with MongoDB backend"}' http://your_server_ip/todo

Этот запрос приводит к ответу с кодом состояния201 CREATED, когда задача сохраняется в MongoDB:

Output{"message":"To-do saved successfully!","status":true}

Вы можете перечислить все заметки о делах из MongoDB с помощью запроса GET для маршрута/todo:

curl -i http://your_server_ip/todo
Output{"data":[{"id":"5c9fa25591cb7b000a180b60","todo":"Dockerize Flask application with MongoDB backend"}],"status":true}

Благодаря этому вы создали Docker для API Flask, выполняющего серверную часть MongoDB с Nginx в качестве обратного прокси-сервера, развернутого на ваших серверах. Для производственной среды вы можете использоватьsudo systemctl enable docker, чтобы ваша служба Docker автоматически запускалась во время выполнения.

Заключение

В этом руководстве вы развернули приложение Flask с Docker, MongoDB, Nginx и Gunicorn. Теперь у вас есть современное API-приложение без сохранения состояния, которое можно масштабировать. Хотя вы можете достичь этого результата, используя команду типаdocker container run,docker-compose.yml упрощает вашу работу, поскольку этот стек можно поместить в систему контроля версий и обновлять по мере необходимости.

Отсюда вы также можете взглянуть на наши дальнейшиеPython Framework tutorials.

Related