プログラムがGCP上で実行されているかを判定する

サーバーアプリケーションを開発していると、現在動いている環境がクラウドか、ローカルかで処理を分けたい場合がある。

自分はよくGCP (Google Cloud Platform) を利用しているが、今動いているのがGCP上なのか判定したい場面が何度かあった。 クラウドの場合のみ手動で環境変数を設定しても良いのだが、できれば自動的に判定してほしい。

そこで探してみたところ、GCPが提供するリポジトリに GCP Resource detection library というモジュールを見つけた。

opentelemetry-operations-go/detectors/gcp at main · GoogleCloudPlatform/opentelemetry-operations-go · GitHub

ここにある Detector.CloudPlatform を呼び出せばGCPのどのプラットフォーム上で動作しているかかんたんに取得できる。

// CloudPlatform returns the platform on which this program is running
func (d *Detector) CloudPlatform() Platform {
    switch {
    case d.onGKE():
        return GKE
    case d.onCloudRun():
        return CloudRun
    case d.onCloudFunctions():
        return CloudFunctions
    case d.onAppEngineStandard():
        return AppEngineStandard
    case d.onAppEngine():
        return AppEngineFlex
    case d.onGCE():
        return GCE
    }
    return UnknownPlatform
}

実装の詳細を見ていると、環境変数またはCompute Metadata経由で現在の環境を取得しているらしい。なるほど!

// GCEの場合
// See the available GCE instance metadata:
// https://cloud.google.com/compute/docs/metadata/default-metadata-values#vm_instance_metadata
const machineTypeMetadataAttr = "instance/machine-type"

func (d *Detector) onGCE() bool {
    _, err := d.metadata.Get(machineTypeMetadataAttr)
    return err == nil
}




// GKEの場合
const (
    // If the kubernetes.default.svc service exists in the cluster,
    // then the KUBERNETES_SERVICE_HOST env var will be populated.
    // Use this as an indication that we are running on kubernetes.
    k8sServiceHostEnv = "KUBERNETES_SERVICE_HOST"
)

func (d *Detector) onGKE() bool {
    _, found := d.os.LookupEnv(k8sServiceHostEnv)
    return found
}

Compute Metadataは内部的にHTTP Requestだし、環境変数は環境変数なので実装で見ている変数の名前さえ抑えておけば、 Go以外の言語でも同じようなDetectorを容易に作れそうである。