grasys blog
Cloud Functionsを使ってCompute Engineを制御するという話
本記事はgrasys が提供する「grasys blog」に掲載された「Cloud Functionsを使ってCompute Engineを制御するという話」を再編集したものです。
こんにちはgrasysの福嶌です。 そろそろ競輪祭の時期ですね。それが終わればグランプリなので1年はあっという間だなと言う感じしかしません。
はじめに
grasysでは検証環境があります、ただ気軽に使えるのではなく金額を気にして使わないと怒られてしまいます。
そのためインスタンスタイプを低くして使うことが多いのですが今回は非力ゆえにスペックの低いGCEインスタンスで起きた事象(CPUが100%に貼り付いてインスタンスにsshすらできなくなる)の解決策(その場しのぎの対応)について書いていこうかと思います。
事象
検証で同僚[1]のインスタンスを間借りしようとしたらsshができなく確認したらCPUが100%に貼り付いている事象が発生していました。
プロセスを確認するとGCEの以下のディレクトリのログが出力されており以下のディレクトリに出力されてました。
/.config/gcloud/logs/
ドキュメントを見ると以下のような記載
ログファイルには、gcloud compute ツールを使用して送信されたすべてのリクエストとそのレスポンスに関する情報が含まれています。
https://cloud.google.com/compute/docs/troubleshooting/general-tips?hl=ja#viewlogs
結局インスタンスタイプが低すぎて当該のプロセスが原因でCPUが100%に貼り付いてしまいインスタンスのリセットを行なうと事象は解決しましたが定期的に発生し都度リセットを行なうと言う作業をしていました。
解決方法
今回のゴールとして以下を設定しました。 CPUが100%になり貼り付いたらそれをトリガーとしてCloud Functions経由でインスタンスの制御を行なう。
構成
今回は以下のような構成で作っていこうと思います。
Cloud Pub/Sub
アラートを飛ばす先のPub/Subの設定をします。アラート通知にPub/Subを設定は作ったPub/Subトピックにモニタリングに向けて権限設定を設定する必要があります。 ドキュメントを参考に以下のコマンドを実施
$ gcloud pubsub topics add-iam-policy-binding projects/{{プロジェクト名}}/topics/{{pub/subトピックID}} --role=roles/pubsub.publisher --member=serviceAccount:xxxxx@gcp-sa-monitoring-notification.iam.gserviceaccount.com
Cloud Monitoring
アラートは以下のように設定
対象インスタンス:自分の検証に利用しているインスタンス
Condition: is above
Threshold: 99.9
For: 5 minutes
99.9%以上の高負荷が5分続いた場合アラートを発砲するようにしました。
通知先は念のためメールとPub/Subにします。
Cloud Functions
制御するコードは以下のようなコードを作成しました。今回はgoogle-authとgoogle-api-python-clientを利用してAPIを叩きます。
#!/usr/bin/python
#coding:utf-8
import sys
import json
import base64
import google.auth
import googleapiclient.discovery
class Variables:
name = {{インスタンス名}}
zone = {{ゾーン名}}}
def reset_instances(compute, project, zone):
# 対象のVMをリセット
try:
compute.instances().reset(project=project, zone=zone, instance=Variables.name).execute()
except Exception as e:
print(e)
sys.exit(1)
return "success"
def alert2pubsubFunc(event, context):
if 'data' in event:
req = base64.b64decode(event['data']).decode('utf-8')
staus = json.loads(req)['incident']['state']
else:
sys.exit(2)
compute = googleapiclient.discovery.build('compute', 'v1')
project = google.auth.default()[1]
# Alert open
if staus == "open":
print(reset_instances(compute, project, Variables.zone))
また、Cloud FunctionsのランタイムはPython3.9を利用します。デプロイは以下のコマンドで実施
$ gcloud functions deploy alert2pubsubFunc --trigger-topic {{pub/subトピックID}} --runtime python39 --region asia-northeast1
デプロイエラーが出ると思ったら、Pyparsingが最新で3.0.6ためCloud Functionsでデプロイエラーを起こしてしまうようです。stackoverflowで探したら解決としてはバージョンを2.4.7に指定し解決しました。
テスト
そしたら早速テストをしてみましょう!
発報するためにアラートの閾値を低めに設定しアラートを飛ばしやすく調整を行ない。サーバー内で以下のコマンドを実行してCPU負荷を高くしてみます。
$ yes > /dev/null
アラートが12:50に発報され…
モニタリングの方で確認したらインスタンスがリセットされた!
うまく動いてますね!
まとめ
今回はアラートをpub/subに送ってCloud FunctionsのトリガーとしてCompute Engineを制御しました。
またCloud FunctionsをHTTPリクエストにしてアラートではなくCloud Schedulerなどを応用して使えば自動起動や自動停止なども簡単にできそうですね。こちらの記事とか参考になると思います。
上記ができれば無駄な稼働時時間をなくすことができるのでお財布に優しいはず!
現場からは以上です!