【AWS】 (初心者向け) CodePipelineを使ったECSコンテナのデプロイ自動化 その1(ECR, ECS Fargate)

# 概要
CodePipelineでコンテナデプロイを実行するCICD構築をまとめました。

実行されるパイプラインの流れは下記です。
1. CodeCommitにプッシュ
1. 特定のブランチへのプッシュをトリガーにCodePipelineを起動
1. CodeBuildにてビルドを開始
1. ECRリポジトリにイメージをプッシュ
1. ECS Fargateにデプロイ

コンテナはFlaskを実行するコンテナを構築します。
CICDに焦点をあてるため、簡単なソース更新にてデプロイ実行を確認します。

# 目次
記事を3つに分割しました。
1. コンテナ構築 / 起動
    1-1. Flaskアプリケーションの作成
    1-2. ローカル環境でコンテナの作成 / 起動確認
    1-3. ECRへイメージをプッシュ
    1-4. ECSでコンテナ起動　__←本記事はここまで__

1. CICDパイプラインの作成
    2-1. CodeCommitの作成
    2-2. CodeBuildの作成
    2-3. CodePipelineの作成

1. 上記のコンテナ / CICDパイプライン構築をコード化
    3-1. CloudFormationテンプレート

後続の記事はこちら
[【AWS】 (初心者向け) CodePipelineを使ったECSコンテナのデプロイ自動化 その2(CodeCommit, CodeBuild, CodePipeline)](https://qiita.com/ramunauna/items/114ffb3b5532cdb7fd2d)
[【AWS】 (中級者向け) CodePipelineを使ったECSコンテナのデプロイ自動化 その3(CloudFormationでインフラコード化)](https://qiita.com/ramunauna/items/f52cdcaeadedf40e5d22)

# 構成図
最終的な構成はこちら
![aws構成図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1813991/f4547411-56f7-7d9e-eaca-0422e14b7d9b.png)


# 1. コンテナ構築 / 起動
### 1-1. Flaskアプリケーションの作成
まずはローカル環境で簡単なFlaskアプリケーションを作成します。
今回はWebサーバーを立てて静的ページを返すだけの超簡単な内容にします。
```bash
# フォルダ構成
.
├── Dockerfile
├── app.py
├── requirements.txt
├── templates
│   └── index.html
└── venv # 仮想環境は必要に応じて
```

Flaskをインストールしておきましょう。
```requirements.txt
Flask
```
```bash
pip install -r requirements.txt
```

* app.py
```python:app.py
from flask import Flask, render_template

app = Flask(__name__)

@app.route('/')
def index():
    return render_template('index.html')

if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0', port=80)
```

* templates/index.html
`render_template`で指定するhtmlファイルは`templates`内に作成します。
内容はなんでもいいです。
```html:templates/index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <title>Flask</title>
</head>
<body>
    <p>Hello from flask</p>
</body>
</html>
```

### 1-2. ローカル環境でコンテナの作成 / 起動確認
つづいてローカル環境でコンテナを構築します。
同じフォルダ内にDockerFileを作成します。
* Dockerfile
ここでは最小限の内容にします。
```Dockerfile:Dockerfile
FROM python:3.9

WORKDIR /app
ADD . /app

RUN pip install --upgrade pip
RUN pip install -r requirements.txt

EXPOSE 80

CMD ["python", "app.py"]
```

下記コマンドでイメージを作成、コンテナを起動します。
```bash
docker build -t docker_flask .
# docker_flaskは任意は名前でok

docker run --name flask -d -p 80:80 docker_flask
# --name　flaskも任意の名前でok

open http://127.0.0.1
# index.htmlの内容が表示されればok
```

### 1-3. ECRへイメージをプッシュ
それではローカル環境で確認したイメージをECRにプッシュしましょう。
AWSマネジメントコンソールにてAmazon ECR管理画面に移動しプライベートリポジトリを作成します。
リポジトリ作成後、プッシュコマンドを実行します。
※イメージ管理画面からコマンドを表示できるのでコピペできます。
```bash
# ECRへログイン
# リージョンは東京リージョン(ap-northeast-1)を使用しています。
# アカウントIDはそれぞれのAWSアカウントIDに変更してください。

aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin ${AWSアカウントID}.dkr.ecr.ap-northeast-1.amazonaws.com
# Login Succeededを確認

# リポジトリにイメージをプッシュできるようタグを付与
docker tag docker_flask:latest ${AWSアカウントID}.dkr.ecr.ap-northeast-1.amazonaws.com/${作成したECRリポジトリ名}:latest

# ECRにプッシュ
docker push ${AWSアカウントID}.dkr.ecr.ap-northeast-1.amazonaws.com/${作成したECRリポジトリ名}:latest
```

### 1-4. ECSでコンテナ起動
今回は設定内容の作り込みはせず、ほぼデフォルトの最小限の設定で作成します。

#### 1-4-1. クラスター作成
AWSマネジメントコンソールにてAmazon ECS管理画面に移動しまずはクラスターを作成します。
クラスターテンプレートの選択はネットワーキングのみを選択。
![ecs_cluster_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1813991/1b773dee-c9ce-2dbc-561e-74841486aaaf.png)
`VPCの作成`にチェックを入れた場合は、CloudFormationが起動して自動でパブリックネットワークが作成されます。
- CloudFormationで作成されるリソースは下記
    - VPC(&セキュリティグループ)
    - サブネット
    - ルートテーブル
    - インターネットゲートウェイ

今回は上記のリソースを前もって作成していないため、VPCの作成にチェックを入れた状態でクラスター作成を進めます。

#### 1-4-2. タスク定義の作成
起動タイプは`Fargate`を選択します。
タスクサイズは今回は最小のもので良いでしょう。
- タスクメモリ (GB)： 0.5GB
- タスク CPU (vCPU)： 0.25vCPU

コンテナの定義で、`コンテナの追加`ボタンをクリックして先ほどECRにプッシュしたイメージを設定します。
`${AWSアカウントID}.dkr.ecr.ap-northeast-1.amazonaws.com/${作成したECRリポジトリ名}:latest`
![ecs_container_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1813991/6e744398-bcbe-e4c1-0d9d-7f3a53396b41.png)
作成したイメージの詳細画面の`URI`をコピペでok
![ecs_container_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1813991/db02c91c-52a5-14ec-9acc-9d1dae006f09.png)

そのほかの設定は今回はデフォルトのままで良いでしょう。

#### 1-4-3. サービス作成
先ほど作成したクラスターを選択してサービスを作成します。
起動タイプに`Fargate`を選択します。
タスク定義には前項目で作成したものを選択し、タスク数は`1`で良いでしょう。
デプロイメントタイプは今回は`ローリングアップデート`を選択します。
![ecs_service_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1813991/d252f2ba-1e28-ff4f-d304-9781bacb505b.png)

ネットワーク構成では、作成したVPC、サブネットを選択します。
![ecs_service_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1813991/2ac2e15e-ee6b-1f84-f4ec-ce5462c44200.png)
今回はセキュリティグループもあわせて自動作成します。もちろん既存のセキュリティグループも選択できます。
自動作成されるセキュリティグループのインバウンドルールは下記。
|タイプ|プロトコル|ポート範囲|ソース|
|:-:|:-:|:-:|:-:|
|HTTP|TCP|80|0.0.0.0/0|

今回はロードバランサー、AutoScalingの設定も無しでスキップします。

サービスを作成したらタスクタブに移動し、先ほど作成したタスク定義を使用したタスクが立ち上がっていることを確認します。
タスクの`前回のステータス`が`RUNNING`になるまで待ちましょう。
ステータスが`RUNNING`になりましたらタスクのパブリックIPにブラウザからアクセスしてみましょう。

先ほど作成したindex.htmlが表示されたらサーバレスコンテナの起動、表示確認は完了です。

# まとめ
今回はECRへプッシュ、ECSへデプロイまでをかなり簡単にまとめました。
次記事でCodeCommitを使ったバージョン管理、ソースの更新後の`ECRへ再プッシュ→ECSへ再デプロイ`の流れをパイプラインで自動化する流れをまとめます。

後続の記事はこちら
[【AWS】 (初心者向け) CodePipelineを使ったECSコンテナのデプロイ自動化 その2(CodeCommit, CodeBuild, CodePipeline)](https://qiita.com/ramunauna/items/114ffb3b5532cdb7fd2d)
[【AWS】 (中級者向け) CodePipelineを使ったECSコンテナのデプロイ自動化 その3(CloudFormationでインフラコード化)](https://qiita.com/ramunauna/items/f52cdcaeadedf40e5d22)