[料理佳餚] C# 使用 Google APIs 來控制 GCE(Google Compute Engine)VM 的開啟跟關閉

如果我們明確地知道我們的服務尖峰及離峰時間,那麼我們可以在離峰時間關閉一些機器來節省一點成本,GCE 沒有提供排程開關機的設定,所以我們只好自己寫,Google APIs 的文件告訴我們可以選擇純 HTTP 方式,或是使用 Google APIs Client Library 來控制 VM 的開關機,底下我就用 Google APIs Client Library for .NET 來撰寫控制 VM 開關機的程式。

建立憑證

首先我們得先取得憑證,用來跟 GCP 認證,GCP 有自動生成一個給 Compute Engine 使用的預設服務帳戶,我們可以使用這個帳戶來建立服務帳戶金鑰,從導覽選單中找到憑證,然後按照下面步驟前進:

  1. 點擊建立憑證
  2. 點選服務帳戶金鑰
  3. 服務帳戶選擇 Compute Engine default service account
  4. 最後點擊建立

金鑰只會建立一次,下載下來的 JSON 檔案記得要妥善保存,萬一遺失了就要重新建立。

載入金鑰

我們至少需要兩個相關套件,可以從 NuGet 下載:

將剛剛下載下來的金鑰 JSON 檔案丟給 GoogleCredential.FromFile() 方法,由於我們這種方式產生出來的憑證是屬於 ServiceAccountCredential 類型,所以需要指定認證範圍,再串接呼叫 CreateScoped() 方法,將 https://www.googleapis.com/auth/cloud-platform 網址丟進去。

private static GoogleCredential GetCredential()
{
    return GoogleCredential.FromFile("xxx.json").CreateScoped("https://www.googleapis.com/auth/cloud-platform");
}

開啟 VM

我們建立一個 ComputeService 物件,並且在建構式裡面丟入一個 BaseClientService.Initializer 物件,將取得的 Credential 指定給 HttpClientInitializer 屬性。

接著我們呼叫 ComputeService.Instances.Start() 方法,產生一個 StartRequest 物件,最後呼叫 StartRequest.Execute() 即可發送開機的要求,那麼在這邊我是使用 StartRequest.ExecuteAsync() 非同步方法。

我們會收到一個型別為 Operation 的回應物件,裡面有一個 Status 的屬性,它有三種狀態:PENDING(工作佇列中)、RUNNING(開機中)、DONE(開機完成)。

private async Operation Start()
{
    var credential = GetCredential();

    var computeService = new ComputeService(
        new BaseClientService.Initializer { HttpClientInitializer = credential, ApplicationName = "自訂(可以使用目前執行的應用程式名稱)" });

    var project = "Project ID";
    var zone = "Zone Name";
    var instance = "Instance Name";

    var request = computeService.Instances.Start(project, zone, instance);
    
    var response = await request.ExecuteAsync();

    return response;
}

關閉 VM

關閉 VM 跟開啟 VM 只差在將 Start() 換成 Stop(),一樣會收到 Operation 物件,Status 也一樣是三種狀態::PENDING(工作佇列中)、RUNNING(關機中)、DONE(關機完成)。

private async Operation Stop()
{
    var credential = GetCredential();

    var computeService = new ComputeService(
        new BaseClientService.Initializer { HttpClientInitializer = credential, ApplicationName = "自訂(可以使用目前執行的應用程式名稱)" });

    var project = "Project ID";
    var zone = "Zone Name";
    var instance = "Instance Name";

    var request = computeService.Instances.Stop(project, zone, instance);
    
    var response = await request.ExecuteAsync();

    return response;
}

最後附上 Compute Enginte 相關的 API 文件連結,每一個 Method 說明頁面的最下面都有範例程式碼,提供給各位朋友參考。

參考資料