GCPのCompute Engine (GCE) は時間単位で仮想マシンを利用できるサービスです。AWSでいうところのEC2に該当するものです。料金は時間単位で課金されるため、必要でないときはできるだけ停止しておく方が安上がりです。そのため、自動で起動したり停止したりする設定を施したくなります。
GCEインスタンスの起動・停止をコントロールできるサービスはいくつかあります。たとえば Cloud SchedulerやApp Engineなどのサービスと連携させる方法がよく使われます。
ですが、単純な起動・停止のルールであれば、GCEの機能(+IAMによる権限設定)だけで設定することが可能です。その手順を紹介します。
参考:
手順
準備
- GCEインスタンスを実行するサービスアカウントの作成
- GCEインスタンスの作成
- GCEインスタンスの起動・停止を行うロールの作成
ケース1:スケジューラーによる起動と停止
- 実験用のスクリプトの作成
- GCEのインスタンススケジューラーの作成
- インスタンスを起動・停止する権限をインスタンススケジューラーを実行するサービスアカウントに付与
- 実験結果
ケース2:インスタンス内からの停止
- インスタンスの起動・停止権限をインスタンスを実行するサービスアカウントに付与
- 実験
準備
GCEインスタンスを実行するサービスアカウントの作成
コンソール上でGCPにログインし、 IAM & Admin > Service Account から、サービスアカウントの管理ページを開きます。
そこで、ページの上の方にある「+ CREATE SERVICE ACCOUNT」をクリックします。
- Service account nameに任意の名前を付けます(ここでは
gce-worker
としました)。 - 現時点では特に権限を付与せずに「DONE」をクリックして完了します。
GCEインスタンスの作成
Compute Engine から、VMの管理ページを開きます。
ページの上の方にある「+ CREATE INSTANCE」をクリックします。
- "Name"には任意の名前を付けます(ここでは
my-test-vm
)。 - "Region"もどこでも良いと思いますが、
us-central1
にしました(実験であればE2-microが月に1インスタンスなら無料のところがお薦めです)。 - "Machine type"は最小の
e2-micro
で良いと思います。 - "Boot disk" (OS) も任意ですが、使い慣れたUbuntuを選択肢ました。
- 最後に、"Service account"には、上で作成したサービスアカウントを指定します。
- 「Create」をクリックして完了します。
GCEインスタンスの起動・停止を行うロールの作成
IAM & Admin > Rolesから、ロールの管理ページを開きます。
GCPにおけるロールは、権限(Permission)の集合のようなものです。デフォルトで数多くのロールが定義されていますが、ぴったり合うものがない場合には自分でカスタムロールを定義して使います。
上の方の「+ CREATE ROLE」をクリックします。
- "Title"には任意の名称を指定します(ここでは
gce-start-stop-role
)。 - "ID"には任意の名前を指定します(ここでは
gceStartStopRole
)。 - "Role launch stage"は、情報提供が目的のフィールドなので、チーム開発での運用ルールなどがない限り
Alpha
のままで良いと思います。 - 「+ ADD PERMISSIONS」をクリックします。
-
compute.instances.start
,compute.instances.stop
を選択します。フィルタをうまく使うと見つけやすいです。 - 「ADD」をクリックします。
- もとのページに戻ったら、「CREATE」をクリックしてロールを作成します。
ケース1:スケジューラーによる起動と停止
実験用のスクリプトの作成
GCEインスタンスが停止している場合は起動(コンソール上でリストな中から選択し、再生ボタンをクリック)します。
起動後、インスタンスにログインします。おすすめのログイン方法は次のコマンドです。Terminal、コマンドプロンプト、またはCloud Shellなどで実行してください(gcloud
コマンドがインストールされていなければ適宜インストールします)。
gcloud beta compute ssh --zone "us-central1-a" --project "{project_id}" "ubuntu@my-test-vm"
-
--zone
,--project
オプションは適宜変更してください。 - ユーザー名は
ubuntu
を選んでいます。他のOSの場合は適宜変更してください。また、指定しないと新しいユーザーが作られるようです。 -
my-test-vm
の部分はインスタンス名です。適宜変更してください。 -
gcloud
を使わずに普通のSSHコマンドでログインすることも可能です。インスタンスの詳細ページで必要な情報を確認できます。
下記のシェルスクリプトを作成します。これはファイルに現在の日時を書き込むだけのスクリプトです。
#!/bin/bash
# This script adds a line to a test file.
echo "$(date +%Y-%m-%d_%H:%M:%S)" >> ~/testfile.txt
スクリプトを実行可能にしておきます。
chmod 700 ~/add-line.sh
Crontabを開き、スクリプトを毎分実行するよう設定します。
crontab -e
# 下記を追記
* * * * * /home/ubuntu/add-line.sh
# every minute, add a new line
設定後、5分ほど待って、testfile.txt
に日時がいくつか追加されていれば成功です。
cat ~/testfile.txt
#2021-08-16_15:45:01
#2021-08-16_15:46:01
#2021-08-16_15:47:01
#...
忘れずに、GCEインスタンスを停止します。
GCEのインスタンススケジューラーの作成
Compute Engineの「INSTANCE SCHEDULE」タブを開きます。
上の方にある「+ CREATE SCHEDULE」クリックします。
- "Name"は任意です(ここでは
gce-start-stop-scheduler
) - "Region"はインスタンスと同じにします
- 上の方の「Use CRON expression」をオンにすると、スケジュールを柔軟に設定できます。
- ここでは、毎日、日本時間の午前1時に起動、午前1時半に停止することにしています。
インスタンスを起動・停止する権限をインスタンススケジューラーを実行するサービスアカウントに付与
Compute Engineの「INSTANCE SCHEDULE」タブを開き、上で作成したスケージューラーインスタンス(gce-start-stop-scheduler
)をクリックし、詳細ページを開きます。
- 「ADD INSTANCES TO SCHEDULE」をクリックし、上で作成したVMインスタンス(
my-test-vm
)を選びます。 - このとき、通常はエラーメッセージが出ます。
service-{projectid}@compute.system.iam.gserviceaccount.com
に必要な権限がない、という意味です。どうやら、このサービスアカウントがVMの起動・停止を行う主体のようです。 - そこで、このサービスアカウントに権限を付与します。
Compute Engineの「INSTANCES」タブを開き、上で作成したVMインスタンス(my-test-vm
)を選択します。
- ページ右の方の「PERMISSIONS」タブを開き、「ADD MEMBER」をクリックします。
- New members のところへ、上で権限が必要と言われたサービスアカウント(
service-{projectid}@compute.system.iam.gserviceaccount.com
)を追加します。 - "Role" に、上で作成した
gce-start-stop-role
を加えます。これにより、サービスアカウントはこのVMについて、インスタンスの開始・停止権限を得ることになります。 - 「SAVE」をクリックします。
改めて、Compute Engineの「INSTANCE SCHEDULE」タブを開き、上で作成したスケージューラーインスタンス(gce-start-stop-scheduler
)をクリックし、詳細ページを開きます。
「ADD INSTANCES TO SCHEDULE」をクリックし、上で作成したVMインスタンス(my-test-vm
)を選びます。
今度は、権限の問題がなくなっているので、追加ができるはずです。
これにより、指定した時刻にVMインスタンスを起動、停止する設定ができました。
実験結果
自動起動、停止を設定した時刻まで待ちます(上の例では午前1時半)。
午前1時半直後だとまだ停止していないことがありますので、インスタンスが停止するまで待ちます(5分から15分程度ラグがあるようです)。
停止を確認したら、改めてインスタンスを起動してログインします。
時刻が記載されるファイルを確認すると、次のようになっていました。
cat ~/testfile.txt
#2021-08-16_15:45:01
#2021-08-16_15:46:01
#2021-08-16_15:47:01
#2021-08-16_15:48:01
#2021-08-16_16:05:01
#2021-08-16_16:06:01
#2021-08-16_16:07:01
#...
#2021-08-16_16:31:01
#2021-08-16_16:32:01
#2021-08-16_16:33:01
#2021-08-16_16:34:01
- 時刻は世界標準時なので、これに9時間足したものが日本時間です
- 最初の4行は開発時の残りです
- 5行目からは自動起動から停止の間の結果です。標準時の16時は日本時間1時なので、仮想マシンは
01:05
ころに起動し、01:34
ころに停止したようです。設定した時刻から5分程度ラグがあります - ドキュメントでは、15分程度の余裕を見て設定することが推奨されています
ケース2:インスタンス内からの停止
インスタンスの停止に関しては、外から決まった時刻ではなくインスタンスの中で停止したいこともあります。
たとえば、時間のかかる作業を寝る前に起動して、終了後に自動で停止させることができると、朝起きて自分で停止するのに比べて費用と手間を節約できます。
インスタンスの中から gcloud
コマンドを実行することで、これを実現できます。ただし、インスタンスを実行するサービスアカウントにその権限を付与する必要があります。
-
hostname
はVMの名前になっているので、my-test-vm
が代入されます。直接VMの名前を書いても大丈夫です。 -
--zone
は適宜変更してください。
gcloud compute instances stop --zone us-central1-a "$(hostname)"
shutdown
やpoweroff
コマンドでVMを停止することも可能ですが(参考:OS から VM を停止する)、sudo
が必要だったりするのでgcloud
の方が使いやすいと思います。
インスタンスの起動・停止権限をインスタンスを実行するサービスアカウントに付与
Compute Engineの「INSTANCES」タブを開き、上で作成したVMインスタンス(my-test-vm
)を選択します。
- ページ右の方の「PERMISSIONS」タブを開き、「ADD MEMBER」をクリックします。
- New members のところへ、VMを実行するサービスアカウント(
gce-worker
)を追加します。 - "Role" に、上で作成した
gce-start-stop-role
を加えます。これにより、サービスアカウントはこのVMについて、インスタンスの開始・停止権限を得ることになります。 - 「SAVE」をクリックします。
実験
VMを起動し、ログインします。
次のシェルスクリプトを作成します。これは、画面上に10から0までを1秒間隔で表示し、その後VMを停止するスクリプトです。
#!/bin/bash
for i in {10..0}
do
echo $i
sleep 1
done
gcloud compute instances stop --zone us-central1-a "$(hostname)"
実行可能ファイルにします。
chmod 700 ~/count-and-stop.sh
実行します。すると、10から0まで数えた後VMが停止され、その結果自動的にSSH接続が切断されました。コンソールで確認すると、確かにVMが停止していることが確認できます。
~/count-and-stop.sh
#10
#9
#8
#7
#6
#5
#4
#3
#2
#1
#0
#Stopping instance(s) my-test-vm...⠶Connection to xxx.xxx.xxx.xxx closed by remote host.
#Connection to xxx.xxx.xxx.xxx closed.
#ERROR: (gcloud.beta.compute.ssh) [/usr/bin/ssh] exited with return code [255].
備考
この方法を自動起動と組み合わせれば、次のように定期バッチを実装することも可能です。
ただし、2つの時間指定(VMの起動とスクリプトの実行)を矛盾なく設定する必要があるので、管理方法としてはやや煩雑かもしれません。
例:
- 毎日決まった時間にインスタンススケジューラーによってVMを起動
- VM側で、「特定のタスクを実行し、その後VMを停止する」スクリプトを定義し、VM起動の15分後にCronjobで実行