利用料金の節約のため、GCP上にある開発環境のサーバーを夜間だけスケールダウンしたいと考えたことはありませんか?
Cloud Schedulerというフルマネージドなcronサービスを利用して、定期的にGCP上のリソースの設定を変更する方法をご紹介します。
GKE(Google Kubernetes Engine)のスケールインを例として紹介しますが、APIが公開されているGCPのリソースであれば同様の方法で設定を変更することが可能です。
Cloud Schedulerについて
具体的な仕組み作りの前にCloud Schedulerについて簡単に説明します。
Cloud Schedulerは安価で簡単に利用することの出来るcronサービスですが、実行可能なタスクは限られています。
できること
- cron形式のタスクのスケジュール
- 実行出来るタスクの種類
- Google Pub/Sub のトピックへのメッセージ送信
- App Engine Http の呼び出し
- 任意のhttp(s)エンドポイントの呼び出し (今回はこれを使用します)
できないこと
- 任意のShell scriptやプログラムなどを直接実行する
- サービスアカウントを使っての認可[1]
-
delete, get, head, post, put 以外のMethodを使用したAPI呼び出し[2]
[1] Google Cloud Next '19でCloud Schedulerに認証を加える発表があったようですが、2019年4月現在はまだ利用できないようです。
この Cloud Scheduler と Cloud Tasks の HTTP Auth はまだ使えない機能に言及しているということで良いのかな(後者は HTTP Push 自体がまだパブリックじゃない)https://t.co/UJUuCiGHeM
— _ (@apstndb) 2019年4月11日
[2] GAになってからはPATCH, OPTIONSも許可されたようです。
https://cloud.google.com/scheduler/docs/reference/rest/v1/projects.locations.jobs#Job
利用するサービス
前述の通りCloud Schedulerだけでは直接GCP上のリソースの設定を変更することは出来ないため以下のサービスを組み合わせて実現します。
Cloud Scheduler Cloud Functionの関数を定期的に呼び出すためのスケジューラー
Cloud Functions GCP上の各種リソースを設定変のAPIを実行する関数
Service Account Cloud Functionsから設定変更を行うための権限付与
Service Accountの作成
IAMと管理から、新たにサービスアカウントを作成して、Cloud Functionsが変更したいリソースに対する編集権限を付与します。
今回はfunction-serviceaccountというアカウントを作成し、GKEのノードプールのサイズを変更するため"Kubernetes Engine Cluster 管理者" の権限を付与します。
Cloud Functionsの作成
Cloud Functionで実際にGCP上のリソースの設定変更を行う関数を作成します。
関数の作成を行うと以下の画像のようにサンプルコードが用意されるので、これを元に関数を作成します。
今回はPythonを使用しますが、GoやNode.jsなどを使用することができます。
表示されているURLはCloud Schedulerが呼び出すエンドポイントとして使用するため控えておきます。
サンプルコードを編集しGKEのノードプールのサイズを変更する関数を作成します。
GCPのAPIのドキュメントには、HTTPでの直接APIを呼び出す方法のほか、各言語からの呼び出し方法のサンプルも記載されているため、これを参考にrequirements.txtとmain.pyの内容を書き換えます。
GKEのAPIドキュメント:
https://cloud.google.com/kubernetes-engine/docs/reference/rest/v1/projects.locations.clusters.nodePools/setSize?hl=ja
foo-projectのasia-northeast1-aにあるbar-clusterのbaz-poolのノードプールのサイズを1に変更する関数のサンプルコードは以下の通りです。
# Function dependencies, for example:
# package>=version
oauth2client
google-api-python-client
from googleapiclient import discovery
from oauth2client.client import GoogleCredentials
import logging
logging.getLogger().setLevel(logging.INFO)
def main(request):
request_json = request.get_json()
if request_json and 'password' in request_json:
if request_json['password'] == 'dolphin':
credentials = GoogleCredentials.get_application_default()
service = discovery.build('container', 'v1', credentials=credentials)
name = 'projects/foo-project/locations/asia-northeast1-a/clusters/bar-cluster/nodePools/baz-pool'
set_node_pool_size_request_body = {
"nodeCount": 1
}
request = service.projects().locations().clusters().nodePools().setSize(name=name, body=set_node_pool_size_request_body)
response = request.execute()
logging.info(str(response))
return str(response)
logging.info("not accept")
return 'not accept'
コードの入力した後は、詳細オプションから先ほど作成したサービスアカウント設定します。
その後、作成ボタンを押すと関数が作成されます。
Cloud Schedulerの作成
Cloud Schedulerで定期的にCloud Functionsを呼び出すスケジュールを作成します。
Cloud ConsoleにはCloud Schedulerを作成するページもありますが、詳細な設定を行うことができず、
API呼び出しの際のContent-Typeを指定する場合はgcloudコマンドを使用する必要があります。
ローカルPCにgcloudコマンドをインストールしてもよいのですが、今回はCloud Shellを使用します。
Cloud ShellはCloud Consoleのヘッダーから起動できます。
Cloud Shellでコマンドを実行して、スケジュールを作成します。
以下は毎日2時に関数を実行するスケジュールの例です。uri部分にはCloud FunctionのURLを設定します。
$ gcloud beta scheduler jobs create http gke-scalein --schedule="0 2 * * *" --uri="https://****.cloudfunctions.net/function-1" --headers Content-Type=application/json --time-zone=Asia/Tokyo --message-body='{"password":"dolphin"}'
Cloud Schedulerの一覧に作成したスケジュールが表示されるので、"今すぐ実行"のボタンを押して動作を確認できます。