【AWS】用語を整理しながら学ぶAWS AWS CloudFormation

## はじめに

この記事では AWSが提供するAWS CloudFormation（以下、cfn）を学習していく記事です。主な内容としては実践したときのメモを中心に書きます。（忘れやすいことなど）
誤りなどがあれば書き直していく予定です。

昔の記事は[こちら](https://qiita.com/ymd65536/items/f58f5504a37fc7d0a767)

### 参考 - Blackbelt

https://youtu.be/4dyiPsYXG8I?feature=shared

## AWS CloudFormation（cfn）とは

IaC（インフラストラクチャアズコード）の概念に則ったインフラをテンプレートで管理できるサービスです。AWSの公式サイトには下記のように表現されています。

> Infrastructure as Code でクラウドプロビジョニングを高速化する

> インフラストラクチャを世界規模でスケールし、1 回の操作ですべての AWS アカウントとリージョンのリソースを管理します。

> ターンキーアプリケーションのディストリビューションとガバナンス制御を提供する AWS のサービス統合により、組織全体のリソース管理を自動化します。

> AWS CloudFormation は、インフラストラクチャをコードとして扱うことで、AWS およびサードパーティーのリソースをモデル化、プロビジョニング、管理することができます。

[参考](https://aws.amazon.com/jp/cloudformation/)

つまり、cfnは`インフラのあるべき姿`をテンプレートとして定義して必要に応じて展開することで
テンプレートで定義されたインフラを展開できます。
これらの作業をIaC（インフラストラクチャアズコード）の概念で実現できます。

インフラのあるべき姿？テンプレート？インフラを展開？IaC？？
ナニモワカラナイですね。順番に見ていきましょう。

## IaCについて

そもそもではあるのですが、IaC（インフラストラクチャアズコード）とはどんなものなのでしょうか。

### IaCとは

実はAWS公式サイトに定義が掲載されています。

> Infrastructure as Code (IaC) とは、手動のプロセスや設定の代わりにコードを使用してコンピューティングインフラストラクチャをプロビジョニングおよびサポートできることをいいます。どのようなアプリケーション環境であっても、オペレーティングシステム、データベース接続、ストレージなどの多くのインフラストラクチャコンポーネントが必要です。デベロッパーは、アプリケーションを開発、テスト、デプロイするためのインフラストラクチャを定期的に設定、更新、メンテナンスする必要があります。 

[Infrastructure as Code (IaC) とは何ですか?](https://aws.amazon.com/jp/what-is/iac/)

つまり、書いたコードを実行することでコードに書かれているインフラがプロビジョニングされます。インフラストラクチャを構成するサービスやツールをコードで展開できて設定できます。

※プロビジョニング：展開して構築すること。上記の場合は、インフラを構築する意味になる。

### IaCを使う意味・メリットなど

AWS公式サイトの定義にもあるとおり、`手動のプロセスや設定の代わり`とあるのでインフラをプロビジョニングする際はコードでなくてもできます。
ではなぜ、コードにするのでしょうか。理由は簡単です。

手動のプロセスでは設定手順を必要とするため、設定手順を履行する人によって構築の品質（正確さやスピードなど）が異なるためです。

また、インフラの設定において一番やってはいけないヒューマンエラー防止という観点もあります。
とくにクラウドサービスではさまざまなアップデートがあるため、設定項目もそれに合わせて増えていきます。
インフラの設定を平準化することに一役買うでしょう。

### IaCの種類

cfnはAWSが提供するIaCのサービスですが、実はIaCを実現するツールがあります。
具体的には下記のとおりです。

- AWS CDK
    - 任意のプログラミング言語でインフラを構築できる
- AWS SDK
    - クラウド上でクラウドを操作するアプリケーションに使われることもあるので微妙なライン
- Terraform
    - Hashicorp社が開発した製品。AWS以外のクラウドやモニタリングツールのIaCも実現できる

## cfnについて見ていこう

IaCについて理解できたところで実際にcfnについて見ていきたいと思います。

### cfnの基本機能

作成・変更・削除の3つがあります。変更の場合はあるべき姿を見て差分を埋めるようにインフラをプロビジョニングします。

### スタックについて

作成・変更・削除などの操作を経て、インフラを構築するわけですが、適用したテンプレートはスタックという形で保存されます。

### 書き方

スタックを作成するためのテンプレートはjsonもしくはYAMLで書きます。

YAMLで書く場合（例：App Runnerを定義）

```yaml
AWSTemplateFormatVersion: 2010-09-09
Description: cicd_handson
Parameters:
  PjName:
    Type: String
    Default: cicdhandson
Resources:
  CICDHandson:
    Type: AWS::AppRunner::Service
    Properties:
      InstanceConfiguration:
        Cpu: "1 vCPU"
        Memory: "2 GB"
      ServiceName: !Sub "${PjName}"
      SourceConfiguration:
        AutoDeploymentsEnabled: true
        ImageRepository:
          ImageConfiguration:
            Port: "80"
          ImageIdentifier:
            !Join [":", [!ImportValue CICDHandsonECRImageURL, "latest"]]
          ImageRepositoryType: ECR
        AuthenticationConfiguration:
          AccessRoleArn: !GetAtt CICDHandsonAppRunnerIAMRole.Arn
      Tags:
        - Key: Name
          Value: cicd_handson
  CICDHandsonAppRunnerIAMRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: iam-role-app-runner
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - build.apprunner.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSAppRunnerServicePolicyForECRAccess

      Tags:
        - Key: Name
          Value: !Sub "${PjName}"
```

### テンプレートのセクションをおさえよう

テンプレートの例を示しましたが、実は記載例にはないセクションも存在します。ここでは一覧を見ていきましょう。

|セクション名|説明|必須or不要|
|:---|:---|:---|
|AWSTemplateFormatVersion|`2010-09-09`で固定|不要|
|Description|テンプレートに関する説明書き|不要|
|Metadata|テンプレートに関する追加情報|不要|
|Parameters|実行にユーザに対して入力を求める|不要|
|Rule|スタックの作成または更新前にパラメータを検証|不要|
|Mappings|条件パラメータ値に利用|不要|
|Conditions|リソースが作成または設定される条件を登録|不要|
|Transform|変換および拡張処理に利用|不要|
|Resources|スタックを構成するリソース|必須|
|Outputs|スタック構築後にリソースの値を出力するセクション|不要|

`不要`となっているものはあってもなくても良いセクションです。見るとわかるとおり、`Resources`だけあればOKです。

### テンプレート内にある関数みたいなもの

各セクションがどんなものか分かりましたが、記述例を見ると`!Sub`や`!Join`、`!ImportValue`があります。これらはどういう意味があるのでしょうか。

## 組み込み関数

テンプレート内にある関数のようなものは組み込み関数と呼ばれているものです。
パラメータに従ってテンプレートの値を変更します。

|関数名|説明|
|:---|:---|
|!Sub|入力された文字変数を指定した値に変更する|
|!Join|指定した文字で配列を結合する|
|!ImportValue|他のスタックにあるOutputsセクションでエクスポートされた値をインポートする|
|!GetAtt|論理IDの属性（Arn、Idなど）を取得する|

他にもさまざまな関数がありますので実現したいことに合わせてリファレンスを参照しましょう。[参考 - 組み込み関数リファレンス](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference.html)

## 擬似パラメータ参照

関数や各種パラメータを記述すればテンプレートは完成しますが、記述した内容でしかテンプレートを構成できないのでしょうか。

実はAWSが提供するパラメータを利用することでリージョン名やアカウントIDを表現できます。
以下のURLにあるパラメータはテンプレートに記述することで特定のパラメータに置き換わります。

[擬似パラメータ参照 - 参考](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/pseudo-parameter-reference.html)

## 利用時の注意事項

### IAMリソースを作る時

IAMリソースも他のサービス同様に作成できますが、IAM関連のリソースが作成されることについてチェックを入れる必要があります。

AWSマネジメントコンソールではチェックボックスへのチェック、AWS CLIなどでテンプレートを起用する場合は`--capabilities CAPABILITY_NAMED_IAM`をつける必要があります。

### AWSでのみ使えるテンプレートであること

「cfnで適用できるテンプレートはAWSでのみ通用するテンプレートである」というところが利用時の注意点として挙げられます。

たとえば、エンジニアのスキルや組織としての方向性にフォーカスした話になるのですが
提供しているインフラをどのように構築するかというところでcfnを採用するかもしくは他のIaCを採用するかが決まります。

つまりは技術選定の一つの要素として検討できるということです。

「将来的にはAWS以外も提供していきたい」となるとcfnという選択は少しだけ検討の余地があるかと思います。何で構築すべきかはエンジニアを中心に考えていきましょう。

## まとめ

cfnの概要について見ていきました。cfnを使うとインフラをコードで定義できるため、使い方によっては手作業によるインフラ構築がなくなります。
ただし、AWSでしか利用できないIaCサービスとなるため、他のクラウドサービスまでコードで定義するとなるとcfnだけでは足りません。

必要に応じて他のIaCツールの利用について検討を進めると良いでしょう。

## おわり