・前提
CI/CD技術に触れたことがなかったので自動化技術の一環としてハンズオンする。
また、今回の学習は以下のコンテンツを参考にする
GitHub Actionsで学ぶCI/CD入門―ビルド・デプロイの基本からAPI自動テスト・AWSへの自動デプロイまで | Udemy
・環境構築
環境構築はudemy講座の作者が用意してくださっているcloudformationスタックを利用して構築
※今回の副産物としてSystems Managerでログインできたので良い経験になった
・前提知識集
- TypescriptはAltJSと呼ばれるJSの代替言語で実行する際JSに変換されフロント・バック両方で使われる
- Node.jsはJSの実行環境の一種でnodeコマンドでJSを実行可能(例:node <JSファイル名>)
- Node.jsはサーバサイドで動くJSの実行環境というイメージ
- npmはNode.jsのライブラリ管理ツールでpackage.jsonというファイルに設定を書いて使用
- Webアプリ開発時[開発モード]と[本番モード]を設けることがある(FWによっては初めから存在)
- 開発モードはコードを書き換えると即時自動で反映され、デバッグのため細かいログまで出力
- 本番モードはコードを書き換えても自動では反映されず、開発モードより効率的・高速に動作
- プログラムを実装からリリースまでに一般に以下のステップがある(実装・単テ→ビルド→テスト環境にデプロイ→テスト環境でテスト→本番環境にデプロイ)
- ビルド→コードを基に本番等のサーバで動かす形式に変換すること(元コードをコンパイル→バンドルして成果物(サーバにupして動かすファイル)にする)
- RubyやPythonなどコードをそのままサーバにアップして実行するためビルドの必要がないものもありJS系も設定次第
- コンテナやVMのイメージを作成して本番環境でイメージを基にプログラムを動かす場合はイメージの作成もビルドと呼ぶ
- つまり、Webアプリをコンテナとして実行する場合、コードのビルドとコンテナイメージのビルドがありうる
- フロント開発でのビルドについて、ブラウザは.jsxや.vueといったファイルを処理できないのでそれらのファイルは一度JSに変換してからWebサーバに配信するので、コードをJSに変換したりJSの複数ファイルを一つにまとめるのがフロントのビルド
- フロントエンドのビルドにはNode.jsのツールを使うことが多い、フロント開発ではnpm run devで開発用Webサーバを起動して動作確認しながら実装することも多い→本番での実行時でなく、開発やビルドに使うのが基本
- CI…ローカルの環境だけでビルドや自動テストが成功するのは無意味なので、トリガを起点にビルドや自動テストを専用の環境で自動的に実行すること
- ymlファイルはインデントの数が違うだけでも意味が変わるので要注意
- StepCIはWebAPIの自動テストツールだが、テストケースをYAML形式で直観的に記述しやすく、HTTPレスポンスの内容までテスト可能でCLIで実行するツールなのでCIに組み込みやすいメリットがある
- 近年のWeb開発はtscやstepciなどNode.jsのツールと切り離せないのでインストール方法の基本は押さえておくべきで、ツール(コマンド)のインストール方法はグローバルインストールorローカルインストールの二種類があるが基本ローカルインストール(現在のディレクトリ以下で使用できるようにする)するべきで./node_modules/以下に格納され、ツールのバージョンはpackage.jsonに管理されている
- package.json内に記述されるdependenciesとdevDependenciesについてライブラリやツールのパッケージは本番環境で使いたいものと開発中だけ使いたいものがあるので上記二つで分けて管理している
- npm install stepciはローカルインストールで本番でも使うパッケージと処理され、–save-devオプションを付けると開発中だけ使うパッケージになる
- npmでローカルインストールしたツールの実行方法はnpx stepci [コマンド]
- 上記のようにコマンドが長くなると気軽にstepciを実行したい需要を満たせないのでnpm scriptsでエイリアスを設定できる
- package.json内のscripts以下を編集するとエイリアスに出来る
- rsyncコマンドを使えばSSH接続をしてファイルを転送できる
- 上記例はrsync -v -e ‘ssh -i <鍵ファイル名>’ <転送元パス> 転送先ホスト@<IP>:<転送先パス>
- EC2でバックエンドを実行するためにはnode <実行ファイル名>(※事前にEC2にNode.jsをインストール必要有)
- ポート番号の変更はsudo PORT=<変更ポート番号> node <実行ファイル名>
- プロセス確認はps aux,ポート確認はss -antup
- 当然だが作成したプログラムは毎回手作業でサーバに入力するのでなくsystemdに起動してもらったほうが良い(理由としては何らかの理由で停止しても再起動してくれるしアプリが出力したログも残るから)
- デプロイ→ビルド成果物を本番などのサーバに配置することや配置したビルド成果物を実行すること
- リリースはデプロイしたものをユーザに公開すること
- CD→本番環境へのデプロイ準備までを自動で実行したり、実際のデプロイまでを自動で実行すること
- 次のような代表的な一連のステップをCI/CDパイプラインという→ローカルPCでgithubにpushしてそれをトリガーにGithub Actionsでビルドテスト(CI)してEC2へ自動デプロイ(CD)
- 自動デプロイはGithub Actionsの設定にデプロイに使うコマンドを並べるだけ(つまり手作業でデプロイできるなら自動化も容易)
・はじめて…
vscodeにサンプルコードを記入しシステムポートを開放して初めてアプリを実行した、感動した。

・今回の学習におけるサンプルアプリのテストの種類
今回配布されたサンプルアプリのテストとして以下のものが考えられ、手動で行うこともあれば自動化することもできる
- プログラムの関数単位のテスト(単体・ユニット)
- WebAPIのテスト
- ブラウザを自動で操作するE2Eテスト
※ずっと得体の知れなかった開発側のテストについて、実際のテストコードを見たらなるほどと思う反面、網羅的に行わなければならないから大変だなと感心する
以下、初めてのテスト実行。開発の人たちはこうやっていたんだと勉強。

テスト対象の関数をいじくって再度実行するとテスト失敗、なるほど

・トラブルシューティング
用意されていた環境であれこれ検証していたが検証環境が全く安定していなかった、サーバスペックがt2.microで弱かったのでインスタンスタイプを変更する必要があった。インスタンスタイプの変更は一度EC2を停止してからということが学びになった
・コードをビルドしてみる
コマンドを入力して成果物の作成を確認


そしてサンプルアプリがブラウザ上で確かに実行することを確認

・Githubと連携しているフォルダにサンプルコードが格納されたディレクトリを移動する
以下のコマンドを入力
mv <コピー元ファイルのパス> <コピー先ファイルのパス>
・いよいよGithub Actionsを触る
今回はvscodeとGithubを連携し、GithubへのpushをトリガーにGithub Actionsで自動テストやビルドを実行する(=CI)ことをハンズオン
Github Actionsは.github/workflowsというディレクトリにGithub Actionsnの設定ファイルをコミットすることで設定が出来る
なのでまずはGithubと連携しているディレクトリの下に新規フォルダを作成(.github)して、その配下にworkflowsというフォルダを作成し、その配下にファイルを作成(今回はbackend.yml)する
ファイル内容は割愛して、githubにpushしたあとGithubに移動してリポジトリからActionsタブを確認すると以下のようにymlファイルが追加されている!

確かに実行されている(今回はhello worldを出力する設定をした)

ここからGithub Actions上で自動テストとビルドの実行を行う
講義の中で配布されているコードを使用したので割愛するが、自動テスト・ビルドについては既に実行している以下のコマンド部分で行っているようだ
- run: npm run test
- run: npm run build
※また、Github Actionsのワークフローが失敗した時はメールで通知が来るので安心

CI完了!
・Github Actionsに関する概念を学ぶ
ワークフロー→/workflowsディレクトリ以下に格納されるymlファイル一つ一つの全体を表し、ymlファイルの内訳について、
- name:ワークフローの名前
- on:トリガの設定
- jobs:ワークフローが実行する単位で複数のこともある
- steps:ジョブを構成する単位でrun以下コマンドを実行することも出来れば、uses以下アクションを実行することも
アーティファクト→ビルドした結果できるファイル(成果物)のことや自動テストの結果をまとめたテストレポートのことでもある
以下、テストレポート(アーティファクト)を作成してみる
npm run test -- --coverage
しかし、vscodeで実行してもエラーが表示されるのでnpm install –save-dev jestを入力して自己解決した
以下エラー

そしてテストレポートの作成を確認

次にアーティファクトを保存する
その文法は公式ドキュメントからコピーして変形する
コードを作成したらGithubにpushする
※挙動がおかしかったら以下の該当部分を選択してログ確認してエラーを確認

そしてアーティファクトも確かに保存されている

続けて、テストコードが失敗した時デフォでは実行を中断しアーティファクトを作成しなくなるのでそういった状況でもアーティファクトを生成するようにif文によるステップの制御を行う
→テストコードの失敗というのは上記のようにsum.test.tsファイルの+を-に変えるなどで行う
以下のように記載すればジョブの実行に失敗してもアーティファクトを保存できる

実際に動かしてみると確かに途中で実行が止まらずアーティファクトを保存している


他にも、ソースコードをpushしたタイミング以外にも日時などの頻度で定期的にワークフローを実行したいときがあるがその時は定期実行の設定を行う
以下のようにLinuxのcronコマンドのようにワークフローの定期実行は指定できる

※バッチの設定をして、最新の実行結果が成功したかどうかを一目で分かるように設定するのは以下の方法

以下で表示されたURLをREADMEに張り付ければ以下のように確認できる

ここからはStepCIというWebAPI自動テストのツールを導入していく
以下をターミナルで入力してStepCIをインストール
npm install --save-dev stepci@2.6.3
npx stepci --version #インストールできたか確認
※nodejsのツールのインストールは近年の開発において不可避のステップ
以下でリクエストで1と2を入力したらレスポンスで3が返ってくるようなAPIのテストをするStepCIのコードを書くが
公式ドキュメントからコードをコピーして編集して作成する
テストコードを作成したら一旦サンプルコードでアプリを実行し、新しいターミナルを展開して作成したテストコードをnpx stepci run <サンプルコードファイル名>で実行

通った
stepciをGithub Actionsに組み込む方法として、ymlファイルのrun~が列挙されている中に以下のように追記

しかし上記だとアプリ実行前にtest:apiが実行されてしまうのでアプリの起動を待つコマンドを間に挟まなければならない
その方法はsleepしたり通信可能になるまで待つツール(今回はwait-on)を使用
※systemdにアプリを実行してもらうための設定についてやり方はsystemdの設定ファイルを作成・記入して配置すればよい
一例としてsudo vi /etc/systemd/system/backend.serviceとして編集,その後systemdにnodeコマンドを実行してもらう
→実際の用途としてはEC2にビルド成果物のindex.jsを転送しsystemdに実行してもらうなど
sudo systemctl daemon-reload
sudo systemctl start backend
jornalctl -u backend #上記でエラーが出たときログを確認する方法
sudo systemctl enable backend #EC2を再起動しても自動でバックエンドのアプリが起動するようになる
以下ではいよいよGithub Actionsを使ったEC2への自動デプロイを構築する
まず、バックエンドのmain関数をいくつか修正する。今回なら以下のように追記

その後build→npm run buildでindex.jsがビルドされているのでこのファイルを再度EC2にリモートでファイル転送

転送OK
その後バーにIPを入力すると…

ナイス!

EC2に違うOS選択してしまったから中々Activeにならなくて大変だったけどトラシューして解決
とりあえず上記のようにバージョンを更新するというデプロイを手作業で行ったので後はこの手順を自動化で実現するのみ
※手作業で実行したコマンドをコードに追記するときhistoryコマンドを使うと便利
今回私の場合でいえば以下のコマンドをymlファイルに追記

↑しかし上記のように鍵ファイルなどの機密情報は絶対にGithubに挙げてはならないのでシークレット機能を使う
GithubのSettingsからSecrets and VariablesのActionsを選択して

上記のように設定できる!
ただ、Github ActionsにSSH接続するためにまだ設定が必要
SSH接続する設定は入り組んでいるのでgithub marketplaceでSSH接続するコードを探す
そしてSSH接続するコードを追加したら例によってgithubにpush

deployが追加されている!
また、CI環境のジョブとCD環境のジョブは全く別の状況とされるので、SSH接続したいときはCI終了後アーティファクト(今回でいえばdist)をCD環境からDLする必要がある
ymlファイル内のupload-artifact部分をdeployブロックのsteps以下に張り付けuploadをdownloadに書き換えpathを書き換える
これでmain関数を編集してgithubからpushするだけで本番環境に変更が反映されるようになった!