SREチームのあおしょん(本名:青木)です。
突然ですが皆様は従量課金性のクラウドリソースの寝かしつけ、してますでしょうか?
もちろん上記の寝かしつけというのは比喩なので歯磨きをして、布団に誘導して、絵本を読んで、灯りを消してから始まり自身が寝落ちしないように耐え忍びながら行う…という様な子供に対することではなく利用していない時間帯のリソース停止のことです。
その日のコンディションや過ごし方にもよりますが、子供が寝ること自体は目を閉じて大人しくしてくれさえすれば(してくれさえすれば)割とすぐにぐっすりだったりします。
クラウドリソースなんてコマンド実行すれば何の抵抗もなく停止します。最高ですね…
ですが、本当に時間がかるのは寝かしつけ前の過程…段取り、ですよね。
今回の記事はクラウドコスト削減の一環で対応したmyTOKYOGASフロントエンドのクラウドリソース停止・起動の運用に至るまでの段取りについてです。
取り組みの背景
少し過去に遡るのですが下記の記事の通り、2023年11月6日(月)に弊社会員サイトmyTOKYOGASがリプレイスされました。
そしてmyTOKYOGASフロントエンドのインフラは当時ただ一人のSREメンバーで、現在SREチームのリーダーである杉山が一馬力で構築しました。
今まで利用経験がなかったAzureでインフラを構築!?しかも一人で!?と入社当時は大きな衝撃を受けましたが2024年7月現在ではSREチームも3人編成となり、引き続きmyTOKYOGASフロントエンドの運用改善に努めています。
そしてリプレイスから約半年が経ち、サービスの運用に関わるメンバーの頑張りにより安定稼働してきたところで、今までやり切れていなかったクラウドコストの最適化が弊SREチームの大きなミッションの一つとして本格的に始動しました。
クラウドコストの最適化についてはそれ自体がテーマの外部イベントが開催されるほど、どの企業でも重要なミッションだと思います。
そのため色々な事例が公開されていますが、まずはやれればすぐにコスト削減できる、本番環境以外のクラウドリソースの利用していない時間帯の停止を着手することにしました。
スケジュールの調整
クラウドリソースを停止すると対象環境のmyTOKYOGASが利用できなくなるので関係各所との調整から始めました。
調整前の整理として、停止するスケジュールは必要最小限のリソースだけ起動してなるべく不要なコストを発生させない、という考えのもと下記の単位に分類しました。
- 環境:開発環境、QA環境、ステージング環境など
- サービス:WEB、モバイル、管理機能など
- リソースの種類:Application Gateway, PostgreSQL
例えば「開発環境、WEB、Application Gateway」がスケジュールの単位です。
そうすることで環境利用者からの下記要望に柔軟に対応できるようにしようと考えました。
- 「この期間だけ○○環境のモバイルは夜間利用出来るようにして欲しい。」
- 「○○環境のWEBの画面のテストしたいので明日は夜間利用出来るようにして欲しい。△△のデータ参照はしないのでDBは起動しなくても良い。」
そして関係各所との調整です。正直、調整稼働が一番大きいだろうな…と思っていたのですが良い意味で裏切られました。
その要因が下記の二点でした。
- プロダクトオーナーのディレクション
- 各チームのメンバーが自分事として捉える
プロダクトオーナーのディレクション
フロントエンド開発チーム、バックエンド開発チーム、ビジネスチームなど各役割のチームとの調整が必要だったので全体周知はするものの各チームと細かい調整はしていこう…と考えていました。
ですがmyTOKYOGASチーム(以下、当チーム)のプロダクトオーナーがコスト削減の重要性を理解したうえで事前に各チームへ話を通してくれたため、各チームともにコスト削減という目的を理解しており、スケジュールはスムーズに決まりました。
右側のディレクションがあるのとないのでは調整する側のSREチームのメンバーも、調整を受ける各チームのメンバーも心持が違ってきます。 SREチームが各チームとスケジュールを調整する、ということ自体は変わらないのですが事前にプロダクトオーナーから各チームへ本取り組みの背景がインプットされているのでとても進めやすかったです。
定性的な内容ですが、同じようにクラウドリソース停止時間などで複数の他チームと調整している同士エンジニアには大分共感を頂けるのではと思います。
各チームのメンバーが自分事として捉える
当然ですがリソース停止をすると各チームが開発、テストなどでそのサービスを利用できない時間帯が発生します。夜間に利用したい場合は都度、私たちSREチームにスケジュール変更を依頼する必要が出てきます。(セルフサービス化は検討していきたいですが…)これは各チームにとって今までは無かった調整ごとです。
従って各チームからはネガティブな反応があるのではないか…というのが私の本音でした。
ですが、話を出したときの各チームからの反応はこぞって「コスト削減の対応、ありがとう!」でした。
この反応からアプリ側、インフラ側と分けずに自社のプロダクトに関することは全て自分事として捉える、という組織の文化が醸成されていることを実感しました。
スケジュールについてもこちらが提示した内容に可能な限り則ってもらいつつ、「この環境のこのサービスは○○の対応があるので停止時間は△時にした方が良いよ」という助言ももらい、しっかりと固めることが出来ました。
また、今回の対応範囲はフロントエンドのみだったのですが、こちらから要望を出していないにも関わらずバックエンドチームが調整したスケジュールに合わせてバックエンドのクラウドリソース停止に向けて動いてくれていました。これも自分事として捉える、という意識からの行動かと思います。とてもありがたかったです。
実装方式
ここに来てようやく少しテックな内容です。
今回のワークフロー自動化ツールはAzure Automation(以下、Automation)を採用しました。当チームでは主にGitHub Actionsをツールとして利用しているのですがあえてAutomationを採用しました。理由は下記となります。
- マネージドIDによる認証が出来る
- Azure PowerShellを利用するならPowerShell ワークフローで楽に実装できる
- 各チームからのスケジュール変更依頼に即座に対応するために、ポータルから変更出来た方が良い
参考としてApplication Gatewayの起動、停止用PowerShellワークフローを掲載します。サービス名やAzureリソース名は掲載のために変更しています。
param( [Parameter(Mandatory = $true)] [ValidateSet('mobile', 'web', 'management')] [string]$ServiceName, [Parameter(Mandatory = $true)] [ValidateSet('Start', 'Stop')] [string]$ActionMode ) Connect-AzAccount -Identity # 対象リソースのリソースグループをセットする $ServiceResourceGroupName = Get-AutomationVariable -Name "$ServiceName-ResourceGroupName" # Application Gatewayの状態を取得する $AppGWName = "$ServiceName-appgw $AppGW = Get-AzApplicationGateway -Name $AppGWName -ResourceGroupName $ServiceResourceGroupName $AppGWStatus = ($AppGw).OperationalState "Application Gateway $AppGWName Status: $AppGWStatus." # Application Gateway 起動、停止処理 If ($ActionMode -eq "Start") { "---- Start Application Gateway ----" If ($AppGWStatus -eq "Stopped") { Start-AzApplicationGateway -ApplicationGateway $AppGw $AppGW = Get-AzApplicationGateway -Name $AppGWName -ResourceGroupName $ServiceResourceGroupName $AppGWStatus = ($AppGw).OperationalState } } else { "---- Stop Application Gateway ----" If ($AppGWStatus -eq "Running") { Stop-AzApplicationGateway -ApplicationGateway $AppGw $AppGW = Get-AzApplicationGateway -Name $AppGWName -ResourceGroupName $ServiceResourceGroupName $AppGWStatus = ($AppGw).OperationalState } } "Application Gateway $AppGWName is $AppGWStatus." # Slackチャンネルへ実行結果を通知する "---- Post Slack Chennel ==> # azure-notifications ----" $WebhokURL = Get-AutomationVariable -Name "SlackWebhookURL" $Message = "$($EnvironmentAndLocation.Split("-")[0]) $ServiceName Application Gateway $ActionMode Action" New-SlackMessageAttachment ` -Color "good" ` -Title "Application Gateway Status" ` -Text "$AppGWName is $AppGWStatus." ` -Fallback "An error occurred." | New-SlackMessage -Text $Message | Send-SlackMessage -Uri $WebhokURL
なお、Slack関連のコマンドレットを利用するにはAutomationのモジュールに PSSlack
を追加します。
上記ワークフローを各環境のAutomationのRunbookに登録してスケジュールを設定しました。
また、各チームでも起動、停止が出来るようにAutomationに対して「Automation ジョブ オペレーター」ロールを割り当てました。これはAzureリソースの構成管理はTerraformで行っているので各チームに「閲覧者」ロールのみ割り当てているためです。
おわりに
こうして停止・起動の運用が開始して本記事の執筆時点では大きな問題も発生せずに、利用していない時間帯の停止によるクラウドコスト削減の実現に至ることが出来ています。
運用開始当初はいくつかの問題が発生し、解消に至ったのですが本筋からは外れるためいずれ筆(キーボード)が進みそうであればショート記事でご紹介します。
段取り、というテーマにしたものの結局はSREチームだけでは成しえず、プロダクトオーナーや各チームの協力がなければ運用開始まで至らなかったと思います。
繰り返しとなりますが、自社のプロダクトに関することは全て自分事として捉えるという信念をSREチーム含め各チームが持つ、というのが大事であることを改めて認識出来た段取りでした。
それでは最後まで読んで頂きありがとうございました。
当チームは積極的な採用を行っています!ご興味ある方はぜひ以下から応募ください!
アプリケーションエンジニアはこちらから! www.wantedly.com
SRE はこちらから! www.wantedly.com