[アップデート] AWS CDK で ECS の hotswap デプロイの最小/最大ヘルス率をカスタマイズ可能になりました

[アップデート] AWS CDK で ECS の hotswap デプロイの最小/最大ヘルス率をカスタマイズ可能になりました

Clock Icon2024.10.26

こんにちは、製造ビジネステクノロジー部の若槻です。

AWS CDK の最新のリリースである v2.164.0 で、下記のアップデートが追加されていました。

cli: add ability to configure hotswap properties for ECS (#30511) (fee2cf8), closes #29618

AWS CDK では Amazon ECS などの一部のサービスで hotswap デプロイがサポートされています。この仕組みにより CloudFormation を経由せずに、スタックの一部のリソースを更新することができます。これにより、デプロイの時間を短縮し、開発者のフィードバックループを高速化できます。

https://aws.amazon.com/jp/blogs/containers/accelerating-development-feedback-loops-with-aws-cdk-hotswap-deployments-for-amazon-ecs/

そして今回の AWS CDK のアップデートにより、この Amazon ECS の hotswap デプロイの最小/最大ヘルス率をカスタマイズ可能になりました。

試してみた

通常のデプロイ

以前紹介したこちらのコードを使用して、まずは通常のデプロイの場合を確認します。
https://dev.classmethod.jp/articles/using-containerimage-fromasset-to-build-container-image-from-source-with-applicationloadbalancedfargateservice-in-aws-cdk-and-amazon-ecs/

実装内容
nodejs-app/index.js
const http = require('http');

const server = http.createServer((req, res) => {
  const currentTime = new Date().toISOString();
  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/plain');
  res.end(`Current time: ${currentTime}`);
});

const port = 3000;
server.listen(port, () => {
  console.log(`Server running at http://localhost:${port}/`);
});
nodejs-app/Dockerfile
FROM node:20

WORKDIR /app

COPY index.js .

CMD ["node", "index.js"]
lib/cdk-sample-stack.ts
import * as ecs from 'aws-cdk-lib/aws-ecs';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as ecsPatterns from 'aws-cdk-lib/aws-ecs-patterns';
import { Stack } from 'aws-cdk-lib';
import { Construct } from 'constructs';

export class CdkSampleStack extends Stack {
  constructor(scope: Construct, id: string) {
    super(scope, id);

    // VPCの作成
    const vpc = new ec2.Vpc(this, 'MyVpc');

    // ECSクラスターの作成
    const cluster = new ecs.Cluster(this, 'MyCluster', {
      vpc,
    });

    // ソースコードからコンテナイメージをビルド
    const image = ecs.ContainerImage.fromAsset('./nodejs-app');

    // ApplicationLoadBalancedFargateService による ECS サービスの作成
    new ecsPatterns.ApplicationLoadBalancedFargateService(this, 'MyService', {
      cluster,
      taskImageOptions: {
        image,
        containerPort: 3000,
        entryPoint: [],
        command: ['node', 'index.js'],
      },
      runtimePlatform: {
        cpuArchitecture: ecs.CpuArchitecture.ARM64,
      },
    });
  }
}

cdk deploy コマンドにより通常のデプロイを実施します。

マネジメントコンソールから ECS サービスのデプロイメントを確認すると、最小ヘルス率が 50 %、最大ヘルス率が 200 %となっていました。

hotswap デプロイ(カスタマイズなし)

続いて、hotswap デプロイを「カスタマイズなし」で実施してみます。ソースコードを変更し、cdk deploy --hotswap コマンドを実行します。

コード変更差分
$ git diff
diff --git a/nodejs-app/index.js b/nodejs-app/index.js
index a60833a..d60f283 100644
--- a/nodejs-app/index.js
+++ b/nodejs-app/index.js
@@ -9,5 +9,6 @@ const server = http.createServer((req, res) => {

 const port = 3000;
 server.listen(port, () => {
+  console.log('hoge');
   console.log(`Server running at http://localhost:${port}/`);
 });
デプロイコマンド実行の出力内容
npm run deploy -- --hotswap

> [email protected] deploy
> cdk deploy --require-approval never --method=direct --hotswap

✨  Synthesis time: 5.86s

⚠️ The --hotswap and --hotswap-fallback flags deliberately introduce CloudFormation drift to speed up deployments
⚠️ They should only be used for development - never use them for your production Stacks!

SampleApp: start: Building fc3e5a21197f0b63abc11f63a5a91d3252483ab49c141b5ff35ef1a1d6feeb4a:current_account-current_region
SampleApp: success: Built fc3e5a21197f0b63abc11f63a5a91d3252483ab49c141b5ff35ef1a1d6feeb4a:current_account-current_region
SampleApp: start: Building ba1f284d1a26624807c3e32c9fdcd320813faeac2d56ce9da90da75eaa00d5c6:current_account-current_region
SampleApp: start: Publishing fc3e5a21197f0b63abc11f63a5a91d3252483ab49c141b5ff35ef1a1d6feeb4a:current_account-current_region
SampleApp: success: Published fc3e5a21197f0b63abc11f63a5a91d3252483ab49c141b5ff35ef1a1d6feeb4a:current_account-current_region
#0 building with "rancher-desktop" instance using docker driver

#1 [internal] load .dockerignore
#1 transferring context:
#1 transferring context: 2B done
#1 DONE 0.0s

#2 [internal] load build definition from Dockerfile
#2 transferring dockerfile: 107B done
#2 DONE 0.0s

#3 [internal] load metadata for docker.io/library/node:20
#3 DONE 7.6s

#4 [internal] load build context
#4 transferring context:
#4 transferring context: 420B done
#4 DONE 0.0s

#5 [1/3] FROM docker.io/library/node:20@sha256:a5e0ed56f2c20b9689e0f7dd498cac7e08d2a3a283e92d9304e7b9b83e3c6ff3
#5 resolve docker.io/library/node:20@sha256:a5e0ed56f2c20b9689e0f7dd498cac7e08d2a3a283e92d9304e7b9b83e3c6ff3 0.0s done
#5 sha256:bd35ad381a72b8e86be94d1eb8db22d595f77c25b52950ae180894b145fe669f 2.50kB / 2.50kB done
#5 sha256:c1e0ef7b956a07c7b090256aa16cbb0550a34d0625d1d23c5b1a76e92a58d01e 0B / 49.58MB 0.1s
#5 sha256:a5e0ed56f2c20b9689e0f7dd498cac7e08d2a3a283e92d9304e7b9b83e3c6ff3 6.41kB / 6.41kB done
#5 sha256:85f76d7c2b89b3e545565c80ac1a21b5bb57f90095a8e09cdeb03b5039506810 6.62kB / 6.62kB done
#5 sha256:95b894d63c771a6056bc65ff25192b251413259ba7d160b0076f0f5d7975dc39 0B / 23.59MB 0.2s
#5 sha256:cb5594266b1bacf9ad6855b00d9c5c98e721001eb115218eda673e548e04fdbf 0B / 64.35MB 0.2s
#5 sha256:c1e0ef7b956a07c7b090256aa16cbb0550a34d0625d1d23c5b1a76e92a58d01e 5.32MB / 49.58MB 0.5s
#5 sha256:95b894d63c771a6056bc65ff25192b251413259ba7d160b0076f0f5d7975dc39 6.80MB / 23.59MB 0.5s
#5 sha256:c1e0ef7b956a07c7b090256aa16cbb0550a34d0625d1d23c5b1a76e92a58d01e 9.10MB / 49.58MB 0.6s
#5 sha256:95b894d63c771a6056bc65ff25192b251413259ba7d160b0076f0f5d7975dc39 9.44MB / 23.59MB 0.6s
#5 sha256:c1e0ef7b956a07c7b090256aa16cbb0550a34d0625d1d23c5b1a76e92a58d01e 16.29MB / 49.58MB 0.9s
#5 sha256:95b894d63c771a6056bc65ff25192b251413259ba7d160b0076f0f5d7975dc39 16.54MB / 23.59MB 0.9s
#5 sha256:c1e0ef7b956a07c7b090256aa16cbb0550a34d0625d1d23c5b1a76e92a58d01e 20.59MB / 49.58MB 1.0s
#5 sha256:95b894d63c771a6056bc65ff25192b251413259ba7d160b0076f0f5d7975dc39 20.74MB / 23.59MB 1.0s
#5 sha256:95b894d63c771a6056bc65ff25192b251413259ba7d160b0076f0f5d7975dc39 23.06MB / 23.59MB 1.1s
#5 sha256:c1e0ef7b956a07c7b090256aa16cbb0550a34d0625d1d23c5b1a76e92a58d01e 29.36MB / 49.58MB 1.3s
#5 sha256:95b894d63c771a6056bc65ff25192b251413259ba7d160b0076f0f5d7975dc39 23.59MB / 23.59MB 1.1s done
#5 sha256:cb5594266b1bacf9ad6855b00d9c5c98e721001eb115218eda673e548e04fdbf 4.19MB / 64.35MB 1.3s
#5 sha256:59d4884f85282b9a352dbcedf2cccd073a63e60b151be84375ce9279dec1c553 0B / 202.64MB 1.3s
#5 sha256:c1e0ef7b956a07c7b090256aa16cbb0550a34d0625d1d23c5b1a76e92a58d01e 32.51MB / 49.58MB 1.4s
#5 sha256:cb5594266b1bacf9ad6855b00d9c5c98e721001eb115218eda673e548e04fdbf 8.39MB / 64.35MB 1.4s
#5 sha256:c1e0ef7b956a07c7b090256aa16cbb0550a34d0625d1d23c5b1a76e92a58d01e 35.65MB / 49.58MB 1.5s
#5 sha256:c1e0ef7b956a07c7b090256aa16cbb0550a34d0625d1d23c5b1a76e92a58d01e 41.94MB / 49.58MB 1.7s
#5 sha256:cb5594266b1bacf9ad6855b00d9c5c98e721001eb115218eda673e548e04fdbf 17.83MB / 64.35MB 1.7s
#5 sha256:c1e0ef7b956a07c7b090256aa16cbb0550a34d0625d1d23c5b1a76e92a58d01e 45.09MB / 49.58MB 1.8s
#5 sha256:c1e0ef7b956a07c7b090256aa16cbb0550a34d0625d1d23c5b1a76e92a58d01e 48.23MB / 49.58MB 1.9s
#5 sha256:cb5594266b1bacf9ad6855b00d9c5c98e721001eb115218eda673e548e04fdbf 24.12MB / 64.35MB 1.9s
#5 sha256:c1e0ef7b956a07c7b090256aa16cbb0550a34d0625d1d23c5b1a76e92a58d01e 49.58MB / 49.58MB 2.0s done
#5 sha256:cb5594266b1bacf9ad6855b00d9c5c98e721001eb115218eda673e548e04fdbf 30.41MB / 64.35MB 2.1s
#5 sha256:4767b1635f4a478c9c34f6169008202af623e1c05ea663f697e49bbb25ac0166 0B / 3.33kB 2.1s
#5 sha256:cb5594266b1bacf9ad6855b00d9c5c98e721001eb115218eda673e548e04fdbf 37.75MB / 64.35MB 2.3s
#5 extracting sha256:c1e0ef7b956a07c7b090256aa16cbb0550a34d0625d1d23c5b1a76e92a58d01e
#5 sha256:59d4884f85282b9a352dbcedf2cccd073a63e60b151be84375ce9279dec1c553 11.53MB / 202.64MB 2.4s
#5 sha256:cb5594266b1bacf9ad6855b00d9c5c98e721001eb115218eda673e548e04fdbf 44.71MB / 64.35MB 2.5s
#5 sha256:4767b1635f4a478c9c34f6169008202af623e1c05ea663f697e49bbb25ac0166 3.33kB / 3.33kB 2.4s done
#5 sha256:54b03e66776a3dc3f59563bd7ed7312bc6bfb4a32d91e96baaef7cb84e3af1ac 0B / 48.18MB 2.5s
#5 sha256:cb5594266b1bacf9ad6855b00d9c5c98e721001eb115218eda673e548e04fdbf 48.23MB / 64.35MB 2.6s
#5 sha256:cb5594266b1bacf9ad6855b00d9c5c98e721001eb115218eda673e548e04fdbf 58.72MB / 64.35MB 2.9s
#5 sha256:59d4884f85282b9a352dbcedf2cccd073a63e60b151be84375ce9279dec1c553 25.17MB / 202.64MB 2.9s
#5 sha256:cb5594266b1bacf9ad6855b00d9c5c98e721001eb115218eda673e548e04fdbf 64.35MB / 64.35MB 3.1s
#5 sha256:cb5594266b1bacf9ad6855b00d9c5c98e721001eb115218eda673e548e04fdbf 64.35MB / 64.35MB 3.1s done
#5 sha256:54b03e66776a3dc3f59563bd7ed7312bc6bfb4a32d91e96baaef7cb84e3af1ac 3.15MB / 48.18MB 3.2s
#5 sha256:36ee4db2c5c58c29030967bde0def18ee575891b59fef27cd97e708752b7653a 0B / 1.25MB 3.2s
#5 sha256:59d4884f85282b9a352dbcedf2cccd073a63e60b151be84375ce9279dec1c553 38.80MB / 202.64MB 3.4s
#5 sha256:54b03e66776a3dc3f59563bd7ed7312bc6bfb4a32d91e96baaef7cb84e3af1ac 8.39MB / 48.18MB 3.4s
#5 sha256:54b03e66776a3dc3f59563bd7ed7312bc6bfb4a32d91e96baaef7cb84e3af1ac 12.58MB / 48.18MB 3.5s
#5 sha256:36ee4db2c5c58c29030967bde0def18ee575891b59fef27cd97e708752b7653a 1.25MB / 1.25MB 3.4s done
#5 sha256:a2a0e0d46948addadab310b4a1b882aff84d7507730aa3f2a28c361fe4338b8b 0B / 443B 3.5s
#5 sha256:54b03e66776a3dc3f59563bd7ed7312bc6bfb4a32d91e96baaef7cb84e3af1ac 15.73MB / 48.18MB 3.6s
#5 sha256:54b03e66776a3dc3f59563bd7ed7312bc6bfb4a32d91e96baaef7cb84e3af1ac 21.11MB / 48.18MB 3.8s
#5 sha256:a2a0e0d46948addadab310b4a1b882aff84d7507730aa3f2a28c361fe4338b8b 443B / 443B 3.7s done
#5 sha256:59d4884f85282b9a352dbcedf2cccd073a63e60b151be84375ce9279dec1c553 51.38MB / 202.64MB 3.9s
#5 sha256:54b03e66776a3dc3f59563bd7ed7312bc6bfb4a32d91e96baaef7cb84e3af1ac 25.51MB / 48.18MB 3.9s
#5 sha256:54b03e66776a3dc3f59563bd7ed7312bc6bfb4a32d91e96baaef7cb84e3af1ac 28.77MB / 48.18MB 4.0s
#5 sha256:54b03e66776a3dc3f59563bd7ed7312bc6bfb4a32d91e96baaef7cb84e3af1ac 32.51MB / 48.18MB 4.1s
#5 sha256:54b03e66776a3dc3f59563bd7ed7312bc6bfb4a32d91e96baaef7cb84e3af1ac 36.49MB / 48.18MB 4.2s
#5 sha256:59d4884f85282b9a352dbcedf2cccd073a63e60b151be84375ce9279dec1c553 62.91MB / 202.64MB 4.4s
#5 sha256:54b03e66776a3dc3f59563bd7ed7312bc6bfb4a32d91e96baaef7cb84e3af1ac 44.04MB / 48.18MB 4.4s
#5 sha256:54b03e66776a3dc3f59563bd7ed7312bc6bfb4a32d91e96baaef7cb84e3af1ac 47.19MB / 48.18MB 4.5s
#5 sha256:54b03e66776a3dc3f59563bd7ed7312bc6bfb4a32d91e96baaef7cb84e3af1ac 48.18MB / 48.18MB 4.6s done
#5 sha256:59d4884f85282b9a352dbcedf2cccd073a63e60b151be84375ce9279dec1c553 77.59MB / 202.64MB 4.8s
#5 sha256:59d4884f85282b9a352dbcedf2cccd073a63e60b151be84375ce9279dec1c553 89.13MB / 202.64MB 5.0s
#5 sha256:59d4884f85282b9a352dbcedf2cccd073a63e60b151be84375ce9279dec1c553 100.66MB / 202.64MB 5.2s
#5 extracting sha256:c1e0ef7b956a07c7b090256aa16cbb0550a34d0625d1d23c5b1a76e92a58d01e 3.0s done
#5 sha256:59d4884f85282b9a352dbcedf2cccd073a63e60b151be84375ce9279dec1c553 112.20MB / 202.64MB 5.4s
#5 extracting sha256:95b894d63c771a6056bc65ff25192b251413259ba7d160b0076f0f5d7975dc39
#5 sha256:59d4884f85282b9a352dbcedf2cccd073a63e60b151be84375ce9279dec1c553 126.60MB / 202.64MB 5.6s
#5 sha256:59d4884f85282b9a352dbcedf2cccd073a63e60b151be84375ce9279dec1c553 139.46MB / 202.64MB 5.8s
#5 sha256:59d4884f85282b9a352dbcedf2cccd073a63e60b151be84375ce9279dec1c553 153.09MB / 202.64MB 6.0s
#5 sha256:59d4884f85282b9a352dbcedf2cccd073a63e60b151be84375ce9279dec1c553 166.72MB / 202.64MB 6.2s
#5 extracting sha256:95b894d63c771a6056bc65ff25192b251413259ba7d160b0076f0f5d7975dc39 0.7s done
#5 extracting sha256:cb5594266b1bacf9ad6855b00d9c5c98e721001eb115218eda673e548e04fdbf
#5 sha256:59d4884f85282b9a352dbcedf2cccd073a63e60b151be84375ce9279dec1c553 186.65MB / 202.64MB 6.5s
#5 sha256:59d4884f85282b9a352dbcedf2cccd073a63e60b151be84375ce9279dec1c553 198.18MB / 202.64MB 6.7s
#5 sha256:59d4884f85282b9a352dbcedf2cccd073a63e60b151be84375ce9279dec1c553 202.64MB / 202.64MB 6.9s done
#5 extracting sha256:cb5594266b1bacf9ad6855b00d9c5c98e721001eb115218eda673e548e04fdbf 2.1s done
#5 extracting sha256:59d4884f85282b9a352dbcedf2cccd073a63e60b151be84375ce9279dec1c553 0.1s
#5 extracting sha256:59d4884f85282b9a352dbcedf2cccd073a63e60b151be84375ce9279dec1c553 5.2s
#5 extracting sha256:59d4884f85282b9a352dbcedf2cccd073a63e60b151be84375ce9279dec1c553 6.6s done
#5 extracting sha256:4767b1635f4a478c9c34f6169008202af623e1c05ea663f697e49bbb25ac0166 done
#5 extracting sha256:54b03e66776a3dc3f59563bd7ed7312bc6bfb4a32d91e96baaef7cb84e3af1ac
#5 extracting sha256:54b03e66776a3dc3f59563bd7ed7312bc6bfb4a32d91e96baaef7cb84e3af1ac 1.8s done
#5 extracting sha256:36ee4db2c5c58c29030967bde0def18ee575891b59fef27cd97e708752b7653a
#5 extracting sha256:36ee4db2c5c58c29030967bde0def18ee575891b59fef27cd97e708752b7653a 0.1s done
#5 extracting sha256:a2a0e0d46948addadab310b4a1b882aff84d7507730aa3f2a28c361fe4338b8b done
#5 DONE 17.5s

#6 [2/3] WORKDIR /app
#6 DONE 0.2s

#7 [3/3] COPY index.js .
#7 DONE 0.0s

#8 exporting to image
#8 exporting layers 0.0s done
#8 writing image sha256:b486534968e22074abea63622920ddd423325663d57ed20cfe8d39eeb172b592 done
#8 naming to docker.io/library/cdkasset-ba1f284d1a26624807c3e32c9fdcd320813faeac2d56ce9da90da75eaa00d5c6 done
#8 DONE 0.0s
SampleApp: success: Built ba1f284d1a26624807c3e32c9fdcd320813faeac2d56ce9da90da75eaa00d5c6:current_account-current_region
SampleApp: start: Publishing ba1f284d1a26624807c3e32c9fdcd320813faeac2d56ce9da90da75eaa00d5c6:current_account-current_region
The push refers to repository [XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/cdk-hnb659fds-container-assets-XXXXXXXXXXXX-ap-northeast-1]
573aa2b2fff9: Preparing
050bd9c62caf: Preparing
3ff98deda135: Preparing
9379da9e1424: Preparing
14055721ce48: Preparing
cfe6829ad098: Preparing
a2b8ce9d73a5: Preparing
59c47e88439d: Preparing
afc6ebde4174: Preparing
5968baa45665: Preparing
59c47e88439d: Waiting
afc6ebde4174: Waiting
5968baa45665: Waiting
cfe6829ad098: Waiting
a2b8ce9d73a5: Waiting
050bd9c62caf: Pushed
573aa2b2fff9: Pushed
9379da9e1424: Pushed
3ff98deda135: Pushed
14055721ce48: Pushed
cfe6829ad098: Pushed
afc6ebde4174: Pushed
5968baa45665: Pushed
59c47e88439d: Pushed
a2b8ce9d73a5: Pushed
ba1f284d1a26624807c3e32c9fdcd320813faeac2d56ce9da90da75eaa00d5c6: digest: sha256:a4fdb59aee02e00e33ca0c6b62d622e611b3bcddbb0468d1ee8dee78d88da887 size: 2417
SampleApp: success: Published ba1f284d1a26624807c3e32c9fdcd320813faeac2d56ce9da90da75eaa00d5c6:current_account-current_region
SampleApp: deploying... [1/1]

✨ hotswapping resources:
   ✨ ECS Task Definition 'SampleAppMyServiceTaskDef6BF43B2D'
   ✨ ECS Service 'SampleApp-MyServiceDD83057A-WMJGdKSxlkQN'
✨ ECS Task Definition 'SampleAppMyServiceTaskDef6BF43B2D' hotswapped!
✨ ECS Service 'SampleApp-MyServiceDD83057A-WMJGdKSxlkQN' hotswapped!

 ✅  SampleApp

✨  Deployment time: 101.11s

Outputs:
SampleApp.MyServiceLoadBalancerDNS1782DE5A = Sample-MySer-p3JkwpAQKu8Q-819364614.ap-northeast-1.elb.amazonaws.com
SampleApp.MyServiceServiceURL4C379FE3 = http://Sample-MySer-p3JkwpAQKu8Q-819364614.ap-northeast-1.elb.amazonaws.com
Stack ARN:
arn:aws:cloudformation:ap-northeast-1:XXXXXXXXXXXX:stack/SampleApp/dd738eb0-8c8d-11ef-bce8-0e118a446357

✨  Total time: 106.97s

ECS サービスのデプロイメントを確認すると、最小ヘルス率が 0 %、最大ヘルス率が 200 %でデプロイが行われていました。これらのヘルス率が hotswap デプロイ時の既定値となるようです。

デプロイが完了した様子です。

CDK パッケージのアップデート

AWS CDK モジュールを v2.164.0 以上にアップデートします。

npm i aws-cdk-lib@latest aws-cdk@latest

hotswap デプロイ(カスタマイズあり)

次に hotswap デプロイを「カスタマイズあり」で実施してみます。

CDK パッケージのアップデートにより、cdk.jsonhotswap.minimumHealthyPercent および hotswap.maximumHealthyPercent フラグが利用可能になります。

cdk.json に次の設定を追加して、hotswap デプロイ時の最小ヘルス率を 100 %、最大ヘルス率を 250 %に設定するカスタマイズを行います。

  "hotswap": {
    "ecs": {
      "minimumHealthyPercent": 100,
      "maximumHealthyPercent": 250
    }
  }

ソースコードを再度変更し、cdk deploy --hotswap コマンドを実行します。

コード変更差分
$ git diff
diff --git a/cdk.json b/cdk.json
index b0d9072..de79473 100644
--- a/cdk.json
+++ b/cdk.json
@@ -31,5 +31,11 @@
     "@aws-cdk/aws-events:eventsTargetQueueSameAccount": true,
     "@aws-cdk/aws-iam:standardizedServicePrincipals": true,
     "@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true
+  },
+  "hotswap": {
+    "ecs": {
+      "minimumHealthyPercent": 100,
+      "maximumHealthyPercent": 250
+    }
   }
 }
diff --git a/nodejs-app/index.js b/nodejs-app/index.js
index d60f283..93ba410 100644
--- a/nodejs-app/index.js
+++ b/nodejs-app/index.js
@@ -9,6 +9,6 @@ const server = http.createServer((req, res) => {

 const port = 3000;
 server.listen(port, () => {
-  console.log('hoge');
+  console.log('piyo');
   console.log(`Server running at http://localhost:${port}/`);
 });
デプロイコマンド実行の出力内容
$ npm run deploy -- --hotswap

> [email protected] deploy
> cdk deploy --require-approval never --method=direct --hotswap

✨  Synthesis time: 6.77s

⚠️ The --hotswap and --hotswap-fallback flags deliberately introduce CloudFormation drift to speed up deployments
⚠️ They should only be used for development - never use them for your production Stacks!

SampleApp: start: Building 4932421c8bc810a9226ebe430f0aaa1103bc9d53ec62bc437d12a5e7199da82c:current_account-current_region
SampleApp: success: Built 4932421c8bc810a9226ebe430f0aaa1103bc9d53ec62bc437d12a5e7199da82c:current_account-current_region
SampleApp: start: Building bd4c6d9b0bc3f9713ed9dcb3d5c88f527b942a5732b341449d1e2f053367c291:current_account-current_region
SampleApp: start: Publishing 4932421c8bc810a9226ebe430f0aaa1103bc9d53ec62bc437d12a5e7199da82c:current_account-current_region
SampleApp: success: Published 4932421c8bc810a9226ebe430f0aaa1103bc9d53ec62bc437d12a5e7199da82c:current_account-current_region
#0 building with "rancher-desktop" instance using docker driver

#1 [internal] load build definition from Dockerfile
#1 transferring dockerfile: 107B done
#1 DONE 0.0s

#2 [internal] load .dockerignore
#2 transferring context: 2B done
#2 DONE 0.0s

#3 [internal] load metadata for docker.io/library/node:20
#3 DONE 3.0s

#4 [1/3] FROM docker.io/library/node:20@sha256:a5e0ed56f2c20b9689e0f7dd498cac7e08d2a3a283e92d9304e7b9b83e3c6ff3
#4 DONE 0.0s

#5 [internal] load build context
#5 transferring context: 420B done
#5 DONE 0.0s

#6 [2/3] WORKDIR /app
#6 CACHED

#7 [3/3] COPY index.js .
#7 DONE 0.0s

#8 exporting to image
#8 exporting layers done
#8 writing image sha256:fb97543d46225fb895880c1100128d72e0fafa5b1989d7ab9b908b6a2f7ba9f6 done
#8 naming to docker.io/library/cdkasset-bd4c6d9b0bc3f9713ed9dcb3d5c88f527b942a5732b341449d1e2f053367c291 done
#8 DONE 0.0s
SampleApp: success: Built bd4c6d9b0bc3f9713ed9dcb3d5c88f527b942a5732b341449d1e2f053367c291:current_account-current_region
SampleApp: start: Publishing bd4c6d9b0bc3f9713ed9dcb3d5c88f527b942a5732b341449d1e2f053367c291:current_account-current_region
The push refers to repository [XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/cdk-hnb659fds-container-assets-XXXXXXXXXXXX-ap-northeast-1]
ce55206a1bea: Preparing
050bd9c62caf: Preparing
3ff98deda135: Preparing
9379da9e1424: Preparing
14055721ce48: Preparing
cfe6829ad098: Preparing
a2b8ce9d73a5: Preparing
59c47e88439d: Preparing
afc6ebde4174: Preparing
5968baa45665: Preparing
cfe6829ad098: Waiting
a2b8ce9d73a5: Waiting
59c47e88439d: Waiting
afc6ebde4174: Waiting
5968baa45665: Waiting
3ff98deda135: Layer already exists
9379da9e1424: Layer already exists
14055721ce48: Layer already exists
050bd9c62caf: Layer already exists
59c47e88439d: Layer already exists
cfe6829ad098: Layer already exists
afc6ebde4174: Layer already exists
a2b8ce9d73a5: Layer already exists
5968baa45665: Layer already exists
ce55206a1bea: Pushed
bd4c6d9b0bc3f9713ed9dcb3d5c88f527b942a5732b341449d1e2f053367c291: digest: sha256:2d89b39d9c3daeb400484bf67d9d2d47f0f0af72805c12e85dddc12e56cfa8ed size: 2417
SampleApp: success: Published bd4c6d9b0bc3f9713ed9dcb3d5c88f527b942a5732b341449d1e2f053367c291:current_account-current_region
SampleApp: deploying... [1/1]

✨ hotswapping resources:
   ✨ ECS Task Definition 'SampleAppMyServiceTaskDef6BF43B2D'
   ✨ ECS Service 'SampleApp-MyServiceDD83057A-WMJGdKSxlkQN'
✨ ECS Task Definition 'SampleAppMyServiceTaskDef6BF43B2D' hotswapped!
✨ ECS Service 'SampleApp-MyServiceDD83057A-WMJGdKSxlkQN' hotswapped!

 ✅  SampleApp

✨  Deployment time: 186.92s

Outputs:
SampleApp.MyServiceLoadBalancerDNS1782DE5A = Sample-MySer-p3JkwpAQKu8Q-819364614.ap-northeast-1.elb.amazonaws.com
SampleApp.MyServiceServiceURL4C379FE3 = http://Sample-MySer-p3JkwpAQKu8Q-819364614.ap-northeast-1.elb.amazonaws.com
Stack ARN:
arn:aws:cloudformation:ap-northeast-1:XXXXXXXXXXXX:stack/SampleApp/dd738eb0-8c8d-11ef-bce8-0e118a446357

✨  Total time: 193.69s

ECS サービスのデプロイメントを確認すると、最小ヘルス率が 100 %、最大ヘルス率が 250 %でデプロイが行われていました。ちゃんとカスタマイズが反映されています。

おわりに

AWS CDK のアップデートにより、この Amazon ECS の hotswap デプロイの最小/最大ヘルス率をカスタマイズ可能になったので、その機能を試してみました。

hotswap デプロイ CloudFormation による正規のデプロイを行わないため、本番環境での使用は推奨されていません。よって開発環境へのデプロイ時に使用される場合が多いかと思いますが、この開発環境がデモ環境などの用途を兼用しているのでなるべくサービス断を抑えたい!という場合に役に立つ機能ではないでしょうか。

参考

https://zenn.dev/intercept6/articles/ed2dfded5aae03

https://dev.classmethod.jp/articles/ecs-fargate-check-service-minimum-healthy-percent/

以上

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.