AWS CloudFormationでEC2インスタンスを立ち上げてmysqlコマンドをインストールするまでの備忘録

AWSから少しご無沙汰気味でだったので、久々に再入門したらあれこれ詰まるところが多かったので、学びの整理も兼ねて備忘録として書き残しています。

# CloudFormationとは

CloudFormationは、Amazon Web Services（AWS）が提供するサービスの1つで、AWSリソースを自動的にデプロイおよび管理するためのサービスです。CloudFormationを使用することで、AWSのリソースをテンプレートとして定義し、スタックとしてデプロイすることができます。

詳しくはAWSの公式サイトをご覧ください。

https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/Welcome.html

# 事前準備

この記事ではCLIを使って環境構築を進めていきますのでAWS CLIコマンドが必要になり、種初期設定が完了していることを前提としています。

https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/getting-started-install.html

# 流れ

1. テンプレート作成
2. スタック作成
3. EC2にSSHログインして動作確認
4. スタック削除

# テンプレート作成

CloudFormationで実行するテンプレートを`main.yaml`という名前にしてファイルを作成します。コマンドを実行する際に指定するファイル名と一致すれば良いので、名前や格納場所は好きなように決めることができます。

全体的なコード：

```yaml:main.yaml
AWSTemplateFormatVersion: "2010-09-09"
Parameters:
  InstanceType:
    Description: Type of EC2 instance.
    Type: String
    Default: "t2.small"

Resources:
  EC2KeyPair:
    Type: AWS::EC2::KeyPair
    Properties:
      KeyName: SampleKeyPair
  EC2:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: "ami-0ffac3e16de16665e"
      InstanceType: !Ref InstanceType
      KeyName: !Ref EC2KeyPair
      UserData:
        Fn::Base64: !Sub |
          #!/bin/bash -xe

          sudo yum update -y
          sudo yum remove -y mariadb-libs
          sudo yum localinstall -y https://dev.mysql.com/get/mysql80-community-release-el7-3.noarch.rpm
          sudo yum-config-manager --disable mysql57-community
          sudo yum-config-manager --enable mysql80-community
          sudo rpm --import https://repo.mysql.com/RPM-GPG-KEY-mysql-2022
          sudo yum install -y mysql-community-client
          mysql --version
```

細かい記述を除いて全体の大枠から説明すると、先頭に記載するお決まりの文言を除けば大きく`Parameters`と`Resources`の2つに分かれています。`Parameters`セクションは、テンプレートで使用するパラメータを定義するために使用されます。`Resources`セクションは、CloudFormationテンプレートで作成するAWSリソースを定義するために使用されます。

```yaml
AWSTemplateFormatVersion:

Parameters:

Resources:

```

`AWSTemplateFormatVersion: "2010-09-09"` は、CloudFormationテンプレートのバージョンを示すものです。このバージョンは、CloudFormationテンプレートで使用できるAWSのリソースと関数を定義するための言語仕様を指定します。このテンプレートは2010年9月9日のバージョンに基づいています。

`Parameters`セクションは、テンプレートで使用するパラメータを定義するために使用されます。これにより、スタックの作成時にユーザーが入力する必要があるパラメータを指定できます。この例では、EC2インスタンスのタイプを指定する`InstanceType`というパラメータが定義されています。

`Resources`セクションは、CloudFormationテンプレートで作成するAWSリソースを定義するために使用されます。この例では、EC2キーペアとEC2インスタンスを定義しています。`EC2KeyPair`は、EC2インスタンスにSSH接続するために必要なキーペアを定義し、`EC2`はEC2インスタンスを定義します。`EC2`の`Properties`セクションには、EC2インスタンスの設定が含まれています。`UserData`は、EC2インスタンスが起動すると自動的に実行されるスクリプトを指定します。この例では、mysqlコマンドをインストールするためのスクリプトが含まれています。

## Parameters

今回は、`InstanceType`のみを可変情報として引数から渡せるように定義しています。

`{{パラメーター名}}`は、パラメーターの役割が明確になるように、任意の名称で記述することができます。

`Description`には、パラメーターに関する説明を記載します。

`Type`は、パラメーターのデータ型を指定でき、StringやNumberなどを記述します。

`Default`は、パラメーターがコマンドラインの引数から指定されなかった場合に、初期値として設定される値を指定することができます。

```yaml
{{パラメーター名}}:
	Description: {{説明}}
	Type: {{パラメーターのデータ型}}
	Default: {{デフォルト値}}
```

# Resources

今回の構成ではEC2のインスタンスをメインとしていますが、EC2を作成するときに使用するキーペアを新しく生成するため、それに関するリソースを加えた2つで構成されています。

```yaml
Resources:
  EC2KeyPair:
  
  EC2:

```

## EC2KeyPair

`EC2KeyPair`は、EC2インスタンスにSSH接続するために必要なキーペアを定義するためのリソースです。このリソースを作成することで、AWSがEC2インスタンスに対して公開鍵と秘密鍵のペアを生成し、秘密鍵をユーザーがダウンロードすることができます。この秘密鍵は、EC2インスタンスにSSH接続するために必要です。

詳しくは[AWSの公式ドキュメント](https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/ec2-key-pairs.html)をご覧ください。

https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/ec2-key-pairs.html

```yaml
{{リソース名}}:
    Type: {{タイプ}}
    Properties:
      KeyName: {{キー名}}
```

`{{リソース名}}`は、任意の名称で記述することができます。リソースがわかりやすくなるような名称をつけましょう。

`Type`は、CloudFormationテンプレートで作成するAWSリソースのタイプを指定するパラメーターです。AWSの公式ドキュメントには、使用可能なリソースタイプの一覧があります。例えば、EC2インスタンスを作成する場合、`AWS::EC2::Instance`を指定します。

`Properties`は、使用するリソースタイプによって記載する内容は異なります。今回は、`AWS::EC2::KeyPair`を指定しているため、keyNameのみを指定しています。KeyName以外にもさまざまなプロパティを指定することができますが、詳しくはAWSの[公式ドキュメント](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-keypair.html)をご覧ください。

https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-keypair.html

## EC2

EC2は、Amazon Web Services（AWS）が提供する仮想サーバーです。EC2を使用することで、必要な時に必要な数のサーバーを簡単に作成できます。EC2インスタンスには、インスタンスタイプに応じて異なるCPU、メモリ、ネットワーク性能があります。インスタンスを起動すると、必要なアプリケーション、ライブラリ、データをインストールして実行することができます。

詳しくはAWSの[公式ドキュメント](https://docs.aws.amazon.com/ja_jp/ec2/)をご覧ください。

https://docs.aws.amazon.com/ja_jp/ec2/

```yaml
EC2:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: "ami-0ffac3e16de16665e"
      InstanceType: !Ref InstanceType
      KeyName: !Ref EC2KeyPair
      UserData:
        Fn::Base64: !Sub |
          #!/bin/bash -xe

          yum update -y
          sudo yum remove mariadb-libs
          sudo yum localinstall -y https://dev.mysql.com/get/mysql80-community-release-el7-3.noarch.rpm
          sudo yum-config-manager --disable mysql57-community
          sudo yum-config-manager --enable mysql80-community
          sudo rpm --import https://repo.mysql.com/RPM-GPG-KEY-mysql-2022
          sudo yum install -y mysql-community-client
          mysql --version
```

`Type`は、EC2インスタンスを構築するため`AWS::EC2::Instance`を指定しています。

`Properties`では、次の値を指定しています。

`ImageId`では、使用するAMIのイメージを指定します。

AMIとはAmazon Machine Imageの略称で、EC2インスタンスを起動するために必要な情報をまとめたものです。AMIには、オペレーティングシステム、アプリケーション、ライブラリ、および関連する設定が含まれます。AMIを使用することで、EC2インスタンスを簡単に作成できます。

`InstanceType`では、使用するインスタンスタイプを指定します。

インスタンスタイプは、EC2インスタンスのCPU、メモリ、ストレージ、ネットワーク性能の異なる設定が定義されたグループです。インスタンスタイプは、使用目的や負荷に応じて選択する必要があります。例えば、t2.microは、開発やテストなどの軽い負荷に最適であり、m5.xlargeは、高いコンピューティングパワーが必要なアプリケーションに最適です。

`KeyName`では、EC2で使用するキーを指定します。今回は、`EC2KeyPair`で作成したキーペアを指定するため、`!Ref`の記述を使用して参照する形で指定します。

https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-ref.html

`UserData`では、インスタンス起動時に実行するスクリプトを記述します。特に実行したいことはなければ、記載を省略して構いません。今回は、EC2からMySQLに接続したいので、mysqlコマンドを実行できるようになるまでに必要な処理を記載していますが、詳しい説明は省略します。

https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-base64.html

https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-sub.html

# スタック作成

テンプレートの作成は慣れるまではかなり苦労しそうですが、なんとか書き上げることができました。

次のコマンドを実行することでスタックを作成することができます。

[スタックの作成 - AWS CloudFormation](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/using-cfn-cli-creating-stack.html)

```bash
aws cloudformation create-stack \
  --stack-name EC2Sample \
  --region ap-northeast-1 \
  --template-body file://main.yml
```

コマンドのリクエストに成功したら、それ以降の進捗に関してはAWSコンソール＞CloudFormationから確認することができます。

CloudFormationの処理が問題なく成功したら、EC2のページにインスタンスが作成されます。

https://ap-northeast-1.console.aws.amazon.com/cloudformation/home

作成されたキー情報の秘密鍵は、[AWS Systems Manager](https://ap-northeast-1.console.aws.amazon.com/systems-manager/parameters)から参照することができますので、コピーしてローカルでファイルを作成します。

説明では簡易的に記載していますが本番環境などで運用する際は、ファイルの取り扱いにはご注意ください。

```bash
pbpaste > SampleKeyPair.pem
chmod 400 SampleKeyPair.pem
```

https://ap-northeast-1.console.aws.amazon.com/systems-manager/parameters

# EC2にSSHログインして動作確認

基本的な操作について省略しますが、詳しくはAWSの[公式ドキュメント](https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/AccessingInstancesLinux.html)をご覧ください。

https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/AccessingInstancesLinux.html

# クリーンアップ

一通り動作確認が終わったら不必要に課金されないように速やかに環境を削除することをお勧めします。よく停止を忘れて気づいた頃にいいお値段の請求書が送られてくる。なんてこともよく聞く話ですので、泣きそうにならないように確実に削除しましょう。

https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/using-cfn-cli-deleting-stack.html

```bash
aws cloudformation delete-stack --stack-name EC2Sample
```

# 最後に

実際にEC2インスタンスが立ち上がって動かすところまでは確認できましたが、ところどころもっとこうした方がいいかも。というところはありそうなので、少しずつブラッシュアップしていきたいところです