NRIネットコム Blog

NRIネットコム社員が様々な視点で、日々の気づきやナレッジを発信するメディアです

ecspressoとTerraformを連携させて複数環境にECSデプロイしてみた

本記事は  【コンテナウィーク】  3日目の記事です。
💻  2日目  ▶▶ 本記事 ▶▶  4日目  📱

はじめまして、2021年キャリア入社の加藤です。

Amazon ECSのデプロイツールであるecspressoを用いて複数環境にECSデプロイを実施してみようと思います。 業務でTerraformを使用する機会が多いので、ecspressoと連携させ、より実践的な使い方を試します。

ecspresso とは

ecspressoはfujiwara氏が公開しているECSのデプロイツール(OSS)です。 github.com

設計思想として 「ECSのデプロイに関わる最小限のリソースのみを管理するツール」と書かれており、ECSデプロイに特化したツールであることが分かります。 ecspressoの管理対象は「ecspressoの設定ファイル」「ECSサービスの設定ファイル」「ECSタスク定義の設定ファイル」のみとなっており、それら以外のリソースを管理する場合はTerraformやAWS CloudFormationなどのIaCツールを用いることが一般的なようです。

ちなみに読み方は「エスプレッソ」です☕️

なぜIaCでECSを管理しないのか

IaCを導入するのであれば、ECSも合わせて管理した方が良いように思えますが、その場合運用上やっかいな事象に直面します。

  • ECSは他インフラリソースと更新のライフサイクルが異なる
  • ECS更新を専用のワークフローで運用するとIaC側との棲み分けを検討する必要がある
    • IaC外での変更を無視する、二重管理しないようIaC側では持たない etc...

私が担当しているシステムでもTerraformでECSサービスやECSタスク定義を構築しつつ、別途デプロイワークフローを構築していることが多いです。デプロイワークフローの構築にはスクリプトを作り込んだりGitHub Actionsを活用したり様々ですが、IaCとは切り離して構築しています。

この辺りの隙間を埋めるためのツールがecspressoです。

ecspressoはTerraformやCloudFormationとの連携が可能なため、IaCとの相性も良いです。またECSを運用する上で使用頻度が高いオペレーション(Force new deploymentやexec等)もサブコマンドとして実装されており、細かい作り込みが不要となり実装コストを抑える効果も期待出来ます。zenn.dev

なお、ECSクラスターは管轄外ですので、IaC側で管理する必要があります。(ECSクラスターの更新頻度は高くないので、あまり気にならないです)

構成図

本題に入ります。まず構築する環境についての構成図です。

VPCにパブリックサブネットとプライベートサブネットを構築しパブリックサブネットにALB、プライベートサブネットにECS(Faragate)を設置します。

環境はdevprodを構築します。これらは同じAWSアカウント同じリージョン別VPCとしています。(クロスアカウントで環境を分ける際はIAMなどアカウントレベルのリソースに考慮が必要です。) これらの環境に対して自端末からecspressoを用いてECSデプロイを実施します。ecspressoはロゴがなかったので☕️にしました。

コード体系

ecspressoとTerraformを管理するリポジトリは下記のようなコード体系とします。

├── config.yaml
├── ecs-service-def.json
├── ecs-task-def.json
└── terraform
    └── aws
        ├── envs
        │   ├── dev
        │   │   ├── backend.tf
        │   │   ├── main.tf
        │   │   └── output.tf
        │   └── prod
        │       ├── (devと同じ)
        └── modules
            ├── ecs
            │   └── main.tf
            └── network
                └── main.tf

各ファイル/ディレクトリについて簡単に解説します。中身については構築時に触れます。

config.yaml

ecspressoの設定ファイルです。対象のECSクラスターやECSサービス、pluginなどを設定します。

環境毎で用意せず単一ファイルを環境間で共通ファイルとして使用します。

ecs-service-def.json

ECSサービスの設定ファイルです。サブネットやALB、デプロイなどを設定します。

こちらもconfig.yaml同様、環境共通ファイルです。

ecs-task-def.json

ECSタスク定義の設定ファイルです。コンテナイメージやコンテナリソースなどを設定します。

同様に環境共通ファイルです。

terraform/aws

AWSリソースのTerraformコードを管理します。Terraformを用いて他のサービス(GCPやAzure、Datadog等)を管理したい場合があるので、この階層を設けました。

envs

各環境のtfファイルを管理します。モジュールは環境で使い回すため、別途ディレクトリを分けて管理します。各ディレクトリのtfファイルは環境毎のパラメータを書くことで環境差分を管理します。

各tfファイルの中身は後々紹介します。

modules

Terraformリソース群(モジュール)をまとめます。モジュールの分け方はリソースのライフサイクル毎で分けるのが良いかと思います。今回はシンプルに「network」と「ecs」とします。

各環境で共通のモジュールを使用することでコードの共通化を図ります。

やってみよう

ではデプロイしていきます。以下のような流れで進めます。

  1. Terraform実行に必要なAWSリソースを構築
  2. ECS周辺のAWSリソースを構築
  3. ECSサービスとECSタスク定義の構築(dev)
  4. ecspressoによる設定ファイルの取り込み
  5. 設定ファイルを修正
  6. ecspresso deploy(prod)

0. 前提

前提として「AWSアカウントが作成されていること」「自端末にIAMユーザのcredential情報が設定されていること」「自端末にTerraformとecspressoがインストールされていること」とします。 各ツールは検証時の最新バージョンを用います。

terraform → v1.6.2
ecspresso → v2.2.4

1. Terraform実行に必要なAWSリソースを構築

まず、Terraformの実行に必要なAWSリソースをAWSマネジメントコンソールから構築します。今回は運用上よく使われる下記3つのリソースを構築します。

  • S3バケット
    • state管理
    • デフォルト設定で構築
  • DynamoDB
    • lock管理
    • パーティションキーに"LockID"を指定し他はデフォルト設定で構築
  • IAMロール
    • Terraform実行用ロール
    • 検証用のためAdministratorAccessを付与
    • 信頼関係にIAMユーザからのAssumeRoleを許可

ここで作成するリソースはenvs/環境/backend.tfで設定します。

dev/backend.tf

terraform {
  backend "s3" {
    bucket         = "t3-kato-terraform-backend"
    key            = "dev/terraform.tfstate"
    region         = "us-west-2"
    dynamodb_table = "t3-kato-terraform-backend"
    assume_role = {
      role_arn = "arn:aws:iam::<<AWSアカウントID>>:role/t3-kato-terraform"
    }
  }
}

prod/backend.tf

terraform {
  backend "s3" {
    bucket         = "t3-kato-terraform-backend"
    key            = "prod/terraform.tfstate"
    region         = "us-west-2"
    dynamodb_table = "t3-kato-terraform-backend"
    assume_role = {
      role_arn = "arn:aws:iam::<<AWSアカウントID>>:role/t3-kato-terraform"
    }
  }
}

2. ECS周辺のAWSリソースを構築

次にECS周辺のAWSリソースをTerraformで構築します。

  • VPC
    • VPC、パブリックサブネット、プライベートサブネット、ルートテーブル、インターネットゲートウェイ、NatGateway
  • セキュリティグループ
    • ALB用とECS用を準備
  • ALB、ターゲットグループ
    • ALBはパブリックサブネットに設置
  • CloudWatchLogs ロググループ
    • ECSサービスのログ出力先として準備
  • ECS クラスター
    • ecspressoではECSクラスターは管理されないためTerraformで定義

modules内のファイルは下記の通りです。

modules/network/main.tf

variable "name" {
  type = string
}

variable "env" {
  type = string
}

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

  name = "${var.name}-${var.env}"
  cidr = "10.0.0.0/16"

  azs             = ["us-west-2a", "us-west-2b"]
  private_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
  public_subnets  = ["10.0.101.0/24", "10.0.102.0/24"]

  enable_nat_gateway = true
  enable_vpn_gateway = false
}

resource "aws_security_group" "ecs" {
  name   = "${var.name}-${var.env}-ecs"
  vpc_id = module.vpc.vpc_id
}

resource "aws_security_group_rule" "ingress_from_alb_to_ecs" {
  type                     = "ingress"
  from_port                = 80
  to_port                  = 80
  protocol                 = "tcp"
  source_security_group_id = module.alb.security_group_id
  security_group_id        = aws_security_group.ecs.id
}

resource "aws_security_group_rule" "egress_from_ecs_to_internet" {
  type              = "egress"
  from_port         = 0
  to_port           = 0
  protocol          = "-1"
  cidr_blocks       = ["0.0.0.0/0"]
  security_group_id = aws_security_group.ecs.id
}

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

  name               = "${var.name}-${var.env}"
  load_balancer_type = "application"
  vpc_id             = module.vpc.vpc_id
  subnets            = module.vpc.public_subnets

  security_group_rules = {
    ingress_http = {
      type        = "ingress"
      from_port   = 80
      to_port     = 80
      protocol    = "tcp"
      cidr_blocks = ["<<許可したいIP>>"] 
    }
    egress_all = {
      type        = "egress"
      from_port   = 0
      to_port     = 0
      protocol    = "-1"
      cidr_blocks = ["0.0.0.0/0"]
    }
  }

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

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

modules/ecs/main.tf

variable "name" {
  type = string
}

variable "env" {
  type = string
}

resource "aws_ecs_cluster" "this" {
  name = "${var.name}-${var.env}"
}

resource "aws_cloudwatch_log_group" "this" {
  name = "/ecs/${var.name}-${var.env}"
}

ここでは積極的にTerraformモジュール(terraform-aws-modules/vpc/aws等)を採用していますが、Terraformモジュールを使うとバージョン管理などが煩雑となるので、実運用で採用する際は考慮が必要です。

modulesディレクトリへの設定が完了したら、envs/dev に移動しterraform applyを実行します。

envs/dev/main.tf

terraform {
  required_version = ">= 1.6.2"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = ">= 5.23.1"
    }
  }
}

provider "aws" {
  region = "us-west-2"
}

locals {
  env    = "dev"
  name   = "t3-kato"
}

module "network" {
  source = "../../modules/network"

  env  = local.env
  name = local.name
}

module "ecs" {
  source = "../../modules/ecs"

  env  = local.env
  name = local.name
}

同様にprodでもterraform applyを実行します。devとprodのmain.tfの差分は下記の通りです。

❯ diff terraform/aws/envs/dev/main.tf terraform/aws/envs/prod/main.tf 
16c16
<   env    = "dev"
---
>   env    = "prod"

applyが正常に完了していると下記のようにtfstateが保存されます。

❯ terraform state list
module.ecs.aws_cloudwatch_log_group.this
module.ecs.aws_ecs_cluster.this
module.network.aws_security_group.ecs
module.network.aws_security_group_rule.egress_from_ecs_to_internet
module.network.aws_security_group_rule.ingress_from_alb_to_ecs
module.network.module.alb.aws_lb.this[0]
module.network.module.alb.aws_lb_listener.frontend_http_tcp[0]
module.network.module.alb.aws_lb_target_group.main[0]
module.network.module.alb.aws_security_group.this[0]
module.network.module.alb.aws_security_group_rule.this["egress_all"]
module.network.module.alb.aws_security_group_rule.this["ingress_http"]
module.network.module.vpc.aws_default_network_acl.this[0]
module.network.module.vpc.aws_default_route_table.default[0]
module.network.module.vpc.aws_default_security_group.this[0]
module.network.module.vpc.aws_eip.nat[0]
module.network.module.vpc.aws_eip.nat[1]
module.network.module.vpc.aws_internet_gateway.this[0]
module.network.module.vpc.aws_nat_gateway.this[0]
module.network.module.vpc.aws_nat_gateway.this[1]
module.network.module.vpc.aws_route.private_nat_gateway[0]
module.network.module.vpc.aws_route.private_nat_gateway[1]
module.network.module.vpc.aws_route.public_internet_gateway[0]
module.network.module.vpc.aws_route_table.private[0]
module.network.module.vpc.aws_route_table.private[1]
module.network.module.vpc.aws_route_table.public[0]
module.network.module.vpc.aws_route_table_association.private[0]
module.network.module.vpc.aws_route_table_association.private[1]
module.network.module.vpc.aws_route_table_association.public[0]
module.network.module.vpc.aws_route_table_association.public[1]
module.network.module.vpc.aws_subnet.private[0]
module.network.module.vpc.aws_subnet.private[1]
module.network.module.vpc.aws_subnet.public[0]
module.network.module.vpc.aws_subnet.public[1]
module.network.module.vpc.aws_vpc.this[0]

モジュール内にモジュールを定義してしまったため、少し読みにくいですね・・・

3. ECSサービスとECSタスク定義の構築(dev)

続いてdevのECSサービスとECSタスク定義を構築します。

  • ECSタスク定義
    • 起動タイプはFargateを選択
    • タスクロールはなし、タスク実行ロールはデフォルトのecsTaskExecutionRoleを選択
    • コンテナはAmazon ECR Public Galleryから最新版のnginxコンテナイメージを選択
    • その他はデフォルトを設定
  • ECSサービス
    • デプロイ方法はローリングアップデートを選択
    • プライベートサブネットを選択
    • パブリックIPは不要なのでオフにしておく
    • 必要なタスク数は1としておく

ECSサービス作成後正常にタスクが起動すればALBのDNS名にアクセスすることでnginxの画面が表示されます。

ここまでで、devの構築は完了です。

続いてecspressoを用いて、prodへデプロイしてみましょう。

4. ecspressoによる設定ファイルの取り込み

ecspressoには以下のコマンドが用意されています。

❯ ecspresso init -h  
Usage: ecspresso init --service=STRING --task-definition=STRING

create configuration files from existing ECS service

このコマンドを用いて、先程作成したECSサービスとECSタスク定義を取り込みます。

ecspresso init --config config.yaml --region us-west-2 --cluster t3-kato-dev --service t3-kato-dev
2023/11/09 15:58:38 t3-kato-dev/t3-kato-dev save service definition to ecs-service-def.json
2023/11/09 15:58:38 t3-kato-dev/t3-kato-dev save task definition to ecs-task-def.json
2023/11/09 15:58:38 t3-kato-dev/t3-kato-dev save config to config.yaml

これで設定ファイルの取り込みは完了です。 各ファイルの中身を見てみましょう。

config.yaml

region: us-west-2
cluster: t3-kato-dev
service: t3-kato-dev
service_definition: ecs-service-def.json
task_definition: ecs-task-def.json
timeout: "10m0s"

ecs-task-def.json

{
  "containerDefinitions": [
    {
      "cpu": 0,
      "essential": true,
      "image": "public.ecr.aws/nginx/nginx:1.25",
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-create-group": "true",
          "awslogs-group": "/ecs/t3-kato-dev",
          "awslogs-region": "us-west-2",
          "awslogs-stream-prefix": "ecs"
        }
      },
      "name": "nginx",
      "portMappings": [
        {
          "appProtocol": "http",
          "containerPort": 80,
          "hostPort": 80,
          "name": "nginx-80-tcp",
          "protocol": "tcp"
        }
      ]
    }
  ],
  "cpu": "1024",
  "executionRoleArn": "arn:aws:iam::<<AWSアカウントID>>:role/ecsTaskExecutionRole",
  "family": "t3-kato-dev",
  "ipcMode": "",
  "memory": "3072",
  "networkMode": "awsvpc",
  "pidMode": "",
  "requiresCompatibilities": [
    "FARGATE"
  ],
  "runtimePlatform": {
    "cpuArchitecture": "X86_64",
    "operatingSystemFamily": "LINUX"
  }
}

ecs-service-def.json

{
  "deploymentConfiguration": {
    "deploymentCircuitBreaker": {
      "enable": true,
      "rollback": true
    },
    "maximumPercent": 200,
    "minimumHealthyPercent": 100
  },
  "deploymentController": {
    "type": "ECS"
  },
  "desiredCount": 1,
  "enableECSManagedTags": true,
  "enableExecuteCommand": false,
  "healthCheckGracePeriodSeconds": 0,
  "launchType": "FARGATE",
  "loadBalancers": [
    {
      "containerName": "nginx",
      "containerPort": 80,
      "targetGroupArn": "arn:aws:elasticloadbalancing:us-west-2:<<AWSアカウントID>>:targetgroup/tf-20231030054829960000000002/76f8f80964e93c67"
    }
  ],
  "networkConfiguration": {
    "awsvpcConfiguration": {
      "assignPublicIp": "DISABLED",
      "securityGroups": [
        "sg-0b7784dbfd998ff98"
      ],
      "subnets": [
        "subnet-079a698011fff2a88",
        "subnet-0304c5170a559deae"
      ]
    }
  },
  "platformFamily": "Linux",
  "platformVersion": "LATEST",
  "propagateTags": "NONE",
  "schedulingStrategy": "REPLICA"
}

各種設定が取り込まれていることがわかります。

試しにecs-task-def.jsonのimageを更新してみます。

      "image": "public.ecr.aws/nginx/nginx:1.25",

      "image": "public.ecr.aws/nginx/nginx:1.24",

とし、ecspresso diffを実行します。

❯ ecspresso diff --config config.yaml
--- arn:aws:ecs:us-west-2:<<AWSアカウントID>>:task-definition/t3-kato-dev:2
+++ ecs-task-def.json
@@ -3,7 +3,7 @@
     {
       "cpu": 0,
       "essential": true,
-      "image": "public.ecr.aws/nginx/nginx:1.25",
+      "image": "public.ecr.aws/nginx/nginx:1.24",
       "logConfiguration": {
         "logDriver": "awslogs",
         "options": {

差分が表示されました。ecspresso diffは差分を確認するだけなので実リソースへの影響はありません。

5. 設定ファイルを修正

4で取り込んだ設定ファイルをprodでも使えるように修正していきます。

環境差分については、以下2パターンで管理するものとします。

  • tfstate
    • ecspressoのpluginを導入し利用
    • サブネットやセキュリティグループなどTerraformリソースで定義されているものはtfstateから参照可能
    • Terraformリソースから取得出来ない値(ECSタスクのCPUやメモリ等)は、outputを活用することで参照可能
    • ただし設定ファイル内のint型で定義されている値については現状tfstateから参照出来ない*1
    • 環境の切り替えはconfig.yamlに記載するtfstateのURLを変更することで切り替える
  • 環境変数
    • env又はmust_envを用いることで環境変数を読み込むことが可能
    • config.yamlではpluginが利用出来ない(つまりtfstateから値が参照できない)ため環境変数を用いる
    • 環境変数は実行基盤(自端末、CodeBuild、GitHub Actions等)に設定追加が必要なため環境差分は極力tfstateに寄せる
    • イメージタグのみデプロイ時に環境変数で埋め込めた方が便利なので例外的に環境変数で持たせる
    • 環境の切り替えはecspresso deploy等のコマンド実行時に変数を代入することで切り替える

なお、SSM pluginを用いることでAWS Systems ManagerのParameter Storeから値を参照することが可能です。 しかし、SSM pluginの構文上、対象のParameter Storeのパスに環境変数などを当て込むことが難しく、こちらを用いての環境切り替えはスクリプトの作り込みなどが必要となりそうでしたので、今回は採用を見送りました。

ではファイルを修正します。以下、修正前と後での差分です。

config.yaml

diff --git a/config.yaml b/config.yaml
index ea088e5..2632d26 100644
--- a/config.yaml
+++ b/config.yaml
@@ -2,2 +2,2 @@ region: us-west-2
-cluster: t3-kato-dev
-service: t3-kato-dev
+cluster: t3-kato-{{ must_env `ENV` }}
+service: t3-kato-{{ must_env `ENV` }}
@@ -6,0 +7,4 @@ timeout: "10m0s"
+plugins:
+  - name: tfstate
+    config:
+      url: s3://t3-kato-terraform-backend/{{ must_env `ENV` }}/terraform.tfstate

ecs-service-def.json

diff --git a/ecs-service-def.json b/ecs-service-def.json
index 8ffb0b1..ab02e22 100644
--- a/ecs-service-def.json
+++ b/ecs-service-def.json
@@ -22 +22 @@
-      "targetGroupArn": "arn:aws:elasticloadbalancing:us-west-2:<<AWSアカウントID>>:targetgroup/tf-20231030054829960000000002/76f8f80964e93c67"
+      "targetGroupArn": "{{ tfstate `module.network.module.alb.aws_lb_target_group.main[0].arn` }}"
@@ -29 +29 @@
-        "sg-0b7784dbfd998ff98"
+        "{{ tfstate `module.network.aws_security_group.ecs.id` }}"
@@ -32,2 +32,2 @@
-        "subnet-079a698011fff2a88",
-        "subnet-0304c5170a559deae"
+        "{{ tfstate `module.network.module.vpc.aws_subnet.private[0].id` }}",
+        "{{ tfstate `module.network.module.vpc.aws_subnet.private[1].id` }}"

ecs-task-def.json

diff --git a/ecs-task-def.json b/ecs-task-def.json
index ed78eb1..a125768 100644
--- a/ecs-task-def.json
+++ b/ecs-task-def.json
@@ -6 +6 @@
-      "image": "public.ecr.aws/nginx/nginx:1.25",
+      "image": "public.ecr.aws/nginx/nginx:{{ must_env `IMAGE_TAG` }}",
@@ -11 +11 @@
-          "awslogs-group": "/ecs/t3-kato-dev",
+          "awslogs-group": "{{ tfstate `module.ecs.aws_cloudwatch_log_group.this.name` }}",
@@ -28 +28 @@
-  "cpu": "1024",
+  "cpu": "{{ tfstate `output.cpu` }}",
@@ -30 +30 @@
-  "family": "t3-kato-dev",
+  "family": "t3-kato-{{ must_env `ENV` }}",
@@ -32 +32 @@
-  "memory": "3072",
+  "memory": "{{ tfstate `output.memory` }}",

output.tfは下記の通りです。prodも同様です。

dev/envs/output.tf

output "cpu" {
  value = "1024"
}

output "memory" {
  value = "3072"
}

6. ecspresso deploy(prod)

いよいよprodにデプロイします。

下記コマンドでECSデプロイを実行します。ecspresso deployコマンドはECSサービスが存在しない場合自動で作成してくれます。

❯ ENV=prod IMAGE_TAG=1.25 ecspresso deploy --config config.yaml
2023/11/09 19:32:36 t3-kato-prod/t3-kato-prod Starting deploy 
2023/11/09 19:32:37 t3-kato-prod/t3-kato-prod Service t3-kato-prod not found. Creating a new service 
2023/11/09 19:32:37 t3-kato-prod/t3-kato-prod Starting create service 
2023/11/09 19:32:37 t3-kato-prod/t3-kato-prod Registering a new task definition...
2023/11/09 19:32:37 t3-kato-prod/t3-kato-prod Task definition is registered t3-kato-prod:8
2023/11/09 19:32:38 t3-kato-prod/t3-kato-prod Service is created
2023/11/09 19:32:41 t3-kato-prod/t3-kato-prod Waiting for service stable...(it will take a few minutes)
2023/11/09 19:32:45 (service t3-kato-prod) has started 1 tasks: (task 11c3ef949b62428290c5770306b75b04).
2023/11/09 19:32:52 t3-kato-prod/t3-kato-prod  PRIMARY t3-kato-prod:8 desired:1 pending:1 running:0 IN_PROGRESS(ECS deployment ecs-svc/3896359576468577722 in progress.)
2023/11/09 19:33:05 (service t3-kato-prod) registered 1 targets in (target-group arn:aws:elasticloadbalancing:us-west-2:<<AWSアカウントID>>:targetgroup/tf-20231030070953159400000002/0ee53b36e1ca3188)
2023/11/09 19:33:12 t3-kato-prod/t3-kato-prod  PRIMARY t3-kato-prod:8 desired:1 pending:0 running:1 IN_PROGRESS(ECS deployment ecs-svc/3896359576468577722 in progress.)
2023/11/09 19:33:24 t3-kato-prod/t3-kato-prod Service is stable now. Completed!

これでECSデプロイは完了です。(何度かやり直したのでECSタスク定義のリビジョンが上がってます・・・)

dev同様にALBのDNS名からnginxの画面が表示されればOKです。

最後に

ecspressoとTerraformを連携して複数環境にECSデプロイを実施してみました。

環境差分をどのように管理するか試行錯誤しましたが、最終的にはtfstateに集約させるのが良さそうという考えに至りました。 ただしtfstateからはint型の代入が難しいなど工夫が必要な箇所もあったので、検討の余地はありそうです。

今回は単純にデプロイしただけですが、ecspressoについて以下の事柄もいつか触ってみたいと思います。

  • 諸々サブコマンドの実行
  • GitHub Actionsの活用
  • B/Gデプロイ
  • ecschedulerの活用

執筆者: 加藤 俊稀

🧑‍💻クラウドエンジニア
📝https://tech.nri-net.com/archive/author/t3-kato