第3回です。
今回はBeanstalkのmulti containerの要でもある、
Dockerrun.aws.jsonについてです。
連載一覧
前提知識
この記事の前提知識としては
Dockerやdocker-composeの基礎を習得していること・・・となります。
Dockerrun.aws.jsonはdocker-compose.ymlのAWS版みたいなもので
docker-compose.ymlを理解していれば記載方法が少し違うくらいなので
docker-compose.ymlの理解が非常に重要です。
今回の説明ポイント
BeanstalkのMulti-Container Dockerでは
EC2インスタンス(以下ホスト)上で任意の数のDockerコンテナ(以下ゲスト)を
起動するという仕組みになります。
今回説明するDockerrun.aws.jsonでは以下がポイントとなります。
- Volumeを使ってホストとゲストのディレクトリを共有する
- ログはVolume越しでホストに出力され、CloudWatchLogsでホストのログを同期
- python(uWSGI+flask)のイメージはDockerリポジトリに作らず配備する度に再構築
※3についてはECRなどのDockerリポジトリを
最終的には利用すべきですが時間があればどこかの回で説明します。
Dockerrun.aws.jsonの構成
{
// multi containerの場合は「2」固定
"AWSEBDockerrunVersion": 2,
// ディレクトリ共有をするホスト側のPATHを名前をつけて設定
"volumes": [],
// ホストの中に立ち上げるコンテナ設定
// 今回はここにNGINXとPython(uWSGI)のコンテナ設定を記載していきます。
"containerDefinitions": []
}
ファイルの構成としてはこのようになります。
volumes
まずは【volumes】の設定例を見て行きましょう。
"volumes": [
{
"name": "host-timezone",
"host": {
"sourcePath": "/etc/localtime"
}
},
{
"name": "xxxxx-src",
"host": {
"sourcePath": "/var/app/current"
}
},
{
"name": "nginx-proxy-conf",
"host": {
"sourcePath": "/var/app/current/proxy/conf.d"
}
}
],
【host-timezone】
ホストのタイムゾーン設定をゲスト(コンテナ)にも反映させる為の設定になります。
ホストのEC2はデフォルトではUTCですので別途(次回以降)に
ebextensionsでJST(Asia/Tokyo)に変更します。
【xxxxx-src】
「eb create」コマンドを実行したカレントディレクトリの中身が
ホストの「/var/app/current」にアップロードされると
前回までの記事でお伝えしました。
今回はDockerリポジトリなどでミドルウェアやプログラムの設定・配備がされていない
状態から始めますのでホストに自動で置かれたデータを
ゲストに配備する為の共有設定です。
【nginx-proxy-conf】
NGINXへのリクエストをuWSGIにリバースプロキシする為の
nginxのconf設定ファイルが置かれているパスです。
eb createを実行するカレントディレクトリの
proxy/conf.d/default.confに配備されています。
server {
listen 80;
server_name localhost;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
location / {
proxy_pass http://python-container:8080;
}
}
中身はこんな感じです。
実運用時はもっと細かい設定が必要かと思われます。
また、リバプロ先のホスト名=python-containerは
Dockerrun.aws.jsonのcontainerDefinitionsの中で設定します。
containerDefinitions
containerDefinitionsでは各コンテナの設定を記載しています。
まずは代表的な設定値の説明をします。
その後にサンプルを見て行きましょう。
name
これはコンテナの名前を表す任意の文字列です。
今回はpython-containerとnginx-proxyとしています。
image
Dockerのイメージファイルになります。
ECRやDockerHubなどを利用する場合はそのイメージ名を指定してください。
今回はDocker公式で公開されているpython:3.7とnginxを使います。
essential
コンテナの起動に失敗した場合にBenasalkのセットアップ全体を
停止(異常終了)とさせるか否か・・・の設定のようですが
試してません。
memory
コンテナに割り当てるメモリです。
memoryReservationも合わせて設定することにより
ホストのメモリに余裕があればmemoryの値を超えても
memoryReservationの値まではメモリを確保するようです。
portMappings
ホストのXXポートにアクセスがきたらコンテナのYYに繋ぐ・・・というような
ポートフォワードの設定です。
今回はNGINXは外部からホスト越しでアクセスされますが
python(uWSGI)はNGINX経由でのアクセスになるので
ホストの80番にきたらゲストの80番に繋ぐ・・・という設定のみをしています。
links
DockerではコンテナのプライベートIPアドレスは
コンテナ起動時に動的に割り当てられます。
NGINX⇨uWSGIにリバースプロキシをする場合にIPが動的では困る為、
NGINX側のコンテナ設定で「python-container」コンテナに対してlink設定することで
NGINXコンテナからはpython-containerというホスト名でuWSGIにアクセスができます。
mountPoints
volumesのセクションでホストのディレクトリ共有を設定しましたが
ここではその共有先をコンテナ側のどのディレクトリを共有させるかの
マッピング設定をします。
readOnly=trueに設定するとコンテナ側でファイルの追加・編集はできなくなります。
Beanstalkではvolumesに指定しなくても
【awseb-logs-{コンテナ名}】という名前で自動的にvolume設定されます。
その為、mountPointsで以下を指定してログファイルの共有をします。
awseb-logs-python-container
awseb-logs-nginx-proxy
entryPoint
Dockerコンテナが立ち上がった直後に実行するコマンドです。
ここで実行したコマンドが終了するとコンテナも停止してしまうので
デーモンなど、プロセスを起動しっぱなしにする必要があります。
今回はここでシェルスクリプトを起動して
uWSGIのインストールやプログラムモジュールのセットアップを行いますが
詳細は次回説明します。
workingDirectory
コンテナが起動した後にentryPointで指定したコマンドを実行する
カレントディレクトリになります。
environment
コンテナ内で利用できる環境変数を設定します。
今回はここでuWSGIの起動コマンドを定義しています。
{
"AWSEBDockerrunVersion": 2,
"volumes": [
{
"name": "host-timezone",
"host": {
"sourcePath": "/etc/localtime"
}
},
{
"name": "xxxxx-src",
"host": {
"sourcePath": "/var/app/current"
}
},
{
"name": "nginx-proxy-conf",
"host": {
"sourcePath": "/var/app/current/proxy/conf.d"
}
}
],
"containerDefinitions": [
{
"name": "python-container",
"image": "python:3.7",
"essential": true,
"memory": 512,
"mountPoints": [
{
"sourceVolume": "host-timezone",
"containerPath": "/etc/localtime",
"readOnly": true
},
{
"sourceVolume": "xxxxx-src",
"containerPath": "/var/app",
"readOnly": true
},
{
"sourceVolume": "awseb-logs-python-container",
"containerPath": "/var/log/xxxdemo"
}
],
"workingDirectory": "/var/app",
"environment": [
{
"name": "UWSGI_NUM_PROCESSES",
"value": "1"
},
{
"name": "UWSGI_NUM_THREADS",
"value": "15"
},
{
"name": "UWSGI_UID",
"value": "uwsgi"
},
{
"name": "UWSGI_GID",
"value": "uwsgi"
},
{
"name": "UWSGI_LOG_FILE",
"value": "/var/log/uwsgi/uwsgi.log"
}
],
"entryPoint": [
"/bin/sh",
"/var/app/start-docker.sh"
]
},
{
"name": "nginx-proxy",
"image": "nginx",
"essential": true,
"memory": 256,
"portMappings": [
{
"hostPort": 80,
"containerPort": 80
}
],
"links": [
"python-container"
],
"mountPoints": [
{
"sourceVolume": "host-timezone",
"containerPath": "/etc/localtime",
"readOnly": true
},
{
"sourceVolume": "nginx-proxy-conf",
"containerPath": "/etc/nginx/conf.d",
"readOnly": true
},
{
"sourceVolume": "awseb-logs-nginx-proxy",
"containerPath": "/var/log/nginx"
}
]
}
]
}