超簡単にサイト公開できるAWS Amplify Consoleを使ってAngularのCI/CD環境を作ってみる #reinvent
どうも!大阪オフィスの西村祐二です。
この記事はAngular Advent Calendar 2018の17日目の記事です。
今回はAWS Amplify Consoleを使ったAngularのCI/CD環境を作ってみたいと思います。
AWS Amplify Consoleとは?
AWS Amplify Consoleは簡単に言うと Webアプリを公開する環境を超簡単にセットアップできるサービス です。
詳細は下記ブログを参照ください。
新サービス「AWS Amplify Console」登場!簡単3ステップでWebアプリのCI/CD環境を構築! #reinvent
re:Growth 2018で「AWS Amplify一族の話」を話しました! #reinvent #cmregrowth
環境
- Angular CLI: 7.1.3
- Node: 8.12.0
- OS: darwin x64
- Angular: 7.1.3
Angularのプロジェクトを作成
今回は「amplify-console-angular」という名前にしておきます。各々好きな名前を設定してください。
$ ng new amplify-console-angular ? Would you like to add Angular routing? Yes ? Which stylesheet format would you like to use? CSS
作成されたファイルをリポジトリにpushします。今回はGithubを使います。
例:Githubにpushする。
$ git remote add origin https://github.com/<repo-name>.git $ git push -u origin master
AWS Amplify Consoleを使ってサイトを公開する
Amplifyのマネージメントコンソールに移動します。Deployの「GET STARTED」をクリックします。
▼今回はGithubを選択
▼認証設定を行い、リポジトリを選択します。先程Angularのファイルをpushしたリポジトリを選択しておきます。
▼AWS Amplify Consoleが自動的にフレームワークを認識し、ビルドファイルを作成してくれます。
▼設定を確認し、「保存してデプロイ」をクリックします。これだけで、サイトを公開することができます。
▼デプロイ状況を確認することができます。
▼様々な解像度での見え方などスクリーンショットを自動的に取得してくれたりもします。デフォルトで
▼超簡単にBasic認証を設定できます。
詳細は下記ブログを参照してください。
超簡単!AWS Amplify ConsoleでWebサイトにアクセス制限(Basic認証)を設定する #reinvent
▼超簡単にドメインの設定ができます。
詳細は下記ブログを参照してください。
CI/CD環境を作る
ここからが本題です。
AWS Amplify Consoleがデプロイ周りなど自動でやってくれるので、自動テストの設定やブランチ設定などを行い、より良いCI/CD環境を作っていきたいと思います。
デプロイ時に自動テストを組み込む
ng test
, ng e2e
をデプロイ時に実行させる
Angularではデフォルトで単体テストとe2eテストをng test
、 ng e2e
で実行することができます。
これを組み込んでみたいと思います。
デフォルトのデプロイファイルは下記の様になっております。
version: 0.1 frontend: phases: preBuild: commands: - yarn install build: commands: - yarn run build artifacts: baseDirectory: dist/<project-name> files: - '**/*' cache: paths: - node_modules/**/*
今回、下記のように修正しました。
version: 0.1 frontend: phases: preBuild: commands: - yarn install - export PATH=$PATH:$PWD/node_modules/.bin/ - curl https://intoli.com/install-google-chrome.sh | bash - ng test --watch=false - ng e2e build: commands: - yarn run build artifacts: baseDirectory: dist/<project-name> files: - '**/*' cache: paths: - node_modules/**/*
簡単に解説します。
- 7行目
- export PATH=$PATH:$PWD/node_modules/.bin/
ng
コマンドを使いたかったのでパスを通してます。
- 8行目
- curl https://intoli.com/install-google-chrome.sh | bash
- chromeブラウザを
ng test
,ng e2e
実行時に利用するため、インストールしています。 - 画面キャプチャなど行ってくれているのでインストールされているかと思ったのですがエラーとなったり、
/usr/bin/
配下をみたのですが、それらしいものがなかったのでインストールしています。
▼Angular内の設定ファイルも修正します。
e2eテスト用の設定ファイル
// Protractor configuration file, see link for more information // https://github.com/angular/protractor/blob/master/lib/config.ts const { SpecReporter } = require('jasmine-spec-reporter'); exports.config = { allScriptsTimeout: 11000, specs: [ './src/**/*.e2e-spec.ts' ], capabilities: { 'browserName': 'chrome', chromeOptions: { args: ["--headless", "--disable-gpu", "--window-size=800,600", "--disable-dev-shm-usage", "--no-sandbox"] } }, directConnect: true, baseUrl: 'http://localhost:4200/', framework: 'jasmine', jasmineNodeOpts: { showColors: true, defaultTimeoutInterval: 30000, print: function() {} }, onPrepare() { require('ts-node').register({ project: require('path').join(__dirname, './tsconfig.e2e.json') }); jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); } };
単体テスト用のテストファイル
// Karma configuration file, see link for more information // https://karma-runner.github.io/1.0/config/configuration-file.html module.exports = function (config) { config.set({ basePath: '', frameworks: ['jasmine', '@angular-devkit/build-angular'], plugins: [ require('karma-jasmine'), require('karma-chrome-launcher'), require('karma-jasmine-html-reporter'), require('karma-coverage-istanbul-reporter'), require('@angular-devkit/build-angular/plugins/karma') ], client: { clearContext: false // leave Jasmine Spec Runner output visible in browser }, coverageIstanbulReporter: { dir: require('path').join(__dirname, '../coverage'), reports: ['html', 'lcovonly', 'text-summary'], fixWebpackSourcePaths: true }, reporters: ['progress', 'kjhtml'], port: 9876, colors: true, logLevel: config.LOG_INFO, autoWatch: true, browsers: ['ChromeHeadlessNoSandbox'], customLaunchers: { ChromeHeadlessNoSandbox: { base: 'ChromeHeadless', flags: ['--no-sandbox'] } }, singleRun: false }); };
これでブランチにpushしてみます。
下記のようなログが出力されれば成功です!
2018-12-16T16:58:19.224Z [INFO]: # Executing command: ng test --watch=false 2018-12-16T16:58:25.804Z [INFO]: [32m16 12 2018 16:58:25.802:INFO [karma-server]: [39mKarma v3.1.3 server started at http://0.0.0.0:9876/ 2018-12-16T16:58:25.807Z [INFO]: [32m16 12 2018 16:58:25.804:INFO [launcher]: [39mLaunching browsers ChromeHeadlessNoSandbox with concurrency unlimited 2018-12-16T16:58:25.809Z [INFO]: [32m16 12 2018 16:58:25.809:INFO [launcher]: [39mStarting browser ChromeHeadless 2018-12-16T16:58:29.247Z [INFO]: [32m16 12 2018 16:58:29.246:INFO [HeadlessChrome 71.0.3578 (Linux 0.0.0)]: [39mConnected on socket XXX with id 000000000000 2018-12-16T16:58:30.769Z [INFO]: HeadlessChrome 71.0.3578 (Linux 0.0.0): Executed 0 of 3 SUCCESS (0 secs / 0 secs) 2018-12-16T16:58:30.857Z [INFO]: [1A[2KHeadlessChrome 71.0.3578 (Linux 0.0.0): Executed 1 of 3 SUCCESS (0 secs / 0.086 secs) 2018-12-16T16:58:30.900Z [INFO]: [1A[2KHeadlessChrome 71.0.3578 (Linux 0.0.0): Executed 2 of 3 SUCCESS (0 secs / 0.129 secs) 2018-12-16T16:58:30.927Z [INFO]: [1A[2KHeadlessChrome 71.0.3578 (Linux 0.0.0): Executed 3 of 3 SUCCESS (0 secs / 0.155 secs) 2018-12-16T16:58:30.938Z [INFO]: [1A[2KHeadlessChrome 71.0.3578 (Linux 0.0.0): Executed 3 of 3 SUCCESS (0.168 secs / 0.155 secs) TOTAL: 3 SUCCESS TOTAL: 3 SUCCESS
2018-12-16T16:58:31.010Z [INFO]: # Executing command: ng e2e 2018-12-16T16:58:33.163Z [INFO]: ** Angular Live Development Server is listening on localhost:4200, open your browser on http://localhost:4200/ ** 2018-12-16T16:58:33.166Z [INFO]: 2018-12-16T16:58:40.758Z [INFO]: Date: 2018-12-16T16:58:40.758Z Hash: Time: 7466ms chunk {main} main.js, main.js.map (main) 11.6 kB [initial] [rendered] chunk {polyfills} polyfills.js, polyfills.js.map (polyfills) 223 kB [initial] [rendered] chunk {runtime} runtime.js, runtime.js.map (runtime) 6.08 kB [entry] [rendered] chunk {styles} styles.js, styles.js.map (styles) 16.3 kB [initial] [rendered] chunk {vendor} vendor.js, vendor.js.map (vendor) 3.67 MB [initial] [rendered] 2018-12-16T16:58:40.891Z [INFO]: [16:58:40] I/config_source - curl -o/codebuild/output/src459569155/src/amplify-cli-console-angular/node_modules/webdriver-manager/selenium/chrome-response.xml https://chromedriver.storage.googleapis.com/ 2018-12-16T16:58:40.902Z [INFO]: [34mℹ[39m [90m「wdm」[39m: Compiled successfully. 2018-12-16T16:58:41.398Z [INFO]: [16:58:41] I/update - chromedriver: file exists /codebuild/output/src459569155/src/amplify-cli-console-angular/node_modules/webdriver-manager/selenium/chromedriver_2.45.zip 2018-12-16T16:58:41.399Z [INFO]: [16:58:41] I/update - chromedriver: unzipping chromedriver_2.45.zip 2018-12-16T16:58:41.544Z [INFO]: [16:58:41] I/update - chromedriver: setting permissions to 0755 for /codebuild/output/src459569155/src/amplify-cli-console-angular/node_modules/webdriver-manager/selenium/chromedriver_2.45 2018-12-16T16:58:41.545Z [INFO]: [16:58:41] I/update - chromedriver: chromedriver_2.45 up to date 2018-12-16T16:58:41.789Z [INFO]: [16:58:41] I/launcher - Running 1 instances of WebDriver 2018-12-16T16:58:41.790Z [INFO]: [16:58:41] I/direct - Using ChromeDriver directly... 2018-12-16T16:58:43.382Z [INFO]: Jasmine started 2018-12-16T16:58:43.982Z [INFO]: 2018-12-16T16:58:43.982Z [INFO]: workspace-project App 2018-12-16T16:58:43.982Z [INFO]: [32m✓ should display welcome message[39m 2018-12-16T16:58:43.983Z [INFO]: 2018-12-16T16:58:43.983Z [INFO]: Executed 1 of 1 spec[32m SUCCESS[39m in 0.602 sec. 2018-12-16T16:58:44.038Z [INFO]: [16:58:44] I/launcher - 0 instance(s) of WebDriver still running 2018-12-16T16:58:44.038Z [INFO]: [16:58:44] I/launcher - chrome #01 passed 2018-12-16T16:58:44.132Z [INFO]: # Completed phase: preBuild
ブランチごとに環境を用意しコマンド切り替える
test環境と、本番環境を用意し、test環境で動作確認をしてOKだったら本番環境に適用するといった戦略をとることがあるかと思います。
さらに、testブランチにpushされたらtest環境にデプロイされ、masterブランチにpushされた本番環境にデプロイするといったこともよくやるかと思います。
今回はこれをやってみます。
testブランチをpush
下記のようなコマンドでGithubのリポジトリにtestブランチを作成します。
$ git checkout -b test $ git push origin test
AWS Amplify Consoleでtestブランチを接続して複数環境を作成
ブランチの接続をクリックし、「test」を選択し環境を作成します。
処理が完了すると下記のような2つの環境ができあがります。
本番環境時のみng build --prod
コマンドを実行させる
現状だと、下記画像のように本番環境用に最適化されていないファイルがデプロイされているので、
- masterブランチにpushされたら
ng build --prod
が実行され、 - それ以外のブランチにpushされたときは
ng build
が実行される
ようにしたいと思います。
▼AWS Amplify Consoleで環境変数を設定する
下記画像のように、masterブランチにpushされたときはENV
を上書きして値をprod
に変更するようにします。
▼Angular内にビルドスクリプトを配置する
環境変数によってコマンドを切り替えるためのスクリプトを配置します。
#!/bin/sh set -xeu if [ "$ENV" = "test" ]; then export NG_CMD="ng build" elif [ "$ENV" = "prod" ]; then export NG_CMD="ng build --prod" fi $NG_CMD
▼ビルド設定を修正
スクリプト実行するようにビルド設定を修正します。
version: 0.1 frontend: phases: preBuild: commands: - yarn install - export PATH=$PATH:$PWD/node_modules/.bin/ - curl https://intoli.com/install-google-chrome.sh | bash - ng test --watch=false - ng e2e build: commands: - sh ./build.sh artifacts: baseDirectory: dist/amplify-cli-console-angular files: - '**/*' cache: paths: - node_modules/**/*
これで準備は完了です。
▼試してみる
masterブランチにpushした際に下記のようなログが出力されれは成功です!
. . . . # Starting phase: build 2018-12-16T16:58:44.132Z [INFO]: # Executing command: sh ./build.sh 2018-12-16T16:58:44.134Z [WARNING]: + '[' prod = test ']' + '[' prod = prod ']' + export 'NG_CMD=ng build --prod' 2018-12-16T16:58:44.134Z [WARNING]: + NG_CMD='ng build --prod' + ng build --prod . . . .
さらに、それ以外のブランチにpushした際は下記のようなログが出力されているはずです。
. . . . # Starting phase: build # Executing command: sh ./build.sh 2018-12-16T16:49:55.651Z [WARNING]: + '[' test = test ']' + export 'NG_CMD=ng build' 2018-12-16T16:49:55.651Z [WARNING]: + NG_CMD='ng build' + ng build . . . .
さいごに
いかがだったでしょうか。
AWS Amplify Consoleを使ってAngularのCI/CD環境を作ってみました。
デプロイ時にテストを挟んだり、複数環境用意し、環境変数でコマンド切り替えることも簡単にできますので、興味のある方は試してみてはいかがでしょうか。
誰かの参考になれば幸いです。