リリース作業を限界まで自動化(ツール化)した話

## AWS CodeシリーズとStep Functionsで実現する、手動作業ゼロの高速デプロイ戦略

### はじめに

アジャイル開発を推進する現代において、継続的かつ高速なCI/CDパイプラインは不可欠です。チームでもAWSのCodeシリーズをフル活用することで、アプリケーションのデプロイ自体までの開発サイクルは高速・自動化しました。それは、**アプリケーションの切り替え（特に本番環境への投入）における手動作業が残っており、これがリリースサイクルのボトルネック**になっていました。

この手動作業は1回のリリースで約2時間も要し、作業の煩雑さから人為的なミスや、特定の担当者への作業負荷の集中（属人化）が発生していました。本記事では、この課題をどのように特定し、AWS Step Functions と Lambda を活用して、**リリース工程の完全自動化と作業の汎用化**を実現したのか、具体的なアプローチと苦労した点を共有します。

#### 対象読者
 * 大規模システム・複雑なアーキテクチャのためにIaC（CloudFormationなど）化が難しく、手作業でのリリース作業などが残っているアプリケーションのDevOpsチームの方
 * EC2のデプロイ（AMI作成・起動テンプレート更新）作業や、ALBターゲットグループの更新作業などは自動化できていない方

### 課題：CI/CDの最終工程に残る手動作業の罠

私たちのCI/CDパイプラインは、AWS CodePipeline, CodeBuild, CodeDeploy を組み合わせることで、アプリケーションのビルドからテスト、デプロイまでを大部分自動化していました。これにより、開発サイクルは大幅に短縮されていました。

しかし、最終的なアプリケーションの切り替えフェーズにおいて、以下の手動作業が残っていました。

1.  **Lambda アプリケーションの場合 (6種のLambda群)**:
    * ALB (Application Load Balancer) のターゲットグループ作成・紐付け作業。
    * ALB のルール内のターゲットグループの重み（トラフィックルーティング比率）を手動で最新バージョンと現行バージョンに更新する作業。

2.  **EC2 アプリケーションの場合 (7種のEC2群)**:
    * 最新のAMI (Amazon Machine Image) 作成作業。
    * AMI を使用して、起動テンプレートのバージョンを手動で更新する作業。
    * オートスケーリンググループ (ASG) の差し替え（新しい起動テンプレートバージョンへの更新）

これらの作業は、毎回2時間程度の時間を要し、長文の手順書を見ながらのダブルチェックでの慎重な作業が必要でした。結果として、リリースのリードタイムが長くなるだけでなく、以下のような問題を引き起こしていました。

* **人為的ミスの発生**: 煩雑な手動作業は、チェック漏れや入力ミスなどの原因となり得ました。
* **作業の属人化**: 特定の経験者が作業に就くことが多く、担当者の負荷が高まり、知識の共有も進みにくい状況でした。
* **リリース頻度の制約**: 継続的デプロイを妨げるボトルネックとなっていました。

### 解決策：Step FunctionsとLambdaによる自動化

この課題を解決するため、既存のリリース手順から、自動化できる工程を洗い出し、それらを徹底的につぶしていきました。

#### 1. Lambdaアプリケーションのデプロイ自動化

ALBのターゲットグループ操作は、ブルー/グリーンデプロイメントにおいて重要なステップ。

* **自動化したプロセス**:
![stepfunctions_graph (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2956558/cc7a03c0-93f4-4321-a34e-cbdfb0f71abd.png)
    1.  **引数入力**
        *  Step Functionsの実行開始時に、デプロイ対象のLambdaアプリケーション名と最新バージョンなどの引数を指定します。
    2.  **ターゲットグループの作成・紐付け**
        * 指定されたアプリケーションの最新バージョンのLambda ARNを取得。
        * 取得したARNを元に、新しいALBターゲットグループを動的に作成し、ターゲットとしてLambda関数を登録します。
    3.  **ALBルールの重み更新**:
        * 別のLambdaが、ALBのリスナールールを更新します。
        * 引数で指定されたトラフィック配分に基づき、新しいターゲットグループと既存のターゲットグループ間の重みを自動で設定します。
        * これにより、手動でALBコンソールを操作することなく、段階的なトラフィック切り替えが可能になりました。
    * **苦労した点**
        * 複数回ツールが実行されることを想定し、ターゲットグループの重複チェック・（重複の場合の）削除処理部分。
            * 削除した場合にAWS内で伝播する時間が生じ、後続処理が失敗。
            * 回避策として、リトライ処理と各リトライに1秒の間隔をいれると、後続処理も失敗せずに動作しました。

#### 2. EC2アプリケーションのデプロイ自動化

EC2環境のデプロイでは、AMIの更新と起動テンプレートの差し替えが課題

* **自動化したプロセス**
 ![stepfunctions_graph.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2956558/80f06c6e-18c3-4b70-b15b-306d40705057.png)
    1.  **引数入力** 
        *  Step Functionsの実行開始時に、対象となるEC2アプリケーションのASG名や最新AMIに関する情報（またはタグなどから自動取得する情報）を引数で渡します。
    2.  **最新AMIの取得**
        * Lambdaが、リリース対象のEC2から、**最新のAMIを自動的に取得**
    3.  **起動テンプレートの更新**
        * 別のLambdaが、取得した最新AMI IDを使用して、対象の起動テンプレートの**新しいバージョンを自動で作成**します。
        * さらに、その新しく作成されたバージョンを**デフォルトバージョンとして設定**する処理も自動化しました。これにより、ASGがスケールアウトする際に、常に最新のAMIを使用するインスタンスが起動されるようになります。
    4.  **オートスケーリンググループの更新**:
        * ASGは、起動テンプレートのデフォルトバージョンが更新されると、通常は自動的に新しいインスタンスを起動し、古いインスタンスを終了していく設定が可能です。
        * これにより、手動でのASGの「差し替え」作業（既存のASGを削除し、新しいASGを作成し直すような作業）が不要になり、ローリングアップデートのような形で自動で更新されます。
        * 差し替え後の基本的な動作確認については、ALBのヘルスチェックやCloudWatchアラームの監視を強化することで、人手を介さない検知・通知体制を構築しました。

    * **苦労した点**
        *  古いAMIの削除も考慮に入れつつ、常に最新かつ正常なAMIを識別するロジックを確立するのに時間がかかった。


### 成果と効果

この自動化により、私たちは以下のような大きな成果を得ることができました。

* **リリースリードタイムの劇的な短縮**: 従来2時間かかっていた手動作業が、**数分で完了する自動プロセス**に置き換わりました。これにより、アプリケーションの変更をより迅速に本番環境へ反映できるようになりました。
* **人為的ミスの削減**: 複雑な手動操作がなくなることで、設定ミスや操作ミスに起因するリリース失敗がゼロになりました。
* **作業の汎用化・属人化の解消**: 定義されたStep Functionsを実行するだけでリリース作業が完結するため、特定の担当者しかできないといった属人性が解消され、誰でも安定してリリース作業を実行できるようになりました。
* **高い再現性**: 自動化されたワークフローは常に同じ手順で実行されるため、どのリリースでも一貫した品質と再現性を保証できます。

### さいごに

AWS Codeシリーズ、特にStep FunctionsとLambdaを組み合わせることで、これまで手動で残っていたリリース工程の「最後の砦」とも言える部分を自動化することができました。この経験を通じて、CI/CDパイプラインはアプリケーションのビルド・デプロイだけでなく、インフラストラクチャの変更管理まで含めて自動化することで、真の高速かつ安定したリリースサイクルを実現できることを実感しました。

もし皆さんのCI/CDパイプラインにも手動で煩雑な作業が残っているのであれば、本記事がStep FunctionsとLambdaによる自動化のヒントになれば幸いです。