はじめに
私はAWSでの構築やPythonプログラムの改修・開発などを行う業務を担当しています。私の開発チームでは開発手法が古く、小規模なチームではあるものの、高品質でスピード感のある開発ができていないという問題がありました。
そこでGitとCI/CDを利用した開発手法を取り入れて、開発チームが高品質でスピード感のある開発ができるような案を考案してみました。チームへの導入はまだ途中ですが、導入背景・課題から構成や具体的な設計方針・運用ルールまでを記載している記事は少ないかと思いますので、同じような問題を抱えている方のお役に少しでも立てればと思い、記事を書きました。
GitやCI/CDを初めて耳にするような方にも理解してもらえるように用語の説明も記載しています。
GitとCI/CD導入の背景・課題
開発は高品質でスピード感あることが理想ですが、私のチームはそんな理想的な開発ができずに困っていました。
そこでデジタル庁のレポート(CI/CDパイプラインにおけるセキュリティの留意点に関する技術レポート)にて定義されている、開発における一般的な業務プロセスごとに現行手法と、その手法によって発生している課題を整理しました。
開発における一般的な業務プロセス
- ソースコードや設定ファイルに対する作業
- 品質保証に関わる作業
- 実行環境への配送および実行
以下のように整理した結果、チームの現行開発手法が全体的に古く、それが原因となってこれら課題が発生していることが分かりました。そして、これら課題が品質・スピードを低下させ、理想的な開発ができていないと推測しました。
業務プロセス | 現行手法 | 課題事例 |
ソースコードや 設定ファイルに対する作業 |
詳細設計書をエクセルで作成する | 実機と差分が発生 |
プログラムをバージョン管理せず、 共有フォルダに保管して管理する |
変更の追跡が困難 共同作業によりデグレ発生 |
|
品質保証に関わる作業 | 作業前後を見比べて、 作業箇所を発見し、レビューする |
作業箇所の見落とし レビューする側の稼働状況により、リリース遅延 |
動作確認テストまたは、机上検証をする | テスト、検証、稼働工数不足 | |
実行環境への配送および実行 | 手作業で構築する | 構築時の設定値誤り |
プログラムを実行環境へ手作業で配置する | 実行環境へのプログラム配置忘れ |
GitとCI/CD導入後の手法
現行手法にGit、CI/CDを取り入れて、先ほどの課題を改善し、高品質化、スピード向上を目指す場合、
下記の改善手法が最適と考えました。なお、AWS環境での開発を前提に検討しています。
業務プロセス | 現行手法 | 検討した改善手法 |
ソースコードや 設定ファイルに対する作業 |
詳細設計書をエクセルで作成する | 詳細設計書をCloudFormationで代替する |
プログラムをバージョン管理せず、 共有フォルダに保管して管理する |
プログラムをGitでバージョン管理する | |
品質保証に関わる作業 | 作業前後を見比べて、 作業箇所を発見し、レビューする |
作業箇所をGitで自動的に表示し、レビューする |
動作確認テストまたは、机上検証をする | 自動動作確認テストまたは、AIによる机上検証する | |
実行環境への配送および実行 | 手作業で構築する | CI/CDを利用して自動で構築する |
プログラムを実行環境へ手作業で配置する | プログラムを実行環境にGitで半自動に配置する |
補足:Gitとは
Gitはファイルの変更履歴を記録・管理するアプリケーションです。
Git周りの用語も説明すると、Gitでは作業者はファイルやディレクトリに対する編集結果を自身の作業端末上の「ローカルリポジトリ」という保管場所に記録します。これを「コミット」と呼びます。
複数人で作業をする場合は、ローカルリポジトリにおける差分を関係者と同期するために、差分をソースコード管理システム上の「リモートリポジトリ(リポジトリ)」に送信します。これを「プッシュ」と呼びます。
他作業者への影響を最小限とするために、一般的に「ブランチ」を作成します。
元のブランチの内容に影響を与えることなく安全に変更を加え、そして変更が完了したら、メインの内容に統合します。これを「マージ」と呼びます。マージの承認依頼を「プルリクエスト」と呼びます。
補足:CI/CDとは
CI(Continuous Integration)は継続的インテグレーションと呼ばれ、ソースコードから環境で実行できる成果物を生成(ビルド)し、動作確認テストをすることを意味します。
CD(Continuous Delivery)は継続的デリバリーと呼ばれ、成果物(ソースコード)を実行環境に自動的に配送することを意味します。
CI/CDパイプラインについて
デジタル庁レポートを参考に、CI/CDパイプラインを用いた実行環境への配備までの各フェーズを説明します。
CI/CDパイプラインにおけるセキュリティの留意点に関する技術レポート
ローカル作業フェーズ
先ほどの表における、業務プロセスの「ソースコードや設定ファイルに対する作業」に相当します。
主に作業者がソースコードや設定ファイルに対する作業と検証を行うフェーズとなります。
作業者は手元の端末や統合開発環境(IDE)で作業をし、その内容をGitでソースコード管理システムに送ります。
ビルドフェーズ
先ほどの表における、業務プロセスの「品質保証に関わる作業」に相当します。
最新のソースコードや設定ファイルを元とした成果物の生成、検証・テスト、保管を行うフェーズです。
CI/CD パイプラインの内、CIがこれに当たります。
デリバリフェーズ
先ほどの表における、業務プロセスの「実行環境への配送および実行」に相当します。
成果物の実行環境への配送と実行を行うフェーズです。CI/CD パイプラインの内、CDがこれに当たります。
GitとCI/CD導入後の構成
今回、改善を行うシステムはAWSを利用しており、開発環境と本番環境の2面構成です。また、業務用プログラムの実行環境として社内に2台のPCを設置しています。
体制は開発チームと運用チームの2チーム体制で、運用チームは監視結果のレポートの発行やお客様の新規追加・解約に合わせて、AWSの構成変更を行います。
こういった環境や体制にGitとCI/CDを導入すると、以下構成になると考えています。
次に、先ほどのデジタル庁レポートで用いられていた3つのフェーズに当てはめて、検証開始から本番環境や実行環境への配備までの作業の流れを説明します。なお、各フェーズを行ったり来たりしますのでご注意ください。
開発環境での作業の流れ
開発環境では、検証や検証完了リソースを本番環境にデプロイする前の動作確認が目的です。
ローカル作業フェーズ
- 開発者は機能開発や改修を契機に開発ブランチから機能検証ブランチを新たに作成して検証を開始します。
- 開発者は検証における作業結果を機能検証ブランチにプッシュします。
- 検証終了後、開発者は機能検証ブランチから開発ブランチへのプルリクエストを送信し、CodeGuruの指摘コメントを反映し、承認者へレビューを依頼します。
- 承認者はプルリクエストをレビューし、問題が無ければ承認の上、機能検証ブランチを開発ブランチへマージします。
ビルドフェーズ
- 開発者からのプルリクエストをトリガにコードチェック用のパイプラインが起動し、CodeGuruが作業結果をレビューし、指摘をプルリクエストのコメントに記載します。
- (AWSデプロイを伴う時)マージをトリガにデプロイ用パイプラインがCloudFormation(CFn)テンプレートをCFnへ取り込める形式に変換して、S3に保管します。
デリバリフェーズ
- (AWSデプロイを伴う時)デプロイ用パイプラインが変換されたCFnテンプレートをCFnに取り込み、CFnがリソースを構築し、動作確認可能な状態とします。
- (実行環境PC上のスクリプト更新を伴う時)開発者が実行環境PC上の開発ブランチでプルを実行。開発ブランチのスクリプトが実行環境PCに配置され、動作確認可能な状態とします。
本番環境での作業の流れ
本番環境では、本番稼働リソースを本番環境へ配備すること、実行環境へプログラムを配備することが目的です。
ローカル作業フェーズ
- 開発環境での動作確認終了後、開発者は開発ブランチから本番ブランチへのプルリクエストを送信し、CodeGuruの指摘コメントを反映し、承認者へレビューを依頼します。
- 承認者はプルリクエストをレビューし、問題が無ければ承認の上、開発ブランチを本番ブランチへマージします。
- (顧客追加・解約時)運用者が開発ブランチにて顧客情報を記載したCFnテンプレートを配置します。
- 運用者は開発ブランチから本番ブランチへのプルリクエストを送信し、CodeGuruの指摘コメントを反映し、承認者へレビューを依頼します。
- (顧客追加・解約時)承認者はプルリクエストをレビューし、問題が無ければ承認の上、開発ブランチを本番ブランチへマージします。
ビルドフェーズ
- プルリクエストをトリガにコードチェック用パイプラインが起動し、CodeGuruが作業結果をレビューし、指摘をプルリクエストのコメントに記載します。
- (AWSデプロイを伴う時)マージをトリガにデプロイ用パイプラインがCFnテンプレートをCFnへ取り込める形式に変換して、S3に保管します。
デリバリフェーズ
- (AWSデプロイを伴う時)デプロイ用パイプラインが変換されたCFnテンプレートをCFnに取り込み、CFnがリソースを構築し、リリースされます。
- (実行環境PC上のスクリプト更新を伴う時)開発者が実行環境PC上の本番ブランチでプルを実行。本番ブランチのスクリプトがPCに配置され、本番利用可能な状態となります。
改善手法を実現するための設計方針・運用ルール
改善手法を実現するための設計方針や運用ルールを記載します。これら設計方針や運用ルールはデジタル庁のレポート(CI/CDパイプラインにおけるセキュリティの留意点に関する技術レポート)を参考にしました。
CloudFormation、Gitについては導入済みで、実績のある設計方針や運用ルールもありますが、それ以外の技術は机上検証はしていますが、実績はありません。以下は参考程度に利用いただき、利用する際は十分に検証してから利用いただくことをお勧めいたします。
CloudFormationにおける運用ルール
テンプレート作成に関するルール
- CloudFormationには機密情報を載せず、最悪ソースコードが流失しても問題ない状態とすること。
- 機密情報、個人情報を利用する場合はParameterStoreへ保管し、そこから取得すること。
- 取得した機密情報、個人情報は後続フェーズへ引き継がないこと。
- テンプレートが詳細設計書としても機能するように、各設定値の真上にコメントでその設定値とした理由を記載すること。
- ただし、JSONの場合は仕様によりコメントを記載できないためコメントは不要とする。
- テンプレートは原則YAML とするが、プログラムで処理がしやすい場合はJSONを利用しても良い。
- 本番、開発環境で一貫して同じテンプレートを利用するため、アカウントIDや自リージョンなどは組み込み関数の変数(例えば、自リージョンは!Ref “AWS::Region”)を利用すること。
- 効率性、安全性を高めるため、原則、ネストテンプレート構成とする。
- リソースの参照はリポジトリ内のリソースパスを参照パスとして利用すること。
CloudFormationへ取り込む前のルール
- テンプレートのアップロード前に”aws cloudformation validate-template”コマンドを使用して、テンプレートの構文に誤りが無いことを事前に検証すること
- リソースによっては設定変更時に一度削除して、構築される場合があるため、テンプレートのアップロード前に変更セットを作成し、意図しない作成、削除が発生しないことを確認してから、アップロードすること。
- 「aws cloudformation create-change-set」コマンドを使用して、変更セットを作成します。
- 変更セットを作成したら、「aws cloudformation describe-change-set」コマンドを使用してその内容を確認できます。
その他
- AWSでの構築は原則、CloudFormationによる構築とし、マネジメントコンソールでの構築は禁止とする。
- 定期的にリソースを自動作成したい場合、定期実行EventBridgeでテンプレートを修正・追記する方針とする。
- EventBridgeで直接リソースを作成し、コードで管理していないリソースを作り出さないため。
Gitにおける運用ルール
作業環境
開発ツール
- 開発者はVSCodeを統合開発環境とし、GitLens(無料版)という拡張機能を導入すること。
- 生成AIを利用し、CFnテンプレートやソースコードのたたき台を作成する時に活用すること。
- 認証情報を一度入力したら以降は毎回入力する必要が無いように、GitCredentialManagerを利用する。
開発ルール
- 誰が更新したのかが分かるようにGitコマンドにおけるUsernameは姓名(アルファベット)で設定し、Emailは会社アドレスを設定する。
- Gitの作業履歴はコミットとして残す方針とし、Gitコマンドの強制プッシュを原則禁止とする。
- 生成AIは社内ガイドラインに沿って利用すること。必要に応じて情報をマスクして利用すること。
- 作業者毎にリポジトリアクセス用IAMユーザを発行し、開発者はフルアクセス権限、それ以外(実行環境PCや運用チーム)には読み取り権限を付与する。
- フルアクセス権限はAWSCodeCommitPowerUserポリシーのみを、読み取り権限はAWSCodeCommitReadOnlyポリシーのみを付与する。
- リポジトリアクセス用ユーザには利便性向上のため、Gitコマンド実行時のMFAを強制しない。
- 開発、本番ブランチの削除、直接のプッシュができない権限をリポジトリアクセス用ユーザ、マネコンユーザに付与する。
- ただし、顧客追加/解約時に利用するため、運用チームはマネコンユーザで開発ブランチへファイルを配置できるようにする。
- 運用チームは原則、実行環境PC上のCFnテンプレートやプログラムの更新を行わないこと。ただし、ブランチにアップロードしていない実行環境PC固有のファイルであれば更新可能
- 実行環境PCではグローバルな.gitignoreファイルを作成すること。(git config –global core.excludesfile ~/.gitignore_global)
- 情報漏えいを防ぐため、個人所有のGit系SaaSの認証情報を作業者端末に設定しない。
ブランチ構成について
- CFnテンプレートを可能な限り検証から本番まで一貫して利用すること。バグの早期発見が目的。
- 開発、本番環境用にブランチを作成する。開発、本番ブランチは削除せずに永続的に残す。
- 開発環境での検証用に機能検証ブランチを複数作成・削除して良い。機能検証ブランチは機能開発やバグ改修のたびに開発ブランチから分岐して、機能検証ブランチを作成すること。
- 緊急改修が必要な時でも機能検証→開発→本番ブランチという順番で迅速に改修できるため、緊急改修ブランチは作成しない。
- 顧客追加/解約時、運用チームはマネコン経由で開発ブランチにCFnテンプレートをアップロードし、本番ブランチへのプルリクエストによって新規顧客に必要なリソースを構築/削除すること。
- 各ブランチの分岐元ブランチ、ブランチへのプッシュ可否、ブランチへマージできるブランチ、ブランチ削除可否は以下表を参照すること。
ブランチ名 | 概要 | 分岐元ブランチ | ブランチへのプッシュ可否 | このブランチへマージできるブランチ | ブランチの削除可否 |
本番ブランチ | 本番環境で稼働するリソースやソースコードが格納されるブランチ | 無 | 不可 | 開発ブランチ | 不可 |
開発ブランチ | 開発環境で稼働するリソースやソースコードが格納されるブランチ | 本番(初回だけ) | 開発チーム:不可 運用チーム:可 |
機能検証 ブランチ |
不可 |
機能検証 ブランチ |
機能開発や改修を頻繁に行うブランチ | 開発 | 可 | 無し | 可 |
- 各ブランチの分岐、マージのイメージを以下に図示する。
プッシュ、プル、プルリクエストについて
- プッシュ時、レビューする人が修正内容を判断しやすくするために、担当した修正タスク名、要件、設計方針のいずれかをプッシュ時のコミットにコメントすること。プッシュが大量に実施される場合は任意のコメントで良い。
- デバッグにより同じ修正タスクに対して、複数回プッシュする必要がある場合、修正タスク名と回数をコメントに記載するなど適当なコメントでも良い。
- 強制プッシュ(例えば、”git push origin main –force”,”git push origin main -f”)を禁止とする。ただし、リモートリポジトリへの影響がないローカル環境での強制力のある操作は許可する。
- 特にVSCodeのエラーウィンドウが出現した際は、強制力のある操作がされることがあるため、forceやf、上書きといった言葉が使われているエラーメッセージの場合は翻訳して意味を理解したうえでOKボタンを押す。
- プッシュしたコミットを取り消す場合、”git revert”を利用し、コミットの取り消しを行う。コミットを取り消した状態のコミットでプッシュしてリモートリポジトリに反映すること。(取り消し履歴を残すことが目的)
- プルリクエスト時、レビューする人が修正内容を判断しやすくするために、プルリクエストのタイトル欄に担当した修正タスク名、説明欄に要件、設計方針、修正したことのいずれかを記載すること。
- コミットしていない変更がある状態でブランチ移動などをしたい場合、”stash”を利用して変更を一時保存する。(コミットしていない変更が存在する場合はブランチ移動などの一部操作が不可のため)
- プッシュ、プルリクエストでコンフリクトが発生した場合、コンフリクト行を影響が無いように修正したうえで再度プッシュ、プルリクエストを送信すること。
- 影響が発生する場合は、必要に応じてGitLensで該当行のコミッターを特定し、そのコミッターと相談してコンフリクトを解消すること。
フォルダ構成について
- 顧客新規追加/解約時はマネコン経由で開発ブランチにCFnテンプレートをアップロードし、本番用ブランチにプルリクする。
- リポジトリルートに.gitignoreファイルを配置して、.conf、.log、.xls、.jsonなどログや認証情報は除外する
レビューについて
レビューイ(レビューしてもらう側)
- 分岐したブランチから本番または、開発用のブランチにプルリクエストをする。
- Amazon CodeGuruがプルリクエストの更新分に対して自動的にレビューし、指摘をコメントする。
- CodeGuruからの指摘コメントがある場合は指摘反映後、そのプルリクエストを閉じて、再度プルリクエストする。指摘コメントがなくなるまで繰り返す。
- CodeGuruからの指摘コメントが無い場合、レビュアーにプルリクエストのレビューを依頼する。
- CodeGuruのレビューコメントが間違っている、意図的にベストプラクティスに沿わないコードとする場合はコメントに対してその理由をコメントし、その指摘を無視する。
レビュアー(レビューする側)
- プルリクエストのマージ先ブランチが正しいことを確認する。
- 意図しないリソースの置き換えが発生していないかを確認する。
- 過去にCodeGuruから指摘があったどうかを確認し、CodeGuruからの指摘を反映できているか確認する。
- ファイル内の特定行に対して指摘があれば、その行にコメントをする。
- ファイルに全体的な指摘があれば、ファイルに対してコメントをする。
- レビュー合格であれば、プルリクエストを承認して、マージする。
- マージ時はソースブランチを削除する。
CI/CDにおける設計方針、運用ルール
CodePipeline
ステージ共通
- パイプラインの構成もCFnテンプレートで管理する。パイプライン用CFnテンプレートをCFnへ手動で取り込んで構築する。
- パイプラインやCloudFormationが利用するIAMロールには基本的にAWS管理ポリシーを付与せず、必要最低限のポリシーを付与すること。
- 開発環境にコードチェック用、AWSデプロイ用のパイプラインを構築し、本番環境にはAWSデプロイ用のパイプラインを構築する。
- 検証ではパイプラインを利用しないため、コードチェック用のパイプラインで実行されるコマンドをローカル環境で実行しておくこと。
ソースステージ
- ソースリポジトリはCodeCommitを指定すること。
- ブランチは本番環境では本番ブランチを、開発環境では開発ブランチまたは、機能検証ブランチを紐づける。機能検証ブランチは複数作成されるため、機能検証ブランチごとにパイプラインを作成すること。
- 検出はEventBridgeを利用してソースの変更を検知する。ソース変更のポーリングは開発、検証環境は自動ポーリングを有効としても良いが、本番は手動ポーリングとする。
ビルドステージ
- ビルド端末内ではソースステージからのアーティファクトを解凍し、ビルドステージの端末内で展開する。
- パッケージ化を行うアクショングループでは、リソースへの参照パスはそのままではCloudFormationへ取り込めないことからS3 URLパスに変更するために親テンプレートをビルド端末内で「aws cloudformation package」コマンドでパッケージ化する。
- 保存先バケットのオブジェクト名にはコミットIDを含める。
- 既に構築されているリソースへの更新、削除はスタックを設定し、ドリフト検出する。
- ビルド端末内で変更セットを作成させ、置き換え、削除、更新が発生する場合、ビルド端末からプルリクエストにコメントを追記すること。コメント追記後に変更セットを削除する。
- ビルド時のログは全てCloudWatchLogsへ保管すること。
コードチェック用パイプライン向け
- CodeGuru Securityへパッケージテンプレートを送信する。
AWSデプロイ用パイプライン向け
- ビルド端末内でパッケージ化したテンプレートをアーティファクトとしてデプロイステージへ引き渡す。
- デプロイステージでアーティファクトの改ざん検証に利用するため、テンプレートのハッシュ値を取得し、パイプラインの変数にハッシュ値を格納する。
デプロイステージ(AWSデプロイ用パイプライン向け)
- アーティファクトが改ざんされていないか検証するため、S3から取得したテンプレートのハッシュ値とパイプラインの変数に格納したハッシュ値を比較し、検証する。
- デプロイステージであるが、CodeBuildを利用して上記を実現する。
- ビルドステージから引き渡されたアーティファクトに対して、パッケージ化されたファイルをデプロイするように設定する。
S3
- バケットはAWS管理のキーで暗号化し、公開設定としないこと。
- バケットはバージョニングを有効化すること。
- バケットポリシーで同環境のコードパイプラインとAdministratorのIAMユーザ以外のアクセスを拒否する。
ParameterStore
- 機密情報、個人情報は全てパラメータストアに保管すること。
IAM、EventBridge
- 以下クロスアカウントアクセス用のIAMロールを開発環境に作成する
- 本番環境のIAMロールが本ロールを引き受けられる(AssumeRoleされる)こと
- 本番環境のCodePipelineが開発環境のCodeCommitにアクセスできること
- CodeCommit上のソースコードを本番におけるCodePipelineのアーティファクトバケットに格納できること
- 以下クロスアカウントアクセス用のIAMロールを本番環境に作成する
- 上記開発環境のIAMロールを引き受ける(AssumeRoleする)こと
- CodeCommitの変更イベントを本番環境に通知するEventbridgeを開発環境に作成し、通知をトリガーにパイプラインを起動するEventbridgeを本番環境に作成する
※IAM、EventBridgeは以下記事を参考にさせていただきました。
https://qiita.com/ozzy3/items/079f82b6123ec57f3c91