lycheejam's tech log

チラ裏のメモ帳 | プログラミングは苦手、インフラが得意なつもり。

GitHub + AWS CodeBuildでVue.jsプロジェクトのビルド&デプロイを自動化する。

概要

GitHubAWS CodeBuildを組み合わせてVue.jsプロジェクトをビルドしてAWS S3に配置するまでを自動化します。
自動化のイメージとしては以下の流れ。

  1. GitHubへPush
    • WebHook発火
  2. CodeBuild呼び出し
    • ソース取得(git clone)
    • ビルド(npm run build)
    • 既存オブジェクト(資産)の削除
    • デプロイ(dist/をS3へ配置)

CodePiplineは使いませんのでテストとかそういったたぐいは出てきません。

目次

環境

f:id:HM_Atlas:20190219121419p:plain

参考サイト様

0.前提

AWS S3でホスティングされたVueプロジェクトがあること。
(私の環境ではAWS S3 + CloudFrontの構成です。)

1.ビルドプロジェクトの作成

CodeBuildのビルドプロジェクト画面からCreate build projectを押下
以下の項目を設定しビルドプロジェクトを作成する。 直感的に設定できる内容かと思うので下記の項目設定はメモ程度で。

※記載の無い項目についてはデフォルト値とする。Project name以外は作成後も変更可能。

  • Project configuration
    • Project Name: 適宜(今回はSampleBuildとする)
  • Source
    • Source provider: GitHubを選択
    • Repository: Connect to GitHubを押下しGitHubアカウントと紐付ける。(紐付け方式は好きな方を選択、今回はConnect using OAuthを選択)
      • GitHubアカウント紐づけ後、項目が変化する。ビルド対象となるリポジトリを選択。
        この際、URLで指定も可。自身のリポジトリについてはプルダウンから選択可。
  • Primary source webhook events
    • Webhook - オプショナル: チェックを入れるとEvent typeを選択可能となる。
    • Event type: 今回はPUSHを選択。
  • Environment
    • Environment image: Managed imageを選択。
      • Custom imageを選択することで任意のDocker imageを選択可能。
        特に開発環境と本番環境をあわせたいと言う思いもないので今回はManaged imageを使用する。
    • Operation system: Ubuntuを選択。てかこれしかない。
    • Runtime: Node.jsを選択。
    • Runtime version: 10.14.1を選択。選択した理由は特にない。
    • Service Role: 適宜
  • Buildspec
    • Build specifications: Use a Buildspec fileを選択。
      • Use a Buildspec file:リポジトリに登録されているbuildspec.ymlを使用。
      • Insert Build commands:CodeBuildの画面上でbuildspec.ymlを編集可能。
        最初の動作確認はこっちのほうがてっとり速く編集できて楽かも、ただエディタがあまりよろしくないのでローカルで書くことをおすすめする。
  • Artifacts ※(ビルドした)成果物の配置先
    • Type: Amazon S3を選択。
    • Bucket name: 適宜選択。
    • Name - オプショナル: /を入力。(※バケット直下にindex.htmlを配置しているため。example.com/index.htmlのような想定)
    • Path - オプショナル: /を入力。同上
    • Artifacts packaging: なしを選択。今回は小さなサイトをデプロイする想定なのでZipで固めたりはしない。
    • Remove artifact encryption: チェックを入れる。
  • Logs 適宜設定すること。

2.buildspec.ymlの作成・追加

Buildspec.ymlについては下記のコードを使用。 下記のコードをbuildspec.ymlとしてプロジェクトフォルダの直下に配置しリポジトリにも反映する。
※1.プロジェクト作成時にInsert Build commandsを選択した場合はブラウザのテキストエディタにコピペ
※2.インデントにはTAB文字は使えない。半角スペースを使用すること。

version: 0.2

# GitHub -> CodeBuild -> S3 -> CloudFront

phases:
  install:
    commands:
      - echo update npm...
      - npm install -g n
      - n latest
      - npm update -g npm
      - echo node -v
      - node -v
      - echo npm -v
      - npm -v
  pre_build:
    commands:
      - echo Installing source NPM dependencies...
      - npm install
  build:
    commands:
      - echo build start
      - npm run build
      - echo build completed
  post_build:
    commands:
      - echo Delete S3 Bucket object...
      - aws s3 rm s3://${S3_BUCKET_NAME} --recursive
      - echo create invalidation 
      - aws cloudfront create-invalidation --distribution-id ${CLOUDFRONT_DISTRIBUTION_ID} --paths '/*'
artifacts:
  files:
    - '**/*'
  base-directory: 'dist'

環境変数について

${S3_BUCKET_NAME}${CLOUDFRONT_DISTRIBUTION_ID}については環境変数としてプロジェクトに登録しています。
ビルドプロジェクト画面Build detailsタブのEnvironmentから編集可能です。
また、入力項目はPlaintextとしています。Parameterとした場合、別設定が必要になります。
(よく知らないですが秘匿する必要のあるアクセスキー等はParameterで暗号化して使用するそうです。)

buildspec.ymlコマンドの解説

ただ、サーバ上で実行しているコマンドの羅列なので特に解説は必要ないと思うが独自要素についてメモとして記述する。

S3バケット内の既存資産(オブジェクト)の削除

過去にビルドし配置されたファイルの削除を行う。
使用しているロールへポリシーの追加が必要。
IAMよりS3のDeleteObject権限を追加すること。

aws s3 rm s3://${S3_BUCKET_NAME} --recursive

awsコマンドについては参考リンクを参照のこと。

CloudFrontのInvalidationの作成

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

aws cloudfront create-invalidation --distribution-id ${CLOUDFRONT_DISTRIBUTION_ID} --paths '/*'

※ネットで見かけたレベルの話ではあるかLambda FunctionでもInvalidationの実装は可能な模様。

artifactsの指定

デプロイする成果物(ビルドで作成されたファイル)を指定する。

artifacts:
  files:
    - '**/*'
  base-directory: 'dist'

files: - '**/*'ディレクトリ配下全てをデプロイする資産として指定する。
ただしこのままではプロジェクトディレクトリ配下全てが指定されてしまうため、base-directorydistディレクトリを指定する。
こうすることでdist配下のファイルをデプロイするファイルとして指定することができる。

閑話休題

上述のartifactsの指定でbase-directoryを指定せずにfiles: - '**/*'を記述したためプロジェクトディレクトリ配下全てがS3にデプロイされる事態となった。
node_moduleとか全てwwww
デプロイが全く終わらなくて辛かった。

3.ビルドの実行

ブラウザの画面からStart build、もしくはリポジトリにPUSHしてWebhookを発火させて試してね。

Github WebhookとBuild projectのEvent発火タイミングについて

イマイチまだ実際の動作とか理解できてなくてとりあえずPUSHしとけみたいなノリです。 全然調べたとかじゃないんですがWebhookとBuild project側のEvent typeってどちらが優先されるんですかね。よくわかんないですけど。
そのうち調べようと思います。

トラブルシュート

詰まりどころを何点か

S3バケットの直下にビルドしたファイルが配置されない。

ビルドプロジェクト画面Build detailsタブのArtifacts(buildspec.ymlの方じゃないよ)を見直す。
想定したパスを指定しているか否か。空欄となっていないかなど確認する。

デプロイうまく行ったのにサイトに繋がらない。

ビルドプロジェクトの暗号化設定を確認する。 ビルドプロジェクト画面Build detailsタブのArtifactsから確認可能。 Remove artifact encryptionにチェックが入っていることを確認する。

また、暗号化されているか否かはS3バケットの該当ファイルをクリックすることでプロパティから確認可能。

雑感

いちいちローカルでビルドしてS3の画面でドラッグ&ドロップでアップロードしてってのが面倒臭くてやった。
Buildspec.ymlのArtifactsってのが全然理解できなくて試しながらでやったので時間がかかった。 今度はホントのアプリケーションを作ってPipelineつかって自動テストとか回してみたいですね。