18
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Terraform+AWS Fargateで、タスク定義を更新(ローリング更新)してみる

Last updated at Posted at 2020-06-07

What's?

  • AWS Fargateに対するデプロイ方法は3種類あり、そのうちローリング更新を試してみたい
  • 環境と更新操作は、Terraformで行う

というのをやってみたいという記事です。

AWS Fargateでのデプロイ方法

Fargateというか、ECSでのデプロイ方法ですが。

ドキュメントによると、3つがあるようです。

Amazon ECS デプロイタイプ

  • ローリング更新
  • CodeDeployを使用したBlue/Greenデプロイ
  • 外部デプロイ

AWS内でやろうとすると、ローリング更新かBlue/Greenデプロイ(CodeDeploy利用)の2つになるということですね。

ローリング更新

ローリング更新に関するドキュメントはこちら、ですが、あんまり書いてないですね…。

ローリング更新

AWSのマネージメントコンソールでECSサービスを作成する時に、ローリング更新に関する記述があるのはドキュメントのうち次の2つのページです。

基本的なサービスパラメータの設定

[ローリング更新] デプロイタイプを使用している場合は、次のデプロイ設定パラメータを入力します。これらのパラメータの使用方法の詳細については、「デプロイ設定」を参照してください。

  • Minimum healthy percent: デプロイ時に RUNNING 状態に保つ必要のあるサービスのタスクの下限数をサービスのタスクの必要数のパーセント値 (最も近い整数に切り上げ) で指定します。

  • Maximum percent: デプロイ時に RUNNING または PENDING 状態にできるサービスのタスクの上限数をサービスの必要数のタスクのパーセント値 (最も近い整数に切り下げ) で指定します。

ローリング更新のデプロイタイプのロードバランサーを設定する

こちらは、主にヘルスチェックに関する話ですね。

ローリング更新に関するパラメーターのリファレンスは、こちらを見ることになります。

サービス定義パラメーター / デプロイ設定

deploymentControllerをデフォルトのECSとした場合、ローリング更新になるということですね。

サービス定義パラメーター / デプロイメントコントローラー

ドキュメントを読んでいくと、ローリング更新というのはサービス内のタスクを順次更新していくもののようです。

どのくらいのタスクを残して更新していくかは、minimumHealthyPercentmaximumPercentで調整することになります。

環境

利用するTerraformと、AWS Providerのバージョンです。

$ terraform version
Terraform v0.12.26
+ provider.aws v2.65.0

構築内容

まっさらなところから、VPCを作ってAWS Fargateクラスタを構築、簡単な動作確認を行うところまでやります。

  • マルチAZ
  • 動作させるコンテナは、nginxとApache(ローリングアップデートで切り替える)
  • ALBはHTTP

TerraformとAWS Providerのバージョン指定

こんな感じで。

terraform {
  required_version = "=  0.12.26"
}

provider "aws" {
  version = "2.65.0"
}

AWSのクレデンシャルは、環境変数で指定します。

export AWS_ACCESS_KEY_ID=.....
export AWS_SECRET_ACCESS_KEY=.....
export AWS_DEFAULT_REGION=.....

VPC〜ALBまで

このあたりは、コミュニティモジュールを使って作っていきます。

VPC。

AWS VPC Terraform module

module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "2.39.0"

  name = "my-vpc"
  cidr = "10.0.0.0/16"

  azs             = ["ap-northeast-1a", "ap-northeast-1c"]
  public_subnets  = ["10.0.101.0/24", "10.0.102.0/24"]
  private_subnets = ["10.0.1.0/24", "10.0.2.0/24"]

  map_public_ip_on_launch = true

  enable_nat_gateway     = true
  single_nat_gateway     = false
  one_nat_gateway_per_az = true
}

ALBとFargateに付与する、Security Group。

AWS EC2-VPC Security Group Terraform module

module "load_balancer_sg" {
  source  = "terraform-aws-modules/security-group/aws//modules/http-80"
  version = "3.10.0"

  name   = "load-balancer-sg"
  vpc_id = module.vpc.vpc_id

  ingress_cidr_blocks = ["0.0.0.0/0"]
}

module "http_server_sg" {
  source  = "terraform-aws-modules/security-group/aws//modules/http-80"
  version = "3.10.0"

  name   = "http-server-sg"
  vpc_id = module.vpc.vpc_id

  ingress_cidr_blocks = ["10.0.0.0/16"]
}

ALB。

AWS Application and Network Load Balancer (ALB & NLB) Terraform module

module "load_balancer" {
  source  = "terraform-aws-modules/alb/aws"
  version = "5.6.0"

  name = "http-server"

  vpc_id             = module.vpc.vpc_id
  load_balancer_type = "application"
  internal           = false

  subnets         = module.vpc.public_subnets
  security_groups = [module.load_balancer_sg.this_security_group_id]

  target_groups = [
    {
      backend_protocol = "HTTP"
      backend_port     = 80
      target_type      = "ip"

      health_check = {
        interval = 20
      }
    }
  ]

  http_tcp_listeners = [
    {
      port     = 80
      protocol = "HTTP"
    }
  ]
}

ここまでのモジュール定義のOutputの利用と、Fargateでのコンテナ定義

ここまでで使用したモジュールのOutputのうち、この後のFargateで使うものをローカル変数としてまとめておきます。

対象は、VPC ID、プライベートサブネットのID、Fargate用のセキュリティグループ、そしてALBのターゲットグループです。

locals {
  vpc_id = module.vpc.vpc_id

  private_subnets                = module.vpc.private_subnets
  ecs_service_security_groups    = [module.http_server_sg.this_security_group_id]
  load_balancer_target_group_arn = module.load_balancer.target_group_arns[0]

  nginx_container_definition = <<JSON
[
  {
    "name": "http-server",
    "image": "nginx:1.19.0",
    "essential": true,
    "portMappings": [
      {
        "protocol": "tcp",
        "containerPort": 80
      }
    ],
    "healthCheck": {
      "command": [
        "CMD-SHELL",
        "curl -f localhost || exit 1"
      ],
      "interval": 5
    }
  }
]
  JSON

  apache_container_definition = <<JSON
[
  {
    "name": "http-server",
    "image": "httpd:2.4.43",
    "essential": true,
    "portMappings": [
      {
        "protocol": "tcp",
        "containerPort": 80
      }
    ],
    "healthCheck": {
      "command": [
        "CMD-SHELL",
        "test -e /proc/1"
      ],
      "interval": 5
    }
  }
]
  JSON
}

また、コンテナ定義も2つ用意しておき、こちらを変更することでFargateのサービス内で稼働するコンテナイメージを切り替えていきます。

ローリング更新と言いつつも、今回はnginxとApacheを切り替えることにしました。

コンテナのヘルスチェックですが、Apacheのイメージにはcurlが入っていなかったので、だいぶ微妙な感じになっていますが…。

コンテナのヘルスチェックの設定については、こちらを参照。

ヘルスチェック

Fargateクラスタの定義

では、Fargateクラスタを定義しましょう。

  • クラスタ定義
  • タスク定義
  • サービス定義

以上を行います。

resource "aws_ecs_cluster" "http_server" {
  name = "http-server-cluster"
}

resource "aws_ecs_task_definition" "http_server" {
  family                   = "http-server-task-definition"
  cpu                      = "256"
  memory                   = "512"
  network_mode             = "awsvpc"
  requires_compatibilities = ["FARGATE"]

  container_definitions = local.nginx_container_definition
  #container_definitions = local.apache_container_definition
}

resource "aws_ecs_service" "http_server" {
  name             = "http-server-service"
  cluster          = aws_ecs_cluster.http_server.arn
  task_definition  = aws_ecs_task_definition.http_server.arn
  desired_count    = 5
  launch_type      = "FARGATE"
  platform_version = "1.4.0"

  deployment_minimum_healthy_percent = 50

  deployment_controller {
    type = "ECS" # default
  }

  network_configuration {
    assign_public_ip = false
    security_groups  = local.ecs_service_security_groups
    subnets          = local.private_subnets
  }

  load_balancer {
    target_group_arn = local.load_balancer_target_group_arn
    container_name   = "http-server"
    container_port   = 80
  }
}

ローリング更新を行う場合、deployment_controllertypeECSにする必要があります。といっても、これはデフォルト値のようですが。

  deployment_controller {
    type = "ECS" # default
  }

minimumHealthyPercentは、50%に設定。

ここ、注意ですね。

レプリカサービスの minimumHealthyPercent のデフォルト値は 100% です。DAEMON サービススケジュールを使用しているデフォルトの minimumHealthyPercent 値は、AWS CLI、AWS SDK、API では 0%、AWS マネジメントコンソール では 50% です。

デプロイ設定

タスク定義は、まずはnginxを利用。

resource "aws_ecs_task_definition" "http_server" {
  family                   = "http-server-task-definition"
  cpu                      = "256"
  memory                   = "512"
  network_mode             = "awsvpc"
  requires_compatibilities = ["FARGATE"]

  container_definitions = local.nginx_container_definition
  #container_definitions = local.apache_container_definition
}

確認

まずは、terraform apply

$ terraform apply -auto-approve

curlで1度確認してみます。

$ curl [ALBのDNS名]
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

nginxコンテナのレスポンスが返ってきました。

この時に、ecs-cli psでコンテナの一覧を見てみます。

$ ecs-cli ps --cluster http-server-cluster --desired-status RUNNING
Name                                              State    Ports                  TaskDefinition                  Health
2a3da558-0dc6-4d26-9304-a5370520a4a4/http-server  RUNNING  10.0.1.226:80->80/tcp  http-server-task-definition:12  HEALTHY
6b6f5927-80b9-46ec-a6ff-8c4c85553804/http-server  RUNNING  10.0.2.220:80->80/tcp  http-server-task-definition:12  HEALTHY
8f0d5f0d-7321-4b75-9bea-b1423260f170/http-server  RUNNING  10.0.1.19:80->80/tcp   http-server-task-definition:12  HEALTHY
a6930cca-75ca-474e-9033-bfb1d889d14f/http-server  RUNNING  10.0.1.193:80->80/tcp  http-server-task-definition:12  HEALTHY
d4b0c60c-737c-42b3-9a74-4f1b7a5ae013/http-server  RUNNING  10.0.2.79:80->80/tcp   http-server-task-definition:12  HEALTHY

では、ここでコンテナ定義をnginxからApacheに変更してみます。

resource "aws_ecs_task_definition" "http_server" {
  family                   = "http-server-task-definition"
  cpu                      = "256"
  memory                   = "512"
  network_mode             = "awsvpc"
  requires_compatibilities = ["FARGATE"]

  #container_definitions = local.nginx_container_definition
  container_definitions = local.apache_container_definition
}
$ terraform apply -auto-approve

すると、次のコンテナが立ち上がり始めます。

$ ecs-cli ps --cluster http-server-cluster
Name                                              State                Ports                  TaskDefinition                  Health
2a3da558-0dc6-4d26-9304-a5370520a4a4/http-server  RUNNING              10.0.1.226:80->80/tcp  http-server-task-definition:12  HEALTHY
3efbc3b2-6618-4ebd-86d2-138ea0b75529/http-server  PENDING              10.0.1.203:80->80/tcp  http-server-task-definition:13  UNKNOWN
6b6f5927-80b9-46ec-a6ff-8c4c85553804/http-server  RUNNING              10.0.2.220:80->80/tcp  http-server-task-definition:12  HEALTHY
7c0694c2-21aa-49a0-b0dd-04da880bfd34/http-server  PENDING              10.0.1.85:80->80/tcp   http-server-task-definition:13  UNKNOWN
8f0d5f0d-7321-4b75-9bea-b1423260f170/http-server  RUNNING              10.0.1.19:80->80/tcp   http-server-task-definition:12  HEALTHY
a6930cca-75ca-474e-9033-bfb1d889d14f/http-server  RUNNING              10.0.1.193:80->80/tcp  http-server-task-definition:12  HEALTHY
bd842250-6b40-4b5c-91fa-9cdaf2c7d30c/http-server  PENDING              10.0.2.205:80->80/tcp  http-server-task-definition:13  UNKNOWN
d4b0c60c-737c-42b3-9a74-4f1b7a5ae013/http-server  RUNNING              10.0.2.79:80->80/tcp   http-server-task-definition:12  HEALTHY
de437ee4-afbd-4ef1-95eb-3d9eeb0f189d/http-server  PENDING              10.0.2.65:80->80/tcp   http-server-task-definition:13  UNKNOWN
e684fa00-e7cb-4765-966b-92b15f1e008f/http-server  PENDING              10.0.2.239:80->80/tcp  http-server-task-definition:13  UNKNOWN

curlの方ではnginxとApacheのレスポンスが交互に表示されたりもしますが、そのうちApacheになります。

$ curl [ALBのDNS名]
<html><body><h1>It works!</h1></body></html>

ecs-cli psの結果。

$ ecs-cli ps --cluster http-server-cluster
Name                                              State                Ports                  TaskDefinition                  Health
2a3da558-0dc6-4d26-9304-a5370520a4a4/http-server  RUNNING              10.0.1.226:80->80/tcp  http-server-task-definition:12  HEALTHY
3efbc3b2-6618-4ebd-86d2-138ea0b75529/http-server  RUNNING              10.0.1.203:80->80/tcp  http-server-task-definition:13  HEALTHY
6b6f5927-80b9-46ec-a6ff-8c4c85553804/http-server  RUNNING              10.0.2.220:80->80/tcp  http-server-task-definition:12  HEALTHY
7c0694c2-21aa-49a0-b0dd-04da880bfd34/http-server  RUNNING              10.0.1.85:80->80/tcp   http-server-task-definition:13  HEALTHY
8f0d5f0d-7321-4b75-9bea-b1423260f170/http-server  RUNNING              10.0.1.19:80->80/tcp   http-server-task-definition:12  HEALTHY
a6930cca-75ca-474e-9033-bfb1d889d14f/http-server  RUNNING              10.0.1.193:80->80/tcp  http-server-task-definition:12  HEALTHY
bd842250-6b40-4b5c-91fa-9cdaf2c7d30c/http-server  RUNNING              10.0.2.205:80->80/tcp  http-server-task-definition:13  HEALTHY
d4b0c60c-737c-42b3-9a74-4f1b7a5ae013/http-server  RUNNING              10.0.2.79:80->80/tcp   http-server-task-definition:12  HEALTHY
de437ee4-afbd-4ef1-95eb-3d9eeb0f189d/http-server  RUNNING              10.0.2.65:80->80/tcp   http-server-task-definition:13  HEALTHY
e684fa00-e7cb-4765-966b-92b15f1e008f/http-server  RUNNING              10.0.2.239:80->80/tcp  http-server-task-definition:13  HEALTHY

さらにしばらく待っていると、nginx側のコンテナが全部終了します。

$ ecs-cli ps --cluster http-server-cluster
3efbc3b2-6618-4ebd-86d2-138ea0b75529/http-server  RUNNING              10.0.1.203:80->80/tcp  http-server-task-definition:13  HEALTHY
7c0694c2-21aa-49a0-b0dd-04da880bfd34/http-server  RUNNING              10.0.1.85:80->80/tcp   http-server-task-definition:13  HEALTHY
bd842250-6b40-4b5c-91fa-9cdaf2c7d30c/http-server  RUNNING              10.0.2.205:80->80/tcp  http-server-task-definition:13  HEALTHY
de437ee4-afbd-4ef1-95eb-3d9eeb0f189d/http-server  RUNNING              10.0.2.65:80->80/tcp   http-server-task-definition:13  HEALTHY
e684fa00-e7cb-4765-966b-92b15f1e008f/http-server  RUNNING              10.0.2.239:80->80/tcp  http-server-task-definition:13  HEALTHY
2a3da558-0dc6-4d26-9304-a5370520a4a4/http-server  STOPPED ExitCode: 0  80->80/tcp             http-server-task-definition:12  HEALTHY
6b6f5927-80b9-46ec-a6ff-8c4c85553804/http-server  STOPPED ExitCode: 0  80->80/tcp             http-server-task-definition:12  HEALTHY
8f0d5f0d-7321-4b75-9bea-b1423260f170/http-server  STOPPED ExitCode: 0  80->80/tcp             http-server-task-definition:12  HEALTHY
a6930cca-75ca-474e-9033-bfb1d889d14f/http-server  STOPPED ExitCode: 0  80->80/tcp             http-server-task-definition:12  HEALTHY
d4b0c60c-737c-42b3-9a74-4f1b7a5ae013/http-server  STOPPED ExitCode: 0  80->80/tcp             http-server-task-definition:12  HEALTHY

簡単にですが、確認できた感じですね。

18
15
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?