• home
  • about
  • 全ての投稿
  • ソフトウェア・ハードウェアの設定のまとめ
  • 分析関連のまとめ
  • ヘルスケア関連のまとめ
  • 生涯学習関連のまとめ

gcp

date: 2021-03-09 excerpt: gcpの便利な使い方

tag: gcp


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)


gcp Share Tweet