MongoDBとDockerでFlaskをセットアップする方法

_著者はhttps://www.brightfunds.org/organizations/internet-archive [インターネットアーカイブ]を選択して、https://do.co/w4do-cta [寄付のための書き込み]プログラムの一環として寄付を受け取りました。

前書き

Webアプリケーションの開発は、さまざまなテクノロジーを構築および保守する際に複雑で時間がかかるようになります。 アプリケーションの複雑さと生産時間を削減するために設計された軽量オプションを検討すると、より柔軟でスケーラブルなソリューションが得られます。 Python上に構築されたマイクロWebフレームワークとして、http://flask.pocoo.org/docs/1.0/ [Flask]は、開発者が拡張機能を通じてアプリケーションを成長させるための拡張可能な方法を提供しますプロジェクトに統合できます。 開発者の技術スタックのスケーラビリティを継続するために、https://www.mongodb.com/ [MongoDB]は、頻繁に変更される場合に拡張および動作するように設計されたNoSQLデータベースです。 開発者はhttps://docs.docker.com/[Docker]を使用して、アプリケーションのパッケージ化とデプロイのプロセスを簡素化できます。

Docker Composeは、アプリケーションサービス、ネットワークボリューム、バインドマウントなどのインフラストラクチャを単一のファイルで定義できるようにすることで、開発環境をさらに簡素化しました。 Docker Composeを使用すると、複数の `+ docker container run +`コマンドを実行するよりも使いやすくなります。 単一のComposeファイルですべてのサービスを定義し、単一のコマンドで構成からすべてのサービスを作成および開始できます。 これにより、コンテナインフラストラクチャ全体でバージョン管理が行われます。 Docker Composeはプロジェクト名を使用して環境を相互に分離します。これにより、単一のホストで複数の環境を実行できます。

このチュートリアルでは、Docker containers内でFlask、Nginx、MongoDBを使用してTo Do Webアプリケーションをビルド、パッケージ化、実行します。 Python、MongoDB、Nginxの設定ファイルとともに、スタック設定全体を `+ docker-compose.yml +`ファイルで定義します。 Flaskでは、HTTPリクエストを処理するためにWebサーバーが必要です。したがって、Python WSGI HTTPサーバーであるhttps://gunicorn.org/[Gunicorn]を使用してアプリケーションを処理します。 Nginxは、処理のためにGunicornにリクエストを転送するリバースプロキシサーバーとして機能します。

前提条件

このチュートリアルを実行するには、次のものが必要です。

ステップ1-Docker Composeでスタック構成を作成する

Dockerでアプリケーションを構築すると、Docker Composeで行った構成変更に応じてインフラストラクチャを簡単にバージョン管理できます。 インフラストラクチャは、単一のファイルで定義し、単一のコマンドで構築できます。 このステップでは、Flaskアプリケーションを実行するために `+ docker-compose.yml +`ファイルを設定します。

+ docker-compose.yml +`ファイルを使用すると、アプリケーションインフラストラクチャを個別のサービスとして定義できます。 サービスは相互に接続でき、それぞれに永続ストレージ用の_ボリューム_を接続できます。 ボリュームは、Dockerによって管理されるホストファイルシステムの一部に保存されます(Linuxでは `+ / var / lib / docker / volumes / +)。

ボリュームは、Dockerでデータを永続化するための最良の方法です。ボリューム内のデータは、他のアプリケーションとエクスポートまたは共有できるためです。 Dockerでのデータ共有の詳細については、https://www.digitalocean.com/community/tutorials/how-to-share-data-between-the-docker-container-and-the-host [How Dockerコンテナとホスト間でデータを共有するには]。

開始するには、サーバーのホームディレクトリにアプリケーションのディレクトリを作成します。

mkdir flaskapp

新しく作成したディレクトリに移動します。

cd flaskapp

次に、 `+ docker-compose.yml +`ファイルを作成します:

nano docker-compose.yml

`+ docker-compose.yml `ファイルは、https://docs.docker.com/compose/compose-file/ [Docker Compose file version]を識別するバージョン番号で始まります。 Docker Composeファイルバージョン ` 3 `は、このセットアップの前提条件であるDocker Engineバージョン ` 1.13.0 +`を対象としています。 次のステップで定義する ` services +`タグも追加します。

docker-compose.yml

version: '3'
services:

これで、 `+ docker-compose.yml `ファイルの最初のサービスとして ` flask +`を定義します。 次のコードを追加して、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:
     MONGODB_PASSWORD:
     MONGODB_HOSTNAME: mongodb
   volumes:
     - appdata:/var/www
   depends_on:
     - mongodb
   networks:
     - frontend
     - backend

+ build`プロパティはビルドの + context`を定義します。 この場合、 + Dockerfile`を含む + app`フォルダー。

`+ container_name `プロパティを使用して、各コンテナの名前を定義します。 ` image `プロパティは、画像名とDocker画像にタグを付けるものを指定します。 ` restart `プロパティは、コンテナの再起動方法を定義します-あなたの場合、それは ` unless-stopped `です。 つまり、コンテナは、Docker Engineが停止/再起動されたとき、またはコンテナを明示的に停止したときにのみ停止されます。 ` unless-stopped +`プロパティを使用する利点は、Docker Engineが再起動されるかエラーが発生するとコンテナが自動的に起動することです。

+ environment`プロパティには、コンテナに渡される環境変数が含まれています。 環境変数 `+ MONGODB_PASSWORD +`の安全なパスワードを提供する必要があります。 `+ volumes +`プロパティは、サービスが使用しているボリュームを定義します。 あなたの場合、ボリューム「+ appdata」はコンテナ内の「+ / var / www」ディレクトリにマウントされます。 `+ depends_on +`プロパティは、Flaskが適切に機能するために依存するサービスを定義します。 この場合、 `+ mongodb`サービスはアプリケーションのデータベースとして機能するため、 + flask + サービスは + mongodb`に依存します。 + depends_on`は、 + mongodb`サービスが実行されている場合にのみ `+ flask`サービスが実行されるようにします。

+ networks`プロパティは、 + flask + サービスがアクセスするネットワークとして + frontend`と `+ backend`を指定します。

+ flask +`サービスを定義したら、MongoDB設定をファイルに追加する準備ができました。 この例では、公式の「+4.0.8+」バージョンの「+ mongo +」イメージを使用します。 `+ flask service ie`に続く + docker-compose.yml`ファイルに次のコードを追加します。

docker-compose.yml

. . .
 mongodb:
   image: mongo:4.0.8
   container_name: mongodb
   restart: unless-stopped
   command: mongod --auth
   environment:
     MONGO_INITDB_ROOT_USERNAME:
     MONGO_INITDB_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 +`ネットワークを介してのみアクセスできます。

次に、アプリケーションのWebサーバーを定義します。 次のコードを `+ 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

ここで、 + building`の + context + を定義しました。これは、 + Dockerfile`を含む + nginx`フォルダーです。 `+ image +`プロパティを使用して、コンテナのタグ付けと実行に使用する画像を指定します。 `+ ports +`プロパティは、Nginxサービスが `+:80 +`と `+:443 +`を介してパブリックにアクセスできるように設定し、 `+ volumes +`は `+ / var /でコンテナ内の + nginxdata + `ボリュームをマウントしますlog / nginx + `ディレクトリ。

Webサーバーサービス + depends_on +`のサービスを `+ flask +`として定義しました。 最後に、 `+ networks`プロパティは、Webサーバーサービスが + frontend`にアクセスできるネットワークを定義します。

次に、_bridge networks_を作成して、コンテナが相互に通信できるようにします。 ファイルの最後に次の行を追加します。

docker-compose.yml

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

接続するサービス用に、2つのネットワーク-「+ frontend 」と「 backend 」を定義しました。 Nginxなどのフロントエンドサービスは、パブリックにアクセスできる必要があるため、「 frontend 」ネットワークに接続します。 MongoDBなどのバックエンドサービスは、「 backend +」ネットワークに接続して、サービスへの不正アクセスを防ぎます。

次に、ボリュームを使用して、データベース、アプリケーション、および構成ファイルを永続化します。 アプリケーションはデータベースとファイルを使用するため、それらに加えられた変更を永続化することが不可欠です。 ボリュームはDockerによって管理され、ファイルシステムに保存されます。 次のコードを `+ docker-compose.yml +`ファイルに追加して、ボリュームを設定します。

docker-compose.yml

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

`+ volumes `セクションは、アプリケーションがデータを永続化するために使用するボリュームを宣言します。 ここでは、MongoDBデータベース、Flaskアプリケーションデータ、およびNginx Webサーバーログをそれぞれ永続化するためのボリューム「 mongodbdata 」、「 appdata 」、および「 nginxdata 」を定義しました。 これらのボリュームはすべて、「 local +」ドライバーを使用してデータをローカルに保存します。 コンテナを再起動すると、MongoDBデータベースやNginx Webサーバーログなどのデータが失われる可能性があるため、ボリュームはこのデータを永続化するために使用されます。

完全な `+ 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:
     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:
     MONGO_INITDB_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-compose.yml +`ファイルで、アプリケーションスタック全体のDocker設定を定義しました。 次に、FlaskとWebサーバーのDockerfileの作成に進みます。

ステップ2-FlaskおよびWebサーバーDockerfilesの作成

Dockerを使用すると、_Dockerfile_というファイルからアプリケーションを実行するコンテナーを構築できます。 Dockerfileは、アプリケーションに必要なソフトウェアをインストールし、要件に基づいてコンテナを構成するために使用できるカスタムイメージを作成できるツールです。 作成したカスタムイメージをhttps://hub.docker.com/[Docker Hub]または任意のプライベートレジストリにプッシュできます。

この手順では、FlaskおよびWebサーバーサービスのDockerfileを作成します。 開始するには、Flaskアプリケーションの `+ app +`ディレクトリを作成します。

mkdir app

次に、 `+ app `ディレクトリにFlaskアプリ用の ` Dockerfile +`を作成します。

nano app/Dockerfile

次のコードをファイルに追加して、Flaskコンテナをカスタマイズします。

app / Dockerfile

FROM python:3.6.8-alpine3.9

LABEL MAINTAINER=" "

ENV GROUP_ID=1000 \
   USER_ID=1000

WORKDIR /var/www/

この + Dockerfile +`では、Alpine 3.9に基づくhttps://hub.docker.com/_/python/ [+ 3.6.8-alpine3.9 +`画像]の上に画像を作成しています。 Python 3.6.8がプリインストールされています。

`+ ENV `ディレクティブは、グループとユーザーIDの環境変数を定義するために使用されます。 + http://refspecs.linux-foundation.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/usernames.html[Linux Standard Base(LSB)]は、https://www.debianを指定しています。 org / doc / debian-policy / ch-opersys.html#uid-and-gid-classes [UIDとGID 0-99]はシステムによって静的に割り当てられます。 https://www.debian.org/doc/debian-policy/ch-opersys.html#uid-and-gid-classes[UID 100-999]は、システムのユーザーとグループに動的に割り当てられることになっています。 https://www.debian.org/doc/debian-policy/ch-opersys.html#uid-and-gid-classes[UID 1000-59999]は、ユーザーアカウントに動的に割り当てられることになっています。 これを念頭に置いて、「 1000+」のUIDとGIDを安全に割り当てることができます。さらに、要件に合わせて「+ GROUP_ID 」と「 USER_ID +」を更新することで、UID / GIDを変更できます。

`+ 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 `フラグは、グループIDを、先に ` Dockerfile `で定義された ` ENV GROUP_ID = 1000 +`変数に設定します。

`+ adduser -D -u $ USER_ID -G www www -s / bin / sh `行は、 ` ENV `変数で定義された ` 1000 `のユーザーIDで ` www `ユーザーを作成します。 ` -s `フラグは、ユーザーのホームディレクトリが存在しない場合に作成し、デフォルトのログインシェルを ` / bin / sh `に設定します。 ` -G `フラグは、ユーザーの初期ログイングループを、前のコマンドで作成された ` www +`に設定するために使用されます。

+ USER`コマンドは、コンテナで実行されるプログラムが + www`ユーザーを使用することを定義します。 Gunicornは `:5000 +`でリッスンするため、 ` EXPOSE +`コマンドでこのポートを開きます。

最後に、 + CMD [" gunicorn "、" -w "、" 4 "、" --bind "、" 0.0.0.0:5000 "、" wsgi "] +`行は、Gunicornサーバーを起動するコマンドを実行します。ポート「+5000+」でリッスンしている4人のワーカー。 通常、サーバーのコアあたりのワーカー数は2〜4の間である必要があります。Gunicornのドキュメントでは、https://docs.gunicorn.org/en/stable/design.html#how-many-workers [+(2 x $ num_cores )+ 1 + `]で始まるワーカーの数。

完成した `+ Dockerfile +`は次のようになります。

app / Dockerfile

FROM python:3.6.8-alpine3.9

LABEL MAINTAINER=" "

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

次に、 `+ nginx `ディレクトリにNginx Webサーバー用の ` Dockerfile +`を作成します。

nano nginx/Dockerfile

次のコードをファイルに追加して、Nginxコンテナーのイメージを構築するDockerfileを作成します。

nginx / Dockerfile

FROM digitalocean.com/alpine:latest

LABEL MAINTAINER=" "

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;"]

このNginxの「+ Dockerfile 」は、「 alpine +」ベースイメージを使用します。これは、セキュリティ用に構築された最小限の攻撃対象領域を持つ小さなLinuxディストリビューションです。

+ RUN +`ディレクティブでは、 `+ nginx +`をインストールし、エラーを公開するためのシンボリックリンクを作成し、標準エラー( `+ / dev / stderr +)と出力( `+ / dev / stdout `へのログにアクセスします) )。 コンテナは一時的なものであるため、エラーを標準エラーと標準出力に公開することをお勧めします。これにより、ログがdockerログに送信され、そこからログをElasticスタックなどのロギングサービスに転送して永続化できます。 これが完了したら、コマンドを実行して ` default.conf `と ` / var / cache / apk / * `を削除し、結果の画像のサイズを小さくします。 これらすべてのコマンドを単一の「 RUN +」で実行すると、イメージ内のレイヤーの数が減り、結果として得られるイメージのサイズも小さくなります。

+ COPY +`ディレクティブは、コンテナ内に `+ app.conf + Webサーバー設定をコピーします。 `+ EXPOSE `ディレクティブは、アプリケーションが `:443 `を安全なポートとして `:80 `で実行されるため、コンテナがポート `:80 `および `:443 +`でリッスンするようにします。

最後に、 `+ CMD +`ディレクティブはNginxサーバーを起動するコマンドを定義します。

ファイルを保存し、テキストエディターを終了します。

`+ Dockerfile +`の準備ができたので、Nginxリバースプロキシを設定して、トラフィックをFlaskアプリケーションにルーティングする準備ができました。

手順3-Nginxリバースプロキシの構成

この手順では、 `+:5000 +`でリクエストをGunicornに転送するリバースプロキシとしてNginxを設定します。 リバースプロキシサーバーは、クライアント要求を適切なバックエンドサーバーに送信するために使用されます。 クライアントとサーバー間のネットワークトラフィックのスムーズなフローを確保するための抽象化と制御の追加レイヤーを提供します。

`+ nginx / conf.d +`ディレクトリを作成して始めましょう:

mkdir nginx/conf.d

Nginxを設定するには、 `+ nginx / conf.d / `フォルダーに次の設定で ` app.conf `ファイルを作成する必要があります。 ` 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;
   }
}

これにより、最初にhttp://nginx.org/en/docs/http/ngx_http_upstream_module.html[upstream server]が定義されます。これは、ルーティングまたは負荷分散のためにWebサーバーまたはアプリサーバーを指定するために一般的に使用されます。

上流サーバーの `+ app_server `は、コンテナ名 ` flask:5000 `で識別される ` server +`ディレクティブでサーバーアドレスを定義します。

Nginx Webサーバーの設定は、 `+ server `ブロックで定義されます。 ` listen `ディレクティブは、サーバーが着信リクエストをリッスンするポート番号を定義します。 ` error_log `および ` access_log `ディレクティブは、ログを書き込むためのファイルを定義します。 ` proxy_pass `ディレクティブは、リクエストを ` http:// +`に転送するためのアップストリームサーバーを設定するために使用されます。

ファイルを保存して閉じます。

Nginx Webサーバーを構成したら、Flask To-Do APIの作成に進むことができます。

ステップ4-Flask To-do APIの作成

環境を構築したら、アプリケーションを構築する準備が整いました。 このステップでは、POST要求から送信されたTo Doノートを保存および表示するTo Do APIアプリケーションを作成します。

`+ app `ディレクトリに ` requirements.txt +`ファイルを作成して始めましょう:

nano app/requirements.txt

このファイルは、アプリケーションの依存関係をインストールするために使用されます。 このチュートリアルの実装では、http://flask.pocoo.org/ [+ Flask +]、https://flask-pymongo.readthedocs.io/en/latest/ [+ Flask-PyMongo +]、およびhttp://flask.pocoo.org/docs/1.0/reqcontext/ [+ requests +]。 `+ requirements.txt +`ファイルに次を追加します。

app / requirements.txt

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

要件を入力したら、ファイルを保存してエディターを終了します。

次に、 + app`ディレクトリにFlaskアプリケーションコードを含む + app.py`ファイルを作成します。

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 +`変数にロードします。 次に、コードは、 `+ os.environ +`を使用して、環境変数からMongoDB接続文字列を構築します。 `+ applicationまたは`オブジェクトを `+ PyMongo()+`メソッドに渡すと、 `+ mongos`オブジェクトが得られ、 + mongo.db + から + db + `オブジェクトが得られます。

次に、インデックスメッセージを作成するコードを追加します。

app / app.py

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

[email protected]( '/')+`は、APIの `+ / + GETルートを定義します。 ここで、 `+ index()`関数は ` jsonify +`メソッドを使用してJSON文字列を返します。

次に、「+ / 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
   )

[email protected]( '/ todo')+`はAPIの `+ / todo + GETルートを定義し、データベース内のto-doを返します。 `+ db.todo.find()`メソッドは、データベース内のすべてのToDoを返します。 次に、 ` todo `を反復処理して、 ` data `配列に追加するオブジェクトの ` id `と ` todo `のみを含む ` item`を作成し、最終的に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

[email protected]( '/ todo')+`はAPIの `+ / todo + POSTルートを定義し、データベースにTo Doノートを作成します。 `+ request.get_json(force = True)`はルートに投稿するJSONを取得し、 ` item `はto-doに保存されるJSONの構築に使用されます。 ` db.todo.insert_one(item)`は、1つのアイテムをデータベースに挿入するために使用されます。 タスクをデータベースに保存した後、 ` 201 CREATED +`のステータスコードでJSONレスポンスを返します。

次に、アプリケーションを実行するコードを追加します。

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)+ `。

次に、キーを最初のパラメーターとして使用し、デフォルト値を2番目のパラメーターとして使用して、 + os.environ.get()+`を使用して、環境変数から `+ ENVIRONMENT_DEBUG +`および `+ ENVIRONMENT_PORT +`の値を取得します。 `+ 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)

ファイルを保存し、エディターを終了します。

次に、 `+ app `ディレクトリに ` wsgi.py +`ファイルを作成します。

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サーバーのアプリケーションオブジェクトを作成します。

To Doアプリが準備できたので、コンテナでアプリケーションを実行する準備が整いました。

ステップ5-コンテナの構築と実行

`+ docker-compose.yml +`ファイルですべてのサービスとその設定を定義したので、コンテナーを開始できます。

サービスは単一のファイルで定義されているため、コンテナーを起動し、ボリュームを作成し、ネットワークをセットアップするために単一のコマンドを発行する必要があります。 このコマンドは、FlaskアプリケーションとNginx Webサーバーのイメージもビルドします。 次のコマンドを実行して、コンテナを構築します。

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ユーザーを作成します。

ステップ6-MongoDBデータベース用のユーザーの作成

デフォルトでは、MongoDBはユーザーが資格情報なしでログインできるようにし、無制限の特権を付与します。 このステップでは、MongoDBデータベースにアクセスする専用ユーザーを作成して、MongoDBデータベースを保護します。

これを行うには、 `+ docker-compose.yml `ファイル環境変数 ` MONGO_INITDB_ROOT_USERNAME `および ` MONGO_INITDB_ROOT_PASSWORD `で ` mongodb +`サービスに設定したルートユーザー名とパスワードが必要です。 一般に、データベースを操作するときは、ルート管理アカウントを使用しない方が良いです。 代わりに、Flaskアプリケーション専用のデータベースユーザーと、Flaskアプリがアクセスできる新しいデータベースを作成します。

新しいユーザーを作成するには、まず `+ mongodb +`コンテナでインタラクティブシェルを起動します。

docker exec -it  bash

`+ -it `フラグとともに実行中のコンテナ内でコマンドを実行し、コンテナ内でインタラクティブシェルを実行するには、 ` docker exec +`コマンドを使用します。

コンテナー内に移動したら、MongoDB * root *管理アカウントにログインします。

mongo -u  -p

`+ docker-compose.yml `ファイルの ` MONGO_INITDB_ROOT_PASSWORD `変数の値として入力したパスワードの入力を求められます。 パスワードは、「 mongodb 」サービスの「 MONGO_INITDB_ROOT_PASSWORD 」に新しい値を設定することで変更できます。この場合、「 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 +」データベースがリストされるため、ユーザーはこのデータベースにアクセスできるため、他のすべてのデータベースを読み書きできます。

最初のTo Doノートを保存すると、https://docs.mongodb.com/manual/core/databases-and-collections/#create-a-database [MongoDBデータベースを作成]が自動的に保存されます。 MongoDBでは、 `+ use `コマンドを使用して、存在しないデータベースに切り替えることができます。 ドキュメントがコレクションに保存されるときにデータベースを作成します。 したがって、データベースはここでは作成されません。これは、APIから最初のTo Doノートをデータベースに保存するときに発生します。 ` use `コマンドを実行して `+`データベースに切り替えます:

use flaskdb

次に、このデータベースへのアクセスを許可する新しいユーザーを作成します。

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

このコマンドは、 + flaskdb +`データベースへの `+ readWrite +`アクセス権を持つユーザーを作成します。 `+ pwd +`フィールドには必ず安全なパスワードを使用してください。 ここの `+ user`と + pwd`は、 `+ flask `サービスの環境変数セクションの下にある ` docker-compose.yml`ファイルで定義した値です。

次のコマンドを使用して、認証済みデータベースにログインします。

mongo -u  -p  --authenticationDatabase flaskdb

ユーザーを追加したら、データベースからログアウトします。

exit

最後に、コンテナを終了します。

exit

これで、Flaskアプリケーション専用のデータベースとユーザーアカウントが構成されました。 データベースコンポーネントの準備ができたので、FlaskのTo Doアプリの実行に進むことができます。

ステップ7-Flask To-doアプリの実行

サービスが設定され実行されたので、ブラウザで「+ http:// 」に移動してアプリケーションをテストできます。 さらに、 ` curl +`を実行して、FlaskからのJSON応答を確認できます。

curl -i http://

次の応答が返されます。

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

Flaskアプリケーションの設定は、 `+ docker-compose.yml `ファイルからアプリケーションに渡されます。 データベース接続に関する設定は、 ` flask `サービスの ` environment `セクションで定義された ` MONGODB _ * +`変数を使用して設定されます。

すべてをテストするには、Flask APIを使用してTo Doノートを作成します。 + / todo +`ルートへの `+ POST curlリクエストでこれを行うことができます:

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

このリクエストの結果、To DoアイテムがMongoDBに保存されると、 `+ 201 CREATED +`のステータスコードが返されます。

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

`+ / todo +`ルートへのGETリクエストを使用して、MongoDBのすべてのTo Doノートをリストできます。

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

これで、サーバーにデプロイされたリバースプロキシとしてNginxでMongoDBバックエンドを実行するFlask APIをDocker化できました。 実稼働環境では、 `+ sudo systemctl enable docker +`を使用して、Dockerサービスが実行時に自動的に開始されるようにすることができます。

結論

このチュートリアルでは、Docker、MongoDB、Nginx、およびGunicornを使用してFlaskアプリケーションをデプロイしました。 これで、機能拡張可能な最新のステートレスAPIアプリケーションが完成しました。 `+ docker container run `のようなコマンドを使用してこの結果を達成できますが、 ` docker-compose.yml +`は、このスタックをバージョン管理に入れ、必要に応じて更新できるため、ジョブを簡素化します。

ここから、さらにhttps://www.digitalocean.com/community/tags/python-frameworks?type=tutorials[Python Framework tutorials]を見ることができます。

Related