はじめに
まず、大前提として、ここから先は現在キャッチアップしているコンテナ関連の学習のために、ECR や ECS を活用しながら、さまざまなコードを書いていきます。
※補足事項
そのため、内容は完全に自分向けとなっています。
また、このブログ投稿サイトは、自分自身の備忘録としても活用する予定です。記録を積み重ねながら、メモを残していきます。
実際の作業の流れ
実際の作業の流れをまとめましたが、本記事ではすべての手順を詳しく紹介するわけではありません。あらかじめご了承ください。
- CloudWatch にロググループ作成
- 対象のリポジトリをクローンする
- ECR に Docker イメージをプッシュする
- ECS でクラスターを作成する
- カスタム JSON を使ってタスク定義を作成する
- ECS のサービスを作成する
- ブラウザからタスク定義のパブリック IP アドレスにアクセスする
ディレクトリ構成
reverse-proxy-django/
│── .env # 環境変数ファイル(SECRET_KEY など)
│── docker-compose.yml # Docker Compose ファイル
│── nginx/
│ ├── default.conf # Nginx 設定ファイル(リバースプロキシ設定)
│── django_app/
│ ├── Dockerfile # Django の Dockerfile
│ ├── requirements.txt # Django の依存関係(Django, Gunicorn)
│ ├── manage.py # Django 管理コマンド
│ ├── templates/ # Django のテンプレートディレクトリ(将来的に使用)
│ └── mysite/ # Django プロジェクト
│ ├── __init__.py
│ ├── settings.py # Django の設定ファイル
│ ├── urls.py # ルーティング設定
│ ├── wsgi.py # WSGI アプリケーションのエントリーポイント
│── nginx.Dockerfile # Nginx の Dockerfile
それぞれのソースコードはこちら
ローカル開発用リポジトリ
ローカル開発の記事
本番 ECS 用リポジトリ
現在、それぞれのリポジトリには README などの説明は記載していませんが、今後追加していく予定です。
Django の通信経路
Nginx は Django へのリバースプロキシとして機能します。
[ブラウザ] → [ECS上のNginx (ポート80)] → [Django (ポート8000)]
CloudWatch にロググループ作成
CloudWatch にロググループが存在するか確認
まず、ロググループがすでに存在しているかを確認します。
aws logs describe-log-groups --query "logGroups[*].logGroupName"
- ここに
"/aws/ecs/reverse-proxy-cluster"
(設定したロググループ)が存在しない場合、次のステップへ進みます。
ロググループを作成
ロググループが存在しない場合、以下のコマンドで作成します。
aws logs create-log-group --log-group-name "/aws/ecs/reverse-proxy-cluster"
※注意点
カスタム JSON ポリシーを使用する場合、この作業を事前に行わないと、以下のエラーが発生します。
エラー内容:
ResourceInitializationError: failed to validate logger args: create stream has been retried 1 times: failed to create CloudWatch log stream: ResourceNotFoundException: The specified log group does not exist. : exit status 1
ECR にプッシュする際のコツ
Django アプリケーションのビルド
django_app
ディレクトリに移動してから、以下のコマンドを実行します。
docker build -t reverse-proxy-django-app .
Nginx のビルド
Nginx の Dockerfile はプロジェクトルートにあるため、以下のように -f
オプションを指定してビルドします。
# Nginx のビルド
docker build -t reverse-proxy-django-nginx -f nginx.Dockerfile .
ECR へのプッシュ
その他のコマンドについては、ECR のリポジトリ作成時に表示されるプッシュコマンドをそのまま使用しています。
ECS のタスク定義が重要
これまでは AWS マネジメントコンソール(マネコン)から設定を行っていましたが、カスタム JSON を使うことで、一発で作成することができます。
{
"family": "reverse-proxy-task",
"executionRoleArn": "arn:aws:iam::xxx:role/ecsTaskExecutionRole",
"networkMode": "awsvpc",
"requiresCompatibilities": ["FARGATE"],
"cpu": "1024",
"memory": "2048",
"containerDefinitions": [
{
"name": "django",
"image": "xxx.dkr.ecr.ap-northeast-1.amazonaws.com/reverse-proxy-django-app",
"cpu": 512,
"memory": 1024,
"portMappings": [
{
"containerPort": 8000,
"protocol": "tcp"
}
],
"essential": true,
"environment": [
{
"name": "DJANGO_SETTINGS_MODULE",
"value": "mysite.settings"
},
{
"name": "DJANGO_SECRET_KEY",
"value": "your-secret-key"
},
{
"name": "STATIC_ROOT",
"value": "/app/staticfiles"
}
],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/aws/ecs/reverse-proxy-cluster",
"awslogs-region": "ap-northeast-1",
"awslogs-stream-prefix": "ecs"
}
}
},
{
"name": "nginx",
"image": "xxx.dkr.ecr.ap-northeast-1.amazonaws.com/reverse-proxy-django-nginx",
"cpu": 512,
"memory": 1024,
"portMappings": [
{
"containerPort": 80,
"protocol": "tcp"
}
],
"essential": true,
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/aws/ecs/reverse-proxy-cluster",
"awslogs-region": "ap-northeast-1",
"awslogs-stream-prefix": "ecs"
}
}
}
]
}
ECS(Fargate)でのセキュリティグループ設定
現在の ECS 環境では、Nginx + Django(Gunicorn) の構成で動作しており、適切な セキュリティグループ(SG) の設定が必要です。
現時点では、ブラウザからのアクセスを目的として以下のルールを許可しました。
(※ただし、一部不要な設定も含まれているため、適宜見直しが必要と考えています。)
プロトコル | ポート | 方向 | 許可元 / 許可先 | 説明 |
---|---|---|---|---|
TCP | 80 | インバウンド | 0.0.0.0/0 または ::/0 | インターネットから Nginx へ HTTP アクセスを許可 |
TCP | 443 | インバウンド | 0.0.0.0/0 または ::/0 | (HTTPS を使用する場合) SSL 通信を許可 |
TCP | 8000 | インバウンド | nginx のセキュリティグループ | Nginx から Django (Gunicorn) への接続を許可 |
TCP | 80 | アウトバウンド | 0.0.0.0/0 | Nginx が外部へ通信する場合(API, S3 など) |
TCP | 443 | アウトバウンド | 0.0.0.0/0 | Nginx が外部の HTTPS リソースへアクセスする場合 |
TCP | 5432 / 3306 | インバウンド | Django のプライベート IP | (データベースが別のサーバーにある場合) Django から DB への接続を許可 |
ALL | ALL | アウトバウンド | 0.0.0.0/0 | ECS タスクが外部のリソースにアクセスするため |
その他で使ったコマンド
タスクのARNを取得
ECS クラスター内のタスク ARN を取得します。
aws ecs list-tasks --cluster reverse-proxy-cluster --query 'taskArns' --output text
取得したタスクARNを使って詳細を確認
上記で取得したタスク ARN を使用し、ECS タスクのエラー理由を確認します。
aws ecs describe-tasks --cluster reverse-proxy-cluster --tasks arn:aws:ecs:ap-northeast-1:881490128743:task/reverse-proxy-cluster/xxxxxxxxxxxxxxxxxxxx --query 'tasks[*].containers[*].reason'
CloudWatch Logs でエラーの詳細を確認
エラーの詳細は reason
に表示されますが、CloudWatch Logs でログを確認することで、より詳しい情報を取得できます。
ロググループの一覧を取得
aws logs describe-log-groups --query "logGroups[*].logGroupName"
コンテナのログを取得
対象のロググループを見つけたら、以下のコマンドで直近 10 分間のコンテナログを取得します。
aws logs tail /aws/ecs/containerinsights/reverse-proxy-cluster/application --since 10m
CloudWatch Logs で詳細エラーを確認
aws logs describe-log-groups --query "logGroups[*].logGroupName"
ログストリームを確認
特定のロググループ内のログストリームを確認する場合は、以下のコマンドを使用します。
aws logs describe-log-streams --log-group-name "/aws/ecs/reverse-proxy-cluster" --query "logStreams[*].logStreamName"
ECS タスク定義にログ設定を追加
ECS のタスク定義に CloudWatch Logs の設定 を追加することで、コンテナのログを取得できるようになります。
"containerDefinitions": [
{
"name": "django",
"image": "xxx.dkr.ecr.ap-northeast-1.amazonaws.com/reverse-proxy-django-app",
"memory": 1024,
"cpu": 512,
"essential": true,
"portMappings": [{ "containerPort": 8000 }],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/aws/ecs/reverse-proxy-cluster",
"awslogs-region": "ap-northeast-1",
"awslogs-stream-prefix": "ecs"
}
}
}
]
直近のログを取得
最新のログを確認するには、以下のコマンドを実行します。
aws logs tail /aws/ecs/reverse-proxy-cluster --since 10m
最新のログストリームを自動で取得する方法
Django の最新ログストリームを取得
以下のコマンドを実行すると、Django の最新のログストリームを取得し、ログを表示できます。
LOG_STREAM=$(aws logs describe-log-streams --log-group-name "/aws/ecs/reverse-proxy-cluster" --query "logStreams[?starts_with(logStreamName, 'ecs/django')].logStreamName | [0]" --output text)
aws logs tail /aws/ecs/reverse-proxy-cluster --log-stream-names "$LOG_STREAM" --since 10m
Nginx の最新ログストリームを取得
Nginx の最新のログストリームを取得し、ログを表示するには以下のコマンドを使用します。
LOG_STREAM=$(aws logs describe-log-streams --log-group-name "/aws/ecs/reverse-proxy-cluster" --query "logStreams[?starts_with(logStreamName, 'ecs/nginx')].logStreamName | [0]" --output text)
aws logs tail /aws/ecs/reverse-proxy-cluster --log-stream-names "$LOG_STREAM" --since 10m
実際に遭遇したエラーたち
修正内容一覧
修正箇所 | 修正内容 |
---|---|
default.conf |
proxy_pass を 127.0.0.1:8000 に変更 |
nginx.Dockerfile |
COPY default.conf /etc/nginx/conf.d/default.conf に修正 |
settings.py |
STATIC_ROOT を /app/staticfiles に設定 |
task-def.json |
STATIC_ROOT の環境変数を追加 |
docker-compose.yml |
depends_on を削除 |
task-def.json |
networkMode を awsvpc に変更 |
まとめ
この記事は、自分用の備忘録としてまとめたものです。その点をご理解いただけると幸いです。
もし、この記事の内容が少しでも参考になれば嬉しく思います。
今後も同様の内容を継続して投稿していきますので、温かく見守っていただけるとありがたいです。