gcpの便利な使い方
特に、GCPの特定の機能について紹介する
cloud shell
概要
web uiから使える最小のshell
基本的なことはできるがブラウザで動作しているのでその制約がある
ローカルからのアクセス
$ gcloud cloud-shell ssh
pythonのライブラリ
google-cloud-logging
google-cloud-bigquery
google-cloud-storage
google-cloud-pubsub
from google.cloud import logging
などで失敗するときはライブラリのバージョンが古いのでアップグレードする
preemtibleの便利な使い方
最大24時間でシャットダウンしてしまうインスタンスで、1/4 ~ 1/5で利用できる。
例えば、以下のスクリプトは、 hook.py
でsshfsで自宅のPCにログイン、マウントさせ、非常に重い処理を行わさている。
結果は細かいファイル粒度でマウントしたディスクに書き込まれるので、切断されてしまっても問題ない。
import pandas as pd
import os
from subprocess import Popen, PIPE
import sys
import json
import shlex
import paramiko
from os import environ as E
import random
import time
from collections import namedtuple
from concurrent.futures import ProcessPoolExecutor
from concurrent.futures import ThreadPoolExecutor
import datetime
class Instance:
def __init__(self, name, preemptible, status, natIP, zone):
self.name = name
self.preemptible = preemptible
self.status = status
self.natIP = natIP
self.zone = zone
"""
instance objectを回収
"""
ret = os.popen("gcloud compute instances list --format json").read()
ret = json.loads(ret)
instances = []
for a in ret:
zone = a.get('zone').split('/')[-1]
name = a.get('name')
preemptible = a.get('scheduling').get('preemptible')
status = a.get('status')
natIP = a.get('networkInterfaces')[0]['accessConfigs'][0].get('natIP')
instance = Instance(name, preemptible, status, natIP, zone)
if instance.preemptible:
instances.append(instance)
"""
コマンドを実行
"""
def process_run(instance):
TIMEOUT = 60 * 1
COMMAND = "python3 ./hook.py"
ALIVE_PATTERN = "pgrep -a python3 | grep hook.py | wc -l"
while True:
try:
def _run(pipe=None):
with Popen(['gcloud', 'compute', 'ssh', f'{instance.name}', f'--zone={instance.zone}', f'--ssh-key-file=~/.ssh/id_github', f'--command', COMMAND, ], stdout=pipe, stderr=pipe,) as proc:
try:
proc.wait(timeout=TIMEOUT)
except Exception as exc:
proc.terminate()
print(f'exc = {exc}', file=sys.stderr)
def _check_alive():
with Popen(['gcloud', 'compute', 'ssh', f'{instance.name}', f'--zone={instance.zone}', f'--ssh-key-file=~/.ssh/id_github', f'--command', ALIVE_PATTERN, ], stdout=PIPE, stderr=PIPE,) as proc:
result = int(proc.stdout.read().strip().decode())
print(instance.name, status, datetime.datetime.now(), result)
return result
"""
最初に未起動のpreemptible instanceを起動する
"""
ret = os.popen(f"gcloud compute instances describe {instance.name} --zone {instance.zone} --format json").read()
ret = json.loads(ret)
status = ret['status']
print(instance.name, status, datetime.datetime.now())
if status == "TERMINATED":
ret = os.popen(f"gcloud compute instances start {instance.name} --zone={instance.zone} --format=json").read()
time.sleep(90.0)
_run(pipe=None)
elif status == "RUNNING":
"""
ALIVE_PATTERNが存在していたら(aka. not 0だったら)何もしないで、していなかったらコマンドを実行
"""
result = _check_alive()
if result == 0:
_run(pipe=None)
except Exception as exc:
print(exc)
time.sleep(10)
MAX_INSTANCES_NUM = 36
while True:
with ThreadPoolExecutor(max_workers=MAX_INSTANCES_NUM) as exe:
exe.map(process_run, instances)