著者は、Write for DOnationsプログラムの一部として寄付を受け取るためにInternet Archiveを選択しました。
前書き
Webアプリケーションの開発は、さまざまなテクノロジーを構築および保守する際に複雑で時間がかかるようになります。 アプリケーションの複雑さと生産時間を削減するために設計された軽量オプションを検討すると、より柔軟でスケーラブルなソリューションが得られます。 Python上に構築されたマイクロWebフレームワークとして、Flaskは、開発者がプロジェクトに統合できる拡張機能を通じてアプリケーションを拡張するための拡張可能な方法を提供します。 開発者の技術スタックのスケーラビリティを継続するために、MongoDBは、頻繁な変更に対応できるように設計されたNoSQLデータベースです。 開発者はDockerを使用して、アプリケーションのパッケージ化と展開のプロセスを簡素化できます。
Docker Composeは、アプリケーションサービス、ネットワークボリューム、バインドマウントなどのインフラストラクチャを単一のファイルで定義できるようにすることで、開発環境をさらに簡素化しました。 Docker Composeを使用すると、複数のdocker container run
コマンドを実行するよりも使いやすくなります。 単一のComposeファイルですべてのサービスを定義し、単一のコマンドで構成からすべてのサービスを作成および開始できます。 これにより、コンテナインフラストラクチャ全体でバージョン管理が行われます。 Docker Composeはプロジェクト名を使用して環境を相互に分離します。これにより、単一のホストで複数の環境を実行できます。
このチュートリアルでは、Dockercontainers内でFlask、Nginx、MongoDBを使用してTo Do Webアプリケーションをビルド、パッケージ化、実行します。 スタック構成全体を、Python、MongoDB、およびNginxの構成ファイルとともにdocker-compose.yml
ファイルで定義します。 FlaskはHTTPリクエストを処理するためにWebサーバーを必要とするため、アプリケーションを処理するためにPython WSGI HTTPサーバーであるGunicornも使用します。 Nginxは、処理のためにリクエストをGunicornに転送するリバースプロキシサーバーとして機能します。
前提条件
このチュートリアルを実行するには、次のものが必要です。
-
Initial Server Setupチュートリアルの手順に従って構成された、
sudo
特権を持つroot以外のユーザー。 -
How To Install and Use Dockerのステップ1とステップ2の手順でインストールされたDocker。
-
How To Install Docker Composeのステップ1の手順でインストールされたDockerCompose。
[[step-1 -—- writing-the-stack-configuration-in-docker-compose]] ==ステップ1— DockerComposeでスタック構成を書き込む
Dockerでアプリケーションを構築すると、Docker Composeで行った構成変更に応じてインフラストラクチャを簡単にバージョン管理できます。 インフラストラクチャは、単一のファイルで定義し、単一のコマンドで構築できます。 このステップでは、Flaskアプリケーションを実行するためにdocker-compose.yml
ファイルを設定します。
docker-compose.yml
ファイルを使用すると、アプリケーションインフラストラクチャを個別のサービスとして定義できます。 サービスは相互に接続でき、永続ストレージ用に各サービスにvolumeを接続できます。 ボリュームは、Dockerによって管理されるホストファイルシステムの一部に格納されます(Linuxでは/var/lib/docker/volumes/
)。
ボリュームは、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 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: flaskuser
MONGODB_PASSWORD: your_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エンジンが再起動されるか、エラーが発生すると、コンテナーが自動的に起動することです。
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
に続く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: 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
ネットワーク経由でのみアクセスできます。
次に、アプリケーションの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
ここでは、build
のcontext
を定義しました。これは、Dockerfile
を含むnginx
フォルダーです。 image
プロパティを使用して、コンテナのタグ付けと実行に使用するイメージを指定します。 ports
プロパティは、:80
および:443
を介してパブリックにアクセスできるようにNginxサービスを構成し、volumes
はコンテナー内のnginxdata
ボリュームを/var/log/nginx
にマウントします。 sディレクトリ。
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: 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
ファイルで定義しました。 次に、FlaskとWebサーバーのDockerfileの作成に進みます。
[[step-2 -—- writing-the-flask-and-web-server-dockerfiles]] ==ステップ2—フラスコとWebサーバーのDockerfilesの書き込み
Dockerを使用すると、Dockerfileというファイルからアプリケーションを実行するためのコンテナーを構築できます。 Dockerfileは、アプリケーションに必要なソフトウェアをインストールし、要件に基づいてコンテナを構成するために使用できるカスタムイメージを作成できるツールです。 作成したカスタムイメージを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="FirstName LastName "
ENV GROUP_ID=1000 \
USER_ID=1000
WORKDIR /var/www/
このDockerfile
では、Python 3.6.8がプリインストールされたAlpine 3.9に基づく3.6.8-alpine3.9
imageの上にイメージを作成しています。
ENV
ディレクティブは、グループとユーザーIDの環境変数を定義するために使用されます。
Linux Standard Base (LSB)は、UIDs and GIDs 0-99がシステムによって静的に割り当てられることを指定します。 UIDs 100-999は、システムユーザーとグループに動的に割り当てられることになっています。 UIDs 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
変数で定義されているように、ユーザーIDが1000
のwww
ユーザーを作成します。 -s
フラグは、ユーザーのホームディレクトリが存在しない場合はそれを作成し、デフォルトのログインシェルを/bin/sh
に設定します。 -G
フラグは、ユーザーの初期ログイングループを前のコマンドで作成されたwww
に設定するために使用されます。
USER
コマンドは、コンテナーで実行されるプログラムがwww
ユーザーを使用することを定義します。 Gunicornは:5000
をリッスンするため、EXPOSE
コマンドを使用してこのポートを開きます。
最後に、CMD [ "gunicorn", "-w", "4", "--bind", "0.0.0.0:5000", "wsgi"]
行はコマンドを実行して、ポート5000
でリッスンしている4人のワーカーでGunicornサーバーを起動します。 通常、サーバーのコアあたりのワーカー数は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
次に、nginx
ディレクトリにNginx WebサーバーのDockerfile
を作成します。
nano nginx/Dockerfile
次のコードをファイルに追加して、Nginxコンテナーのイメージを構築するDockerfileを作成します。
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
)にアクセスするためのシンボリックリンクを作成します。 コンテナは一時的なものであるため、エラーを標準エラーと標準出力に公開することをお勧めします。これにより、ログがdockerログに送信され、そこからログをElasticスタックなどのロギングサービスに転送して永続化できます。 これが完了したら、コマンドを実行してdefault.conf
と/var/cache/apk/*
を削除し、結果の画像のサイズを縮小します。 これらすべてのコマンドを単一のRUN
で実行すると、画像内のレイヤーの数が減り、結果の画像のサイズも小さくなります。
COPY
ディレクティブは、コンテナー内のapp.conf
Webサーバー構成をコピーします。 EXPOSE
ディレクティブは、コンテナーがポート:80
および:443
でリッスンすることを保証します。これは、アプリケーションが:443
をセキュアポートとして:80
で実行されるためです。
最後に、CMD
ディレクティブは、Nginxサーバーを起動するコマンドを定義します。
ファイルを保存し、テキストエディターを終了します。
Dockerfile
の準備ができたので、トラフィックをFlaskアプリケーションにルーティングするようにNginxリバースプロキシを構成する準備が整いました。
[[step-3 -—- configuring-the-nginx-reverse-proxy]] ==ステップ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;
}
}
これにより、最初にupstream serverが定義されます。これは、ルーティングまたは負荷分散のためにWebサーバーまたはアプリサーバーを指定するために一般的に使用されます。
アップストリームサーバーapp_server
は、コンテナー名flask:5000
で識別されるserver
ディレクティブを使用してサーバーアドレスを定義します。
Nginx Webサーバーの構成は、server
ブロックで定義されます。 listen
ディレクティブは、サーバーが着信要求をリッスンするポート番号を定義します。 error_log
およびaccess_log
ディレクティブは、ログを書き込むためのファイルを定義します。 proxy_pass
ディレクティブは、要求をhttp://app_server
に転送するためのアップストリームサーバーを設定するために使用されます。
ファイルを保存して閉じます。
Nginx Webサーバーを構成したら、Flask To-Do APIの作成に進むことができます。
[[step-4 -—- creating-the-flask-to-do-api]] ==ステップ4— Flask To-doAPIの作成
環境を構築したら、アプリケーションを構築する準備が整いました。 このステップでは、POST要求から送信されたTo Doノートを保存および表示するTo Do APIアプリケーションを作成します。
app
ディレクトリにrequirements.txt
ファイルを作成することから始めます。
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
ディレクトリに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
から、MongoDBと対話するためにPyMongo
オブジェクトをインポートしました。
次に、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()
メソッドに渡すと、mongo
オブジェクトが得られ、これにより、mongo.db
からdb
オブジェクトが得られます。
次に、インデックスメッセージを作成するコードを追加します。
app/app.py
. . .
@application.route('/')
def index():
return jsonify(
status=True,
message='Welcome to the Dockerized Flask MongoDB app!'
)
@application.route('/')
は、APIの/
GETルートを定義します。 ここで、index()
関数はjsonify
メソッドを使用してJSON文字列を返します。
次に、/todo
ルートを追加して、すべての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')
は、APIの/todo
GETルートを定義します。これにより、データベース内のToDoが返されます。 db.todo.find()
メソッドは、データベース内のすべてのToDoを返します。 次に、_todos
を反復処理して、id
とtodo
のみを含むitem
を構築し、それらを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')
は、APIの/todo
POSTルートを定義します。これにより、データベースにToDoノートが作成されます。 request.get_json(force=True)
は、ルートに投稿するJSONを取得し、item
は、ToDoに保存されるJSONを構築するために使用されます。 db.todo.insert_one(item)
は、データベースに1つのアイテムを挿入するために使用されます。 To Doがデータベースに保存された後、ステータスコード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__
がプログラムへのエントリポイントであるかどうかを確認し、アプリケーションを実行するために使用されます。 __name__
が"__main__"
と等しい場合、if
ブロック内のコードは、このコマンドapplication.run(host='0.0.0.0', port=ENVIRONMENT_PORT, debug=ENVIRONMENT_DEBUG)
を使用してアプリを実行します。
次に、os.environ.get()
を使用して、環境変数からENVIRONMENT_DEBUG
とENVIRONMENT_PORT
の値を取得します。最初のパラメーターとしてキーを使用し、2番目のパラメーターとしてデフォルト値を使用します。 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 ---コンテナーの構築と実行]] ==ステップ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ユーザーを作成します。
[[step-6 -—- creating-a-user-for-your-mongodb-database]] ==ステップ6—MongoDBデータベースのユーザーを作成する
デフォルトでは、MongoDBはユーザーが資格情報なしでログインできるようにし、無制限の特権を付与します。 このステップでは、MongoDBデータベースにアクセスする専用ユーザーを作成して、MongoDBデータベースを保護します。
これを行うには、mongodb
サービスのdocker-compose.yml
ファイル環境変数MONGO_INITDB_ROOT_USERNAME
およびMONGO_INITDB_ROOT_PASSWORD
で設定したrootユーザー名とパスワードが必要になります。 一般に、データベースを操作するときは、ルート管理アカウントを使用しない方が良いです。 代わりに、Flaskアプリケーション専用のデータベースユーザーと、Flaskアプリがアクセスできる新しいデータベースを作成します。
新しいユーザーを作成するには、最初にmongodb
コンテナーで対話型シェルを開始します。
docker exec -it mongodb bash
実行中のコンテナー内でコマンドを実行するには、docker exec
コマンドを使用し、-it
フラグを使用して、コンテナー内で対話型シェルを実行します。
コンテナ内に入ると、MongoDBrootの管理者アカウントにログインします。
mongo -u mongodbuser -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
データベースがリストされているため、ユーザーはこのデータベースにアクセスでき、他のすべてのデータベースに対して読み取りと書き込みを行うことができます。
最初のやることメモを保存すると、自動的にcreate the MongoDB databaseになります。 MongoDBでは、use database
コマンドを使用して、存在しないデータベースに切り替えることができます。 ドキュメントがコレクションに保存されるときにデータベースを作成します。 したがって、データベースはここでは作成されません。 APIからデータベースに最初のTo Doノートを保存すると発生します。 use
コマンドを実行して、flaskdb
データベースに切り替えます。
use flaskdb
次に、このデータベースへのアクセスを許可する新しいユーザーを作成します。
db.createUser({user: 'flaskuser', pwd: 'your password', roles: [{role: 'readWrite', db: 'flaskdb'}]})
exit
このコマンドは、flaskdb
データベースへのreadWrite
アクセス権を持つflaskuserという名前のユーザーを作成します。 必ずpwd
フィールドに安全なパスワードを使用してください。 ここでのuser
とpwd
は、flask
サービスの環境変数セクションの下のdocker-compose.yml
ファイルで定義した値です。
次のコマンドを使用して、認証済みデータベースにログインします。
mongo -u flaskuser -p your password --authenticationDatabase flaskdb
ユーザーを追加したら、データベースからログアウトします。
exit
最後に、コンテナを終了します。
exit
これで、Flaskアプリケーション専用のデータベースとユーザーアカウントが構成されました。 データベースコンポーネントの準備ができたので、FlaskのTo Doアプリの実行に進むことができます。
[[step-7 -—- running-the-flask-to-do-app]] ==ステップ7— FlaskTo-doアプリの実行
サービスが構成されて実行されたので、ブラウザーでhttp://your_server_ip
に移動してアプリケーションをテストできます。 さらに、curl
を実行して、FlaskからのJSON応答を確認できます。
curl -i http://your_server_ip
次の応答が返されます。
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://your_server_ip/todo
このリクエストにより、To DoアイテムがMongoDBに保存されると、ステータスコード201 CREATED
の応答が返されます。
Output{"message":"To-do saved successfully!","status":true}
/todo
ルートへのGETリクエストを使用して、MongoDBからのすべてのToDoノートを一覧表示できます。
curl -i http://your_server_ip/todo
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
はジョブを簡素化します。
ここから、さらにPython Framework tutorialsを確認することもできます。