こんにちは、CX事業本部 Delivery部の若槻です。
cdk deploy
で Hotswap deployments を使用すると、CloudFormation を介さずに変更をデプロイできるため、デプロイを高速化することができます。
この Hotswap では、Lambda functions や S3 Bucket Deployments だけでなく、AWS Step Functions State Machines の定義変更もサポートしています。
- Definition changes of AWS Step Functions State Machines.
そこで今回は、AWS Step Functions ワークフローの構築で AWS CDK の Hotswap deployments を使ってみました。
試してみた
最初の CDK コード
最初に次のような定義の State Machine を作成します。
lib/cdk-sample-stack.ts
import { aws_stepfunctions, Stack, StackProps } from 'aws-cdk-lib';
import { Construct } from 'constructs';
export class CdkSampleStack extends Stack {
public readonly myFileObjectKey: string;
constructor(scope: Construct, id: string, props: StackProps) {
super(scope, id, props);
new aws_stepfunctions.StateMachine(this, 'MyStateMachine', {
stateMachineName: 'MyStateMachine',
stateMachineType: aws_stepfunctions.StateMachineType.EXPRESS,
definitionBody: aws_stepfunctions.ChainDefinitionBody.fromChainable(
new aws_stepfunctions.Pass(this, 'MyPassState', {
result: aws_stepfunctions.Result.fromObject({ myKey: 'myValue' }),
})
),
});
}
}
CDK デプロイします。
cdk deploy
デプロイされたステートマシンを同期実行すると結果を取得できました。正常にデプロイが行われています。
$ aws stepfunctions start-sync-execution \
--state-machine-arn ${stateMachineArn} \
--query output | jq -r .
{"myKey":"myValue"}
通常の変更デプロイ
続いて、ワークフローの定義を変更してみます。
lib/cdk-sample-stack.ts
import { aws_stepfunctions, Stack, StackProps } from 'aws-cdk-lib';
import { Construct } from 'constructs';
export class CdkSampleStack extends Stack {
public readonly myFileObjectKey: string;
constructor(scope: Construct, id: string, props: StackProps) {
super(scope, id, props);
new aws_stepfunctions.StateMachine(this, 'MyStateMachine', {
stateMachineName: 'MyStateMachine',
stateMachineType: aws_stepfunctions.StateMachineType.EXPRESS,
definitionBody: aws_stepfunctions.ChainDefinitionBody.fromChainable(
new aws_stepfunctions.Pass(this, 'MyPassState', {
result: aws_stepfunctions.Result.fromObject({ myKey: 'myValue2' }),
})
),
});
}
}
CDK デプロイを行うと、完了まで約 20 秒を要しました。
cdk deploy
Synthesis time: 2.84s
CdkSampleStack: start: Building ed610dcd08cc23e5160d1c309f5a3d26c864aded667a1aae35904e95619ebfc3:current_account-current_region
CdkSampleStack: success: Built ed610dcd08cc23e5160d1c309f5a3d26c864aded667a1aae35904e95619ebfc3:current_account-current_region
CdkSampleStack: start: Publishing ed610dcd08cc23e5160d1c309f5a3d26c864aded667a1aae35904e95619ebfc3:current_account-current_region
CdkSampleStack: success: Published ed610dcd08cc23e5160d1c309f5a3d26c864aded667a1aae35904e95619ebfc3:current_account-current_region
CdkSampleStack: deploying... [1/1]
CdkSampleStack: creating CloudFormation changeset...
CdkSampleStack
Deployment time: 17.39s
Stack ARN:
arn:aws:cloudformation:ap-northeast-1:XXXXXXXXXXXX:stack/CdkSampleStack/e68b6900-f01c-11ed-8538-06bbc29e5367
Total time: 20.23s
当然ですが、ワークフローを実行するとデプロイにより更新されていることが分かります。
$ aws stepfunctions start-sync-execution \
--state-machine-arn ${stateMachineArn} \
--query output | jq -r .
{"myKey":"myValue"}
--hotswap
による変更デプロイ
続いて今回の本題である Hotswap deployments を試してみます。
ワークフローの定義をさらに変更します。また、Hotswap の対象とならないリソースとして、AWS SSM Parameter を追加します。
lib/cdk-sample-stack.ts
import { aws_stepfunctions, aws_ssm, Stack, StackProps } from 'aws-cdk-lib';
import { Construct } from 'constructs';
export class CdkSampleStack extends Stack {
public readonly myFileObjectKey: string;
constructor(scope: Construct, id: string, props: StackProps) {
super(scope, id, props);
// ステートマシン以外のリソースを定義
new aws_ssm.StringParameter(this, 'MyParameter', {
parameterName: 'MyParameter',
stringValue: 'MyParameterValue',
});
new aws_stepfunctions.StateMachine(this, 'MyStateMachine', {
stateMachineName: 'MyStateMachine',
stateMachineType: aws_stepfunctions.StateMachineType.EXPRESS,
definitionBody: aws_stepfunctions.ChainDefinitionBody.fromChainable(
new aws_stepfunctions.Pass(this, 'MyPassState', {
result: aws_stepfunctions.Result.fromObject({ myKey: 'myValue3' }),
})
),
});
}
}
ローカルのスタック定義と CloudFormation スタックの差分を確認します。
$ cdk diff
Stack CdkSampleStack
Resources
[+] AWS::SSM::Parameter MyParameter MyParameter18BA547D
[~] AWS::StepFunctions::StateMachine MyStateMachine MyStateMachine6C968CA5
└─ [~] DefinitionString
├─ [-] {"StartAt":"MyPassState","States":{"MyPassState":{"Type":"Pass","Result":{"myKey":"myValue2"},"End":true}}}
└─ [+] {"StartAt":"MyPassState","States":{"MyPassState":{"Type":"Pass","Result":{"myKey":"myValue3"},"End":true}}}
--hotswap
を使用して Hotswap deployments を行います。すると約 4 秒でデプロイされました。デプロイが高速化されていますね。
$ cdk deploy --hotswap
Synthesis time: 3.2s
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!
CdkSampleStack: start: Building 661e5f2cafaf455ab59361db85609648b9bcdd5272f9a6366e8972228089d215:current_account-current_region
CdkSampleStack: success: Built 661e5f2cafaf455ab59361db85609648b9bcdd5272f9a6366e8972228089d215:current_account-current_region
CdkSampleStack: start: Publishing 661e5f2cafaf455ab59361db85609648b9bcdd5272f9a6366e8972228089d215:current_account-current_region
CdkSampleStack: success: Published 661e5f2cafaf455ab59361db85609648b9bcdd5272f9a6366e8972228089d215:current_account-current_region
CdkSampleStack: deploying... [1/1]
hotswapping resources:
AWS::StepFunctions::StateMachine 'MyStateMachine'
AWS::StepFunctions::StateMachine 'MyStateMachine' hotswapped!
CdkSampleStack
Deployment time: 0.96s
Stack ARN:
arn:aws:cloudformation:ap-northeast-1:XXXXXXXXXXXX:stack/CdkSampleStack/e68b6900-f01c-11ed-8538-06bbc29e5367
Total time: 4.16s
再度差分を確認すると、Hotswap deployments 前と差分に変更がなく、CloudFormation API ではなく AWS SDK を使用して直接 ワークフロー定義の更新が行われていることが分かります。
$ cdk diff
Stack CdkSampleStack
Resources
[+] AWS::SSM::Parameter MyParameter MyParameter18BA547D
[~] AWS::StepFunctions::StateMachine MyStateMachine MyStateMachine6C968CA5
└─ [~] DefinitionString
├─ [-] {"StartAt":"MyPassState","States":{"MyPassState":{"Type":"Pass","Result":{"myKey":"myValue2"},"End":true}}}
└─ [+] {"StartAt":"MyPassState","States":{"MyPassState":{"Type":"Pass","Result":{"myKey":"myValue3"},"End":true}}}
ワークフローを実行すると Hotswap deployments によりワークフロー定義が更新されていることが分かります。
$ aws stepfunctions start-sync-execution \
--state-machine-arn ${stateMachineArn} \
--query output | jq -r .
{"myKey":"myValue3"}
--hotswap-fallback
による変更デプロイ
--hotswap-fallback
を使用すると、Hotswap deployments をサポートしていないリソースの変更を検知した場合に、Hotswap deployments ではなく通常の変更デプロイが行われます。検知されなかった場合は Hotswap deployments となります。
先程から CDK 定義を変更せずに、--hotswap-fallback
を使用してデプロイを行います。すると通常のデプロイとなりました。
$ cdk deploy --hotswap-fallback
Synthesis time: 3.44s
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!
CdkSampleStack: deploying... [1/1]
The following non-hotswappable changes were found:
logicalID: MyParameter18BA547D, type: AWS::SSM::Parameter, reason: resource 'MyParameter18BA547D' was created by this deployment
Could not perform a hotswap deployment, as the stack CdkSampleStack contains non-Asset changes
Falling back to doing a full deployment
CdkSampleStack: creating CloudFormation changeset...
CdkSampleStack
Deployment time: 18.08s
Stack ARN:
arn:aws:cloudformation:ap-northeast-1:XXXXXXXXXXXX:stack/CdkSampleStack/e68b6900-f01c-11ed-8538-06bbc29e5367
Total time: 21.53s
CloudFormation によるデプロイが行われたので、スタックの差分も解消されています。
$ cdk diff
Stack CdkSampleStack
There were no differences
その他の検証
ワークフローの定義以外の変更があった場合
ワークフローの定義以外の変更は、Hotswap deployments の対象とならないことを確認してみます。
ワークフローの定義を変更し、またログ出力の設定を行います。
lib/cdk-sample-stack.ts
new aws_stepfunctions.StateMachine(this, 'MyStateMachine', {
stateMachineName: 'MyStateMachine',
stateMachineType: aws_stepfunctions.StateMachineType.EXPRESS,
definitionBody: aws_stepfunctions.ChainDefinitionBody.fromChainable(
new aws_stepfunctions.Pass(this, 'MyPassState', {
result: aws_stepfunctions.Result.fromObject({ myKey: 'myValue4' }),
})
),
logs: {
destination: new aws_logs.LogGroup(this, 'MyStateMachineLogGroup'),
level: aws_stepfunctions.LogLevel.ALL,
},
});
Hotswap deployments を行うと、rejected changes: LoggingConfiguration, reason: resource properties 'LoggingConfiguration' are not hotswappable on this resource type
とありログ出力の設定は変更されず、ワークフロー定義の変更のみデプロイされました。
$ cdk deploy --hotswap
Synthesis time: 3.52s
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!
CdkSampleStack: start: Building 0517e4b9f2d793ea4d9c11e823cdd2357ed4cae41a133006bdfc21dc894c8dbe:current_account-current_region
CdkSampleStack: success: Built 0517e4b9f2d793ea4d9c11e823cdd2357ed4cae41a133006bdfc21dc894c8dbe:current_account-current_region
CdkSampleStack: start: Publishing 0517e4b9f2d793ea4d9c11e823cdd2357ed4cae41a133006bdfc21dc894c8dbe:current_account-current_region
CdkSampleStack: success: Published 0517e4b9f2d793ea4d9c11e823cdd2357ed4cae41a133006bdfc21dc894c8dbe:current_account-current_region
This deployment will make potentially sensitive changes according to your current security approval level (--require-approval broadening).
Please confirm you intend to make the following modifications:
IAM Statement Changes
┌───┬──────────┬────────┬─────────────────────────────────┬─────────────────────────────────┬───────────┐
│ │ Resource │ Effect │ Action │ Principal │ Condition │
├───┼──────────┼────────┼─────────────────────────────────┼─────────────────────────────────┼───────────┤
│ + │ * │ Allow │ logs:CreateLogDelivery │ AWS:${MyStateMachine/Role} │ │
│ │ │ │ logs:DeleteLogDelivery │ │ │
│ │ │ │ logs:DescribeLogGroups │ │ │
│ │ │ │ logs:DescribeResourcePolicies │ │ │
│ │ │ │ logs:GetLogDelivery │ │ │
│ │ │ │ logs:ListLogDeliveries │ │ │
│ │ │ │ logs:PutResourcePolicy │ │ │
│ │ │ │ logs:UpdateLogDelivery │ │ │
└───┴──────────┴────────┴─────────────────────────────────┴─────────────────────────────────┴───────────┘
(NOTE: There may be security-related changes not in this list. See https://github.com/aws/aws-cdk/issues/1299)
Do you wish to deploy these changes (y/n)? y
CdkSampleStack: deploying... [1/1]
The following non-hotswappable changes were found. To reconcile these using CloudFormation, specify --hotswap-fallback
logicalID: MyStateMachine6C968CA5, type: AWS::StepFunctions::StateMachine, rejected changes: LoggingConfiguration, reason: resource properties 'LoggingConfiguration' are not hotswappable on this resource type
hotswapping resources:
AWS::StepFunctions::StateMachine 'MyStateMachine'
AWS::StepFunctions::StateMachine 'MyStateMachine' hotswapped!
CdkSampleStack
Deployment time: 1.11s
Stack ARN:
arn:aws:cloudformation:ap-northeast-1:XXXXXXXXXXXX:stack/CdkSampleStack/e68b6900-f01c-11ed-8538-06bbc29e5367
Total time: 4.63s
念のためワークフローを実行すると、変更後の値 myValue4
が出力され、変更されていることが分かります。
$ aws stepfunctions start-sync-execution \
--state-machine-arn ${stateMachineArn} \
--query output | jq -r .
{"myKey":"myValue4"}
ワークフローの定義の変更でワークフロー以外のリソースの変更があった場合
ワークフローの定義の変更でワークフロー以外のリソースの変更があった場合のパターンも試してみます。
ワークフローの定義で SNS Topic への Publish を行うように変更し、Publish 先の SNS Topic を定義します。
lib/cdk-sample-stack.ts
import {
aws_stepfunctions,
aws_stepfunctions_tasks,
aws_sns,
Stack,
StackProps,
} from 'aws-cdk-lib';
import { Construct } from 'constructs';
export class CdkSampleStack extends Stack {
public readonly myFileObjectKey: string;
constructor(scope: Construct, id: string, props: StackProps) {
super(scope, id, props);
const myTopic = new aws_sns.Topic(this, 'MyTopic', {
topicName: 'MyTopic',
});
new aws_stepfunctions.StateMachine(this, 'MyStateMachine', {
stateMachineName: 'MyStateMachine',
stateMachineType: aws_stepfunctions.StateMachineType.EXPRESS,
definitionBody: aws_stepfunctions.ChainDefinitionBody.fromChainable(
new aws_stepfunctions_tasks.SnsPublish(this, 'MyTask', {
topic: myTopic,
message: aws_stepfunctions.TaskInput.fromJsonPathAt('$.message'),
})
),
});
}
}
Hotswap deployments を行うと、rejected changes: IAM, reason: resource 'MyTopic86869434' was created by this deployment
とあり、Hotswap の対象とならないリソースの解決が上手くできていないようです。
$ cdk deploy --hotswap
Synthesis time: 3.09s
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!
This deployment will make potentially sensitive changes according to your current security approval level (--require-approval broadening).
Please confirm you intend to make the following modifications:
IAM Statement Changes
┌───┬────────────┬────────┬─────────────┬────────────────────────────┬───────────┐
│ │ Resource │ Effect │ Action │ Principal │ Condition │
├───┼────────────┼────────┼─────────────┼────────────────────────────┼───────────┤
│ + │ ${MyTopic} │ Allow │ sns:Publish │ AWS:${MyStateMachine/Role} │ │
└───┴────────────┴────────┴─────────────┴────────────────────────────┴───────────┘
(NOTE: There may be security-related changes not in this list. See https://github.com/aws/aws-cdk/issues/1299)
Do you wish to deploy these changes (y/n)? y
CdkSampleStack: deploying... [1/1]
hotswapping resources:
AWS::StepFunctions::StateMachine 'MyStateMachine'
Could not perform a hotswap deployment, because the CloudFormation template could not be resolved: Parameter or resource 'MyTopic86869434' could not be found for evaluation
CdkSampleStack (no changes)
Deployment time: 1.16s
Stack ARN:
arn:aws:cloudformation:ap-northeast-1:XXXXXXXXXXXX:stack/CdkSampleStack/e68b6900-f01c-11ed-8538-06bbc29e5367
Total time: 4.26s
ワークフローの定義の変更であっても別のリソースの変更が絡む場合は Hotswap deployments が上手く動かない場合があるようです。
おわりに
AWS Step Functions ワークフローの構築で AWS CDK の Hotswap deployments を使ってみました。
ワークフロー定義の変更のデプロイを大きく高速化できることが確認できました。
一方で、ワークフロー定義の変更でワークフロー以外のリソースの変更が絡む場合は Hotswap deployments が上手く動かない場合があるようなので、そういう場合は下記のエントリで紹介している --method=direct
を使用してもデプロイを十分高速化できるので併用をすると良いかと思います。
以上