【AWS】ALB + ECS(Fargate) + RDS構成レシピ【terraform付き】

**細かいTodoとかスクショは載ってませんm(_ _)m**
**infraガチ勢じゃないので叩くところあったら叩いてくださいm(_ _)m**
**DBはSQLServerを使っています**

## コレは何
社内技術検証中に、**ECSにKotlinで書いたAPIをデプロイしたくなった**のですが、設定周りで結構つまづいたのでメモ。
詳細な手順は載せませんm(_ _)m。
本業の合間に3日間ぐらいマネジメントコンソールをぽちぽち~詰まってはまたぽちぽちを繰り返しました。（ツラかった）

ECR（DockerイメージをPushする先）とECS（DockerイメージをPushした先）だけ気にしてりゃええやろ、と思っていたら`VPCエンドポイント`と`Application Load Balancer`の設定がキーポイントでした。

## 読者想定
* Dockerfileは書ける/Docker Buildはできる/RepositoryにPushできる
    * [公式を参考にしてみてください](https://docs.aws.amazon.com/ja_jp/AmazonECR/latest/userguide/docker-push-ecr-image.html)
* AWSアカウントを持っていて、コンソールからぽちぽちする
* ネットワーク周りの知見がある
    * ここ全然言語化できてなくてスミマセン...**自分infraが本職じゃないのでうまく細分化してかけないのですが、cidrとかtcp/ipとかの知識は最低限あると良いと思いました**
* 任意の言語でアプリが書ける
    * ワイはKotlin*SpringBootで適当なAPIを書きました

## 作りたかった構成

構成図
![AWS_ECS_TRIAL.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/552268/620d4cdc-5ac7-e3e2-50c5-40c3da59ec9b.jpeg)

このブログの構成図をめちゃくちゃ参考にしました
https://blog.not75743.com/post/ecs_private/

参考

## 必要なもの（改めて言語化）
レシピのようなものです。下記を新規作成しました。
(デフォルトのVPCとかは使ってないです)

### VPC周り
* VPC1個
* サブネット4個
    * 2AZ * Public/Privateで4つ
* インターネットゲートウェイ1個
    * パブリックにしたい方のサブネットに紐づける
* ルートテーブル2個
    * Publicに紐づける用/Privateに紐づける用で2個
* セキュリティグループ3つ
    * ApplicationLoadBalancer用
        * Internetからの入口
        * 任意のアドレスからポート８０８０の通信を許可
    * ECSコンテナ用
        * ALB->ECSの通信許可用
        * 上記ALB用SGからポート8080の通信を許可。(コンテナは8080ポートを解放している前提)
    * VPCエンドポイント用
        * ECS->CloudWatch等のAWSリソースへの通信許可用
        * 後で作るVPCエンドポイントと紐づける
        * ECSコンテナ用SGからの443(HTTPS)通信を許可。
    * RDS用
        * ECS->Databaseの通信許可用
        * VPCのCidrからのtcp通信を許可　ポートはどのDB製品を使うかによる(MySQL->3306,SQLServer->1433
    
### EC2

#### VPCエンドポイント
VPCエンドポイントはインターネットを介さず、VPC内でのAWSリソース間通信を可能にするものです。

https://qiita.com/miyuki_samitani/items/9d9f7a0c417cb75a6c85

* VPCエンドポイント3つ
    * ECS->ECR接続用に2つ.DockerImageをPullするための通信に必要.下記サービスを有効化
        * com.amazonaws.ap-northeast-1.ecr.dkr/interface型
        * com.amazonaws.ap-northeast-1.ecr.api/interface型
    * ECS->CloudWatch接続用に2つ.log等を出すためのもの.下記サービスを有効化
        * com.amazonaws.ap-northeast-1.logs/interface型
    * ECS->S3接続用に1つ.
        * com.amazonaws.ap-northeast-1.s3/gateway型 

#### Application Load Balancer

インターネットを通じてAPI叩けるように設定していきます。

* ターゲットグループ
    * VPCと紐付け
    * port:8080
    * protcol: HTTP
    * ターゲットタイプ:IP
    * ヘルスチェック追加
        * APIにヘルスチェック用APIを生やす必要があります
        * 作ったヘルスチェック用APIのパスを設定
* LoadBalancer
    *　ApplicationLoadBalancer型 
    *　internet-facing
    *　IPv4型
    *　上記で作ったALB用セキュリティグループと紐付け
    *　プライベートサブネット2つ（a,c)と紐付け
    *　リスナー作成
        *　port:8080
        *　protcol:HTTP
        *　"forward to"として上記ターゲットグループを選択

### RDS周り

#### 各種〇〇グループ
* DBサブネットグループ(上で作ったVPCサブネットグループとは別)
    * 上記で作ったプライベートグループ2つと紐付け
* DBパラメータグループ(←マネジメントコンソールからDBインスタンス作れば自動生成される)
* DBオプショングループ(←マネジメントコンソールからDBインスタンス作れば自動生成される)

#### DBインスタンス
* DBインスタンス
    * ここまで作ってきたVPC/Subnet/DBSubnetを紐づける
    * SSMSとかDBeaver等のSQLクライアントからSQL流したい場合は、パブリックアクセスをtrueに

### ECS周り
* Elastic Container Repository（ECR)
    * BuildしたイメージをPushする先
    * ContainerがイメージをPullし、動作する
* タスク定義
    * FARGATEで起動
    * コンテナの定義(**ここが大事**)
        * ECRにPushしたイメージ/タグを指定
            * ex:{ECR番号}dkr.ecr.{region}.amazonaws.com/{image名}:{タグ名}
            * ポートマッピングとしてhostPort:8080,containerPort:8080
            * 環境変数が必要ならそちらを利用
* クラスター
    * "ネットワーキングのみ"指定
    * 作成済のVPCと紐付け
* サービス
    * 起動タイプはFARGATE型
    * 作成したタスク定義(おそらくversionは１になってるはず)を指定
    * 作成済のVPC/プライベートサブネット/ECSコンテナようセキュリティグループと紐付け
    * タスク数を1に指定
        * コレを0にするとタスクが立ち上がらない状態を作れる
    * 作成済のロードバランサと紐付け
        * 型はApplicationLoadBalancer

## 動作確認

自分はURL`http://{ALB名}.{Region名}.elb.amazonaws.com:8080/{アプリで指定したルーティング}`にPostmanで通信しました。curlでやってもブラウザから叩いてもOK、お好きなようにどうぞ！

まずはアプリ側で200を返すだけの"/health_check"をみたいなAPIを生やして、デプロイできたか確認するのがおすすめです。

## terraform化してみた
https://github.com/kannna5296/lambda-s3-to-RDS-infra

* Lambdaもくっついてるけど無視して下さい

## 参考文献
特に１件目のブログには大変お世話になりました。

https://blog.not75743.com/post/ecs_private/

https://dev.classmethod.jp/articles/ecs-deploy-all/

## 改善点
まだできてない、実運用だと絶対やるべきだよなぁというやつ
※あくまでAPIで200OKが返ってくることをゴールに作ったので許してください

* デプロイ自動化周り
    * ECSをBlue/Greenデプロイ仕様にする
        * サービス止めずにデプロイするのに便利なはず...
    * ECRへのPushも自動化
        * GitHubActionsかCodePipeline使うんだろうと思っている
    * IAM/権限周りの整理
        * 今結構ガバガバ 
* タグのlatest運用をやめる
    * 切り戻しとかができない/いつPushしたバージョンを使ってるのか不明になる、などの理由からNG 
* ドメインの設定
    * APIを実際に利用したい時、本記事の設定だとALBが自動で発行したドメイン`http://{ALB名}.{Region名}.elb.amazonaws.com:{Port}/{アプリで指定したルーティング}`みたいなやつを利用す流必要があります。
    * 多分Route５３を使うんだと思う、知らんけど