はじめに
docker-composeでDockerコンテナの内部IPアドレスを固定化し、nginx + uwsgi + flask を使ってWebサイトの環境を構築します。
サイトの中身自体は hello world するだけの超簡単な内容にしてあるので、正直nginxを挟む必要は無いですが、コンテナが内部IPアドレスで通信できることを確かめるためにnginxを使っています。
環境
- Ubuntu 16.04
- docker 18.09.7
- docker-compose 1.23.2
Dockerとdocker-composeのインストール方法は下記をご参考ください。
ちなみにDocker for Mac (macOS Catalina)でも変わらず作れます!
全体構成
nginxとuwsgiのコンテナを2つ作ります。 また、app_netをいう名前で内部ネットワークを作成します。
app_netのサブネットは172.30.0.0/24
の範囲とし、nginxコンテナに172.30.0.2
のIPアドレスを、uwsgiコンテナに172.30.0.3
のIPアドレスを割り当てます。
172.30.0.1
となっているbridgeは自動的に作成されます。
nginxコンテナ
nginxコンテナを構築するために、nginxの設定ファイルとDockerfileを作成します。
まずは好きなディレクトリで下記を実行します。
mkdir nginxuwsgi cd nginxuwsgi/
nginx.conf
nginx
ディレクトリを作成し、その中にnginx.conf
を作成します。
(nginxは素人なので余計なパラメタ設定もあるかもしれません。。。)
user nginx; worker_processes 1; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; events { worker_connections 1024; } http { include /etc/nginx/mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; sendfile on; keepalive_timeout 65; server { listen 80; charset utf-8; location / { include uwsgi_params; uwsgi_pass 172.30.0.3:8765; } } }
重要なのは、最後のservser
の部分です。
listen 80; charset utf-8; location / { include uwsgi_params; uwsgi_pass 172.30.0.3:8765; }
nginxコンテナの80ポートに来たアクセスを、172.30.0.3:8765
(uwsgiコンテナ)に受け渡す設定となっています。
Dockerfile
続いては、同じnginx
ディレクトリの中にDockerfileを作成しますが、中身はとてもシンプルです。
FROM nginx CMD ["nginx", "-g", "daemon off;", "-c", "/etc/nginx/nginx.conf"]
nginxがあらかじめインストールされたベースイメージを使っています。
またCMDで、先ほど作成したnginx.confを指定してnginxサーバを起動しています。
/etc/nginx/
を指定していますが、後ほどdocker-compose.ymlを作る時に、ホストのnginx.confをコンテナにボリュームマウントします。
ここまでで、下記のようになっているはずです。
nginxuswgi └── nginx ├── Dockerfile └── nginx.conf
uwsgiコンテナ
uwsgiコンテナを構築するために、flaskのソースコード(app.py)、uwsgiの設定ファイル(uwsgi.ini)、Dockerfileを作成します。
flask(app.py)
uwsgi
ディレクトリを作成し、hello worldを表示するためのソースコードをapp.pyとして作成します。
# -*- coding: utf-8 -*- from flask import Flask app = Flask(__name__) @app.route("/") def index(): return "Hello, World!" if __name__ == "__main__": app.run()
uwsgi.ini
続いて同じuwsgi
ディレクトリの中にuwsgiの設定ファイルを作成します。
[uwsgi] wsgi-file = /var/www/app.py callable = app master = true processes = 1 socket = :8765 chmod-socket = 666 vacuum = true die-on-term = true py-autoreload = 1
wsgi-file = /var/www/app.py
でwebサーバとして起動する元となるソースコードを指定しています。/var/www
としていますが、nginxの時と同様、docker-compose.ymlにてホストのapp.pyをボリュームマウントします。
socket = :8765
でリクエストを受け付けるポート番号を指定しています。先ほどnginx.confで8765ポートを指定したので、同じポート番号にする必要があります。
Dockerfile
最後にDockerfileです。(uwsgi
ディレクトリの中で作成します。)
FROM python:3.6 RUN pip install uwsgi flask RUN mkdir /var/www/ WORKDIR /var/www/ CMD ["uwsgi", "--ini", "/var/www/uwsgi.ini"]
ベースはpython3.6があらかじめインストールされているイメージにしています。
またCMDで、先ほど作成したuwsgi.iniを指定してuwsgiサーバを起動しています。
ここまでで、下記のようになっているはずです。
nginxuswgi ├── nginx │ ├── Dockerfile │ └── nginx.conf └── uwsgi ├── Dockerfile ├── app.py └── uwsgi.ini
docker-compose
最後にdocker-compose.ymlを作成し、コンテナを起動します。
serviceでコンテナの設定を記述し、networksで内部ネットワークの設定を記述しています。
docker-compose.yml
version: "3.5" services: nginx: build: ./nginx volumes: - ./nginx/nginx.conf:/etc/nginx/nginx.conf ports: - "10080:80" networks: app_net: ipv4_address: 172.30.0.2 uwsgi: build: context: ./uwsgi volumes: - ./uwsgi:/var/www/ networks: app_net: ipv4_address: 172.30.0.3 networks: app_net: name: app_net driver: bridge ipam: driver: default config: - subnet: 172.30.0.0/24
networksでは、内部ネットワークのドライバとしてbridgeを指定し、サブネットとして172.30.0.0/24
を指定しています。これで、172.30.0.2 ~ 172.30.0.254
をコンテナの内部ネットワークとして利用できます。
serviceではnginxとuwsgiのコンテナの設定を記述しています。build:
でそれぞれDockerfileの場所を指定することで、コンテナビルドごとdocker-composeで実施してしまっています。(事前にコンテナビルドしてイメージを作成しdocker-compose.ymlで指定する形式ではない。)
また、volumes:
でそれぞれの設定ファイルをボリュームマウントさせてコンテナに渡しています。
networks.app_net.ipv4_address
の部分ではコンテナそれぞれのIPアドレスを指定しています。
コンテナの起動とアクセス確認
最終的な構成は以下のようになっているはずです。
nginxuswgi ├── docker-compose.yml ├── nginx │ ├── Dockerfile │ └── nginx.conf └── uwsgi ├── Dockerfile ├── app.py └── uwsgi.ini
では、コンテナを起動してみます。docker-compose.ymlが配置されている場所で下記コマンドを実行します。-d
はバックグラウンド起動のオプションです。
$ docker-compose up -d Creating network "app_net" with driver "bridge" Creating nginxuswgi_nginx_1 ... done Creating nginxuswgi_uwsgi_1 ... done
errorにならずdoneが表示されればOKです。
ブラウザでhttp://<ホストマシンのIPアドレス>:10080
にアクセスしてみてください。
画面にHello, World!
と表示されれば、正常にサーバが稼働し疎通ができています。
もし、エラーが発生した場合は、docker logs nginxuswgi_nginx_1
などのコマンドを実行しログから原因を探ってみてください。
ネットワーク構成を確認
コンテナが問題なく起動している状態で、ネットワークの構成を確認してみます。
$ docker network ls NETWORK ID NAME DRIVER SCOPE 2a94d4756996 app_net bridge local f5e41246ea45 bridge bridge local 4920c3cc5a3e host host local 6278bf6b8cc0 none null local
app_net
が作成されていることがわかります。docker network inspect app_net
でより詳細な情報を確認できます。サブネットや所属しているコンテナの情報まで表示されます。(出力が多いので省略)
また、ifconfigでブリッジが1つ作成されていることも確認できます。
$ ifconfig br-2a94d4756996 Link encap:イーサネット ハードウェアアドレス XX:XX:XX:XX:XX:XX inetアドレス:172.30.0.1 ブロードキャスト:172.30.0.255 マスク:255.255.255.0 inet6アドレス: fe80::42:a6ff:XXXX:XXXX/64 範囲:リンク UP BROADCAST RUNNING MULTICAST MTU:1500 メトリック:1 RXパケット:0 エラー:0 損失:0 オーバラン:0 フレーム:0 TXパケット:44 エラー:0 損失:0 オーバラン:0 キャリア:0 衝突(Collisions):0 TXキュー長:0 RXバイト:0 (0.0 B) TXバイト:5372 (5.3 KB) (省略)
最後に掃除
起動したコンテナや作成したネットワークは下記のコマンドで削除できます。
docker-compose down Stopping nginxflask_uwsgi_1 ... done Stopping nginxflask_nginx_1 ... done Removing nginxflask_uwsgi_1 ... done Removing nginxflask_nginx_1 ... done Removing network app_net
おわりに
dockerのネットワークについての基本を知りたい方はこちらをどうぞ!