Amazon Web Services ブログ

GitHub からの AWS CloudFormation デプロイ自動化

本記事は 2023年11月26日に AWS DevOps Blog で公開された ”Automate safe AWS CloudFormation deployments from GitHub” を翻訳したものです。翻訳は Partner Sales Solutions Architect の 福井 敦 が担当しました。

AWS CloudFormation は、Infrastructure as Code (IaC) サービスで、AWS およびサードパーティのリソースをモデル化、プロビジョニング、管理できます。新しくトラッキングしている Git リポジトリが更新されるたびに、Git 同期 によって自動的にデプロイメントがトリガーされるようになりました。
これにより、開発者は Git ワークフローに統合し、コンテキストの切り替えによる時間の浪費を減らすことで、CloudFormation の開発サイクルを大幅に高速化できます。この新しい Git 同期は、GitHubGitHub EnterpriseGitLabBitbucket に対応しています。

この投稿では、GitHub のネイティブツールと CloudFormation の Git 同期を使った最新の開発体験について説明します。
GitHub CodeSpaces を使用してクラウド開発環境を作成し、GitHub ActionsCloudFormation Linter を使用してプルリクエストに直接フィードバックし、安全なデプロイを自動化します。

要件

空のリポジトリの作成

今回は、新しい GitHub リポジトリから始めます。GitHub では無料で新しい Git リポジトリを作成できます。この例では、git-sync という名前のリポジトリを作成します。

Creating a repository called Git sync

Codespace の設定

リポジトリを作成すると、Codespace を作成するオプションが表示されます。Codespace は GitHub が管理するリモートの開発環境で、設定済の仮想マシン環境でどこからでも開発できます。

Creating a new code space on the Git sync repository

Codespaces は、Visual Studio Code を選択したコードエディターとして利用します。Visual Studio Code は拡張機能をインストールできるため、非常に柔軟で拡張性に優れたオープンソースのコードエディターです。

Codespace using Visual Studio Code as code editor

作成が完了したら、ローカルの開発環境と同様に環境を設定できます。テンプレート開発時に、エディタ内で即座にフィードバックを得られるよう CloudFormation Linter 拡張機能を追加します。
これにより、検証のためテンプレートを CloudFormation に送信する必要はなく、送信する前にテンプレートが有効であることを確認できます。コマンドラインと Visual Studio Code 拡張機能の両方でインストールを行います。ターミナルで次のコマンドを実行してください。

pip3 install cfn-lint

インストールされたら、拡張機能パネルで CloudFormation Linter をインストールできます。

Installing the CloudFormation Linter Visual Studio Code Extension

次に、ベースディレクトリに vpc.yaml という名前のテンプレートを作成します。
入力を始めると、 CloudFormation Linter が推奨事項とオートコンプリート機能を提供します。

Linter recommending autocompletion for AWS::EC2::VPC

次のテンプレートを新しく作成した vpc.yaml ファイルにコピーしてください:

AWSTemplateFormatVersion: "2010-09-09"
 Resources:
  VPC:
    Type: AWS::EC2::VPC 
    Properties:
      CidrBlock: 10.0.0.0/16 

このテンプレートは、CIDR ブロック 10.0.0.0/16 の VPC を作成します。

テンプレートにエラーがないことを確認するには、ターミナルで cfn-lint を実行し、エラーが返されないことを確認します。

cfn-lint -t vpc.yaml

デプロイファイルの追加

Git 同期では多様なデプロイメントをサポートするため、Git リポジトリから CloudFormation スタックを管理するための柔軟性を提供するスタックデプロイファイルをサポートしています。
この設定ファイルは、テンプレートファイルの場所、使用したいパラメータやタグの管理を行います。
パラメータやタグの管理には、このスタックデプロイファイルを使うことを強くお勧めします。監査や決定論的なデプロイメントが容易になるためです。

リポジトリ内に deployment-file.yaml という新しいファイルを作成します。このスタックにはパラメータやタグがないため、シンプルです。

template-file-path: ./vpc.yaml 

後からコンソールでこのファイルを追加することもできます。

Pull Request アクションの追加

これで開発環境の設定が完了しました。次はプルリクエストを送るだれもが、ローカルで受けているのと同じようなフィードバックを受け取れるようにしたいと思います。
GitHub Actions を使えば、これが可能になります。GitHub Actions は、プルリクエストフィードバックと CI ビルドを自動化する、カスタマイズ可能なワークフローツールです。

次のようなディレクトリとファイルを作成します。.github/workflows/pull-request.yamlこのファイルの内容は以下のとおりです。

name: Pull Request workflow

on:
  - pull_request

jobs:
  cloudformation-linter:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v3
      - name: Linter install
        uses: scottbrenner/cfn-lint-action@v2
        with:
          command: cfn-lint -t ./vpc.yaml

この設定により、プルリクエストに対して linter の結果がフィードバックされるようになります。作業内容をリモートブランチにプッシュしてください。

git add -A
git commit -m "add pull request linting workflow, add base vpc template"
git push origin main

これから VPC にサブネットを追加しますが、VpcId ではなく VpcName という無効なプロパティを意図的に追加します。

AWSTemplateFormatVersion: "2010-09-09"
 Resources:
  VPC:
    Type: AWS::EC2::VPC 
    Properties:
      CidrBlock: 10.0.0.0/16 

  Subnet:
    Type: AWS::EC2::Subnet 
    Properties:
      VpcName: ! Ref VPC 
      CidrBlock: 10.0.0.1/16 

ローカルの linter は、これが無効であることをすぐに指摘します:

CloudFormation Linter GitHub Action indicating errors and line numbers

これらは今のところ無視してかまいません。プルリクエストを作成するには、新しいブランチを作成し、ローカルの変更をコミットする必要があります。以下のコマンドを実行してください。

git switch -c add-subnet
git add -A
git commit -m "add subnet"
git push origin add-subnet

これらのコミットをプッシュすると、GitHub から main ブランチに対するプルリクエストを作成できるようになります。
ただし、プルリクエストを作成すると、GitHub Actions の実行が終わったときにチェックが失敗したことがわかります。

Stack Deployments File section with "I am providing my own file in my repository" selected

「Files changed」タブを確認すると、どこが間違っているかがわかります。Linter アクションはプルリクエスト上で直接フィードバックを提供し、ブランチ保護を設定した場合はマージのアクションをブロックします。
このリポジトリでは、少なくとも 1 人のレビュアーと全てのチェックの成功が必要なので、これら両方の失敗を解決しなければなりません。

CloudFormation Linter GitHub Action indicating errors and line numbers

フィードバックと問題があった行番号を取得できたので、テンプレートに戻り、VpcNameVpcId に修正しましょう。

AWSTemplateFormatVersion: "2010-09-09"
 Resources:
  VPC:
    Type: AWS::EC2::VPC 
    Properties:
      CidrBlock: 10.0.0.0/16 

  Subnet:
    Type: AWS::EC2::Subnet 
    Properties:
      VpcId: ! Ref VPC 
      CidrBlock: 10.0.0.1/16 

ローカルの linter は問題ありません。コミットしなおすと、リモートの linter も同様に問題がないことを確認できます。レビュアーからの承認を得た後、コミットを main ブランチにマージできます。

Approval from reviewer and passing checks enabling a merge

Git 同期の有効化

開発環境が整い、プルリクエストの過程でテンプレートがマージ前に Lint されるようになりました。
main ブランチに到達した CloudFormation テンプレートはデプロイの準備ができています。
次に、新しく公開された CloudFormation の Git 同期を利用して、デプロイされたスタックを新しいテンプレートに自動的に同期させます。

まず、CloudFormation がスタックをデプロイするために必要な IAM ロールを作成します。このロールは、CloudFormation がデプロイするリソースを制御します。ロールの名前は後の手順で使用するので控えておきましょう。この例ではロール名を vpc-example-cloudformation-deployment-role とし、次の許可ポリシーを設定します。

{
  "Version": "2012-10-17",
  "Statement": [ 
    {
      "Effect": "Allow",
      "Action": [ 
        "ec2:CreateVpc",
        "ec2:CreateSubnet",
        "ec2:DescribeVpcs",
        "ec2:DescribeSubnets",
        "ec2:DeleteVpc",
        "ec2:DeleteSubnet",
        "ec2:ModifySubnetAttribute",
        "ec2:ModifyVpcAttribute"
      ],
      "Resource": "*",
      "Condition": {
        "ForAnyValue:StringEquals": {
          "aws:CalledVia": ["cloudformation.amazonaws.com"] 
        }
      }
    }
  ] 
}

ロールを作成したら、次はスタックを新しく作成します。

Template source section with sync from Git option selected

こちらでは、新しいオプション Sync from Git を選びテンプレートのソースを設定します。既にスタックデプロイファイルを作成済みのため、I am providing my own file in my repository. を選択します。

Stack Deployments File section with "I am providing my own file in my repository" selected

次に、Git 統合を設定してリポジトリを選択します。あらかじめ作成したデベロッパーツールの Github への接続を使用し、リポジトリを選択する必要があります。

Git sync configuration with CodeStar connection selected, repository set to "Git sync" and branch of "main" selected

GitHub接続リポジトリブランチデプロイファイルのパスを選択してください。

最後に新しい IAM ロールを選択して、サービスマネージドロールを作成します。このロールにより、Git 同期がリポジトリに接続できるようになります。この作業は 1 回限りで、今後はここで作成する既存のロールを使用できます。

IAM Role selection

次のページでは、このスタックをデプロイするために必要な作成済の IAM ロールvpc-example-cloudformation-deployment-roleを選択します。このロールは、CloudFormation がデプロイするリソースを制御します。このように、Git 同期によってスタックを管理するには、事前にロールを作成しておく必要があります。

最後に、「Git と同期」タブで、設定内容、同期のステータス、プロビジョニングのステータス、そして必要に応じて同期の再試行や接続解除が可能であることを確認できます。

Git sync configuration data indicting repository, provider, branch, deployment file path, and Git sync status

結論

この投稿では、CloudFormation テンプレートの作成および更新時にフィードバックを得るためのリモート開発環境を設定しました。プルリクエストを作成する際も同様に、フィードバックを得られます。テンプレートが main ブランチにマージされると、自動的にスタックにデプロイされます。このように、AWS リソースを Infrastructure as Code として管理するための、堅牢で拡張性のある CI/CD システムが構築されました。この Git 同期についてのフィードバックをお待ちしています!

著者について

Dan Blanco

Dan is a senior AWS Developer Advocate based in Atlanta for the AWS IaC team. When he ’ s not advocating for IaC tools, you can either find him in the kitchen whipping up something delicious or flying in the Georgia sky. Find him on twitter (@ TheDanBlanco) or in the AWS CloudFormation Discord.