ECSでサービス間を「NLBでつなぐ」のと「Service Connectでつなぐ」のと、どっちがデプロイが速いかをチェックしてみた

忘れる前にやっとこかなと思って、続きをやることにした。

bufferings.hatenablog.com

やりたいこと

この2つでデプロイ時間にどれくらい差があるかなぁってことを見たい

  • NLBあり + Service Connectなし
  • NLBなし + Service Connectあり

今日のコードはここにある

github.com

環境を再構築

OpenTofuで作っておいたから楽ね。

❯ terragrunt apply -auto-approve

...

Apply complete! Resources: 18 added, 0 changed, 0 destroyed.

Outputs:

nlb_dns_name = "<生成されたNLBのDNS名>"

はい。できた。

ECSのTask Execution Roleが必要だった

忘れてたので追加。こんな感じ。

❯ git diff
diff --git a/infra/main.tf b/infra/main.tf
index 12e0447..0cf5e24 100644
--- a/infra/main.tf
+++ b/infra/main.tf
@@ -161,6 +161,33 @@ resource "aws_service_discovery_http_namespace" "namespace" {
   name = "${local.main_name}-namespace"
 }

+#########################################
+# ECS Role
+#########################################
+
+resource "aws_iam_role" "task_execution" {
+  name = "${local.main_name}-task-execution-role"
+
+  assume_role_policy = jsonencode({
+    Version = "2012-10-17"
+    Statement = [
+      {
+        Sid    = ""
+        Effect = "Allow"
+        Action = "sts:AssumeRole"
+        Principal = {
+          Service = "ecs-tasks.amazonaws.com"
+        }
+      }
+    ]
+  })
+}
+
+resource "aws_iam_role_policy_attachment" "task_execution" {
+  role       = aws_iam_role.task_execution.name
+  policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
+}
+
 #########################################
 # Output
 #########################################

ecspressoの設定ファイルを作成

ECSへのサービスとタスクのデプロイにはecspressoを使う。とても便利。

github.com

NLBあり + Service Connectなし

じゃ、設定ファイルを作っていく。前回AWSのWebコンソールから手で作ってからecspressoでダウンロードしてきた設定が手元にあったのでそれをごにょごにょして用意した。

まずはNLBにつなぐNginxから。作るファイルは3つ。全体設定、タスク設定、サービス設定。

全体設定 ecspresso.yml

tfstateから設定を読み込みたいので plugins でtfstateの場所を指定。って、あぁ、カレントディレクトリに main.tf を置いちゃったので、/./terraform.tfstate になっちゃってるや。まいっか。tfstateから取ってこれるの便利。

region: ap-northeast-1
cluster: ecs20240121-ecs
service: nginx-nlb
service_definition: ecs-service-def.json
task_definition: ecs-task-def.json
timeout: "10m0s"

plugins:
  - name: tfstate
    config:
      url: s3://ecs20240121/./terraform.tfstate

タスク設定 ecs-task-def.json

これは普通にコンテナの定義だけ。ECRにコンテナをプッシュして使おうかなぁ?って思ったけど、素のNginxコンテナでいっかと思ったのでそうした。

{
  "containerDefinitions": [
    {
      "cpu": 0,
      "essential": true,
      "image": "nginx",
      "name": "nginx-nlb",
      "portMappings": [
        {
          "appProtocol": "http",
          "containerPort": 80,
          "hostPort": 80,
          "name": "nginx-nlb-80-tcp",
          "protocol": "tcp"
        }
      ],
      "healthCheck": {
        "command": [
            "CMD-SHELL",
            "curl -f http://localhost/ || exit 1"
        ],
        "interval": 10,
        "timeout": 5,
        "retries": 3,
        "startPeriod": 10
      }
    }
  ],
  "cpu": "1024",
  "executionRoleArn": "{{ tfstate `aws_iam_role.task_execution.arn` }}",
  "family": "nginx-nlb",
  "ipcMode": "",
  "memory": "3072",
  "networkMode": "awsvpc",
  "pidMode": "",
  "requiresCompatibilities": [
    "FARGATE"
  ],
  "runtimePlatform": {
    "cpuArchitecture": "X86_64",
    "operatingSystemFamily": "LINUX"
  }
}

サービス設定 ecs-service-def.json

NLBのターゲットグループにつなぐ設定がはいったサービス。

{
  "deploymentConfiguration": {
    "deploymentCircuitBreaker": {
      "enable": true,
      "rollback": true
    },
    "maximumPercent": 200,
    "minimumHealthyPercent": 100
  },
  "deploymentController": {
    "type": "ECS"
  },
  "desiredCount": 2,
  "enableECSManagedTags": true,
  "enableExecuteCommand": false,
  "healthCheckGracePeriodSeconds": 10,
  "launchType": "FARGATE",
  "loadBalancers": [
    {
      "containerName": "nginx-nlb",
      "containerPort": 80,
      "targetGroupArn": "{{ tfstate `aws_lb_target_group.main.arn` }}"
    }
  ],
  "networkConfiguration": {
    "awsvpcConfiguration": {
      "assignPublicIp": "ENABLED",
      "securityGroups": [
        "{{ tfstate `aws_security_group.app.id` }}"
      ],
      "subnets": [
        "{{ tfstate `aws_subnet.main.id` }}"
      ]
    }
  },
  "platformFamily": "Linux",
  "platformVersion": "LATEST",
  "propagateTags": "NONE",
  "schedulingStrategy": "REPLICA"
}

NLBなし + Service Connectあり

つぎは、NLBへ接続せずにService Connectを使う設定。↑のと違うのは、細かい名前とかの違いは置いといて、サービス設定だけだな。NLBの設定がなくて、Service Connectの設定が入ってる。

{
  "deploymentConfiguration": {
    "deploymentCircuitBreaker": {
      "enable": true,
      "rollback": true
    },
    "maximumPercent": 200,
    "minimumHealthyPercent": 100
  },
  "deploymentController": {
    "type": "ECS"
  },
  "desiredCount": 2,
  "enableECSManagedTags": true,
  "enableExecuteCommand": false,
  "launchType": "FARGATE",
  "networkConfiguration": {
    "awsvpcConfiguration": {
      "assignPublicIp": "ENABLED",
      "securityGroups": [
        "{{ tfstate `aws_security_group.app.id` }}"
      ],
      "subnets": [
        "{{ tfstate `aws_subnet.main.id` }}"
      ]
    }
  },
  "platformFamily": "Linux",
  "platformVersion": "LATEST",
  "propagateTags": "NONE",
  "schedulingStrategy": "REPLICA",
  "serviceConnectConfiguration": {
    "enabled": true,
    "namespace": "ecs20240121-namespace",
    "services": [
      {
        "clientAliases": [
          {
            "dnsName": "nginx-sc-80-tcp.ecs20240121-namespace",
            "port": 80
          }
        ],
        "discoveryName": "nginx-sc-80-tcp",
        "portName": "nginx-sc-80-tcp"
      }
    ]
  }
}

これで、準備できた。

サービスをデプロイ

cd nginx-nlb
❯ \time ecspresso deploy

2024/01/22 22:16:29 nginx-nlb/ecs20240121-ecs Service is stable now. Completed!
       65.07 real         0.07 user         0.03 sys
cd nginx-sc
❯ \time ecspresso deploy

2024/01/22 22:30:46 nginx-sc/ecs20240121-ecs Service is stable now. Completed!
       98.09 real         0.10 user         0.05 sys

初回デプロイは既存コンテナの処理がないので速い。たまたまかもしれないけど、NLBの方がService Connectの方より速いのは面白いな。NLBへの接続はそんなに遅くなくて、Service Connect用の追加コンテナダウンロードとCloudMapへの登録の方が遅いってことなのかなぁ?

でも、知りたいのは再デプロイにかかる時間の違いなので、そこは今日は気にせずに、それぞれで再度デプロイを実行する。

NLBあり + Service Connectなし

2024/01/22 22:22:30 nginx-nlb/ecs20240121-ecs Service is stable now. Completed!
      301.30 real         0.21 user         0.09 sys
2024/01/22 22:37:00 nginx-nlb/ecs20240121-ecs Service is stable now. Completed!
      369.54 real         0.22 user         0.09 sys
2024/01/22 22:50:37 nginx-nlb/ecs20240121-ecs Service is stable now. Completed!
      326.58 real         0.19 user         0.08 sys
2024/01/22 23:15:20 nginx-nlb/ecs20240121-ecs Service is stable now. Completed!
      348.01 real         0.22 user         0.12 sys
2024/01/22 23:34:01 nginx-nlb/ecs20240121-ecs Service is stable now. Completed!
      303.46 real         0.21 user         0.09 sys

NLBなし + Service Connectあり

2024/01/22 22:35:35 nginx-sc/ecs20240121-ecs Service is stable now. Completed!
      286.73 real         0.18 user         0.08 sys
2024/01/22 22:48:33 nginx-sc/ecs20240121-ecs Service is stable now. Completed!
      204.81 real         0.13 user         0.07 sys
2024/01/22 23:16:23 nginx-sc/ecs20240121-ecs Service is stable now. Completed!
      225.20 real         0.15 user         0.07 sys
2024/01/22 23:21:03 nginx-sc/ecs20240121-ecs Service is stable now. Completed!
      195.17 real         0.13 user         0.08 sys
2024/01/22 23:31:18 nginx-sc/ecs20240121-ecs Service is stable now. Completed!
      248.07 real         0.20 user         0.09 sys

んー

単純に平均をとると

  • NLBあり + Service Connectなし → 329.78
  • NLBなし + Service Connectあり → 232.00

Service Connectの方が100sぐらい速いかなぁってところか。次回はもう少し詳しくどこに時間がかかっているのかを、ログから見てみようかな。

後片付け

ecspressoでサービスをdeleteして、terragruntでインフラをdestroyして今日の実験は終わり。IaCしておくと楽でいいね。

cd ../nginx-nlb
❯ ecspresso delete --force --terminate
...
2024/01/22 23:34:09 (service nginx-nlb) has reached a steady state.
2024/01/22 23:37:35 nginx-nlb/ecs20240121-ecs Service is deleted

❯ cd ../nginx-sc
❯ ecspresso delete --force --terminate
...
2024/01/22 23:31:23 (service nginx-sc) has reached a steady state.
2024/01/22 23:37:47 nginx-sc/ecs20240121-ecs Service is deleted

❯ cd ../../infra
❯ terragrunt destroy -auto-approve
...
aws_service_discovery_http_namespace.namespace: Destruction complete after 1m10s

Destroy complete! Resources: 20 destroyed.

今日も面白かった。