nuxtプロジェクトを独自ドメインでSSR（CloudFront -> ALB -> Fargate）

* nuxtあまり関係なかった
* 2018.10.4現在
* スケーリングや死活監視、CI・CDのぞく、実運用環境ではなく取り敢えず動かしてみました系です

## 全体像

* 目的： https://example.jp でfargateコンテナのnuxt ssrにアクセスする
* 手順
   1. Docker対応（image作ってECRにpush）
   2. Fargateクラスタ作成
   3. ALB設定
   4. CloudFront設定

## 1. Docker対応（image作ってECRにpush）

目的：現プロジェクト(nuxt)をdockerに対応する

1. プロジェクトのpackage.jsonと同じディレクトリに`Dockerfile`, `.dockerignore`ファイルを作って配置

    ``` Dockerfile:Dockerfile 
    FROM node:10-alpine
    
    ENV HOST 0.0.0.0
    
    RUN mkdir -p /app
    COPY . /app
    WORKDIR /app
    
    ARG ENV
    ENV ENV $ENV
    
    RUN yarn && yarn build

    EXPOSE 3000

    CMD ["yarn", "start"]
    ```

    ```:.dockerignore
    node_modules/
    .nuxt/
    ```

1. `docker image build` でプロジェクトのimageを作る。

    ```zsh
    $ cd path/to/dir
    // "hoge/fuga"がimage名、"0.0.1"がタグ、"."でカレントディレクトリ
    $ docker image build -t hoge/fuga:0.0.1 .
    ```

1. `docker tag`でタグ付け（バージョニング）
   * 先にECR関係の設定をしておく必要がある。
   * まず、`Amazon ECS`からリポジトリを登録する。上記例の場合は`hoge/fuga`がリポジトリ名
   * つぎに、ECRにアクセスするためにawsへログイン。"region" "profile"はそれぞれ合わせる
   * https://docs.aws.amazon.com/ja_jp/AmazonECR/latest/userguide/ECR_GetStarted.html

        ```zsh
        $ $(aws ecr get-login --no-include-email --region ap-northeast-1 --profile hoge)
        ```
        ```zsh
        $ docker tag hoge/fuga:0.0.1 xxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/hoge/fuga:0.0.1
        
        $ docker tag xxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/hoge/fuga:0.0.1 xxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/hoge/fuga:latest
        ```
1. `docker push`でリポジトリに登録

    ```docker
    $ docker push xxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/hoge/fuga:latest
    ```

#### image作成完了後

* dockerコンテナをローカルで起動すると`http://localhost:3000`でアクセスできる 

    ```
    $ docker container run -d -p 3000:3000 --name fuga hoge/fuga:0.0.1
    ```



## 2. Fargateクラスタ作成

* AWS Web Consoleにて、ECS設定画面>クラスター画面>`今すぐはじめる`ボタンでFargateのクラスター作成チュートリアル画面にうつる（なんじゃそりゃ）

1. 最初の画面
  * `コンテナの定義`の`Custom`の`設定`ボタンから
     * `コンテナ名` ECRでつけたimage名から適当に
     * `イメージ` ECR一覧の該当リポジトリの`リポジトリの URI`
     * `メモリ制限` とりあえず空で大丈夫なはず
     * `ポートマッピング` **3000**
     * `詳細コンテナ設定` とりあえずskipしても動く
  * `タスク定義`
     * cpuとメモリ制限設定して無ければ何もいじらなくて大丈夫
2. ふたつめの画面 
  * `サービスを定義する`
     * `ロードバランサーの種類` Application Load Balancer(ALB)を選ぶ
     * 最初の画面でポートマッピングが自動で反映される
3. みっつめの画面
  * `クラスターの設定`
     * `クラスター名` ECRのイメージ名-cluster とか適当に 

* 作成実行
  * ちょっと時間がかかる
  * サービスの生成に失敗することがある。[同じ内容で再度作成すると成功したりする](https://qiita.com/propella/items/d261879e89774a06e2bb)
  * なんどか失敗するようなら`コンテナ定義`のcpuとメモリ制限設定をタスク定義と同じもの設定すると良いかもしれないし変わらないかもしれない


#### 設定完了後

* ALBのDNS名+3000ポートでブラウザからアクセスできる。（セキュリティグループ等何か特別な設定してない限り）


## 3. ALB設定

1. 自動で作られたALBにドメインを設定する。CloudFrontかます事考えてorigin用ドメイン（例：origin.example.jp）
  1. リッスンにhttps追加、証明書はACMで発行が楽
     * 証明書ドメインは`example.jp`に、`*.example.jp`を追加する形で作っとくと管理が楽。 `origin.example.jp`のみでも問題なし
  1. DNS設定（Route53等）で`origin.example.jp`をこのALBに向ける
      * Route53の場合は、Aレコードで`ALIAS`設定すると良い。それ以外のDNS管理ツールなら`CNAME`
1. 外側port`３０００`を`ssl(443)`に変更、セキュリティグループも同様に`３０００`から`443`に変更
  * `(internet)<->ALB`の話で、`ALB<->Fargate`間（内部）は3000のまま

#### 設定完了後

* `https://origin.example.jp`でアクセスできる


## 4. CloudFront設定

* Create Distributionから
    * `Origin Domain Name` origin.example.jp
    * `Origin Protocol Policy` HTTPS only
    * `Viewer Protocol Policy` Redirect HTTP to HTTPS
    * `Allowed HTTP Methods` 必要なものを
    * `Alternate Domain Names(CNAMEs)` example.jp
    * `SSL Certificate` Request or Import Certificate with ACMから**バージニアリージョン**で`example.jp`の証明書を作る（またはimport）
       * tokyoリージョンと同じドメインで証明書作れる
    * 他お好みで調整の上作成
* DNS設定
    * Route53でAレコードAliasする際は、CloudFrontの`Distribution Status`が`InProgress`から`Deployed`に変わってないと設定できないので注意


#### 設定完了後

* `https://example.jp`でアクセスできる


## @. Fargateのデプロイ

* 新しいdocker imageをlatestタグ付けしてECRにアップ後、`Amazon ECS`>`クラスター`>`対象クラスタ`>`サービス名リンククリック`>`更新`ボタンから、 `新しいデプロイの強制`にチェック入れて他そのままで更新すると、勝手にlatestでデプロイしてくれる(数分かかる)

## @.その後の展望

* CodeBuild CodeDeployなどを使って、releaseブランチへのpushから自動でdocker build、fargate更新するとか
* Fargateのオートスケーリング設定するとか
* CｌoudWatchやX-Rayでサービス監視


## 参考

* https://note.mu/ar_ojisan/n/n02334166cf57
* https://qiita.com/riywo/items/b223bdad2b3ae3bebf55
* https://dev.classmethod.jp/cloud/aws/cloudfront_elb_ssl_traffic/
* https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/CNAMEs.html