Infrastructure as Codeを取り入れた話
はじめに
新規アプリケーションのインフラ構築をする際に、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 リソースのモデル化およびセットアップに役立つサービスです。リソース管理に割く時間を減らし、AWS で実行するアプリケーションにさらに注力できるようになります。使用するすべての AWS リソース (Amazon EC2 インスタンスや Amazon RDS DB インスタンスなど) を記述するテンプレートを作成すれば、CloudFormation がお客様に代わってこれらのリソースのプロビジョニングや設定を受け持ちます。
AWS CloudFormationドキュメント(AWS公式から引用)
テンプレートについて詳細なイメージができるように、
まずは下記テンプレート(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機能を設定しています。
- AWS CodeCommit : GitLabリポジトリのミラーリング
- IAM User / IAM Role : AWSでの操作権限設定
- Amplify Application : (Amplify内の)アプリケーション設定
- Amplify Branch : (Amplify内の)ブランチ登録
- 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