Vue.jsをAWSのS3に自動デプロイする

こんにちは！

前回の記事では、LaravelのプロジェクトをEC2に立てましたが、今回はフロント側をAWSに移行させたいと思います。

バックエンド側については下記記事を参照ください。

https://qiita.com/matsunao722/items/d9480d0042da4ed07937

Vue.jsを移行させるために考えることは、Githubにpushした際に、AWSのS3に自動デプロイするようなことを考えています。

S3は、静的ウェブサイトホスティングサービスも提供しているため、S3にデプロイします。

## 事前知識

### Codepipelineとは？

awsのcodeシリーズの一つ。

コードソフトウェアの構築、テスト、デプロイまでの過程を自動化し、短時間でアップデートできるようci／cdをサポートするマネージメント型の継続的デリバリーサービスである。

Codepipelineを使えば、Codecommitに保持されているコードをEC2インスタンスにデプロイといったことも可能になる。

ソースコードの変更を検知するが、そのソースコードはCodeCommit、Amazon ECR、Amazon S3から取得が可能。

ビルドやテストはCodebuildで実行される。

### Codebuildとは？

その名の通り、ビルドが実行される。

ソースコードをコンパイルし、テストを実行し、デプロイ可能なソフトウェアパッケージを作成できる完全マネージド型のビルドサービス。

CodeBuild は連続的にスケールされ、複数のビルドが同時に処理されるので、

ビルドが待機状態でキュー内に残されることがありません。

Githubとの連携もできるため、push時にビルドを走らせることが可能。

### CloudFront とは？

「高速コンテンツ配信ネットワーク機能」のことで、データ、動画、アプリケーションなど、静的・動的なさまざまなWebコンテンツをスムーズに配信できるコンテンツデリバリネットワーク（CDN）。

さらにCDNとは、コンテンツデリバリネットワークの略で、ウェブコンテンツを効率的かつスピーディーに配信できるように工夫されたネットワークのことを指す。CDNが高速配信できるのはキャッシュサーバーを利用しているから。

参考記事：https://www.kagoya.jp/howto/network/cdn/


Cloudfrontの導入事例として、Amazon Prime VideoやHuluなどの動画配信サービスで使われており、その高速性や安定性に定評がありそうです。

## 実際にやった流れ

1. Vueプロジェクトの作成
1. Githubにリポジトリをpushしておく
1. buildspec.ymlの作成
1. S3のIAMユーザの作成
1. S3のバケット準備
1. バケットのホスティング設定
1. バケットポリシー変更(アクセスできるようにする)
1. CodePipelineの設定
1. CloudFrontの設定
1. Route 53の設定
1. 動作確認

1と2に関しては省略。
Vueプロジェクトのビルドに関しては、yarnで実施する。


### buildspec.ymlの設定

プロジェクトルートに設置するファイル。このファイルをもとにCodebuildを使用する。これもGithub管理させる。

```
version: 0.2

phases:
  install:
    commands:
      - if [ -e /tmp/node_modules.tar ]; then tar xf /tmp/node_modules.tar; fi
      - echo update npm...
      - npm install -g
      - npm update -g npm
      - echo node -v
      - node -v
      - echo npm -v
      - npm -v
      - echo install yarn...
      - npm install -g yarn
      - echo yarn -v
      - yarn -v
  pre_build:
    commands:
      - echo Installing source NPM dependencies...
      - yarn install
  build:
    commands:
      - echo Build started on `date`
      - echo Compiling the Node.js code
      - yarn run build
  post_build:
    commands:
      - tar cf /tmp/node_modules.tar node_modules
      # - echo Delete S3 Bucket object...
      # - aws s3 rm s3://バケット名 --recursive
      # - echo create invalidation
      # - aws cloudfront create-invalidation --distribution-id ${CLOUDFRONT_DISTRIBUTION_ID} --paths '/*'
artifacts:
  files:
    - '**/*'
  base-directory: dist
cache:
  paths:
    - /tmp/node_modules.tar
```

コメントアウトしている箇所はうまく行っていない・・・
環境変数をCodebuildに登録する必要がある。(下記記事参照)

https://dev.classmethod.jp/articles/codebuild-env/

しかし、buildでエラーを起こすため、うまくいかなかったため、コメントアウトした・・・

```
      # - echo Delete S3 Bucket object...
      # - aws s3 rm s3://バケット名 --recursive
```

上記コードは、過去にビルドし配置されたファイルの削除を行うが、使用しているロールへポリシーの追加が必要。

IAMよりS3のDeleteObject権限を追加する必要あり。

```
      # - echo create invalidation
      # - aws cloudfront create-invalidation --distribution-id
```

S3 + CloudFrontの構成であるため配置された資産がキャッシュされている。
アップロードした資産を即時反映するためには都度キャッシュの削除が必要である。
そのためInvalidationを作成してキャッシュを削除し即時反映させる。
こちらもロールへのポリシーの追加が必要。IAMより該当ロールにCloudFrontのCreateInvalidation権限を追加すること。

こちらの記事も参考にアレンジするといい

https://www.lanches.co.jp/blog/10249

https://kitigai.hatenablog.com/entry/2019/02/19/200000


補足だが、artifactsのbase-directoryはS3にデプロイするディレクトリを指定している。
これせんと、プロジェクト全部がデプロイされるし、node_moduleはクソ時間かかる・・・


### S3のパブリックアクセスについて

直接S3にインターネットからアクセスする際にはパブリックアクセスを許可しないといけないが、今回は直接アクセスする必要ないため、全面拒否のままにしておくといいということだったが、、、、

結局アクセス許可する設定を実施した。

### Codepipelineの設定について

パイプラインで自動ビルドとデプロイの設定をする。

### CloudFrontの設定

S3を公開するにあたり、そのCDNとなるのが、CloudFrontである。
もちろんCloudfrontがなくてもS3でホスティングサービスがあるのでできる。その際は、パプリックアクセスを許可する必要あり。

## 実際のインフラ構成図

今回はフロントアプリだけの構成となるため、バックエンドのサーバーを立てるよりは簡単である。

![スクリーンショット 2021-03-27 5.54.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/255267/6b6615c5-5860-664d-c5f0-091d8db42d16.png)

流れとしては、開発者がgithubのdevelopやfeatureブランチにpush。pushしたブランチからmasterへプルリクを作成し、マージされることで、masterブランチの変更を検知する。

そうするとCodepipelineによってCodebuildによってビルドが開始される。

ビルドについては、先ほど作成した「buildspec.yml」に基づいて実施される。

ビルド後、ファイルについてはS3ストレージにデプロイされて格納され、CloudfrontをCDNとしてサイトにアクセスすることができるようになる。

アクセスについては独自ドメインを使用するため、Route 53を経由してアクセスする。

## 手こずったこと

### Cloudfrontでの独自ドメイン使用

cloudfrontが用意したドメインではアクセスできるのだが、独自ドメインではうまくいかず、四苦八苦

https://qiita.com/NaokiIshimura/items/46994e67b712831c3016

こちらの「Altername Domain Name」に独自ドメイン(今回はtest.one-pre.com)と入れたができなかった。
SSL照明が必要とのこと。
(※この記事ではS3アクセス許可をしているが、今回はインターネットからS3にアクセスすることはないため不要)

そのため、下記記事を参照に証明書を作成し、その後独自ドメイン登録をした。

https://dev.classmethod.jp/articles/cloudfront-s3-customdomain/

https://qiita.com/Yuki_BB3/items/c98354417e449616ad04



1. 証明書発行(Certificate Managerにて)
1. Cloudfrontで独自ドメイン登録
1. Route 53で登録した独自ドメインのレコードを作成

**S3バケットで注意なのが、バケット名は想定しているドメイン名で作成しましょう。**

証明書発行で注意なのが、**バージニア北部リージョン**で発行しましょう。

Cloudfrontが用意したドメインではHTTPSアクセスができたのですが、独自ドメインではできないという事象も発生したので注意です。。。

### アクセス制限

S3バケットアクセスを全面拒否したままにしており、CloudfrontからS3にアクセスすると

**This XML file does not appear to have any style information associated with it. The document tree is shown below.**

というのが出た。

S3のホスティング設定もできていなかったので、ここで設定を実施。

Index Document (インデックスドキュメント)に「index.html」を設定。

また、バケットポリシーアクセス制限を解除。バケットポリシーの一部を下記に変更した。

```
"Principal": "*",
```


## 今後の検討・課題
現状、テストコードがないため、テストを通過したらビルドという設定ができない。フロント側のコードであるのでテストコードを作成することはあまりないが、要検討としたい。