🥨

Infrastructure as Codeを取り入れた話

2024/08/13に公開

はじめに

新規アプリケーションのインフラ構築をする際に、Infrastructure as Codeを取り入れることになったので、今回の記事にまとめようと思います。

Infrastructure as Code (IaC) とは

Infrastructure as Code (以下、IaC) とは、インフラ環境をコード化したものです。手動のプロセスや設定の代わりにコードを使用することで、インフラ環境のプロビジョニングおよびサポートをしてくれます。つまり、「インフラ環境の設計図」と言い表せます。IaCにより、インフラ環境の望ましい状態を定義でき、インフラ構築や管理が自動化されるため、インフラ管理のコスト削減が期待できます。

なぜIaCを取り入れたのか

前述の通り、インフラ環境の運用/保守の管理コストを抑えることを目的としてIaC導入を決めました。現在の職場では、メンバーはフルスタックエンジニアとして、インフラ業務だけでなく、フロントエンド・バックエンド業務にも取り組んでおり、多岐にわたる各業務での管理コスト削減は必要不可欠でした。そこで、今回はAWS(Amazon Web Services)を他サービスでも利用していることが多かったので、「AWS CloudFormation」を利用することにしました。

AWS CloudFormationとは

AWS CloudFormation

AWS CloudFormation は AWS リソースのモデル化およびセットアップに役立つサービスです。リソース管理に割く時間を減らし、AWS で実行するアプリケーションにさらに注力できるようになります。使用するすべての AWS リソース (Amazon EC2 インスタンスや Amazon RDS DB インスタンスなど) を記述するテンプレートを作成すれば、CloudFormation がお客様に代わってこれらのリソースのプロビジョニングや設定を受け持ちます。
AWS CloudFormationドキュメント(AWS公式から引用)

テンプレートについて詳細なイメージができるように、
まずは下記テンプレート(ymlファイル)をご覧ください。

テンプレート(設計図)

sample_template.yml
AWSTemplateFormatVersion: 2010-09-09
Description: 'sample_template'

Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Parameters:
          - DomainName
          - RepositoryName

Parameters:
  DomainName:
    Type: String
    Default: sample.jp
    AllowedPattern: .+
    Description: The custom domain name for Amplify app [required]
  RepositoryName:
    Type: String
    Default: sample_app
    AllowedPattern: .+
    Description: The repository name on GitLab [required]

Resources:
  # CodeCommit
  CodeCommitRepository:
    Type: AWS::CodeCommit::Repository
    Properties:
      RepositoryDescription: !Sub 'GitLab「${RepositoryName}」リポジトリをミラーリング'
      RepositoryName: !Sub ${RepositoryName}-mirroring
  # IAM User
  CodeCommitIAMUser:
    Type: AWS::IAM::User
    DependsOn: CodeCommitRepository
    Properties:
      Policies:
        - PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - codecommit:GitPull
                  - codecommit:GitPush
                Resource: !GetAtt CodeCommitRepository.Arn
          PolicyName: !Sub ${RepositoryName}-CodeCommitPolicy
      UserName: !Sub ${RepositoryName}-user
  # IAM Role
  AmplifyIAMRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service: amplify.amazonaws.com
            Action: sts:AssumeRole
      Description: !Sub 'Amplify App [${RepositoryName}]'
      Policies:
        - PolicyName: !Sub ${RepositoryName}-AWSAmplifyCodeCommitExecutionPolicy
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Sid: PushLogs
                Effect: Allow
                Action:
                  - logs:CreateLogStream
                  - logs:PutLogEvents
                Resource: arn:aws:logs:{$(リージョン)}:{$(AccountId)}:log-group:/aws/amplify/*:log-stream:*
              - Sid: CreateLogGroup
                Effect: Allow
                Action: logs:CreateLogGroup
                Resource: arn:aws:logs:{$(リージョン)}:{$(AccountId)}:log-group:/aws/amplify/*
              - Sid: DescribeLogGroups
                Effect: Allow
                Action: logs:DescribeLogGroups
                Resource: arn:aws:logs:{$(リージョン)}:{$(AccountId)}:log-group:*
              - Effect: Allow
                Action: codecommit:GitPull
                Resource: !GetAtt CodeCommitRepository.Arn
      RoleName: !Sub ${RepositoryName}-AWSAmplifyCodeCommitExecutionRole
  # Amplify
  AmplifyApp:
    Type: AWS::Amplify::App
    DependsOn: AmplifyIAMRole
    Properties:
      Description: 'sample_app'
      IAMServiceRole: !GetAtt AmplifyIAMRole.Arn
      Name: !Ref RepositoryName
      OauthToken: '{{resolve:secretsmanager:sample_app/GitLabOAuthToken:SecretString:GitLabOAuthToken}}' # Secrets Manager
      Platform: WEB_COMPUTE
      Repository: !Sub 'https://git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/${CodeCommitRepository.Name}'
  AmplifyDevBranch:
    Type: 'AWS::Amplify::Branch'
    DependsOn: AmplifyApp
    Properties:
      AppId: !GetAtt AmplifyApp.AppId
      BasicAuthConfig:
        EnableBasicAuth: true
        Username: '{{resolve:secretsmanager:sample_app/Amplify/BasicAuth:SecretString:username}}' # Secrets Manager
        Password: '{{resolve:secretsmanager:sample_app/Amplify/BasicAuth:SecretString:password}}' # Secrets Manager
      BranchName: 'development'
      EnableAutoBuild: true
  AmplifyMainBranch:
    Type: 'AWS::Amplify::Branch'
    DependsOn: AmplifyApp
    Properties:
      AppId: !GetAtt AmplifyApp.AppId
      BranchName: 'main'
      EnableAutoBuild: true
  AmplifyDomain:
    Type: AWS::Amplify::Domain
    DependsOn: AmplifyMainBranch
    Properties:
      AppId: !GetAtt AmplifyApp.AppId
      DomainName: !Ref DomainName
      SubDomainSettings:
        - BranchName: !GetAtt AmplifyDevBranch.BranchName
          Prefix: 'dev'
        - BranchName: !GetAtt AmplifyMainBranch.BranchName
          Prefix: ''

このテンプレート内容を要約すると、
大きく分けて5つのAWS機能を設定しています。

  1. AWS CodeCommit : GitLabリポジトリのミラーリング
  2. IAM User / IAM Role : AWSでの操作権限設定
  3. Amplify Application : (Amplify内の)アプリケーション設定
  4. Amplify Branch : (Amplify内の)ブランチ登録
  5. Amplify Domain : (Amplify内の)ドメイン登録
AWSTemplateFormatVersion: 2010-09-09
Description: 'sample_template'

ここに関しては、そのままコピペして問題ないです。
AWSTemplateFormatVersion: 現時点でフォーマットバージョンは上記のみ
Description: テンプレートの説明

Parameters:
  DomainName:
    Type: String
    Default: sample.jp
    AllowedPattern: .+
    Description: The custom domain name for Amplify app [required]
  RepositoryName:
    Type: String
    Default: sample_app
    AllowedPattern: .+
    Description: The repository name on GitLab [required]

Parameters:では、テンプレート内で利用する変数を定義しています。

Resources:

~ 省略 ~

Resources:では、各AWSサービスの情報を記述しています。
記述にあたっては、CloudFormation公式ドキュメントを参考に作成するのが良いと思います。

また、OauthTokenやユーザー情報など秘匿情報を記載する場合には、同じくAWSから提供されている「AWS Secrets Manager」を利用することでセキュリティを高めることができます。
前述のテンプレート内にも利用されているので、ぜひご参考までにご確認ください。

テンプレート登録 / スタック作成

あとは、作成したテンプレートを用いて、AWS CloudFormationにてスタック作成することでインフラ環境が記述した通りに自動構築してくれます。今回の新規アプリケーションでは、テンプレートを用いて、登録したGitLabリポジトリに変更内容をpushするだけで、AWS AmplifyにてデプロイされるCI/CDを環境構築しました。

さいごに

繰り返しになりますが、テンプレート作成をすることで今後の管理コスト削減に繋がります。
公式ドキュメントもわかりにくいところもありますが、新規インフラ構築(もしくは、既存環境をテンプレート化)の機会がありましたら、ぜひ思い切って作成してみてください。

Discussion