AWS CopilotでECS FargateにRailsをデプロイ

# Copilotとは？
Copilotは[Amazon ECS CLI](https://github.com/aws/amazon-ecs-cli)の後継に当たるもので、
ECSでのコンテナ実行をより簡単に行う為に開発された環境構築ツールです
Copilotで構築するAWSリソースはCloudFormationによって管理され、
AWS CDK(プログラムでCloudFormationテンプレートを管理するツール)と違ってコードを書く必要は殆どありません！

[GitHub - aws/copilot-cli](https://github.com/aws/copilot-cli)
[Wiki](https://github.com/aws/copilot-cli/wiki/Getting-Started)

# Copilotのインストールと事前準備
homebrewでインストールまたはcurlで直接インストールができます

```
# homebrew
$ brew install aws/tap/copilot-cli

# curlで直接インストール
$ curl -Lo /usr/local/bin/copilot https://github.com/aws/copilot-cli/releases/download/v0.3.0/copilot-darwin-v0.3.0 && chmod +x /usr/local/bin/copilot && copilot --help

# バージョン確認
$ copilot -v
```

その他に必要なものも準備しておきましょう

- docker
- aws-cli
- AWSアカウント

# CopilotによるECS環境作成
Copilotを使って実際にwebアプリをECSにデプロイしてみましょう！

デプロイの実行状況・実行されるCloudFormationテンプレートは以下の手順で参照できます
作成されるAWSリソースもここから確認可能です
**AWSコンソール > CloudFormation > スタック**

## 1. アプリケーションを準備する
デプロイしたいアプリケーションをdockerを使って構築します
今回はこちらのrailsアプリをcopilotを使ってデプロイしてみましょう

https://github.com/git-gen/copilot-rails-deploy

**初期設定**

```yml
# config/database.yml

default: &default
  adapter: mysql2
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  database: ## RDS database ##
  host: ## RDS host ##
  username: ## RDS username ##
  password: ## RDS password ##

development:
  <<: *default

test:
  <<: *default

production:
  <<: *default
```

```
$ docker-compose build

$ docker-compose up -d
```
http://localhost:3000 で確認ができたら準備OKです！

Copilotで作成されるアプリの仕組みです
これらを一つずつ作成して行きます

- Application：Copilotアプリケーションのまとめ
- Enviroment：テスト環境、本番環境など環境別でアプリケーションを分ける仕組み
- Service：ECSで実行されるコンテナアプリケーション

![85873795-7da9c480-b786-11ea-9990-9604a3cc5f01.png](https://user-images.githubusercontent.com/879348/85873795-7da9c480-b786-11ea-9990-9604a3cc5f01.png)
[Environments · aws/copilot-cli Wiki · GitHub](https://github.com/aws/copilot-cli/wiki/Environments)

## 2. copilot applicationの作成
Copilotでアプリケーションを作成します
その際にアプリ名を聞かれるので設定しましょう

```
$ copilot app init
What would you like to name your application? [? for help]
> copilot-app

# 作成したapplication確認
$ copilot app init
```

## 3. copilot environmentの作成
environmentを複数作る事でテスト環境・本番環境というように環境分けができます
environmentを作る際にVPC/サブネットの設定を求められますが、
デフォルト設定では新規でVPC/サブネット/セキュリティグループが生成されます

```
$ copilot env init
What is your environment's name? [? for help]
> development

# environment確認
$ copilot env ls
```

**既存のVPC/サブネットを使いたい場合はこのようにオプションをつけます**
ちなみにセキュリティグループの設定は、
まだCopilotでは未対応で設定できないようです

```
$ copilot env init \
 --import-vpc-id vpc-****** \
 --import-public-subnets subnet-******,subnet-****** \
 --import-private-subnets subnet-******
```

## 4. copilot serviceの作成
railsのサービスを追加します
nginx等は使用せずALBから直接railsを呼んでいます

```
$ copilot svc init

Which service type best represents your service's architecture?  [Use arrows to move, type to filter, ? for more help]
  > Load Balanced Web Service
    Backend Service

What do you want to name this Load Balanced Web Service? [? for help]
  > app

Which Dockerfile would you like to use for app?  [Use arrows to move, type to filter, ? for more help]
  > ./Dockerfile

# service確認
$ copilot svc ls
```

Dockerfileはこんな感じです
RailsのDocker化についてはこちらを参照してもらえると！
https://docs.docker.com/compose/rails/

```Dockerfile
FROM ruby:2.7.0-alpine3.11

ENV LANG=C.UTF-8
ENV TZ=Asia/Tokyo

RUN apk update && \
  apk upgrade && \
  apk add --no-cache \
  gcc \
  g++ \
  git \
  libc-dev \
  libxml2-dev \
  linux-headers \
  make \
  nodejs \
  mariadb-dev \
  tzdata && \
  apk add --virtual build-packs --no-cache \
  build-base \
  curl-dev

RUN mkdir /app
WORKDIR /app

COPY Gemfile /app/Gemfile
COPY Gemfile.lock /app/Gemfile.lock
RUN bundle install
COPY . /app
RUN apk del build-packs

# Add a script to be executed every time the container starts.
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000

# Start the main process.
CMD ["rails", "server", "-b", "0.0.0.0"]
```

## 5. 設定ファイルの確認
これでデプロイ準備は完了です！
プロジェクトのルートディレクトリに設定ファイルが生成されているので確認しましょう

```
copilot-rails-deploy/
　├ copilot/
　│　├ app/
　│　│　└ manifest.yml
　│　└ .workspace
　│...
```

manifest.ymlではタスクのスペックや定数が設定できます
ECSのサイドカー構成等もここで設定できます

```yml
name: app
type: Load Balanced Web Service

image:
  build: ./Dockerfile
  port: 3000

http:
  path: "/"
  healthcheck: "/health_check"

cpu: 1024
memory: 2048
count: 1

variables:
  RAILS_ENV: development
```

タスク定義のスペックですが、
サポートされている数値が決まっているので変更する場合はこの範囲で設定しましょう

|CPUの値|メモリの値(MiB)|
|:-:|:-:|
|256 (.25 vCPU)|512 (0.5 GB)、1024 (1 GB)、2048 (2 GB)|
|512 (.5 vCPU)|1024 (1 GB)、2048 (2 GB)、3072 (3 GB)、4096 (4 GB)|
|1024 (1 vCPU)|2048 (2 GB)、3072 (3 GB)、4096 (4 GB)、5120 (5 GB)、6144 (6 GB)、7168 (7 GB)、8192 (8 GB)|
|2048 (2 vCPU)|4096 (4 GB) ～ 16384 (16 GB) (1024 (1 GB) のインクリメント)|
|4096 (4 vCPU)|8192 (8 GB) ～ 30720 (30 GB) (1024 (1 GB) のインクリメント)|

## 6. デプロイ
Copilotでアプリをデプロイします

```
$ copilot deploy
```

デプロイが成功すると、コマンドラインにURLが書き出されるので、
アクセスしてrailsの画面が開かれればデプロイ成功です！
![deploy.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478226/cc5301b4-0861-a3a9-a684-07dceef14f70.png)


# アプリケーションの削除
Copilotで作成したAWSリソースはdeleteコマンドで一括削除できます
今回作成したアプリを削除しちゃいましょう

```bash
# copilotのアプリを参照
$ copilot app ls
copilot-app

# アプリを削除する
$ copilot app delete copilot-app
Are you sure you want to delete application copilot-app? Yes
```