Docker学習 - docker-composeでnginx+Flaskのwebアプリを構築する方法
以前に以下の記事でdockerで簡単なFlaskで作成したWebアプリを作成しました。
今回は、dockerコンテナを単体で動作するのではなく、複数のコンテナを利用するようなシステムを作成していきたいと思います。
では、docker-composeを利用してFlaskのWebアプリとnginxを組み合わせたシステムを構築してみましょう。
docker-composeで構築するシステムの構成
システムの構成図
docker-composeで全部で3つのdockerコンテナを配置し、ユーザからのアクセスはnginxで受付てURLにより対応する2台のWebサーバに振り分ける構成となっています。
コンテナ | 機能 |
---|---|
nginx | ・ユーザからのアクセスを80ポートで待ち受ける ・http://localhost/web1/の場合はweb1サーバへ振り分ける ・http://localhost/web2/の場合はweb2サーバへ振り分ける |
web1(Flask) | ・web1サーバのindex.htmlファイルの内容を出力 |
web2(Flask) | ・web2サーバのindex.htmlファイルの内容を出力 |
処理フロー例
システム構成図の通りですが、処理フローを順に追っていくとこうなります。
「http://localhost/web1」にアクセスした場合
- ユーザが「http://localhost/web1/」にアクセスする
- nginxは「http://localhost/web1/」にアクセスされた場合にweb1サーバの5001ポートへアクセスする
- web1サーバはHTMLデータをnginxへ返却する
- ユーザのブラウザにnginxから返却されたHTMLが表示される
「http://localhost/web2」にアクセスした場合
- ユーザが「http://localhost/web2/」にアクセスする
- nginxは「http://localhost/web2/」にアクセスされた場合にweb2サーバの5002ポートへアクセスする
- web2サーバはHTMLデータをnginxへ返却する
- ユーザのブラウザにnginxから返却されたHTMLが表示される
フォルダ/ファイル構成
Visual Studio Codeのスクリーンショットですが、以下のような構成になっています。
「docker_compose_demo」フォルダをルートとして「nginx」「web1」「web2」は各コンテナのフォルダです。
docker-composeの設計情報を記載するファイルである「docker-compose.yml」は「docker_compose_demo」フォルダの直下に配置しておきましょう。
それでは、ファイルのサンプルを順に説明します。
web1コンテナのファイル
app.py
web1コンテナのメインファイルです。
from flask import Flask, render_template, request
app = Flask(__name__)
@app.route('/')
def index():
return render_template('index.html')
@app.route('/<name>')
def hello(name):
return render_template('hello.html', title='webサーバ1', name=name)
if __name__ == "__main__":
app.run(debug=True, host='0.0.0.0', port=5000)
前回作成したFlaskアプリを流用しています。
ポイントだけ説明すると、
- 「ルート(/)」にアクセスすると「index.html」の内容を返却する
- 「/xxx」にアクセスすると「hello.html」の内容を返却する
- 5000ポートで待ち受ける
です。
index.html
<html>
<title>docker demo flask</title>
<head></head>
<body>
<h1>Webサーバ1</h1>
<div>トップページ</div>
</body>
</html>
web1であることがわかるようなHTMLファイルであればどのような内容でも大丈夫です。
サンプルでは<h1>タグで「Webサーバ1」としました。
hello.html
<html>
<head>
<title>{{ title }}</title>
</head>
<body>
<h1>Web1サーバ</h1>
<div>Hello!!</div>
<div>{{ name }}さん</div>
</body>
</html>
時間がなければ、index.htmlだけでも大丈夫です。
requirements.txt
dockerコンテナを作成する際にインストールするpythonのパッケージを記載します。
「pip install -r requirements.txt」で指定するファイルです。
今回はFlaskを指定しておきましょう。
Flask==1.1.1
Dockerfile
web1のコンテナを作成するためのDockerfileです。
公開するポートは5000としておきます。
# python v3.6 をベースにDockerイメージを作成
FROM python:3.6
# 作業ディレクトリを指定
WORKDIR /app
# カレントディレクトリのファイルをDockerコンテナの「/app」 ディレクトリにコピー
ADD . /app
# インストール
RUN pip install -r requirements.txt
# 外部に公開するポートを指定
EXPOSE 5000
# コンテナの実行コマンドを指定
CMD ["python", "app.py"]
web2コンテナのファイル
web1と全く別のWebアプリを作成してもよかったのですが、今回はdocker-composeを使ってnginxで振り分けることを木邸としているので、web2コンテナ用のファイルはweb1とほとんど同じにしました。
ただ、URLでWebサーバが振り分けされていることがわかるように以下の3つのファイルの「Webサーバ1」の部分を「Webサーバ2」に変更はしておいてください。
- app.py
- index.html
- hello.html
nginxコンテナのファイル
default.conf
nginxのコンテナはURLによるWebサーバの振り分けを行うために、「default.conf」を準備しましょう。
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
location /web1 {
proxy_pass http://web1:5001/;
}
location /web2 {
proxy_pass http://web2:5002/;
}
}
設定内容は大きく4つです。
- 80ポートで待ち受ける
- 「http://localhost/」の場合は「/usr/share/nginx/html/index.html」を表示する
- 「http://localhost/web1」の場合は「http://web1:5001/」へ転送する
- 「http://localhost/web2」の場合は「http://web2:5002/」へ転送する
web1コンテナとweb2コンテナのURLのホスト名部分は「localhost」や「127.0.0.1」ではなく、「web1」と「web2」にしておいてください。
理由については、次の「docker-compose.yml」ファイルで説明します。
docker-compose.yml
docker-compose.ymlファイルはdocker-composeコマンドで指定する設定ファイルです。
docker-composeはファイル名を指定しない場合「docker-compose.yml」をデフォルトで読み込みます。
version: "3"
services:
nginx:
image: nginx:latest
container_name: nginx
ports:
- "80:80"
volumes:
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf
depends_on:
- web1
- web2
networks:
- nginx_network
web1:
build: ./web1
container_name: web1
ports:
- 5001:5000
networks:
- nginx_network
web2:
build: ./web2
container_name: web2
ports:
- 5002:5000
networks:
- nginx_network
networks:
nginx_network:
driver: bridge
各コンテナ間の通信はサービス名で行われる
そのため、nginxからweb1コンテナへのアクセスは「http://web1:5001/」となる
■image:docker imageとしてnginxの最新を指定
■ports:nginxのデフォルトポートの80をそのまま指定
■volumes:作成したdefault.confをコンテナへコピーします
■depends_on:コンテナ間で通信を可能にするためにサービス名を指定しますので、
今回は、web1とweb2のコンテナを指定しましょう
■networks:指定しない場合はデフォルトのbridgeネットワークが作成されますが明示的に指定しておきます。
■build:Flaskで作成したWebアプリからコンテナイメージを作成するためBuildを指定します。
■ports:5001ポートとして公開います。※5000のままだとweb2と重複するため
■networks:nginxと同じ設定にします
webとほぼ同じ設定ですが、portsのみ5002とします。
docker-composeで実行/確認/停止する
docker-composeで実行する
早速、docker-composeでdockerコンテナ3つを稼働させましょう。
コマンドは以下の通りです。
docker-compose up -d
実行すると初回はnginxのイメージのダウンロードやweb1コンテナのビルドなどが実行されますが、2解明校は以下のように数秒で実行されます。
$ docker-compose up -d
Creating network "dockercomposedemo_nginx_network" with driver "bridge"
Creating web2 ...
Creating web1 ...
Creating web2
Creating web2 ... done
Creating nginx ...
Creating nginx ... done
docker-compose でステータスを確認する
実行できたかを確認するために以下のコマンドを実行しましょう
docker-compose ps
以下のように表示されれば、無事起動しています。
$ docker-compose ps
Name Command State Ports
-----------------------------------------------------------------------
nginx nginx -g daemon off; Up 0.0.0.0:80->80/tcp
web1 python app.py Up 0.0.0.0:5001->5000/tcp, 5001/tcp
web2 python app.py Up 0.0.0.0:5002->5000/tcp, 5002/tcp
ブラウザで確認してみましょう
3つのURLにアクセスして、
- nginxのデフォルトトップページ
- web1のページ
- web2のページ
が表示されれば完成です。
http://localhost/
http://localhost/web1/
http://localhost/web2/
docker-composeで停止する
docker-composeでコンテナを停止する場合は以下のコマンドを実行します。
docker-compose down
正常に停止できれば以下のような表示になります
$ docker-compose down
Stopping nginx ... done
Stopping web1 ... done
Stopping web2 ... done
Removing nginx ... done
Removing web1 ... done
Removing web2 ... done
Removing network dockercomposedemo_nginx_network
まとめ
複数のコンテナを組み合わせてシステムを作成する場合、dockerのrunコマンドでも実現は可能です。
ですが、docker-composeを利用することで、複数コンテナをまとめて実行や停止できるため、docker開発には欠かせないツールですので、実際に手を動かして覚えておきたい技術ですね。
少し長くなりましたがdocker-composeの開発に役立つことができれば幸いです。