
Vueプロジェクトの簡単なGitLab CI/CDフロー
-
2021年6月9日
こんにちは。ウェブ開発室のコンテンツチームのソーントンです。
皆さん、CI/CDでテストを自動的に実行していますか?そのテストを通った場合、自動的にデプロイしていますか?もし答えがノーでしたら、ご安心ください。本記事ではウェブプロジェクトで使える簡単なGitLab CI/CDパイプラインをゼロから作っていきます。
事前準備
GitLab CI/CDパイプラインの作成にフォーカスしたいので、チュートリアルについていきたい方は下記のサービス登録やプログラムのインストールなどを事前に行ってください。
・GitLab への登録
・GitLabで新規プロジェクトの作成(空)
・Node.js のインストール
(バージョンは2021/06時点LTSのv14.17.0ですが、最新LTSでもいいかと思います)
・静的ファイルをデプロイできるサービスの準備(本記事でAWSのS3を使います)
目標
一般的なフロントエンドのプロジェクトには次のスクリプトが入っているかと思います。
(カッコ内はこちらのチュートリアルで使っているツール名)
・静的解析(ESLint)
・単体テスト(Jest)
・E2Eテスト(Cypress)
・静的ファイルのビルド(Webpack)
・静的ファイルのデプロイ(S3)
こちら5つの処理をGitLab CI/CDで実行できるパイプラインを作りたいと思います。が、まずはプロジェクトが必要なのでVueのCLIツールで簡単に立ち上げます。
Vue CLIでプロジェクトを立ち上げましょう
まずはVue CLIのインストールを行います。
$ npm install -g @vue/cli
$ vue --version
でインストールの確認ができます。
$ vue --version @vue/cli 4.5.13
最後は $ vue create <プロジェクト名>
で新規のVueプロジェクトを作成しましょう。プロジェクト名はお任せしますが、オプションは次の通りにしてください。
$ vue create gitlab-cicd-test Vue CLI v4.5.13 ? Please pick a preset: Manually select features ? Check the features needed for your project: Choose Vue version, Linter, Unit, E2E ? Choose a version of Vue.js that you want to start the project with 2.x ? Pick a linter / formatter config: Prettier ? Pick additional lint features: Lint on save, Lint and fix on commit ? Pick a unit testing solution: Jest ? Pick an E2E testing solution: Cypress ? Where do you prefer placing config for Babel, ESLint, etc.? In dedicated config files ? Save this as a preset for future projects? No
NPMのパッケージのインストールなどに少し時間がかかります。できたら、プロジェクトディレクトリに移動します。
$ cd gitlab-cicd-test
一旦、ローカルでテスト・ビルドのスクリプトを実行できるかを確認します。
# 静的解析 $ npm run lint # 単体テスト $ npm run test:unit # E2Eテスト(--headlessオプションでCLIのみで回す) $ npm run test:e2e -- --headless # ビルド $ npm run build
問題がなければおめでとうございます。簡単なフロントエンドのプロジェクトができたので、「事前準備」で作成したGitLabのリポジトリに反映しましょう。
# 実際のGitLabのプロジェクトURLで書き換えてください $ git remote add origin "https://gitlab.com/USERNAME/PROJECT" $ git push origin master
.gitlab-ci.ymlを作りましょう
お疲れ様です。プロジェクトを立ち上げてGitLabまでプッシュしましたが、残念ながらCI/CDがまだ実行されていません。
幸運な事に使い始めるための手順はとてもシンプルで、プロジェクトのルートに .gitlab-ci.yml
というファイルを追加するだけとなります。プロジェクトのCI/CDコンフィグがすべてこちらのファイルに入ります。
これはプログラミング系のチュートリアルなので、最初はHello Worldを作らないといけませんね。GitLab上のEditor機能で作成しましょう。
まずプロジェクト画面の左メニューから CI/CD > Editor
を選択してください。
(「Editor」ってまだ翻訳されてないんですね)
次の画面で「Create new CI/CD Pipeline」を選択すれば、エディター画面が表示されます。
ようやくCI/CDパイプラインの作成を始められます!簡単なHello Worldを作りましょう。最小限のコンフィグになります。
yml hello_world: script: - echo "Hello, world!"
日本語に翻訳すれば、hello_world
という「ジョブ」で、 echo
コマンドを実行する、という意味合いです。
「Commit changes」ボタンで一旦コミットすれば、パイプラインが自動的に始まります。左メニューの CI/CD > ジョブ
を選択すれば、ジョブ一覧に hello_world
が追加されていることを確認できます。
ジョブの実行が完了したら、ステータスの「成功」をクリックして出力を見ることができます。
下の方で見れるかと思いますが、script
で指定した echo
コマンドがちゃんと実行されましたね!これで基本の基本ができましたが、Hello Worldではなく、lintスクリプトを実行したいですね。早速ですが、lintジョブを作成しましょう。
lintジョブ
左メニューの CI/CD > Editor
からエディター画面に戻ります。 hello_world
を削除し、 lint
というジョブを作ります。その script
はVueプロジェクトの package.json
に入っているスクリプトを使います。
yml lint: script: - npm run lint
でも実はこれでは上手くいきません。 hello_world
ジョブの出力で気づいたかもしれませんが、Dockerのイメージは ruby:2.5
でしたね。Nodeもnpm入っていないイメージなので、Nodeのイメージを使う必要があります。 更にプロジェクトの依存性パッケージをインストールしないとスクリプトを実行できません。
yml lint: image: node:lts # Dockerイメージの指定 script: - npm ci # npmパッケージのインストール - npm run lint
「Commit changes」でコミットし、問題がなければジョブが成功します!
DRYなコンフィグ
lintジョブが無事に通れば、次は単体テストを実行したいです。依存性は lint
ジョブと同じで、ほとんどコピペで追加できます。
yml lint: image: node:lts script: - npm ci - npm run lint "test:unit": image: node:lts script: - npm ci - npm run test:unit
これでコミットしたら確かに成功しますが、プログラマーのあなたは「DRYじゃないよ」と突っ込みたいですよね。その通りです。 両方のジョブの image
が同じだし、 script
の最初に npm ci
を実行します。幸運にもGitLabさんはDRYの書き方ができるように作ってくれています。 default
と before_script
を使って、重複を削減しましょう。
yml # グローバルの設定。全部のジョブに付与されます。 default: image: node:lts # scriptの前に実行されるスクリプト before_script: - npm ci lint: script: - npm run lint "test:unit": script: - npm run test:unit
すっきりしましたね!これで default
文に設定されているオプションは全部のジョブに付与されるようになりました。コミットしてジョブの実行を確認しましょう!
次はE2Eテストのスクリプトを実行しましょう。残念ながら、Cypressにはブラウザーが必要なので、 node:lts
のイメージでは実行できません。Cypressさんが提供しているDockerイメージはおすすめです。 (https://github.com/cypress-io/cypress-docker-images)
yml default: image: node:lts # 省略 # 省略 "test:e2e": image: cypress/base:14.16.0 script: # --headlessとはCLIのみで実行するオプション - npm run test:e2e -- --headless
あれ、先ほど default
で image
を設定したのにまたジョブのほうで image
を設定しているの?と思ったらご安心ください。ジョブのほうの設定は優先度が高く、好きに default
の設定を上書きすることができます。ここでコミットして、3つのジョブを確認しましょう。
ステージの紹介
テスト系のジョブが揃いました。次にビルドとデプロイを追加したいのですが、ちょっとした整理が必要になります。ビルドとデプロイをこのまま追加すれば5つのジョブが並行で実行されるので、テストが通らなくてもデプロイされてしまう恐れがあるのです!では、この問題を解決してくれる「ステージ」を紹介したいのですが、それは公式ドキュメントにお任せします。
パイプラインは、継続的なインテグレーション、デリバリ、デプロイメントのトップレベルのコンポーネントです。
パイプラインの構成は、以下のとおりです。・ジョブとは、何をするかを定義するものです。例えば、コードをコンパイルしたり、テストしたりするジョブがあげられます。
・ステージとは、ジョブを実行するタイミングを定義するものです。例えば、テストを実行するステージは、コードをコンパイルするステージの後に実行するなどです。ジョブはRunnerによって実行されます。同じステージ内の複数のジョブは、同時に動作可能なRunnerがあれば並列に実行されます
ステージ内のすべてのジョブが成功すれば、パイプラインは次のステージに進みます。
あるステージのジョブがどこかで失敗すると、一般的に次のステージは実行されず、パイプラインはそこで終了します。
通常パイプラインは自動的に実行され、一度作成されたパイプラインへ介入する必要はありません。しかし、手動でパイプラインとやり取りする場合もあります。
https://gitlab-docs.creationline.com/ee/ci/pipelines/index.html
つまり、テスト系のジョブは並行で実行されてもいいので、1つのステージに入れてもいいのです。テストを通れば、ビルド・デプロイに進みたいのでテストのステージ移行にステージに入れればいいとのことです。テストの中のいずれかのジョブが失敗したら、ビルドのステージに進まないので安心ですね。
まずは、 test
ステージを明示的にしましょう。
yml stages: - test # 省略 lint: stage: test # 省略 "test:unit": stage: test # 省略 "test:e2e": stage: test # 省略
そしてビルドのジョブを新たな build
ステージで作ります。
yml stages: - test - build # 省略 build: stage: build script: - npm run build
これでテストが通ったらビルドに進むようになりました。一旦コミットして、パイプラインの結果を確認しましょう。
環境変数&artifacts
build
ジョブで dist/
ディレクトリが生成されるので、次の deploy
ジョブにそのディレクトリをS3に上げたいです。AWSのCLIが必要なので、またDockerイメージを変えることになります。幸運な事に、GitLabさんが提供してくれています。
(https://docs.gitlab.com/ee/ci/cloud_deployment/#run-aws-commands-from-gitlab-cicd)
.gitlab-ci.yml
のエディター画面に戻り、 deploy
ステージを stages
の最後に入れて、 deploy
ジョブも追加します。検証のためにまずは ls dist/
を実行します。
yml stages: - test - build - deploy # 省略 deploy: stage: deploy # GitLab提供のAWSイメージ image: registry.gitlab.com/gitlab-org/cloud-deploy/aws-base:latest # npmインストールの必要がないため、デフォルトを上書きします before_script: [] script: - ls dist/
ここで一旦コミットしてCI/CDの結果を見れば、下記のエラーがデプロイジョブで出てきました。
$ ls dist/ ls: cannot access 'dist/': No such file or directory
build
ジョブで生成された dist/
ディレクトリは deploy
ジョブに渡されていないようですね。これはなぜかというと、ジョブの最初に git clean
が実行されて、gitで管理していないファイルは全て削除されてしまいます。この場合は artifacts
を設定すれば解決できます。あるジョブの `artifacts` 設定に入っているファイル・ディレクトリは、それ移行のステージに渡されます。 build
ジョブのほうで追加します。
yml # 省略 build: stage: build script: - npm run build artifacts: paths: - dist/ # 省略
ここでコミットし、もう一度デプロイジョブの出力を見てみましょう。
$ ls dist/ css favicon.ico img index.html js
成功です!最後にAWSのCLIが使えるように、認証情報を設定します。
AWSの認識情報を環境変数として設定すれば、スクリプトのほうでログイン処理を行う必要がなくなるのでそうします。
左メニューの 設定 > CI/CD
を選択し、「変数」のセクションを展開します。「変数の追加」ボタンから、次の3つを設定します。
変数名 | 説明 |
---|---|
AWS_ACCESS_KEY_ID | アクセスキー |
AWS_SECRET_ACCESS_KEY | シークレットキー |
AWS_DEFAULT_REGION | リージョンコード (us-east-2など) |
環境変数の設定ができたら、CI/CDのエディター画面に戻ります。デプロイジョブのスクリプトに aws s3 sync
コマンドを記入します。S3のURIは書き換えてください。
yml # 省略 deploy: # 省略 script: - aws s3 sync dist/ "s3://example.com/path/to/your/instance"
コミットしてパイプラインが終わったら、デプロイ先を確認します。
上記のページが表示されていればおめでとうございます!GitLab CI/CDでのデプロイが無事できました。
チュートリアルはこれで以上となります。ありがとうございました!
※.gitlab-ci.ymlは最終的にこちらになります:
yml stages: - test - build - deploy default: image: node:lts before_script: - npm ci lint: stage: test script: - npm run lint "test:unit": stage: test script: - npm run test:unit "test:e2e": stage: test image: cypress/base:14.16.0 script: - npm run test:e2e -- --headless build: stage: build script: - npm run build artifacts: paths: - dist/ deploy: stage: deploy image: registry.gitlab.com/gitlab-org/cloud-deploy/aws-base:latest before_script: [] script: - aws s3 sync dist/ "s3://example.com/path/to/your/instance"
※こちらのチュートリアルで触れていないオプションが多く、もっと知りたい方は公式のリファレンスを参考にしてください。
ココネでは一緒に働く仲間を募集中です。
ご興味のある方は、以下のリンクから是非ご応募ください。