コンテンツにスキップ

public_traffic_container_service pattern

概要

public_traffic_container_service patternモジュールでは、インターネットからのトラフィックを受ける想定のロードバランサーおよびコンテナサービス環境を構築します。また、サービスを公開するにあたってのSSL/TLS証明書やDNSレコードの設定も行います。

このpatternにより構築されるコンテナサービスでは、バックエンドのサーバーアプリケーションがコンテナとして動作します。このアプリケーションは、ロードバランサーを介してインターネットに公開され、利用者に対してサービスや機能を提供します。

想定する適用対象環境

public_traffic_container_service patternは、Runtime環境での使用を想定しています。

依存するpattern

public_traffic_container_service patternは、事前に以下のpatternが適用されていることを前提としています。

pattern名 利用する情報
network pattern パブリックサブネット、プライベートサブネット

またコンテナサービスで使用するコンテナイメージおよび動作するコンテナが、次のようなリソース、情報を必要とする場合は依存するpatternが追加されます。

  • Amazon ECRに格納されたDockerイメージを使用する
  • コンテナ内からデータストアを使用する
  • 環境変数(秘匿情報)を参照する
pattern名 利用する情報
ci_pipeline pattern Delivery環境に構築されたAmazon ECR上のDockerイメージ
parameter_store pattern AWS Systems Manager パラメータストアに格納された秘匿情報
database pattern RDBMS
redis pattern Redis

本patternが依存するリソースを他の構築手段で代替する場合は、依存するpatternと入出力リファレンスの内容を参考に、本patternが必要とするリソースを構築してください。

構築されるリソース

このpatternでは、以下のリソースが構築されます。

リソース名 説明
Elastic Load Balancing(Application Load Balancer) インターネットからのトラフィックを受けるロードバランサーを構築します
AWS Fargate アプリケーションコンテナを動作させるサービスを構築します
AWS Certificate Manager SSL/TLS証明書を作成します
Amazon Route 53 DNSレコードを作成します
Amazon S3 ALBのアクセスログ格納先
Amazon CloudWatch Logs コンテナログの格納先

⚠️ public_traffic_container_service patternでは、ドメインの取得は行いません。事前にドメインの取得が必要です。

モジュールの理解に向けて

一般にサーバーアプリケーションをインターネットに公開する際には、以下のような環境を構築する必要があります。

  • 負荷分散や可用性を考慮した、ロードバランサーや複数インスタンスで動作するサーバー環境
  • インターネット公開に必要な、DNSレコードやSSL/TLS証明書の設定

public_traffic_container_service patternでは、これらを実現するリソースを構築します。

public_traffic_container_serviceの全体像

Eponaでは、アプリケーションがコンテナ化されていることを前提としています。
public_traffic_container_service patternを適用することにより、以下の環境が得られます。

  • コンテナの稼働数を柔軟に増減(スケールイン・アウト)できる、AWS Fargateクラスター
    • コンテナを稼働させるインスタンスは、利用者は管理不要(AWS管理となる)
  • インターネットからのトラフィックを受け付け、AWS Fargateクラスターへ転送するApplication Load Balancer

ℹ️ Application Load Balancerは、AWS CodeDeployと連携することを想定しています。
ℹ️ 具体的には、Blue/Greenデプロイが行われることを想定し、ターゲットグループが2つ作成されます。
ℹ️ 詳しくは、cd_pipeline_backend patternも参照してください。

また、今日のインターネットに公開されるWebサービス、Webサイトには固有のドメイン名でアクセスできることは当然として、HTTPSでのアクセスが求められるようになっている状況です。

このため、インターネット公開を前提として以下の環境を構成します。

  • Amazon Route 53を使用した、サービス公開用のDNSレコードの取得
  • サービス公開用のドメイン名に合わせた、AWS Certificate ManagerによるSSL/TLS証明書の取得

ここで作成するDNSレコードおよびSSL/TLS証明書は、同時に作成されるApplication Load Balancerへ紐付けられます。

ドメイン取得について

public_traffic_container_service patternでは、ドメインの登録自体は範囲外となっています。

事前に、AWSのマネジメントコンソールで必要なドメインを取得してください。

Amazon Route 53 を使用したドメイン名の登録

ドメイン取得がpublic_traffic_container_service patternの範囲外になっているのは、Terraformが対応していないことがひとつの理由です。加えて、ドメイン取得に関してはメール確認といった人手による作業が必要になるため、完全な自動化はできません。このため、Eponaの範囲外でドメインを取得する前提としています。

public_traffic_container_service patternは、事前のドメイン取得およびドメイン取得に伴うホストゾーンの作成が完了した後に適用されることを想定しています。

ℹ️ ホストゾーンの作成は、Amazon Route 53でドメインを取得した際に、自動的に作成されます。

public_traffic_container_service patternでは、作成済みのホストゾーンに対して、DNSレコードを作成します。

ログの保存について

AWS Fargateのようなコンテナを管理するプラットフォーム上で動作するアプリケーションは、ログを標準出力として書き出すことで記録します。

ただ、AWS Fargateはコンテナインスタンスを実行している仮想マシンへは直接アクセスできないため、デフォルトではコンテナのログを確認できません。

このため、実際の利用にはログをクラスター外に保存することが必須となるでしょう。

public_traffic_container_service patternでは、ログはAmazon CloudWatch Logsへの保存を想定しています。

ロググループはcontainer_log_group_namesに、ロググループ名を指定して作成します。タスク内のコンテナ数分、ロググループを作成しましょう。

  container_log_group_names             = ["ロググループ名1", "ロググループ名2", "ロググループ名3", ...]

ここで指定したロググループ名は、タスクのlogConfigurationに設定してコンテナのログを保存していきます。

Amazon CloudWatch Logsへのログ出力は、AWS FireLensを利用して行うことをおすすめします。詳しくは、以下のドキュメントを参照してください。

Amazon ECS上のコンテナログを、AWS FireLensを使ってAmazon CloudWatch Logsに送信する

さらにDatadogが利用可能な場合は、ログを集約できます。詳しくはこちらを参照してください。

タスク定義で使用するコンテナについて

本patternで設定するタスク定義のコンテナには、実際のアプリケーションのものではなく、ダミーのものを設定するようにしてください。

本patternで構築されるFargate環境の更新は、AWS CodeDeployから行う前提となっています。 つまり、本patternに実際のアプリケーションのタスク定義を書いた場合、AWS CodeDeploy用のタスク定義と二重管理になってしまいます。 また、本patternは環境を構築するための最初の1回のみしか適用しないため、タスク定義の管理にコストをかけることは好ましくありません。

したがって、本patternでデプロイする初回のコンテナは、ダミーのコンテナを使用することを推奨します。

具体的なダミーのコンテナとしては、HashiCorp社が提供しているhttp-echoなどがあります。 次節のサンプルコードでは、http-echoをコンテナイメージに設定した例を記載しています。

なお、本pattern適用時にFargateへデプロイされるコンテナイメージこそダミーですが、コンテナ定義以外のリソースはすべて本来利用すべきものを構築します。 したがって、DNSレコードやクラスター名、ロググループの定義等は実際の利用で必要なものを作成してコンテナのみを差し替えます。

たとえば、ロググループを例にして説明します。 cd_pipeline_backend patternによりデプロイするコンテナが以下の3つだとします。

  • アプリケーションコンテナ
  • Fluent Bitコンテナ
  • Datadog Agentコンテナ

この場合、public_traffic_container_service pattern適用時にデプロイするコンテナと作成するロググループは、次のようになります。

  • デプロイするコンテナ
    • http-echoのみ
  • 作成するロググループ
    • アプリケーションコンテナ用ロググループ
    • Fluent Bitコンテナ用ロググループ
    • Datadog Agentコンテナ用ロググループ

ロードバランサーのバックエンドのアクセス制御について

本パターンではALBのリスナーにルールを追加することで、特定のトラフィックのみバックエンドのコンテナサービスへ転送する等の柔軟なルーティングを実現できます。
ルーティングに関する設定をしない場合は、ALBはすべてのトラフィックをバックエンドのコンテナサービスへと転送します。
詳しくは ALBのリスナールール を参照してください。

public_traffic_container_service patternでは以下のアクションタイプをサポートしています。

  • 転送(forward)
  • 固定レスポンス(fixed-response)
  • リダイレクト(redirect)

リスナールール毎に、リクエストURLのパスパターンに基づいた条件を設定することでアクションを実行するかどうかを制御します。 ルールを複数設定した場合は、ルール毎に優先度を付けることでルールを評価する順番を制御できます。

転送(forward)アクション

トラフィックをバックエンドのコンテナサービスへ転送します。 詳しくは 転送アクション を参照してください。
転送先のターゲットグループは、デフォルトアクションの転送先をもとにEponaが自動的に設定します。
⚠️ このため、本パターンでは、ALBリスナーのデフォルトアクションはECSへの転送アクションで固定としており、使用できません。

固定レスポンス(fixed-response)アクション

HTTPステータスコードとオプションのメッセージを含む固定のHTTPレスポンスを返却します。 ALBがサポートしているレスポンスコードとコンテントタイプは以下になります。

  • HTTPステータスコード
    • 2XX
    • 4XX
    • 5XX
  • コンテントタイプ
    • text/plain
    • text/css
    • text/html
    • application/javascript
    • application/json

詳しくは 固定レスポンスアクション を参照してください。

リダイレクト(redirect)アクション

インターネットからのトラフィックを別のURLにリダイレクトします。
HTTPステータスコードとして一時的 (HTTP 302) または恒久的 (HTTP 301)が設定できます。
リダイレクト先として以下の項目が設定できます。設定をしなかった項目は元の値が保持されます。

  • host
  • port
  • path
  • protocol
  • query

詳しくは リダイレクトアクション を参照してください。

転送アクションのデフォルト設定について

転送アクションに関する設定をしない場合、すべてのトラフィックをバックエンドに転送するリスナールールをEponaが内部的に作成します。
このリスナールールは最優先で適用されます。 そのため、転送アクションを設定しない状態で、「/*」に対する固定レスポンスやリダイレクトアクションだけを設定した場合、 転送アクションが優先されてしまい、意図した挙動にならない場合があります。 固定レスポンスやリダイレクトのアクションだけ設定する場合でも、適切な優先度を設定した転送アクションをあわせて追加するようにしてください。

サンプルコード

public_traffic_container_service patternを使用したサンプルコードを、以下に記載します。

module "public_traffic_container_service" {
  source = "git::https://gitlab.com/eponas/epona.git//modules/aws/patterns/public_traffic_container_service?ref=v0.2.6"

  name = "[リソースに共通的に付与する名前]"

  vpc_id                             = data.terraform_remote_state.production_network.outputs.network.vpc_id
  public_subnets                     = data.terraform_remote_state.production_network.outputs.network.public_subnets
  public_traffic_protocol            = "HTTPS"
  public_traffic_port                = 443
  public_traffic_inbound_cidr_blocks = ["0.0.0.0/0"]

  # リダイレクトのルールの追加例
  # `/redirect/*` のパスにアクセスしたときに`host-to-redirect`にリダイレクトします
  # ホスト以外のURLは元のURLを引き継ぎます
  alb_redirect_listener_rules = [
    {
      priority     = "10"
      host         = "host-to-redirect"
      status_code  = "HTTP_301"
      path_pattern = "/redirect/*"
    }
  ]

  # アクセス制御の例
  # `/api/*`のパスだけバックエンドのECSに転送し、それ以外のパスへのアクセスは403エラーを返却します
  alb_forward_listener_rules = [
    {
      priority     = "90"
      path_pattern = "/api/*"
    }
  ]
  alb_fixed_response_listener_rules = [
    {
      priority     = "100"
      content_type = "text/plain"
      message_body = "403 Forbidden"
      status_code  = "403"
      path_pattern = "/*"
    }
  ]

  dns = {
    zone_name   = "example.com"
    record_name = "chat-example-backend.example.com"
  }

  container_subnets  = data.terraform_remote_state.production_network.outputs.network.private_subnets
  container_protocol = "HTTP"
  container_port     = 8080

  container_health_check_path           = "/"
  container_cluster_name                = "chat-example"
  container_traffic_inbound_cidr_blocks = ["AWS Fargateを配置するVPCのCIDRブロック"]
  container_service_desired_count       = 3
  container_service_platform_version    = "1.4.0"
  container_task_cpu                    = 512
  container_task_memory                 = "1024"


  default_ecs_task_iam_role_name             = "ChatExampleContainerServiceTaskRole"
  default_ecs_task_iam_policy_name           = "ChatExampleContainerServiceTaskRolePolicy"
  default_ecs_task_execution_iam_policy_name = "ChatExampleContainerServiceTaskExecution"
  default_ecs_task_execution_iam_role_name   = "ChatExampleContainerServiceTaskExecutionRole"

  container_log_group_names             = ["fargate-log-group/chat-example"]

  container_definitions = <<-JSON
  [
    {
      "name": "[タスク名]",
      "image": "hashicorp/http-echo:0.2.3",
      "essential": true,
      "portMappings": [
        {
          "protocol": "tcp",
          "containerPort": 8080
        }
      ],
      "logConfiguration": {
        # ログ設定
      },
      "command": [
          "-listen",
          ":8080",
          "-text",
          "echo"
      ]
    }
  ]
  JSON

  tags = {
    # 任意のタグ
    Environment        = "runtime"
    RuntimeEnvironment = "production"
    ManagedBy          = "epona"
  }
}

関連するpattern

public_traffic_container_service patternに関連するpatternを、以下に記載します。

pattern名 説明
ci_pipeline pattern アプリケーションをコンテナイメージとしてビルドし、Amazon ECRへPushできるようになります
cd_pipeline_backend_trigger pattern Amazon ECRへのコンテナイメージPushをトリガーに、デプロイメントパイプラインを起動できるようになります
cd_pipeline_backend pattern デプロイメントパイプラインを構築して、AWS FaragateクラスターへのBlue/Greenデプロイが可能になります

ログの集約

public_traffic_container_service patternでは、ALBのログをAmazon S3に出力します。
また、コンテナのログはAmazon CloudWatch Logsに出力します。

Amazon CloudWatch Logsへのログ出力は、AWS FireLensを利用して行うことをおすすめします。

Amazon ECS上のコンテナログを、AWS FireLensを使ってAmazon CloudWatch Logsに送信する

また、Datadogが使用できる場合はdatadog_log_trigger patternを使ったログ集約を行いましょう。

システムメトリクスの収集

public_traffic_container_service patternでは、コンテナのシステムメトリクス(CPU使用率やメモリ使用量など)を収集する仕組みは提供されません。

下記ガイドで、コンテナのメトリクスをDatadogへ送信する方法を解説しているので、そちらを参照してください。

入出力リファレンス

Requirements

Name Version
terraform ~> 0.14.10
aws >= 3.37.0, < 4.0.0

Inputs

Name Description Type Default Required
container_cluster_name コンテナサービスのクラスター名 string n/a yes
container_definitions コンテナサービスのタスクで実行する、コンテナ定義のリスト string n/a yes
container_health_check_path ロードバランサーの、コンテナに対するヘルスチェックのパス string n/a yes
container_port ロードバランサーがコンテナに転送する際のポート number n/a yes
container_protocol ロードバランサーがコンテナに転送する際のプロトコル string n/a yes
container_service_desired_count コンテナサービス内の、タスクのインスタンス数 number n/a yes
container_service_platform_version コンテナサービスを実行するプラットフォームのバージョン string n/a yes
container_subnets コンテナサービスを配置する、サブネットIDのリスト list(string) n/a yes
container_task_cpu コンテナサービス内で実行されるタスクに割り当てるCPU number n/a yes
container_task_memory コンテナサービス内で実行されるタスクに割り当てるメモリ string n/a yes
container_traffic_inbound_cidr_blocks コンテナサービスが受け付けるトラフィックの、CIDRブロックのリスト list(string) n/a yes
dns ロードバランサーのDNSに関する設定(zone_name, record_name)。
zone_name = record_nameを登録するホストゾーン名
record_name = Amazon Route 53に登録するレコードセットの名前
map(any) n/a yes
name コンテナサービス、ロードバランサーに関する名前 string n/a yes
public_subnets ロードバランサーに割り当てる、パブリックサブネットのIDのリスト list(string) n/a yes
public_traffic_inbound_cidr_blocks ロードバランサーが受け付けを許可するトラフィックのCIDRブロックのリスト list(string) n/a yes
public_traffic_port ロードバランサーが受け付けるトラフィックのポート number n/a yes
public_traffic_protocol ロードバランサーが受け付けるトラフィックのプロトコル string n/a yes
vpc_id VPC ID string n/a yes
alb_fixed_response_listener_rules ロードバランサーのリスナーに設定する固定レスポンスルールのリスト
レスポンスコードとオプションのメッセージを返すことができる
[
{
priority = ルールの優先順位。値が小さいルールから順に評価される。(例: "10") # Required
content_type = コンテントタイプ (例: "text/plain") # Required content_typeに設定できる値についてはcontent_typeを参照してください
message_body = メッセージボディ (例: "403 Forbidden") # Required
status_code = HTTPレスポンスコード (例: "403") # Required 2XX,4XX,5XXのいずれかを設定してください
path_pattern = ルールのアクションが実行される条件。カンマ区切りで複数指定が可能。 (単一の場合の例: "/*" 複数の場合の例: "/foo/*,/bar/*") # Required
}
]
list(map(string)) [] no
alb_forward_listener_rules ロードバランサーのリスナーに設定するフォワードアクションルールのリスト
[
{
priority = ルールの優先順位。値が小さいルールから順に評価される。 (例: "10") # Required
path_pattern = ルールのアクションが実行される条件。カンマ区切りで複数指定が可能。 (単一の場合の例: "/*" 複数の場合の例: "/foo/*,/bar/*") # Required
}
]
list(map(string)) [] no
alb_redirect_listener_rules ロードバランサーのリスナーに設定するリダイレクトルールのリスト
hostpathportprotocolqueryに関しては #{host} のように記述することで、元のURLの値を再利用できます
詳細についてはリダイレクトアクションを参照してください
[
{
priority = ルールの優先順位 (例: "10") # Required
host = リダイレクト先のホスト (例: "example.com") # Optional 省略した場合 "#{host}" が設定されます
path = リダイレクト先のURLパス (例: "/bar") # Optional 省略した場合 "/#{path}" が設定されます
port = リダイレクト先のポート番号 (例: "8080") # Optional 省略した場合 "#{port}" が設定されます
protocol = プロトコル HTTPもしくはHTTPS (例: "HTTPS") # Optional 省略した場合 "#{protocol}" が設定されます
query = クエリパラメータ (例: "key=aaa") # Optional 省略した場合 "#{query}" が設定されます
status_code = HTTPリダイレクトコード (例: "HTTP_301") # Required "HTTP_301"か"HTTP_302"のいずれかを設定してください
path_pattern = ルールのアクションが実行される条件。カンマ区切りで複数指定が可能。 (単一の場合の例: "/*" 複数の場合の例: "/foo/*,/bar/*") # Required
}
]
list(map(string)) [] no
container_log_group_kms_key_id CloudWatch Logsを暗号化するためのKMS CMKのARN string null no
container_log_group_names コンテナのログ出力先と成るCloudWatch Logsのグループ名のリスト list(string) [] no
container_log_group_retention_in_days CloudWatch Logsに保存した、コンテナログの保持日数 number null no
container_task_execution_role_arn コンテナサービスのタスクに割り当てるタスク実行IAMロールのARN。create_default_ecs_task_execution_roleをfalseにする場合に指定すること string null no
container_task_role_arn コンテナサービスのタスクが、他のAWSサービスを呼び出せるように割り当てるIAMロールのARN string null no
container_traffic_inbound_protocol コンテナサービスが受け付けるトラフィックのプロトコル string "tcp" no
create_default_ecs_task_execution_role デフォルトのタスク実行ロールを作成する場合、trueを指定する bool true no
create_default_ecs_task_role デフォルトのタスク実行ロールを作成する場合、trueを指定する bool true no
create_public_traffic_certificate ロードバランサーで利用するSSL/TLS証明書を作成する場合、true bool true no
default_ecs_task_execution_iam_policy_name デフォルトのタスク実行ロールを作成する場合のIAMポリシー名 string "DefaultContainerServiceTaskExecutionRolePolicy" no
default_ecs_task_execution_iam_role_name デフォルトのタスク実行ロールを作成する場合のIAMロール名 string "DefaultContainerServiceTaskExecutionRole" no
default_ecs_task_iam_policy_name デフォルトのタスクロールを作成する場合のIAMポリシー名 string "DefaultContainerServiceTaskRolePolicy" no
default_ecs_task_iam_role_name デフォルトのタスクロールを作成する場合のIAMロール名 string "DefaultContainerServiceTaskRole" no
public_traffic_access_logs_bucket ロードバランサーのアクセスログを保存するS3バケット名。public_traffic_access_logs_enabledがtrueで、この変数を指定しない場合、nameから自動導出する string null no
public_traffic_access_logs_create_bucket bucketに指定したS3バケットをこのモジュールで作成する場合、trueを指定する。デフォルトでtrueが指定されたものとして振る舞う bool true no
public_traffic_access_logs_enabled ロードバランサーのアクセスログを有効にする場合、trueを指定する。デフォルトでtrueが指定されたものとして振る舞う bool true no
public_traffic_access_logs_force_destroy destroy時、データがあったとしても強制的にアクセスログ用S3バケットを削除する bool false no
public_traffic_access_logs_prefix アクセスログをS3バケットに保存する時のprefix。指定しない場合は、ログはS3のルートに保存される string null no
public_traffic_certificate_arn ロードバランサーに与えるSSL/TLS証明書のARN。このpattern外部で証明書を作成する場合に使用する string null no
public_traffic_inbound_protocol ロードバランサーが受け付けるトラフィックのプロトコル。セキュリティグループの指定に利用 string "tcp" no
public_traffic_ssl_policy ロードバランサーのデフォルトのセキュリティポリシー string "ELBSecurityPolicy-TLS-1-2-Ext-2018-06" no
tags このモジュールで作成するリソースに、共通的に付与するタグ map(string) {} no

Outputs

Name Description
cloudwatch_container_log_names コンテナのログ出力先となる、CloudWatch Logsのロググループ名のリスト
ecs_cluster_name ECSクラスター名
ecs_service_name ECSサービス名
load_balancer_access_logs_bucket ロードバランサーのアクセスログ出力用のS3バケット名
load_balancer_access_logs_bucket_id ロードバランサーのアクセスログ出力用のS3バケットのID
load_balancer_arn ロードバランサーのARN
load_balancer_prod_listener_arn 本番環境用トラフィックを受け持つ、ロードバランサーのListenerのARN
load_balancer_target_group_names LoadBalancerのターゲットグループ名のリスト

※ このドキュメントはクリエイティブコモンズ(Creative Commons) 4.0 の「表示—継承」に準拠しています。

※ このドキュメントに記載されている会社名、製品名は、各社の登録商標または商標です。

© 2021 TIS Inc.