GAEの起動/停止をスケジューリングする

この記事は、カサレアルAdvent Calender 2022 の21日目のエントリです。

お疲れ様です。松村です。

GCPのプロジェクトを今年から担当したのですが、なかなか手探り状態でうまくいかないことも多かったです。
ということでGCPのプロジェクトで最初に困ったことを書こうと思います。

はじめに

昨今、AWSだったりGCPだったりクラウドサービスを利用するにあたって
費用とかやっぱり気になりますよね。時間当たりで課金されちゃったりするので
開発環境とか、深夜帯に動かす必要が全くありません。
なので夜間は止めたい。もちろん休日も!そして手動じゃなくて自動がいいよね!

GCP環境

GCPだと APサーバは普通にGCEを立てると思いますが
これはインスタンススケジュールというものが存在しているので簡単にサーバの上げ下げがスケジューリングできます。
ですが、GAEのようなものになってくるとマルチサーバなのでアクセスが来ると起動するので、そこの管理もGoogleさんが握っているのでうまくいきません。そこでどうするかー というお話になってきます。

GAEを止める方法は二つ考えられます

  • app.yamlを書き換える
  • GAEサービスごと止める

です。

今回はGAEサービスを止めます。なぜかというとapp.yamlを書き換えるのが怖かったからです
app.yamlもバージョン管理ツールなんかで管理されていたりすると思うので
GCPのサービスだけで完結する形を取ります。

  • できること
    自動でGAEのサービス開始および停止
  • できないこと
    マルチプロジェクトの場合にサービスごとに時間やスケジュールを設定する

参考にしたサイト

GCPでやりたいことを探そうとすると、なかなか見つからないんですよね。特に日本語。
AWSに比べてシェアの低さを実感できます。

そんななかとても役に立ったのが下記サイト。
GMOアドパートナーズさんのTECH BLOG
CloudSQLのインスタンスを自動停止/自動開始をスケジュールする方法
とても読みやすくわかりやすい記事でした。ありがとうございます。
また、GAEの止め方については
公式ドキュメントを参考にしました。

GAE停止フロー

停止するまでの処理はこんな感じです。

よくある流れですが、cloud functions でサービスを開始・停止する流れが書ければ
正直どのサービスでも止められると思います。

Cloud Functions

Cloud Functionsには下記を設定しています。
実行環境は python 3.7 です。

import base64
import json
import os
from googleapiclient import discovery
APP_NAME = os.getenv('GCP_PROJECT')

def google_app_emgine_status_change(data, context):

    appengine = discovery.build(
        'appengine',
        'v1',
        cache_discovery=False
    )
    apps = appengine.apps()

    # Get the target app's serving status
    target_app = apps.get(appsId=APP_NAME).execute()
    current_status = target_app['servingStatus']

    pubsub_data = base64.b64decode(data['data']).decode('utf-8')
    pubsub_json = json.loads(pubsub_data)
    status = pubsub_json['status']
    
    # Disable target app, if necessary
    if status == 'stop':
        if current_status == 'SERVING':
            body = {'servingStatus': 'USER_DISABLED'}
            apps.patch(appsId=APP_NAME, updateMask='serving_status', body=body).execute()
    elif status == 'start':
         if current_status == 'USER_DISABLED':
            body = {'servingStatus': 'SERVING'}
            apps.patch(appsId=APP_NAME, updateMask='serving_status', body=body).execute()
    else:
        print(f'Attempting to disable app {APP_NAME}...')

5行目のGCP_PROJECTが python3.7以降で使えなくなっているようなので
python3.7にしました。プロジェクト名を直接書き込んで良ければそれ以降のバージョンでも動くかもしれません(未検証)
ちなみに 
requirements.txtは

google-api-python-client==2.47.0

これだけ追加しています。公式のいうことは絶対。

また21、22行目で pub/subから ステータスを受け取っています。
なので停止のCloud Schedulerの[実行内容を構成する]メッセージ本文に、
起動の場合は {“status”:”start”}
停止の場合は {“status”:”stop”}

を設定するだけです。
実際の動作を確認するにはCloud Schedulerで実行したあと
App Engine のサービスへ行き、設定からアプリが有効になっているか無効になっているか確認できます。

おわりに

いかがでしたでしょうか?実際にプロジェクトや自分でサービス立ち上げたりする時には
実行環境の費用は重くのしかかってくると思います。ですが、もうその環境を構築するときには
停止スケジュールとかがないと毎日手動でやらざるを得ないので、こういった処理はすぐ必要なのかなと思います。
少しでも参考になれば幸いです。


--------------------------
システム開発のご要望・ご相談はこちらから

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です