AWSクラウドの開発ワークフロー概略
大きく以下の3ステップをAWSクラウドの開発においては意識する必要があります。
ローカル開発・テスト
自身のPCにエディタやコンテナなどの開発ツールをインストール。ソースコードを記述して開発を行うフェーズです。実装したソースコードはローカルでのテストもしくはクラウドへ直接デプロイしてテストを行います。
バージョン管理ツールへのPush・Pull Request
ソースコードは会社もしくはチームの資産として保存し、すべての変更やリリースなどの履歴を管理するためにGitHubやGitLabなどのバージョン管理ツールにホストします。ローカルでの開発が一区切りしたら定期的にバージョン管理ツールの作業ブランチに作業内容をPushします。そして担当の開発が完了すればPull Requestを作成して、レビューのプロセスに入ります。レビュー後はmain等の成果物が集約されるブランチにマージされることで、開発タスクとしては完了となります。
CI/CD
GitHub ActionsやCircleCIといったCI/CDの環境を提供してくれるサービスを使用してテストとデプロイのプロセスを自動化します。これらはGitHub等のプルリクエストのワークフローと組み合わせて設定することが多いです。CIを使ったテスト自動化によりソフトウェアのバグを開発サイクルの中で素早く検知し、品質を安定させます。また、CDを使ったデプロイの自動化により常に同じ手順でクラウドへのデプロイが行われることを保証し、毎回同じ状態のソフトウェアが本番へ調達されることを保証します。
ローカル開発
ローカル開発の方法としては以下のようなやり方が考えられますが、現状ではSAM Localを使用したやり方が一番オススメです。sam local start-api
コマンドで API Gateway をモックしたAPIエンドポイントを立ち上げてくれます。特にPython だと AWS Lambda Powertools と組み合わせて API ローカル開発はかなりしやすくなったのではないかと感じます
・SAM Local (AWS Toolkit とか含む)
・AWS Identity Center (SSO) で発行した一時クレデンシャルを環境変数に設定して実行スクリプト書いてそのまま実行
・serverless-offlineやwrangler等を使用してローカルサーバーを立てる
・LocalStackを使う
sam local start-api
コマンドを使うと以下のように各種エンドポイントがローカルで立ち上がります。
Mounting getByIdFunction at http://127.0.0.1:3000/{id} [GET] Mounting getAllItemsFunction at http://127.0.0.1:3000/ [GET] Mounting putItemFunction at http://127.0.0.1:3000/ [POST]
curlコマンドなどでリクエストを送ると以下のようにレスポンスを返してくれます。
$ curl "http://127.0.0.1:3000/121"
{"result":{"id":{"S":"121"},"name":{"S":"John"}}}
また、API Gateway以外のAmazon SQSやAmazon S3といった別のイベントソースの場合はsam local generate-event
コマンドを使うことでイベントのペイロードのサンプルを生成し、それをローカルでシュミレートしたLambdaファンクションに渡すことでローカル開発が可能となります。例えば、Amazon S3バケットにオブジェクトをPUTした時にトリガーされるAWS Lambdaのペイロードに渡るイベントは以下のように生成することが出来ます。
% sam local generate-event s3 put
{
“Records”: [
{
“eventVersion”: “2.0”,
“eventSource”: “aws:s3”,
“awsRegion”: “us-east-1”,
“eventTime”: “1970-01-01T00:00:00.000Z”,
“eventName”: “ObjectCreated:Put”,
“userIdentity”: {
“principalId”: “EXAMPLE”
},
“requestParameters”: {
“sourceIPAddress”: “127.0.0.1”
},
“responseElements”: {
“x-amz-request-id”: “EXAMPLE123456789",
“x-amz-id-2”: “EXAMPLE123/5678abcdefghijklambdaisawesome/mnopqrstuvwxyzABCDEFGH”
},
“s3”: {
“s3SchemaVersion”: “1.0”,
“configurationId”: “testConfigRule”,
“bucket”: {
“name”: “example-bucket”,
“ownerIdentity”: {
“principalId”: “EXAMPLE”
},
“arn”: “arn:aws:s3:::example-bucket”
},
“object”: {
“key”: “test/key”,
“size”: 1024,
“eTag”: “0123456789abcdef0123456789abcdef”,
“sequencer”: “0A1B2C3D4E5F678901”
}
}
}
]
}
例えばこれをsam local generate-event s3 put > s3.jsonのようなコマンドでファイルに書き込み、後からローカルでLambdaファンクションを実行する時にイベントのペイロードとして渡すことでローカルでの開発が可能となります。
$ sam local invoke --event s3.json HelloWorldFunction
No current session found, using default AWS::AccountId
Invoking app.lambda_handler (python3.9)
Local image is up-to-date
Using local image: public.ecr.aws/lambda/python:3.9-rapid-x86_64.
Mounting /Users/horiketakahiro/src/http/sam-app/hello_world as /var/task:ro,delegated, inside runtime container
START RequestId: e5f634b4-4689-4f53-984e-75c1eba64ff0 Version: $LATEST
END RequestId: bbe3a521-292f-41a2-ba48-62bfdfc4543a
REPORT RequestId: bbe3a521-292f-41a2-ba48-62bfdfc4543a Init Duration: 0.08 ms Duration: 62.63 ms Billed Duration: 63 ms Memory Size: 128 MB Max Memory Used: 128 MB
プルリクエストベースの開発を通したチームでのコラボレーション
チーム開発においてバージョン管理ツールを使用してPull Requestをベースに開発を行っていくことは最もポピュラーな手法のひとつです。ここではGitHubを使用しながらそのワークフローについて解説します。
1. issueを立てて実装内容をまとめる
実装前に要件や仕様などの実装内容をまとめて実装者に提示する必要があります。GitHubではissueの機能を使ってそれを行います。JiraやBacklogなどの他のプロジェクト管理ツールを使用している場合にはそれらを使用するのでも構いません。基本的にはプロジェクトのリーダ等のマネジメント担当者が以下のような内容をまとめます。
・実装内容
・実装の目的
・スケジュール
・担当者
また、不具合修正の際は以下のような内容をまとめることになります。
・バグの概要
・バグの再現手順
・期待する動作
これらはプロジェクトやその内容によって事前に決めておくよ良いでしょう。GitHubにはテンプレートの機能があり、事前に設定した項目をissueを立てた時に記述出来るようにすることが可能です。
2. ローカル開発
issueの内容に従って実装を進めます。必ず作業ブランチを作成して開発を行うようにします。PushしてPull Requestの作成 開発とその動作確認が完了すれば、PushしてPull Requestを作成します。主に以下のような内容を記述します。
・実装内容
・実施したテスト
・関連issue
・影響範囲
これもプロジェクトやその内容によって事前に決めておくよ良いでしょう。Pull Requestにも同様にテンプレートの機能が使えるので、Pull Request作成時に記述すべき項目を定義することが出来ます。
3. レビュワーによるコードレビュー
Pull Requestが作成できたらレビュワーにレビューを依頼をしましょう。レビュワーはその開発をリードしているようなメンバーが担当することが望ましいでしょう。コードレビューは人間による目視でのソースコードのチェックです。以下のような内容を確認します。
・仕様を満たす実装になっているか
・将来的に不具合が発生しそうなコードは無いか
・重複した処理など非効率なコードは無いか
そして以下のような目的と狙いで行います。
・属人性の排除による品質の安定化
・チームでのナレッジの共有
・品質を良くするための活発な議論の場として
副次的な効果として、開発者同士でのコミュニケーションを行いチームとしての信頼関係を築くと場としても活用できます。
4. Pull Requestのマージ
レビューでの指摘とその修正を何度か繰り返して、レビュワーが問題ないと判断したタイミングでマージを行い、一連の開発は完了します。
CI/CDパイプラインを定義してプルリクエストのワークフローに組み合わせる
上記のGitHubのワークフローにGitHub Actionsを使用したCI/CDの仕組みを組み合わせることでより効果的な開発体験を得ることが出来ます。例えば以下のような形です。
- Pull Requestが作成されたタイミングで自動テストを行う
Pull Requestが作成されたタイミングで必ず自動テストが走ることで、テストが通っていないものはそもそもレビューが行えません。毎回、レビューのたびにテストが落ちていることやコーディング規約が守られていないことを指摘するのはあまり効率的とは言えません。システムで防げる不備はシステムで防いで、人間の目視でしか出来ないレビューのみを行うことで効率のよいワークフローとなるでしょう。
- mainブランチにマージしたタイミングでステージング環境へ自動デプロイ
テストとレビューを通過した最新バージョンのコードのみがステージング環境にデプロイされるようにすることで常に最新の常態のアプリのテストや動作確認が可能になります。もし、手動でのステージング環境へのデプロイを許可してしまうとすると、誰かが間違ってレビューに通過してないコードをデプロイしてしまっている可能性もあります。こういった危険性はCI/CDパイプラインを整備する中で除去してしまいましょう。
このCi/CDパイプラインはあくまで一例です。最適なCI/CDパイプラインは各開発プロジェクトによって変わってくるでしょう。チームで開発を行いながらそのプロジェクトとチームに合ったやり方を調整していくことをお勧めします。