2019-01-07

Terraform を使って Django を ECS (Fargate) に自動デプロイしてみた!

前の記事 では、手動でデプロイしていましたが、 人間様がわざわざ AWSコンソールをポチポチやるなんて非効率ですし、いつかミスをするに決まっています。

そこで今回は Terraform を使って自動化してみることにします。

準備

必要なソフトウェアのインストールをします。

不要な場合は読み飛ばしてください。

tfenv

Terraform は活発に更新されているので バージョンアップによって仕様が変わり、不具合が発生しないとも言い切れません。

もちろん Terraform 単体でも動きますが、 tfenv を使うと案件ごとに Terraform のバージョンを使い分けられたりして便利なので積極的に使っていきたいです。

というわけでインストールします。

$ git clone https://github.com/tfutils/tfenv ~/.tfenv Cloning into '/home/righ/.tfenv'... remote: Enumerating objects: 725, done. remote: Total 725 (delta 0), reused 0 (delta 0), pack-reused 725 Receiving objects: 100% (725/725), 105.98 KiB | 384.00 KiB/s, done. Resolving deltas: 100% (453/453), done. $ echo 'export PATH="$HOME/.tfenv/bin:$PATH"' >> ~/.bash_profile $ tfenv install latest [INFO] Installing Terraform v0.12.0 [INFO] Downloading release tarball from https://releases.hashicorp.com/terraform/0.12.0/terraform_0.12.0_linux_amd64.zip ##O=-# # curl: (22) The requested URL returned error: 403 tfenv: tfenv-install: [ERROR] Tarball download failed

おや ..

0.12.0 をインストールしようとしたけどないだと

$ tfenv list * 0.11.11 (set by /home/righ/.tfenv/version) $ tfenv list-remote 0.12.0 0.11.11 0.11.9 0.11.9-beta1

ブラウザで見に行くと

うーん、この

現時点では 0.12.0 は出てないようなので、 0.11.11 をインストールします

tfenv install 0.11.11 [INFO] Installing Terraform v0.11.11 [INFO] Downloading release tarball from https://releases.hashicorp.com/terraform/0.11.11/terraform_0.11.11_linux_amd64.zip ######################################################################################################################## 100.0% [INFO] Downloading SHA hash file from https://releases.hashicorp.com/terraform/0.11.11/terraform_0.11.11_SHA256SUMS tfenv: tfenv-install: [WARN] No keybase install found, skipping GPG signature verification Archive: tfenv_download.KCaXZs/terraform_0.11.11_linux_amd64.zip inflating: /home/righ/.tfenv/versions/0.11.11/terraform [INFO] Installation of terraform v0.11.11 successful [INFO] Switching to v0.11.11 [INFO] Switching completed

OK ぽいです。

今回はとりあえず以下ののバージョンを使います

$ terraform --version Terraform v0.11.11

参考

tfenvでTerraformのバージョン管理をする - QiitatfenvはTerraformのバージョン管理を簡単にするために作ったツールです。rbenvにインスパイアされてます。現在複数の環境でTerraformを使ってて、それぞれ使っているバージョンが違…https://qiita.com/kamatama_41/items/ba59a070d8389aab7694 macOSで「dyld: Library not loaded: /usr/local/opt/readline/lib/libreadline.6.dylib」というエラーが出るようになった - そんな今日この頃の技術ネタ新しく買ったMacbook Proでhomebrewでansibleをインストールしようとした所、以下のようなエラーが出てきた。 dyld: Library not loaded: /usr/local/opt/readline/lib/libreadline.6.dylib じゃあってんでreadlineなるものをhomebrewでインストールしようとしたところ、既にインストールされていると出る。どうやらバージョンが7に進んだことで該当のライブラリが無くなったことが問題なようだ。 該当のパス/usr/local/opt/readline/lib/を確認すると7系は存在しそうなので、こいつのシ…https://blue1st-tech.hateblo.jp/entry/2017/09/16/230132

Terraform について

Terraform についてよく知らなかったのですこし勉強しました。 すで詳しい人は次のセクションまで飛ばしてください。

重要なポイントを自分なりに整理すると以下のような感じでしょうか。

  • 変数は variable で宣言できる
    • 環境変数や、実行時引数、 module の引数から値を渡すことができる
    • 指定しない場合 default が使われる
  • Terraform の実行単位はディレクトリ
    • デフォルトでは カレントディレクトリに配置された .tf ファイルをすべて読みこんで実行する
    • 別のディレクトリを読み込む場合は module を使う。(今回は使ってないけど)
      • module で読み込んだディレクトリに 自動的に変数は引き継がれないので、引数として渡す必要がある
        • source, version, providers は別の用途で使うので渡せないし、そもそも変数として使うべきではない
      • module で読み込んだディレクトリのリソース値を取得するには output を使う
  • <リソースの種類>.<リソース名>.<属性名> のようにして、リソースの属性値を参照できる
    • 作成されたリソースの属性も同様に参照できる
    • リソースの作成順は depends_on で制御できる

読み込みがディレクトリ単位というのは 少し特殊な概念なのでちゃんと理解しましょう。(Golangのパッケージっぽい)

参考

AWSでTerraformに入門 | DevelopersIOOSやミドルウェアの機能検証を実施した場合など、オンデマンドで一時的な検証環境を構築できるのもクラウドサービスの醍醐味です。 検証対象のOSやミドルウェアは異なれど、検証に必要な環境はある程度共通であることが少なくなく、 …https://dev.classmethod.jp/articles/terraform-getting-started-with-aws/ https://github.com/hashicorp/best-practices/tree/master/terraform/providers/aws Terraformにおけるディレクトリ構造のベストプラクティス | DevelopersIOはじめに こんにちは、中山です。 Terraformを使用していく中で、どのようなディレクトリ構造(tfファイルの配置方式)がベストなのかと考えたことはありませんか。私自身いろいろと試している最中なのですが、現時点で私が …https://dev.classmethod.jp/articles/directory-layout-bestpractice-in-terraform/ Terraform職人入門: 日々の運用で学んだ知見を淡々とまとめる - Qiitaはじめにこの記事は CrowdWorks Advent Calendar 2017 の8日目の記事です。Terraform職人の @minamijoyo です。Infrastructure as…https://qiita.com/minamijoyo/items/1f57c62bed781ab8f4d7

ECSにアプリをデプロイする

Django を ECS(Fargate) に手動デプロイしたログ のシナリオと同様にサンプル用アプリケーションを ECS にデプロイします。

さて、単に Terraform を使ってデプロイすると言っても、 すべてのリソースを毎回作成する必要があるとは限りません。

例えば、ECR のコンテナリポジトリは一度作成すればよく、 すでにある状態で作成しようとするとエラーになります。

そこで「初回のみ作成するリソース」と「毎回作成するリソース」に わけ、前者は init というディレクトリの中に作成します。

このように、用途別にディレクトリを区切るのが Terraform のやり方のようです。

今回は次のような構成にしました。 わかりやすさ重視なので、ベストプラクティスには従っていません。

setup/
  • init/
info
  • PostgreSQL を指定して aws_db_instance.db: Error creating DB Instance: InvalidParameterValue: Invalid DB engine と言われたら postgres を指定する
  • 今回利用するユーザが属するグループは AdministratorAccess ポリシーを持っているものとします。

初期化デプロイ

まずは初回のみ必要なデプロイを行います。 初回しか必要ないので手動でもいいと思いますが、今回は敢えて Terraform でやります。

Dockerリポジトリの作成 (とイメージのPush) だけです。

何故かDNS認証がうまくいかなかったので証明書は作りませんでした..

$ cd init/ # バックエンドの初期化 $ terraform init Initializing provider plugins... - Checking for available provider plugins on https://releases.hashicorp.com... - Downloading plugin for provider "aws" (1.54.0)... The following providers do not have any version constraints in configuration, so the latest version was installed. To prevent automatic upgrades to new major versions that may contain breaking changes, it is recommended to add version = "..." constraints to the corresponding provider blocks in configuration, with the constraint strings suggested below. * provider.aws: version = "~> 1.54" Terraform has been successfully initialized! You may now begin working with Terraform. Try running "terraform plan" to see any changes that are required for your infrastructure. All Terraform commands should now work. If you ever set or change modules or backend configuration for Terraform, rerun this command to reinitialize your working directory. If you forget, other commands will detect it and remind you to do so if necessary.
$ terraform apply -var "access_key=XXXXXXXXXXXXXXXXXXXX" -var "secret_key=YYYYYYYYYYYYYYYYYYYYYYYYYYYY" aws_ecr_repository.nginx-repo: Refreshing state... (ID: djample-nginx) aws_ecr_repository.app-repo: Refreshing state... (ID: djample-app) aws_acm_certificate.cert: Refreshing state... (ID: arn:aws:acm:us-west-2:XXXXXXXXXXXX:cert...e/322dc8e9-26d1-41ef-ba64-53da42641ebe) An execution plan has been generated and is shown below. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: + aws_ecr_repository.app-repo id: <computed> arn: <computed> name: "djample-app" registry_id: <computed> repository_url: <computed> + aws_ecr_repository.nginx-repo id: <computed> arn: <computed> name: "djample-nginx" registry_id: <computed> repository_url: <computed> Plan: 2 to add, 0 to change, 0 to destroy. Do you want to perform these actions? Terraform will perform the actions described above. Only 'yes' will be accepted to approve. Enter a value: yes aws_ecr_repository.app-repo: Creating... arn: "" => "<computed>" name: "" => "djample-app" registry_id: "" => "<computed>" repository_url: "" => "<computed>" aws_ecr_repository.nginx-repo: Creating... arn: "" => "<computed>" name: "" => "djample-nginx" registry_id: "" => "<computed>" repository_url: "" => "<computed>" aws_ecr_repository.app-repo: Creation complete after 2s (ID: djample-app) aws_ecr_repository.nginx-repo: Creation complete after 2s (ID: djample-nginx) Apply complete! Resources: 2 added, 0 changed, 0 destroyed. Outputs: app-repo-url = XXXXXXXXXXXX.dkr.ecr.us-west-2.amazonaws.com/djample-app nginx-repo-url = XXXXXXXXXXXX.dkr.ecr.us-west-2.amazonaws.com/djample-nginx

続いて、イメージと作成したリポジトリを紐づけ、PUSHします (ここは前回と同様です)

# docker に AWS認証情報を登録 $ $(aws --profile djample ecr get-login --no-include-email --region us-west-2) WARNING! Using --password via the CLI is insecure. Use --password-stdin. Login Succeeded # リポジトリとイメージを紐付けてPUSHする $ docker tag djample-app:latest XXXXXXXXXXXX.dkr.ecr.us-west-2.amazonaws.com/djample-app:latest $ docker push XXXXXXXXXXXX.dkr.ecr.us-west-2.amazonaws.com/djample-app:latest The push refers to repository [XXXXXXXXXXXX.dkr.ecr.us-west-2.amazonaws.com/djample-app] 6836c8c88b45: Pushed 615d45681fa6: Pushed 15b6883e063f: Pushed c5eee45b9f53: Pushed 8e771df6e17b: Pushed dab2c9255521: Pushed 016210a3d295: Pushed ef7a479213de: Pushed 374f3534200b: Pushed 8fec0692e6a1: Pushed 219d5a9f3bbe: Pushed 67b9b2a215ea: Pushed 956940650d5d: Pushed latest: digest: sha256:6e78416aee66fd997e9d3eacb15ee602a14dba76a72fcb0dbc100dcd39f4c6f8 size: 3031 # Nginx も同様にやる $ docker tag djample-nginx:latest XXXXXXXXXXXX.dkr.ecr.us-west-2.amazonaws.com/djample-nginx:latest $ docker push XXXXXXXXXXXX.dkr.ecr.us-west-2.amazonaws.com/djample-nginx:latest The push refers to repository [XXXXXXXXXXXX.dkr.ecr.us-west-2.amazonaws.com/djample-nginx] f514a6aae98f: Pushed 82544808b996: Pushed 942f421fc8f4: Pushed 67f95e015a50: Pushed 3803fdb990e6: Pushed 5871f1dd9014: Pushed 4cc529071e3b: Pushed cdb3f9544e4c: Pushed latest: digest: sha256:8b467500656e208d712a8ae7cb25f13896cf81e207d891469e9848b8da6f7d93 size: 1987

アプリをデプロイする

最後にアプリをデプロイします

$ cd ../ # バックエンドの初期化 $ terraform init Initializing provider plugins... - Checking for available provider plugins on https://releases.hashicorp.com... - Downloading plugin for provider "aws" (1.54.0)... - Downloading plugin for provider "template" (1.0.0)... The following providers do not have any version constraints in configuration, so the latest version was installed. To prevent automatic upgrades to new major versions that may contain breaking changes, it is recommended to add version = "..." constraints to the corresponding provider blocks in configuration, with the constraint strings suggested below. * provider.aws: version = "~> 1.54" * provider.template: version = "~> 1.0" Terraform has been successfully initialized! You may now begin working with Terraform. Try running "terraform plan" to see any changes that are required for your infrastructure. All Terraform commands should now work. If you ever set or change modules or backend configuration for Terraform, rerun this command to reinitialize your working directory. If you forget, other commands will detect it and remind you to do so if necessary.
$ terraform apply -var "access_key=XXXXXXXXXXXXXXXXXXXXXXXX" -var "secret_key=YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY" data.aws_ecr_repository.nginx: Refreshing state... data.aws_ecr_repository.app: Refreshing state... An execution plan has been generated and is shown below. Resource actions are indicated with the following symbols: + create <= read (data resources) Terraform will perform the following actions: <= data.template_file.djample-web-containers id: <computed> rendered: <computed> template: "[\n {\n \"portMappings\": [\n {\n \"hostPort\": 3031,\n \"protocol\": \"tcp\",\n \"containerPort\": 3031\n }\n ],\n \"environment\": [\n {\n \"name\": \"DJANGO_DATABASES__default__ENGINE\",\n \"value\": \"django.db.backends.postgresql\"\n },\n {\n \"name\": \"DJANGO_DATABASES__default__HOST\",\n \"value\": \"${db_host}\"\n },\n {\n \"name\": \"DJANGO_DATABASES__default__NAME\",\n \"value\": \"${db_name}\"\n },\n {\n \"name\": \"DJANGO_DATABASES__default__PASSWORD\",\n \"value\": \"${db_password}\"\n },\n {\n \"name\": \"DJANGO_DATABASES__default__PORT\",\n \"value\": \"${db_port}\"\n },\n {\n \"name\": \"DJANGO_DATABASES__default__USER\",\n \"value\": \"${db_user}\"\n }\n ],\n \"image\": \"${image_app}\",\n \"essential\": true,\n \"name\": \"djample-app\"\n },\n {\n \"portMappings\": [\n {\n \"hostPort\": 80,\n \"protocol\": \"tcp\",\n \"containerPort\": 80\n }\n ],\n \"environment\": [],\n \"image\": \"${image_nginx}\",\n \"essential\": true,\n \"name\": \"djample-nginx\"\n }\n]" vars.%: <computed> + aws_alb.default id: <computed> access_logs.#: <computed> arn: <computed> arn_suffix: <computed> dns_name: <computed> enable_deletion_protection: "false" enable_http2: "true" idle_timeout: "60" internal: "false" ip_address_type: <computed> load_balancer_type: "application" name: "djample-alb" security_groups.#: <computed> subnet_mapping.#: <computed> subnets.#: <computed> vpc_id: <computed> zone_id: <computed> + aws_alb_listener.http id: <computed> arn: <computed> default_action.#: "1" default_action.0.order: <computed> default_action.0.target_group_arn: "${aws_alb_target_group.default.arn}" default_action.0.type: "forward" load_balancer_arn: "${aws_alb.default.arn}" port: "80" protocol: "HTTP" ssl_policy: <computed> + aws_alb_target_group.default id: <computed> arn: <computed> arn_suffix: <computed> deregistration_delay: "300" health_check.#: "1" health_check.0.healthy_threshold: "3" health_check.0.interval: "30" health_check.0.matcher: <computed> health_check.0.path: "/" health_check.0.port: "traffic-port" health_check.0.protocol: "HTTP" health_check.0.timeout: <computed> health_check.0.unhealthy_threshold: "3" name: "djample-target-group" port: "80" protocol: "HTTP" proxy_protocol_v2: "false" slow_start: "0" stickiness.#: <computed> target_type: "ip" vpc_id: "${aws_vpc.default.id}" + aws_db_instance.default id: <computed> address: <computed> allocated_storage: "10" apply_immediately: <computed> arn: <computed> auto_minor_version_upgrade: "true" availability_zone: <computed> backup_retention_period: <computed> backup_window: <computed> ca_cert_identifier: <computed> character_set_name: <computed> copy_tags_to_snapshot: "false" db_subnet_group_name: "test-db-subnet" endpoint: <computed> engine: "postgres" engine_version: "10.4" hosted_zone_id: <computed> identifier: "djample" identifier_prefix: <computed> instance_class: "db.t2.micro" kms_key_id: <computed> license_model: <computed> maintenance_window: <computed> monitoring_interval: "0" monitoring_role_arn: <computed> multi_az: <computed> name: "djampledb" option_group_name: <computed> parameter_group_name: "${aws_db_parameter_group.default.id}" password: <sensitive> port: <computed> publicly_accessible: "false" replicas.#: <computed> resource_id: <computed> skip_final_snapshot: "true" status: <computed> storage_type: "gp2" timezone: <computed> username: "djampleuser" vpc_security_group_ids.#: <computed> + aws_db_parameter_group.default id: <computed> arn: <computed> description: " "djample postgresql parameter"" family: "postgres10" name: "djample-parameter-group" name_prefix: <computed> parameter.#: "1" parameter.3863681210.apply_method: "immediate" parameter.3863681210.name: "log_min_duration_statement" parameter.3863681210.value: "100" + aws_db_subnet_group.default id: <computed> arn: <computed> description: " "test db subnet"" name: "test-db-subnet" name_prefix: <computed> subnet_ids.#: <computed> + aws_ecs_cluster.default id: <computed> arn: <computed> name: "djample-cluster" + aws_ecs_service.web id: <computed> cluster: "${aws_ecs_cluster.default.id}" deployment_maximum_percent: "200" deployment_minimum_healthy_percent: "100" desired_count: "1" enable_ecs_managed_tags: "false" iam_role: <computed> launch_type: "FARGATE" load_balancer.#: "1" load_balancer.~563643602.container_name: "djample-nginx" load_balancer.~563643602.container_port: "80" load_balancer.~563643602.elb_name: "" load_balancer.~563643602.target_group_arn: "${aws_alb_target_group.default.arn}" name: "djample-web-service" network_configuration.#: "1" network_configuration.0.assign_public_ip: "true" network_configuration.0.security_groups.#: <computed> network_configuration.0.subnets.#: <computed> scheduling_strategy: "REPLICA" task_definition: "${aws_ecs_task_definition.web.arn}" + aws_ecs_task_definition.web id: <computed> arn: <computed> container_definitions: "${data.template_file.djample-web-containers.rendered}" cpu: "256" execution_role_arn: "${aws_iam_role.default.arn}" family: "djample-web-task" memory: "512" network_mode: "awsvpc" requires_compatibilities.#: "1" requires_compatibilities.3072437307: "FARGATE" revision: <computed> task_role_arn: "${aws_iam_role.default.arn}" + aws_iam_role.default id: <computed> arn: <computed> assume_role_policy: "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Sid\": \"\",\n \"Effect\": \"Allow\",\n \"Principal\": {\n \"Service\": \"ecs-tasks.amazonaws.com\"\n },\n \"Action\": \"sts:AssumeRole\"\n }\n ]\n}\n" create_date: <computed> force_detach_policies: "false" max_session_duration: "3600" name: "assume_role" path: "/" unique_id: <computed> + aws_iam_role_policy.default id: <computed> name: "assume_role_policy" policy: "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Effect\": \"Allow\",\n \"Action\": \"*\",\n \"Resource\": \"*\"\n }\n ]\n}\n" role: "${aws_iam_role.default.id}" + aws_internet_gateway.default id: <computed> owner_id: <computed> tags.%: "1" tags.Name: "djample-igw" vpc_id: "${aws_vpc.default.id}" + aws_route_table.default id: <computed> owner_id: <computed> propagating_vgws.#: <computed> route.#: "1" route.~570683813.cidr_block: "0.0.0.0/0" route.~570683813.egress_only_gateway_id: "" route.~570683813.gateway_id: "${aws_internet_gateway.default.id}" route.~570683813.instance_id: "" route.~570683813.ipv6_cidr_block: "" route.~570683813.nat_gateway_id: "" route.~570683813.network_interface_id: "" route.~570683813.transit_gateway_id: "" route.~570683813.vpc_peering_connection_id: "" tags.%: "1" tags.Name: "main" vpc_id: "${aws_vpc.default.id}" + aws_route_table_association.a1 id: <computed> route_table_id: "${aws_route_table.default.id}" subnet_id: "${aws_subnet.default1.id}" + aws_route_table_association.a2 id: <computed> route_table_id: "${aws_route_table.default.id}" subnet_id: "${aws_subnet.default2.id}" + aws_route_table_association.a3 id: <computed> route_table_id: "${aws_route_table.default.id}" subnet_id: "${aws_subnet.default3.id}" + aws_security_group.db id: <computed> arn: <computed> description: " "Allow traffic for db"" egress.#: "1" egress.482069346.cidr_blocks.#: "1" egress.482069346.cidr_blocks.0: "0.0.0.0/0" egress.482069346.description: "" egress.482069346.from_port: "0" egress.482069346.ipv6_cidr_blocks.#: "0" egress.482069346.prefix_list_ids.#: "0" egress.482069346.protocol: "-1" egress.482069346.security_groups.#: "0" egress.482069346.self: "false" egress.482069346.to_port: "0" ingress.#: "1" ingress.~2994424545.cidr_blocks.#: "0" ingress.~2994424545.description: "" ingress.~2994424545.from_port: "5432" ingress.~2994424545.ipv6_cidr_blocks.#: "0" ingress.~2994424545.prefix_list_ids.#: "0" ingress.~2994424545.protocol: "tcp" ingress.~2994424545.security_groups.#: <computed> ingress.~2994424545.self: "false" ingress.~2994424545.to_port: "5432" name: "djample-db-sg" owner_id: <computed> revoke_rules_on_delete: "false" vpc_id: "${aws_vpc.default.id}" + aws_security_group.web id: <computed> arn: <computed> description: " "Allow traffic for web"" egress.#: "1" egress.482069346.cidr_blocks.#: "1" egress.482069346.cidr_blocks.0: "0.0.0.0/0" egress.482069346.description: "" egress.482069346.from_port: "0" egress.482069346.ipv6_cidr_blocks.#: "0" egress.482069346.prefix_list_ids.#: "0" egress.482069346.protocol: "-1" egress.482069346.security_groups.#: "0" egress.482069346.self: "false" egress.482069346.to_port: "0" ingress.#: "2" ingress.2214680975.cidr_blocks.#: "1" ingress.2214680975.cidr_blocks.0: "0.0.0.0/0" ingress.2214680975.description: "" ingress.2214680975.from_port: "80" ingress.2214680975.ipv6_cidr_blocks.#: "0" ingress.2214680975.prefix_list_ids.#: "0" ingress.2214680975.protocol: "tcp" ingress.2214680975.security_groups.#: "0" ingress.2214680975.self: "false" ingress.2214680975.to_port: "80" ingress.2617001939.cidr_blocks.#: "1" ingress.2617001939.cidr_blocks.0: "0.0.0.0/0" ingress.2617001939.description: "" ingress.2617001939.from_port: "443" ingress.2617001939.ipv6_cidr_blocks.#: "0" ingress.2617001939.prefix_list_ids.#: "0" ingress.2617001939.protocol: "tcp" ingress.2617001939.security_groups.#: "0" ingress.2617001939.self: "false" ingress.2617001939.to_port: "443" name: "djample-web-sg" owner_id: <computed> revoke_rules_on_delete: "false" vpc_id: "${aws_vpc.default.id}" + aws_subnet.default1 id: <computed> arn: <computed> assign_ipv6_address_on_creation: "false" availability_zone: "us-west-2a" availability_zone_id: <computed> cidr_block: "10.0.1.0/24" ipv6_cidr_block: <computed> ipv6_cidr_block_association_id: <computed> map_public_ip_on_launch: "false" owner_id: <computed> vpc_id: "${aws_vpc.default.id}" + aws_subnet.default2 id: <computed> arn: <computed> assign_ipv6_address_on_creation: "false" availability_zone: "us-west-2b" availability_zone_id: <computed> cidr_block: "10.0.2.0/24" ipv6_cidr_block: <computed> ipv6_cidr_block_association_id: <computed> map_public_ip_on_launch: "false" owner_id: <computed> vpc_id: "${aws_vpc.default.id}" + aws_subnet.default3 id: <computed> arn: <computed> assign_ipv6_address_on_creation: "false" availability_zone: "us-west-2c" availability_zone_id: <computed> cidr_block: "10.0.3.0/24" ipv6_cidr_block: <computed> ipv6_cidr_block_association_id: <computed> map_public_ip_on_launch: "false" owner_id: <computed> vpc_id: "${aws_vpc.default.id}" + aws_vpc.default id: <computed> arn: <computed> assign_generated_ipv6_cidr_block: "false" cidr_block: "10.0.0.0/16" default_network_acl_id: <computed> default_route_table_id: <computed> default_security_group_id: <computed> dhcp_options_id: <computed> enable_classiclink: <computed> enable_classiclink_dns_support: <computed> enable_dns_hostnames: <computed> enable_dns_support: "true" instance_tenancy: "default" ipv6_association_id: <computed> ipv6_cidr_block: <computed> main_route_table_id: <computed> owner_id: <computed> Plan: 22 to add, 0 to change, 0 to destroy. Do you want to perform these actions? Terraform will perform the actions described above. Only 'yes' will be accepted to approve. Enter a value: yes aws_iam_role.default: Creating... arn: "" => "<computed>" assume_role_policy: "" => "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Sid\": \"\",\n \"Effect\": \"Allow\",\n \"Principal\": {\n \"Service\": \"ecs-tasks.amazonaws.com\"\n },\n \"Action\": \"sts:AssumeRole\"\n }\n ]\n}\n" create_date: "" => "<computed>" force_detach_policies: "" => "false" max_session_duration: "" => "3600" name: "" => "assume_role" path: "" => "/" unique_id: "" => "<computed>" aws_ecs_cluster.default: Creating... arn: "" => "<computed>" name: "" => "djample-cluster" aws_db_parameter_group.default: Creating... arn: "" => "<computed>" description: "" => "djample postgresql parameter" family: "" => "postgres10" name: "" => "djample-parameter-group" name_prefix: "" => "<computed>" parameter.#: "" => "1" parameter.3863681210.apply_method: "" => "immediate" parameter.3863681210.name: "" => "log_min_duration_statement" parameter.3863681210.value: "" => "100" aws_vpc.default: Creating... arn: "" => "<computed>" assign_generated_ipv6_cidr_block: "" => "false" cidr_block: "" => "10.0.0.0/16" default_network_acl_id: "" => "<computed>" default_route_table_id: "" => "<computed>" default_security_group_id: "" => "<computed>" dhcp_options_id: "" => "<computed>" enable_classiclink: "" => "<computed>" enable_classiclink_dns_support: "" => "<computed>" enable_dns_hostnames: "" => "<computed>" enable_dns_support: "" => "true" instance_tenancy: "" => "default" ipv6_association_id: "" => "<computed>" ipv6_cidr_block: "" => "<computed>" main_route_table_id: "" => "<computed>" owner_id: "" => "<computed>" aws_ecs_cluster.default: Creation complete after 3s (ID: arn:aws:ecs:us-west-2:XXXXXXXXXXXX:cluster/djample-cluster) aws_iam_role.default: Creation complete after 3s (ID: assume_role) aws_iam_role_policy.default: Creating... name: "" => "assume_role_policy" policy: "" => "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Effect\": \"Allow\",\n \"Action\": \"*\",\n \"Resource\": \"*\"\n }\n ]\n}\n" role: "" => "assume_role" aws_iam_role_policy.default: Creation complete after 1s (ID: assume_role:assume_role_policy) aws_db_parameter_group.default: Creation complete after 7s (ID: djample-parameter-group) aws_vpc.default: Creation complete after 10s (ID: vpc-06346176fa149789f) aws_subnet.default3: Creating... arn: "" => "<computed>" assign_ipv6_address_on_creation: "" => "false" availability_zone: "" => "us-west-2c" availability_zone_id: "" => "<computed>" cidr_block: "" => "10.0.3.0/24" ipv6_cidr_block: "" => "<computed>" ipv6_cidr_block_association_id: "" => "<computed>" map_public_ip_on_launch: "" => "false" owner_id: "" => "<computed>" vpc_id: "" => "vpc-06346176fa149789f" aws_subnet.default1: Creating... arn: "" => "<computed>" assign_ipv6_address_on_creation: "" => "false" availability_zone: "" => "us-west-2a" availability_zone_id: "" => "<computed>" cidr_block: "" => "10.0.1.0/24" ipv6_cidr_block: "" => "<computed>" ipv6_cidr_block_association_id: "" => "<computed>" map_public_ip_on_launch: "" => "false" owner_id: "" => "<computed>" vpc_id: "" => "vpc-06346176fa149789f" aws_subnet.default2: Creating... arn: "" => "<computed>" assign_ipv6_address_on_creation: "" => "false" availability_zone: "" => "us-west-2b" availability_zone_id: "" => "<computed>" cidr_block: "" => "10.0.2.0/24" ipv6_cidr_block: "" => "<computed>" ipv6_cidr_block_association_id: "" => "<computed>" map_public_ip_on_launch: "" => "false" owner_id: "" => "<computed>" vpc_id: "" => "vpc-06346176fa149789f" aws_internet_gateway.default: Creating... owner_id: "" => "<computed>" tags.%: "0" => "1" tags.Name: "" => "djample-igw" vpc_id: "" => "vpc-06346176fa149789f" aws_security_group.web: Creating... arn: "" => "<computed>" description: "" => "Allow traffic for web" egress.#: "" => "1" egress.482069346.cidr_blocks.#: "" => "1" egress.482069346.cidr_blocks.0: "" => "0.0.0.0/0" egress.482069346.description: "" => "" egress.482069346.from_port: "" => "0" egress.482069346.ipv6_cidr_blocks.#: "" => "0" egress.482069346.prefix_list_ids.#: "" => "0" egress.482069346.protocol: "" => "-1" egress.482069346.security_groups.#: "" => "0" egress.482069346.self: "" => "false" egress.482069346.to_port: "" => "0" ingress.#: "" => "2" ingress.2214680975.cidr_blocks.#: "" => "1" ingress.2214680975.cidr_blocks.0: "" => "0.0.0.0/0" ingress.2214680975.description: "" => "" ingress.2214680975.from_port: "" => "80" ingress.2214680975.ipv6_cidr_blocks.#: "" => "0" ingress.2214680975.prefix_list_ids.#: "" => "0" ingress.2214680975.protocol: "" => "tcp" ingress.2214680975.security_groups.#: "" => "0" ingress.2214680975.self: "" => "false" ingress.2214680975.to_port: "" => "80" ingress.2617001939.cidr_blocks.#: "" => "1" ingress.2617001939.cidr_blocks.0: "" => "0.0.0.0/0" ingress.2617001939.description: "" => "" ingress.2617001939.from_port: "" => "443" ingress.2617001939.ipv6_cidr_blocks.#: "" => "0" ingress.2617001939.prefix_list_ids.#: "" => "0" ingress.2617001939.protocol: "" => "tcp" ingress.2617001939.security_groups.#: "" => "0" ingress.2617001939.self: "" => "false" ingress.2617001939.to_port: "" => "443" name: "" => "djample-web-sg" owner_id: "" => "<computed>" revoke_rules_on_delete: "" => "false" vpc_id: "" => "vpc-06346176fa149789f" aws_alb_target_group.default: Creating... arn: "" => "<computed>" arn_suffix: "" => "<computed>" deregistration_delay: "" => "300" health_check.#: "" => "1" health_check.0.healthy_threshold: "" => "3" health_check.0.interval: "" => "30" health_check.0.matcher: "" => "<computed>" health_check.0.path: "" => "/" health_check.0.port: "" => "traffic-port" health_check.0.protocol: "" => "HTTP" health_check.0.timeout: "" => "<computed>" health_check.0.unhealthy_threshold: "" => "3" name: "" => "djample-target-group" port: "" => "80" protocol: "" => "HTTP" proxy_protocol_v2: "" => "false" slow_start: "" => "0" stickiness.#: "" => "<computed>" target_type: "" => "ip" vpc_id: "" => "vpc-06346176fa149789f" aws_subnet.default1: Creation complete after 2s (ID: subnet-08022d6c8417edca8) aws_subnet.default3: Creation complete after 2s (ID: subnet-0b2b0c2e4ae1f2a66) aws_subnet.default2: Creation complete after 2s (ID: subnet-09d44ac8bf7c95769) aws_db_subnet_group.default: Creating... arn: "" => "<computed>" description: "" => "test db subnet" name: "" => "test-db-subnet" name_prefix: "" => "<computed>" subnet_ids.#: "" => "3" subnet_ids.2370142301: "" => "subnet-0b2b0c2e4ae1f2a66" subnet_ids.2494457805: "" => "subnet-09d44ac8bf7c95769" subnet_ids.3574656835: "" => "subnet-08022d6c8417edca8" aws_internet_gateway.default: Creation complete after 4s (ID: igw-04a6eb2ff12954c0e) aws_route_table.default: Creating... owner_id: "" => "<computed>" propagating_vgws.#: "" => "<computed>" route.#: "" => "1" route.2780151265.cidr_block: "" => "0.0.0.0/0" route.2780151265.egress_only_gateway_id: "" => "" route.2780151265.gateway_id: "" => "igw-04a6eb2ff12954c0e" route.2780151265.instance_id: "" => "" route.2780151265.ipv6_cidr_block: "" => "" route.2780151265.nat_gateway_id: "" => "" route.2780151265.network_interface_id: "" => "" route.2780151265.transit_gateway_id: "" => "" route.2780151265.vpc_peering_connection_id: "" => "" tags.%: "" => "1" tags.Name: "" => "main" vpc_id: "" => "vpc-06346176fa149789f" aws_alb_target_group.default: Creation complete after 4s (ID: arn:aws:elasticloadbalancing:us-west-2:.../djample-target-group/0cf7190ec2060917) aws_db_subnet_group.default: Creation complete after 3s (ID: test-db-subnet) aws_security_group.web: Creation complete after 6s (ID: sg-085110806fab80ae0) aws_security_group.db: Creating... arn: "" => "<computed>" description: "" => "Allow traffic for db" egress.#: "" => "1" egress.482069346.cidr_blocks.#: "" => "1" egress.482069346.cidr_blocks.0: "" => "0.0.0.0/0" egress.482069346.description: "" => "" egress.482069346.from_port: "" => "0" egress.482069346.ipv6_cidr_blocks.#: "" => "0" egress.482069346.prefix_list_ids.#: "" => "0" egress.482069346.protocol: "" => "-1" egress.482069346.security_groups.#: "" => "0" egress.482069346.self: "" => "false" egress.482069346.to_port: "" => "0" ingress.#: "" => "1" ingress.1726492711.cidr_blocks.#: "" => "0" ingress.1726492711.description: "" => "" ingress.1726492711.from_port: "" => "5432" ingress.1726492711.ipv6_cidr_blocks.#: "" => "0" ingress.1726492711.prefix_list_ids.#: "" => "0" ingress.1726492711.protocol: "" => "tcp" ingress.1726492711.security_groups.#: "" => "1" ingress.1726492711.security_groups.2467559028: "" => "sg-085110806fab80ae0" ingress.1726492711.self: "" => "false" ingress.1726492711.to_port: "" => "5432" name: "" => "djample-db-sg" owner_id: "" => "<computed>" revoke_rules_on_delete: "" => "false" vpc_id: "" => "vpc-06346176fa149789f" aws_alb.default: Creating... access_logs.#: "" => "<computed>" arn: "" => "<computed>" arn_suffix: "" => "<computed>" dns_name: "" => "<computed>" enable_deletion_protection: "" => "false" enable_http2: "" => "true" idle_timeout: "" => "60" internal: "" => "false" ip_address_type: "" => "<computed>" load_balancer_type: "" => "application" name: "" => "djample-alb" security_groups.#: "" => "1" security_groups.2467559028: "" => "sg-085110806fab80ae0" subnet_mapping.#: "" => "<computed>" subnets.#: "" => "3" subnets.2370142301: "" => "subnet-0b2b0c2e4ae1f2a66" subnets.2494457805: "" => "subnet-09d44ac8bf7c95769" subnets.3574656835: "" => "subnet-08022d6c8417edca8" vpc_id: "" => "<computed>" zone_id: "" => "<computed>" aws_route_table.default: Creation complete after 4s (ID: rtb-0948f223bd8f3791d) aws_route_table_association.a1: Creating... route_table_id: "" => "rtb-0948f223bd8f3791d" subnet_id: "" => "subnet-08022d6c8417edca8" aws_route_table_association.a2: Creating... route_table_id: "" => "rtb-0948f223bd8f3791d" subnet_id: "" => "subnet-09d44ac8bf7c95769" aws_route_table_association.a3: Creating... route_table_id: "" => "rtb-0948f223bd8f3791d" subnet_id: "" => "subnet-0b2b0c2e4ae1f2a66" aws_route_table_association.a1: Creation complete after 0s (ID: rtbassoc-0b66b625616f40b40) aws_route_table_association.a2: Creation complete after 1s (ID: rtbassoc-0e50b908e3f8214db) aws_route_table_association.a3: Creation complete after 1s (ID: rtbassoc-02dea821a448a1ac6) aws_security_group.db: Creation complete after 7s (ID: sg-05442bb3a6ccef9cc) aws_db_instance.default: Creating... address: "" => "<computed>" allocated_storage: "" => "10" apply_immediately: "" => "<computed>" arn: "" => "<computed>" auto_minor_version_upgrade: "" => "true" availability_zone: "" => "<computed>" backup_retention_period: "" => "<computed>" backup_window: "" => "<computed>" ca_cert_identifier: "" => "<computed>" character_set_name: "" => "<computed>" copy_tags_to_snapshot: "" => "false" db_subnet_group_name: "" => "test-db-subnet" endpoint: "" => "<computed>" engine: "" => "postgres" engine_version: "" => "10.4" hosted_zone_id: "" => "<computed>" identifier: "" => "djample" identifier_prefix: "" => "<computed>" instance_class: "" => "db.t2.micro" kms_key_id: "" => "<computed>" license_model: "" => "<computed>" maintenance_window: "" => "<computed>" monitoring_interval: "" => "0" monitoring_role_arn: "" => "<computed>" multi_az: "" => "<computed>" name: "" => "djampledb" option_group_name: "" => "<computed>" parameter_group_name: "" => "djample-parameter-group" password: "<sensitive>" => "<sensitive>" port: "" => "<computed>" publicly_accessible: "" => "false" replicas.#: "" => "<computed>" resource_id: "" => "<computed>" skip_final_snapshot: "" => "true" status: "" => "<computed>" storage_type: "" => "gp2" timezone: "" => "<computed>" username: "" => "djampleuser" vpc_security_group_ids.#: "" => "1" vpc_security_group_ids.1275660647: "" => "sg-05442bb3a6ccef9cc" aws_alb.default: Still creating... (10s elapsed) aws_db_instance.default: Still creating... (10s elapsed) aws_alb.default: Still creating... (20s elapsed) aws_db_instance.default: Still creating... (20s elapsed) aws_alb.default: Still creating... (30s elapsed) aws_db_instance.default: Still creating... (30s elapsed) aws_alb.default: Still creating... (40s elapsed) aws_db_instance.default: Still creating... (40s elapsed) aws_alb.default: Still creating... (50s elapsed) aws_db_instance.default: Still creating... (50s elapsed) aws_alb.default: Still creating... (1m0s elapsed) aws_db_instance.default: Still creating... (1m0s elapsed) aws_alb.default: Still creating... (1m10s elapsed) aws_db_instance.default: Still creating... (1m10s elapsed) aws_alb.default: Still creating... (1m20s elapsed) aws_db_instance.default: Still creating... (1m20s elapsed) aws_alb.default: Still creating... (1m30s elapsed) aws_db_instance.default: Still creating... (1m30s elapsed) aws_alb.default: Still creating... (1m40s elapsed) aws_db_instance.default: Still creating... (1m40s elapsed) aws_alb.default: Still creating... (1m50s elapsed) aws_db_instance.default: Still creating... (1m50s elapsed) aws_alb.default: Still creating... (2m0s elapsed) aws_db_instance.default: Still creating... (2m0s elapsed) aws_alb.default: Still creating... (2m10s elapsed) aws_db_instance.default: Still creating... (2m10s elapsed) aws_alb.default: Still creating... (2m20s elapsed) aws_db_instance.default: Still creating... (2m20s elapsed) aws_alb.default: Still creating... (2m30s elapsed) aws_db_instance.default: Still creating... (2m30s elapsed) aws_alb.default: Still creating... (2m40s elapsed) aws_db_instance.default: Still creating... (2m40s elapsed) aws_alb.default: Still creating... (2m50s elapsed) aws_db_instance.default: Still creating... (2m50s elapsed) aws_alb.default: Still creating... (3m0s elapsed) aws_db_instance.default: Still creating... (3m0s elapsed) aws_alb.default: Still creating... (3m10s elapsed) aws_db_instance.default: Still creating... (3m10s elapsed) aws_alb.default: Still creating... (3m20s elapsed) aws_db_instance.default: Still creating... (3m20s elapsed) aws_alb.default: Still creating... (3m30s elapsed) aws_alb.default: Creation complete after 3m36s (ID: arn:aws:elasticloadbalancing:us-west-2:...ancer/app/djample-alb/4046b85f0d60d20d) aws_alb_listener.http: Creating... arn: "" => "<computed>" default_action.#: "" => "1" default_action.0.order: "" => "<computed>" default_action.0.target_group_arn: "" => "arn:aws:elasticloadbalancing:us-west-2:XXXXXXXXXXXX:targetgroup/djample-target-group/0cf7190ec2060917" default_action.0.type: "" => "forward" load_balancer_arn: "" => "arn:aws:elasticloadbalancing:us-west-2:XXXXXXXXXXXX:loadbalancer/app/djample-alb/4046b85f0d60d20d" port: "" => "80" protocol: "" => "HTTP" ssl_policy: "" => "<computed>" aws_db_instance.default: Still creating... (3m30s elapsed) aws_alb_listener.http: Creation complete after 1s (ID: arn:aws:elasticloadbalancing:us-west-2:...-alb/4046b85f0d60d20d/c2bc0c68eafdb2a9) aws_db_instance.default: Still creating... (3m40s elapsed) aws_db_instance.default: Still creating... (3m50s elapsed) aws_db_instance.default: Still creating... (4m0s elapsed) aws_db_instance.default: Still creating... (4m10s elapsed) aws_db_instance.default: Still creating... (4m20s elapsed) aws_db_instance.default: Still creating... (4m30s elapsed) aws_db_instance.default: Still creating... (4m40s elapsed) aws_db_instance.default: Still creating... (4m50s elapsed) aws_db_instance.default: Still creating... (5m0s elapsed) aws_db_instance.default: Still creating... (5m10s elapsed) aws_db_instance.default: Still creating... (5m20s elapsed) aws_db_instance.default: Still creating... (5m30s elapsed) aws_db_instance.default: Creation complete after 5m31s (ID: djample) data.template_file.djample-web-containers: Refreshing state... aws_ecs_task_definition.web: Creating... arn: "" => "<computed>" container_definitions: "" => "[{\"environment\":[{\"name\":\"DJANGO_DATABASES__default__ENGINE\",\"value\":\"django.db.backends.postgresql\"},{\"name\":\"DJANGO_DATABASES__default__HOST\",\"value\":\"djample.civihq7xgpb5.us-west-2.rds.amazonaws.com:5432\"},{\"name\":\"DJANGO_DATABASES__default__NAME\",\"value\":\"djampledb\"},{\"name\":\"DJANGO_DATABASES__default__PASSWORD\",\"value\":\"djamplepass\"},{\"name\":\"DJANGO_DATABASES__default__PORT\",\"value\":\"5432\"},{\"name\":\"DJANGO_DATABASES__default__USER\",\"value\":\"djampleuser\"}],\"essential\":true,\"image\":\"XXXXXXXXXXXX.dkr.ecr.us-west-2.amazonaws.com/djample-app\",\"name\":\"djample-app\",\"portMappings\":[{\"containerPort\":3031,\"hostPort\":3031,\"protocol\":\"tcp\"}]},{\"environment\":[],\"essential\":true,\"image\":\"XXXXXXXXXXXX.dkr.ecr.us-west-2.amazonaws.com/djample-nginx\",\"name\":\"djample-nginx\",\"portMappings\":[{\"containerPort\":80,\"hostPort\":80,\"protocol\":\"tcp\"}]}]" cpu: "" => "256" execution_role_arn: "" => "arn:aws:iam::XXXXXXXXXXXX:role/assume_role" family: "" => "djample-web-task" memory: "" => "512" network_mode: "" => "awsvpc" requires_compatibilities.#: "" => "1" requires_compatibilities.3072437307: "" => "FARGATE" revision: "" => "<computed>" task_role_arn: "" => "arn:aws:iam::XXXXXXXXXXXX:role/assume_role" aws_ecs_task_definition.web: Creation complete after 1s (ID: djample-web-task) aws_ecs_service.web: Creating... cluster: "" => "arn:aws:ecs:us-west-2:XXXXXXXXXXXX:cluster/djample-cluster" deployment_maximum_percent: "" => "200" deployment_minimum_healthy_percent: "" => "100" desired_count: "" => "1" enable_ecs_managed_tags: "" => "false" iam_role: "" => "<computed>" launch_type: "" => "FARGATE" load_balancer.#: "" => "1" load_balancer.2891655293.container_name: "" => "djample-nginx" load_balancer.2891655293.container_port: "" => "80" load_balancer.2891655293.elb_name: "" => "" load_balancer.2891655293.target_group_arn: "" => "arn:aws:elasticloadbalancing:us-west-2:XXXXXXXXXXXX:targetgroup/djample-target-group/0cf7190ec2060917" name: "" => "djample-web-service" network_configuration.#: "" => "1" network_configuration.0.assign_public_ip: "" => "true" network_configuration.0.security_groups.#: "" => "1" network_configuration.0.security_groups.2467559028: "" => "sg-085110806fab80ae0" network_configuration.0.subnets.#: "" => "3" network_configuration.0.subnets.2370142301: "" => "subnet-0b2b0c2e4ae1f2a66" network_configuration.0.subnets.2494457805: "" => "subnet-09d44ac8bf7c95769" network_configuration.0.subnets.3574656835: "" => "subnet-08022d6c8417edca8" scheduling_strategy: "" => "REPLICA" task_definition: "" => "arn:aws:ecs:us-west-2:XXXXXXXXXXXX:task-definition/djample-web-task:17" aws_ecs_service.web: Creation complete after 2s (ID: arn:aws:ecs:us-west-2:XXXXXXXXXXXX:service/djample-web-service) Apply complete! Resources: 22 added, 0 changed, 0 destroyed. Outputs: alb_dns_name = djample-alb-1372101420.us-west-2.elb.amazonaws.com

output によって表示された ALBのホストにアクセスしてみると.. (もうないです)

表示されました! これにて一件落着。

その他参考