eden: Amazon ECS Dynamic Environment Manager (Amazon ECS動的環境マネージャ)¶
Amazon ECSを使った環境を簡単に複製するためのツールです。 edenに参照するためのAmazon ECS Serviceを指定すると、edenがそれを複製します。
edenは高速です。作成/削除コマンドの実行は5秒以内に完了します。
なぜ?¶
edenは、多くのプレビュー開発環境が必要だがデータベースやその他のリソースが共有可能なユースケースのために作られています。
どうやって?¶
edenは、参照ECSサービスからタスク定義、ECSサービス、およびターゲットグループを複製します。
edenは、すべてのクローンされたサービスに対して1つの共通ALBを使用することでコストと実行時間を削減します(ALBの作成には最大5分かかる場合があります)。 edenはターゲットグループを作成し、サービスを複製します。作成したターゲットグループを共通のALBにアタッチし、共通のALBを指すRoute 53 A ALIASレコードを作成します。
リソース作成順序¶
- ECSタスク定義
- 参照サービスから複製
- ALBターゲットグループ
- 設定は、参照サービスに接続されたターゲットグループからコピーされます
- ECSサービス
- 参照サービスと同じクラスターに作成
- ALBリスナールール
- ホストヘッダールール
- Route 53 A ALIASレコード
- 共通ALBを指す
- Environments JSONファイルへの追加
注釈
リソースの削除は逆の順序で実行されます。作成と削除のいずれもの実行が5秒以内に完了します。
前提条件¶
- S3バケット内のEnvironments JSONファイル
- ファイル構成や詳細は こちら<eden_envs_json_> で説明されています。
- ターゲットグループがアタッチされた参照先となるECSサービス
- edenが管理するサービスのための共通ALB
- ホストヘッダーリスナールールを用いて全ての環境によって再利用されるます
- 参照サービスが使用するものとは別のもの
- HTTPSリスナーが必要です
- リスナーには、ターゲットダイナミックゾーンのワイルドカード証明書が必要です
- 単純なALBの利用
- 複数のパスルールを利用しない、など
- 1つのECSサービスごとに1つのALB
準備¶
工事中
Environments JSONファイル¶
Environments JSONファイルは次の目的で使用されます:
- 存在する環境とそのエンドポイントの確認
- クライアントアプリケーションに利用可能な環境を知らせる
Environments JSONファイルの例:
{
"environments": [
{
"env": "dev",
"name": "dev-dynamic-test",
"api_endpoint": "api-test.dev.example.com"
}
]
}
上記の例では、 config_update_key = api_endpoint
を前提としています。
同じ名前で複数の環境を作成できます。単一のeden環境内に複数のエンドポイントを作れるようにするために、 config_update_key
設定が異なるプロファイルを使用すればよいです。たとえば、API、管理ツール、およびフロントエンドサービスを単一の環境として作成したいというユースケースがあるとします。
Let's say we have three profiles, api
, admin
, and frontend
.
These profiles are pre-configured with config_update_key
equal to
api_endpoint
, admin_endpoint
, frontend_endpoint
respectively.
$ eden create -p api --name foo --image-uri xxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/api:latest
$ eden create -p admin --name foo --image-uri xxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/admin:latest
$ eden create -p frontend --name foo --image-uri xxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/frontend:latest
このとき、Environments JSONファイルは以下のようになります:
{
"environments": [
{
"env": "dev",
"name": "dev-dynamic-test",
"api_endpoint": "api-test.dev.example.com",
"admin_endpoint": "admin-test.dev.example.com",
"frontend_endpoint": "test.dev.example.com"
}
]
}
Environments JSONファイル内では、単一のJSONオブジェクトに複数のエンドポイントが存在します。このオブジェクトにある最後のエンドポイントが削除されると、このオブジェクトがEnvironments JSONファイルから削除されます。
警告
上記の例のように単一の環境で複数のエンドポイントを扱う場合、エンドポイントの作成/削除の時間差により、環境が不完全になる可能性があることに注意してください (必要なすべてのエンドポイントが揃っていない環境が存在しうる)。
CLIとAPI¶
まず、eden CLIを試すことをお勧めします。edenをCI/CDパイプラインに追加する準備ができたら、eden APIの利用を推奨します。APIのための プロファイル のプッシュにはCLIが必要であることに注意してください。
eden CLIのインストール¶
$ pip3 install aws-eden-cli
$ eden -h
usage: eden [-h] {create,delete,ls,config} ...
ECS Dynamic Environment Manager. Clone Amazon ECS environments easily.
positional arguments:
{create,delete,ls,config}
create Create environment or deploy to existent
delete Delete environment
ls List existing environments
config Configure eden
optional arguments:
-h, --help show this help message and exit
ヒント: サブコマンドでも -h
を使用できます。
$ eden config -h
usage: eden config [-h] {setup,check,push,remote-rm} ...
positional arguments:
{setup,check,push,remote-rm}
setup Setup profiles for other commands
check Check configuration file integrity
push Push local profile to DynamoDB for use by eden API
remote-rm Delete remote profile from DynamoDB
optional arguments:
-h, --help show this help message and exit
$ eden config push -h
usage: eden config push [-h] [-p PROFILE] [-c CONFIG_PATH] [-v]
[--remote-table-name REMOTE_TABLE_NAME]
optional arguments:
-h, --help show this help message and exit
-p PROFILE, --profile PROFILE
profile name in eden configuration file
-c CONFIG_PATH, --config-path CONFIG_PATH
eden configuration file path
-v, --verbose
--remote-table-name REMOTE_TABLE_NAME
profile name in eden configuration file
eden CLIの設定¶
まず、プロファイルを作成してみましょう。プロファイルを利用すれば、コマンドを実行する際に毎回すべてのパラメーターを指定する必要がなくなり、プロファイル名の指定のみで十分です。
$ eden config setup --endpoint-s3-bucket-name servicename-config
$ eden config setup --endpoint-s3-key endpoints.json
$ eden config setup --endpoint-name-prefix servicename-dev
$ eden config setup --endpoint-update-key api_endpoint
$ eden config setup --endpoint-env-type dev
$ eden config setup --domain-name-prefix api
$ eden config setup --dynamic-zone-id Zxxxxxxxxxxxx
$ eden config setup --master-alb-arn arn:aws:elasticloadbalancing:ap-northeast-1:xxxxxxxxxxxx:loadbalancer/app/dev-alb-api-dynamic/xxxxxxxxxx
$ eden config setup --name-prefix dev-dynamic
$ eden config setup --reference-service-arn arn:aws:ecs:ap-northeast-1:xxxxxxxxxxxx:service/dev/dev01-api
$ eden config setup --target-cluster dev
設定は ~/.eden/config
に保存されます。上記のコマンドで default
というプロファイルが作成されました:
$ cat ~/.eden/config
[api]
name_prefix = dev-dynamic
reference_service_arn = arn:aws:ecs:ap-northeast-1:xxxxxxxxxxxx:service/dev/dev01-api
target_cluster = dev
domain_name_prefix = api
master_alb_arn = arn:aws:elasticloadbalancing:ap-northeast-1:xxxxxxxxxxxx:loadbalancer/app/dev-alb-api-dynamic/xxxxxxxxxx
dynamic_zone_name = dev.example.com.
dynamic_zone_id = Zxxxxxxxxxxxx
config_bucket_name = servicename-config
config_bucket_key = endpoints.json
config_update_key = api_endpoint
config_env_type = dev
config_name_prefix = servicename-dev
target_container_name = api
設定ファイルの整合性をチェックしましょう:
$ eden config check
No errors found
edenのプロファイル¶
複数のプロファイルを使用できます。設定で複数のプロファイルを作成し、コマンドを実行する際にの -p プロファイル名
で使用するプロファイルを指定できます。
$ eden config check -p api
No errors found
ローカルプロファイルをDynamoDBに保存することで、eden APIでそのプロファイルが使用できるようになります。
$ eden config push -p api
Waiting for table creation...
Successfully pushed profile api to DynamoDB
注釈
edenのプロファイルを保存するためのDynamoDBテーブルが存在しない場合、eden CLIがテーブルを自動的に作成します
同じコマンドで既存のプロファイルが上書きされます (既存のプロファイルにプッシュすると上書きされます):
$ eden config push -p api
Successfully pushed profile api to DynamoDB table eden
remote-rmコマンドでリモートのプロファイルを削除することができます:
$ eden config remote-rm -p api
Successfully removed profile api from DynamoDB table eden
コマンドの実行¶
環境の作成:
$ eden create -p api --name foo --image-uri xxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/api:latest
Checking if image xxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/api:latest exists
Image exists
Retrieved reference service arn:aws:ecs:ap-northeast-1:xxxxxxxxxx:service/dev/api
Retrieved reference task definition from arn:aws:ecs:ap-northeast-1:xxxxxxxxxx:task-definition/api:20
Registered new task definition: arn:aws:ecs:ap-northeast-1:xxxxxxxxxx:task-definition/dev-dynamic-api-foo:1
Registered new task definition: arn:aws:ecs:ap-northeast-1:xxxxxxxxxx:task-definition/dev-dynamic-api-foo:1
Retrieved reference target group: arn:aws:elasticloadbalancing:ap-northeast-1:xxxxxxxxxx:targetgroup/api/xxxxxxxxxxxx
Existing target group dev-dynamic-api-foo not found, will create new
Created target group arn:aws:elasticloadbalancing:ap-northeast-1:xxxxxxxxxx:targetgroup/dev-dynamic-api-foo/xxxxxxxxxxxx
ELBv2 listener rule for target group arn:aws:elasticloadbalancing:ap-northeast-1:xxxxxxxxxx:targetgroup/dev-dynamic-api-foo/xxxxxxxxxxxx and host api-foo.dev.example.com does not exist, will create new listener rule
ECS Service dev-dynamic-api-foo does not exist, will create new service
Checking if record api-foo.dev.example.com. exists in zone Zxxxxxxxxx
Successfully created CNAME: api-foo.dev.example.com -> dev-alb-api-dynamic-297517510.ap-northeast-1.elb.amazonaws.com
Updating config file s3://example-com-config/endpoints.json, environment example-api-foo: nodeDomain -> api-foo.dev.example.com
Existing environment not found, adding new
Successfully updated config file
Successfully finished creating environment dev-dynamic-api-foo
注釈
create、deleteコマンドは、リモートステート(DynamoDBテーブル)を更新します。 eden config push
と同様に、テーブルが存在しない場合、テーブルが自動的に作成されます。
作成の確認:
$ eden ls
Profile api:
dev-dynamic-api-foo api-foo.dev.example.com (last updated: 2019-11-20T19:44:10.179760)
注釈
この一覧は、 Environments JSON ファイルではなく、リモートステートのDynamoDBテーブルから生成されます。最後に更新されたタイムスタンプは、createでの環境の新規作成、すでに存在する環境へのデプロイで更新されます。
環境を削除し、削除を確認します:
$ eden delete -p api --name foo
Updating config file s3://example-com-config/endpoints.json, delete environment example-api-foo: nodeDomain -> api-foo.dev.example.com
Existing environment found, and the only optional key is nodeDomain,deleting environment
Successfully updated config file
Checking if record api-foo.dev.example.com. exists in zone Zxxxxxxxxx
Found existing record api-foo.dev.example.com. in zone Zxxxxxxxxx
Successfully removed CNAME record api-foo.dev.example.com
ECS Service dev-dynamic-api-foo exists, will delete
Successfully deleted service dev-dynamic-api-foo from cluster dev
ELBv2 listener rule for target group arn:aws:elasticloadbalancing:ap-northeast-1:xxxxxxxxxx:targetgroup/dev-dynamic-api-foo/xxxxxxxxxxxx and host api-foo.dev.example.com found, will delete
Deleted target group arn:aws:elasticloadbalancing:ap-northeast-1:xxxxxxxxxx:targetgroup/dev-dynamic-api-foo/xxxxxxxxxxxx
Deleted all task definitions for family: dev-dynamic-api-foo, 1 tasks deleted total
Successfully finished deleting environment dev-dynamic-api-foo
$ eden ls
No environments available
APIへの移行¶
CLIとAPIの両方がDynamoDBテーブルでステートを管理します。このテーブルはCLIによってのみ作成されます。また、APIはリモートステートに格納されたプロファイルのみを使用できます。 APIを初めて実行する前に、 eden config --push
を実行して、APIのためのプロファイルをプッシュしてください。TerraformでAPIを構築する際に、リモートステートテーブルが存在しない場合、terraform applyの実行が失敗します。
API内部¶
eden APIは以下の要素で構成されます:
- Lambda関数 (API本体)
- API GatewayとAPIを保護するためのAPIキー
- ステート管理用のDynamoDBテーブル
- デフォルトのテーブル名は「eden」です。
Terraformを使用したeden APIの構築¶
module "eden_api" {
source = "baikonur-oss/lambda-eden-api/aws"
version = "0.2.0"
lambda_package_url = "https://github.com/baikonur-oss/terraform-aws-lambda-eden-api/releases/download/v0.2.0/lambda_package.zip"
name = "eden"
# eden API Gateway variables
api_acm_certificate_arn = "${data.aws_acm_certificate.wildcard.arn}"
api_domain_name = "${var.env}-eden.${data.aws_route53_zone.main.name}"
api_zone_id = "${data.aws_route53_zone.main.zone_id}"
endpoints_bucket_name = "somebucket"
dynamic_zone_id = "${data.aws_route53_zone.dynamic.zone_id}"
}
警告
ステート管理のためのDynamoDBテーブルはeden CLIによって作成されます。 terraform apply
を実行する前に、一度 eden config --push
を実行してください。
複数のプロファイルを使うことで、1つのアカウント/リージョンに対して1つのeden APIで十分です。詳しくは プロファイル セクションを参照してください。
eden APIのコマンド¶
eden APIには、createとdeleteという2つのAPIコマンドのみあります。
eden APIキー¶
eden API Terraformモジュールは、1つのAPIキーを作成します。API GatewayコンソールからAPIキーが確認できます。
APIにアクセスするには、このキーを指定しなければなりません。
APIキーをHTTPヘッダーとして指定する必要があります:
x-api-key: YOURAPIKEY
API使用例¶
api
という名前のリモートプロファイルを使ってcreate APIを実行してみましょう:
curl https://eden.example.com/api/v1/create?name=test-create&image_uri=xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/servicename-api-dev:latest&profile=api -H "x-api-key:YOURAPIKEY"
APIのLambda関数が出力したログを見てみましょう:
2019-04-08T20:32:05.151Z INFO [main.py:check_cirn:382] Checking if image xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/servicename-api-dev:latest exists
2019-04-08T20:32:05.270Z INFO [main.py:check_cirn:401] Image exists
2019-04-08T20:32:05.446Z INFO [main.py:create_env:509] Retrieved reference service arn:aws:ecs:ap-northeast-1:xxxxxxxxxxxx:service/dev/dev01-api
2019-04-08T20:32:05.484Z INFO [main.py:create_task_definition:58] Retrieved reference task definition from arn:aws:ecs:ap-northeast-1:xxxxxxxxxxxx:task-definition/dev01-api:15
2019-04-08T20:32:05.557Z INFO [main.py:create_task_definition:96] Registered new task definition: arn:aws:ecs:ap-northeast-1:xxxxxxxxxxxx:task-definition/dev-dynamic-test-create:1
2019-04-08T20:32:05.584Z INFO [main.py:create_target_group:112] Retrieved reference target group: arn:aws:elasticloadbalancing:ap-northeast-1:xxxxxxxxxxxx:targetgroup/dev01-api/9c68a5f91f34d9a4
2019-04-08T20:32:05.611Z INFO [main.py:create_target_group:125] Existing target group dev-dynamic-test-create not found, will create new
2019-04-08T20:32:06.247Z INFO [main.py:create_target_group:144] Created target group
2019-04-08T20:32:06.310Z INFO [main.py:create_alb_host_listener_rule:355] ELBv2 listener rule for target group arn:aws:elasticloadbalancing:ap-northeast-1:xxxxxxxxxxxx:targetgroup/dev-dynamic-test-create/b6918e6e5f10389d and host api-test.dev.example.com does not exist, will create new listener rule
2019-04-08T20:32:06.361Z INFO [main.py:create_env:554] ECS Service dev-dynamic-test-create does not exist, will create new service
2019-04-08T20:32:07.672Z INFO [main.py:check_record:414] Checking if record api-test.dev.example.com. exists in zone Zxxxxxxxxxxxx
2019-04-08T20:32:08.133Z INFO [main.py:create_cname_record:477] Successfully created ALIAS: api-test.dev.example.com -> dev-alb-api-dynamic-xxxxxxxxx.ap-northeast-1.elb.amazonaws.com
2019-04-08T20:32:08.134Z INFO [main.py:create_env:573] Successfully finished creating environment dev-dynamic-test-create
環境のステートがリモートのDynamoDBテーブルで管理されているため、eden CLIで環境の作成を確認できます:
$ eden ls
Profile api:
dev-dynamic-test-create api-test.dev.example.com (last updated: 2019-04-08T20:32:08.134469)
次のコマンドを実行して、この環境を削除しましょう:
curl https://eden.example.com/api/v1/delete?name=test&profile=api -H "x-api-key:YOURAPIKEY"
API Lambdaログは次のようになります:
2019-04-10T23:11:38.515Z INFO [main.py:check_record:495] Checking if record api-test.dev.example.com. exists in zone Zxxxxxxxxxxxx
2019-04-10T23:11:38.752Z INFO [main.py:check_record:506] Found existing record api-test.dev.example.com. in zone Zxxxxxxxxxxxx
2019-04-10T23:11:38.996Z INFO [main.py:delete_cname_record:596] Successfully removed ALIAS record api-test.dev.example.com
2019-04-10T23:11:39.245Z INFO [main.py:delete_env:665] ECS Service dev-dynamic-test exists, will delete
2019-04-10T23:11:39.401Z INFO [main.py:delete_env:670] Successfully deleted service dev-dynamic-test from cluster dev
2019-04-10T23:11:39.573Z INFO [main.py:delete_alb_host_listener_rule:397] ELBv2 listener rule for target group arn:aws:elasticloadbalancing:ap-northeast-1:xxxxxxxxxxxx:targetgroup/dev-dynamic-test/xxxxxxxx and host api-test.dev.example.com found, will delete
2019-04-10T23:11:40.483Z INFO [main.py:delete_env:697] Deleted all task definitions for family: dev-dynamic-test, 5 tasks deleted total
2019-04-10T23:11:40.483Z INFO [main.py:delete_env:700] Successfully finished deleting environment dev-dynamic-test