terraform と ECS の学習のため、
下図のAWS環境を terraform で構築してみました。
ECSで試したかったことは以下のとおり。
- EC2インスタンス1台でマイクロサービスのコンテナを4つ(backend,user,auth,worker)動かす。
- スケールアウトできるように1サービス:1コンテナ(1タスク)にし、コンテナには、ALB経由でアクセスする。
- workerコンテナは、awsvpc にして、プライベートサブネットに入れる。
- SSMでEC2インスタンスの docker コマンドを実行する。
- コンテナのログをCloudWatchLogsで収集する。
- Route53にALBをDNS(インターナル)登録する。
実施した構築作業と動作確認の流れを、備忘録として、以下に記述します。
Dockerイメージの準備
まず、テスト用のマイクロサービスとして、下記のDockerイメージを2つ用意しました。
- blue21/micro.backend
backendコンテナで使用し、user,auth,workerにアクセスしてレスポンスを表示します。 - blue21/micro.workers
user, auth, worker コンテナで使用し、コンテナのIPアドレスを返します。
今回作成した docker-compose のソースは、以下の Bitbucketからダウンロードできます。
上記ソースを使用したDockerイメージ準備作業の流れは、以下のとおり。
最終的に、DockerHUBにイメージを登録します。
イメージのサイズがECRの無料使用枠に収まらないと思ったので、DockerHUBに登録しました。
1. マイクロサービスの Docker イメージをビルドする。
docker-compose でイメージを2つ作成します。
# docker-compose build # docker images REPOSITORY TAG IMAGE ID CREATED SIZE blue21/micro.workers latest 88fa4a7edec0 2 days ago 261MB blue21/micro.backend latest cc75da278726 2 days ago 297MB
2. ローカル環境でDockerイメージの動作確認
docker-composeで コンテナを4つ起動して、動作確認します。
# docker-compose up -d # docker-compose ps Name Command State Ports --------------------------------------------------------- auth python3 app.py Up 80/tcp backend python3 app.py Up 0.0.0.0:5000->5000/tcp user python3 app.py Up 80/tcp worker python3 app.py Up 80/tcp # curl http://localhost:5000 <!DOCTYPE html> <html> <head> <title>[demo] マイクロサービス</title> </head> <body> <h1>[demo] マイクロサービス</h1> <ul> <li><h2>worker</h2><strong>Service Response:</strong> こんにちは、worker です. Host は、worker.dev.blue21.local(172.18.0.4) です. </li> <li><h2>user</h2><strong>Service Response:</strong> こんにちは、user です. Host は、user.dev.blue21.local(172.18.0.2) です. </li> <li><h2>auth</h2><strong>Service Response:</strong> こんにちは、auth です. Host は、auth.dev.blue21.local(172.18.0.3) です. </li> </ul> </body>
3. DockerイメージをDockerHUB に登録
Dockerイメージを DockerHUB の自分のアカウントに登録します。
# docker login # docker push blue21/micro.backend:latest # docker push blue21/micro.workers:latest
今回は、無償のパブリックなレポジトリとして登録したので、下記で参照できます。
https://hub.docker.com/u/blue21/
AWS環境構築
terraform でAWS環境を構築します。
terraform コマンドは、dockerコンテナを使用しました。(前回の記事を参照)
今回作成したソースは、以下の Bitbucket で参照できます。
https://bitbucket.org/blue21/aws-sample-ecs/src/master/
上記ソースでは、terraform の workspace を利用して 開発環境と本番環境を構築できるように考慮していますが、本番環境構築の動作確認はしていません。
また、terra.sh というシェルを用意して、dockerコンテナの terraform コマンドを実行しています。
今回は、開発環境(workspace=dev)を構築します。ちなみに。本番環境の場合は workspace = prod になります。
1. envfile の準備
envfile にアクセスキー、シークレットアクセスキーを定義します。
今回は、Adminstrator 権限を持ったキーを使用しました。
AWS_ACCESS_KEY_ID=<アクセスキー> AWS_SECRET_ACCESS_KEY=<シークレットアクセスキー>
envfile は terra.sh で使用し、/root/conf/envfile に配置します。
2. common.tfvars の準備
使用するリージョンを定義します。
今回は us-east-1 を使用するので、ECSで使用する EC2インスタンス用のAMIは、us-east-1 用です。
myip は、セキュリティグループの定義で使用します。myip に定義したIPアドレスのみEC2インスタンスへのSSH接続を許可します。
/* * COMMON VARIABLES * */ common = { # default default.region = "us-east-1" # リージョン default.project = "demo" # プロジェクト名 default.myip = "110.165.221.254" # 管理者IP default.zone_name = "blue21.local" # DNS }
3. terraform で AWSに network環境を作成
下記のコマンドでネットワーク環境を構築します。
VPC、サブネット、IGW、ルートテーブル、セキュリティグループを作成します。
# ./terra.sh 10.network init # ./terra.sh 10.network workspace new dev # ./terra.sh 10.network plan # ./terra.sh 10.network apply
terraformで作成したリソースを、AWSコンソールで確認すると下図のようになります。
[VPC]
[サブネット]
[ルートテーブル]
[IGW]
[セキュリティグループ]
4. terraform で AWSに IAMロールを作成
下記のコマンドでIAMロールを作成します。
# ./terra.sh 20.iam init # ./terra.sh 20.iam workspace new dev # ./terra.sh 20.iam plan # ./terra.sh 20.iam apply
terraformで作成したリソースを、AWSコンソールで確認すると下図のようになります。
[ロール]
4. terraform で AWSに ALBを作成
下記のコマンドでALBを作成します。
# ./terra.sh 30.ec2 init # ./terra.sh 30.ec2 workspace new dev # ./terra.sh 30.ec2 plan # ./terra.sh 30.ec2 apply
terraformで作成したリソースを、AWSコンソールで確認すると下図のようになります。
[ターゲット]
[ロードバランサ]
7. terraform で AWSに ECSを作成
下記のコマンドでECSを作成します。
ここで作成するEC2インスタンスのキーペアは、"virginia_key" という名前にしています。
また、EC2インスタンスには、userdata を使用して、SSMエージェントをインストールしています。
# ./terra.sh 40.ecs init # ./terra.sh 40.ecs workspace new dev # ./terra.sh 40.ecs plan # ./terra.sh 40.ecs apply
terraformで作成したリソースを、AWSコンソールで確認すると下図のようになります。
[EC2インスタンス]
ENIが2つ作成され、プライベートIPが2つ割当てられます。1つは、ネットワークタイプを "awsvpc" にした worker コンテナ用です。
[ECS: タスク定義]
[ECS: クラスタ]
[ECS: サービス]
[ECS: タスク]
[ECS: ECSインスタンス]
8. terraform で AWSに Route53 を作成
VPC内部で使用可能なインターナルなゾーンを作成します。
# ./terra.sh 50.r53 init # ./terra.sh 50.r53 workspace new dev # ./terra.sh 50.r53 plan # ./terra.sh 50.r53 apply
terraformで作成したリソースを、AWSコンソールで確認すると下図のようになります。
[ゾーン]
[レコードセット]
動作確認
上記でAWS環境ができたので、いろいろ試します。
マイクロサービス
AWSの外側からALBにアクセスしてみます。
成功すると、以下のように各コンテナのIPアドレスが表示されます。
[root@centos701 ~]# curl http://demo-dev-alb-1527439969.us-east-1.elb.amazonaws.com <!DOCTYPE html> <html> <head> <title>[demo] マイクロサービス</title> </head> <body> <h1>[demo] マイクロサービス</h1> <ul> <li><h2>worker</h2><strong>Service Response:</strong> こんにちは、worker です. Host は、worker.dev.blue21.local(10.0.10.104) です. </li> <li><h2>user</h2><strong>Service Response:</strong> こんにちは、user です. Host は、user.dev.blue21.local(172.17.0.3) です. </li> <li><h2>auth</h2><strong>Service Response:</strong> こんにちは、auth です. Host は、auth.dev.blue21.local(172.17.0.2) です. </li> </ul> </body> </html>[root@centos701 ~]#
成功すると以下のように workerコンテナのIPアドレスが表示されます。
[root@centos701 ~]# curl -H "Host: worker.dev.blue21.local" http://demo-dev-alb-1527439969.us-east-1.elb.amazonaws.com こんにちは、worker です. Host は、worker.dev.blue21.local(10.0.10.104) です.[root@centos701 ~]#
CloudWatchLogs
AWSコンソールで CLoudWatchLogs を参照すると、下図のとおり。
コンテナのログを参照できます。
[コンテナのログ一覧]
[backend のログ(アクセスログ)]
SSMでのコマンド実行
AWSコンソールの[EC2]>[SYSTEM MANAGER SERVICES]でコマンドを実行してみます。
ECS用のEC2インスタンス上で"docker ps"コマンドを実行すると下図のように表示されました。
Route53
VPC内部で、blue21.local のDNS名でマイクロサービスにアクセスしてみます。
ECS用のEC2インスタンスにSSHログインして、以下のように curl コマンドで backend に アクセスしてみました。
成功すると以下のように表示されます。
[ec2-user@ip-10-0-0-4 ~]$ curl http://backend.dev.blue21.local <!DOCTYPE html> <html> <head> <title>[demo] マイクロサービス</title> </head> <body> <h1>[demo] マイクロサービス</h1> <ul> <li><h2>worker</h2><strong>Service Response:</strong> こんにちは、worker です. Host は、worker.dev.blue21.local(10.0.10.104) です. </li> <li><h2>user</h2><strong>Service Response:</strong> こんにちは、user です. Host は、user.dev.blue21.local(172.17.0.3) です. </li> <li><h2>auth</h2><strong>Service Response:</strong> こんにちは、auth です. Host は、auth.dev.blue21.local(172.17.0.2) です. </li> </ul> </body> </html>[ec2-user@ip-10-0-0-4 ~]$
user,auth,workerコンテナにアクセスすると、成功すれば、以下のよう表示されます。
[ec2-user@ip-10-0-0-4 ~]$ curl http://user.dev.blue21.local こんにちは、user です. Host は、user.dev.blue21.local(172.17.0.3) です.[ec2-user@ip-10-0-0-4 ~]$ [ec2-user@ip-10-0-0-4 ~]$ curl http://auth.dev.blue21.local こんにちは、auth です. Host は、auth.dev.blue21.local(172.17.0.2) です.[ec2-user@ip-10-0-0-4 ~]$ [ec2-user@ip-10-0-0-4 ~]$ curl http://worker.dev.blue21.local こんにちは、worker です. Host は、worker.dev.blue21.local(10.0.10.104) です.[ec2-user@ip-10-0-0-4 ~]$ [ec2-user@ip-10-0-0-4 ~]$
コンテナのスケールアウト
user コンテナを手動でスケールアウトしてみます。
modules/ecs/main.tf の 下記 "desired_count" を 2 に修正して、user コンテナを2つ起動するようにソースを変更します。
resource "aws_ecs_service" "user" { name = "${local.name_prefix}-user" cluster = "${aws_ecs_cluster.default.id}" task_definition = "${aws_ecs_task_definition.user.arn}" desired_count = 2 health_check_grace_period_seconds = 30 iam_role = "${var.m-role-ecs.["ecs-service-role-arn"]}" load_balancer { target_group_arn = "${var.m-alb.["target-user-id"]}" container_name = "user" container_port = 80 } }
terraform で上記の変更を反映します。
# ./terra.sh 40.ecs apply
AWSコンソールで変更結果を確認すると下図のとおり。
[userサービスのコンテナが2つある]
[CloudwatchLogs が追加されている]
マイクロサービスにアクセスすると、以下のように user のIPアドレスが変わります。
# curl http://demo-dev-alb-1527439969.us-east-1.elb.amazonaws.com <!DOCTYPE html> <html> <head> <title>[demo] マイクロサービス</title> </head> <body> <h1>[demo] マイクロサービス</h1> <ul> <li><h2>worker</h2><strong>Service Response:</strong> こんにちは、worker です. Host は、worker.dev.blue21.local(10.0.10.104) です. </li> <li><h2>user</h2><strong>Service Response:</strong> こんにちは、user です. Host は、user.dev.blue21.local(172.17.0.3) です. </li> <li><h2>auth</h2><strong>Service Response:</strong> こんにちは、auth です. Host は、auth.dev.blue21.local(172.17.0.2) です. </li> </ul> </body> </html>下記は、user コンテナのIPアドレスが上記と異なっているので、ALBで振り分けできてることがわかります。
# curl http://demo-dev-alb-1527439969.us-east-1.elb.amazonaws.com <!DOCTYPE html> <html> <head> <title>[demo] マイクロサービス</title> </head> <body> <h1>[demo] マイクロサービス</h1> <ul> <li><h2>worker</h2><strong>Service Response:</strong> こんにちは、worker です. Host は、worker.dev.blue21.local(10.0.10.104) です. </li> <li><h2>user</h2><strong>Service Response:</strong> こんにちは、user です. Host は、user.dev.blue21.local(172.17.0.5) です. </li> <li><h2>auth</h2><strong>Service Response:</strong> こんにちは、auth です. Host は、auth.dev.blue21.local(172.17.0.2) です. </li> </ul> </body> </html>
あとかたずけ
遊び終わったら、上記で作成したAWS環境を、以下の順番で削除します。お金がもったいないので。
# ./terra.sh 50.r53 destroy # ./terra.sh 40.ecs destroy # ./terra.sh 30.ec2 destroy # ./terra.sh 20.iam destroy # ./terra.sh 10.network destroy
ちなみに、夜などAWSをさわらないときは、
お金のかからない network, iam だけ残して、ec2, ecs, r53 は削除し、検証時に毎回、ec2, ecs, r53 を作成してました。