存取執行個體中繼資料

Google Cloud Platform 提供了一個中繼資料伺服器,該伺服器知道 App Engine 執行個體的詳情,例如包含專案 ID、服務帳戶,以及服務帳戶使用的憑證。您可使用簡單的 HTTP 要求存取此資料:不需要用戶端程式庫。

此頁面說明如何透過相對應的中繼資料伺服器端點進行 HTTP 呼叫,從已部署的 Java 8 執行階段應用程式存取執行個體中繼資料。

使用此 API 的一個便利功能是取得服務帳戶憑證,並將其做為不記名憑證 (憑證位於一個 Google Cloud API 的授權標頭中),為這特定的 API 服務進行應用程式驗證。有關使用這些不記名憑證的範例,請參閱 Google Cloud Translation API

辨識要使用的中繼資料端點

下表列出可讓您針對特定中繼資料發出 HTTP 要求的端點:您可以從 http://metadata.google.internal 存取中繼資料伺服器。

中繼資料端點 說明
/computeMetadata/v1/project/numeric-project-id 指派給專案的專案編號。
/computeMetadata/v1/project/project-id 指派給專案的專案 ID。
/computeMetadata/v1/instance/zone 執行個體運作所在的區域。
/computeMetadata/v1/instance/service-accounts/default/aliases
/computeMetadata/v1/instance/service-accounts/default/email 指派給專案的預設服務帳戶電子郵件。
/computeMetadata/v1/instance/service-accounts/default/ 列出專案所有的預設服務帳戶。
/computeMetadata/v1/instance/service-accounts/default/scopes 列出預設服務帳戶所有的支援範圍。
/computeMetadata/v1/instance/service-accounts/default/token 傳回的驗證憑證可用來為其他 Google Cloud API 進行應用程式驗證。

例如,如要擷取專案 ID,請將要求傳送至 http://metadata.google.internal/computeMetadata/v1/project/project-id

發出中繼資料要求

以下的範例程式碼會取得並顯示執行個體可用的中繼資料,但服務帳戶憑證例外。

@SuppressWarnings("serial")
// With @WebServlet annotation the webapp/WEB-INF/web.xml is no longer required.
@WebServlet(name = "Metadata", description = "Metadata: Write info about GAE Standard",
    urlPatterns = "/metadata")
public class MetadataServlet extends HttpServlet {

  private final String[] metaPath = {
      "/computeMetadata/v1/project/numeric-project-id", //  (pending)
      "/computeMetadata/v1/project/project-id",
      "/computeMetadata/v1/instance/zone",
      "/computeMetadata/v1/instance/service-accounts/default/aliases",
      "/computeMetadata/v1/instance/service-accounts/default/email",
      "/computeMetadata/v1/instance/service-accounts/default/",
      "/computeMetadata/v1/instance/service-accounts/default/scopes",
      // Tokens work - but are a security risk to display
      //      "/computeMetadata/v1/instance/service-accounts/default/token"
  };

  final String[] metaServiceAcct = {
      "/computeMetadata/v1/instance/service-accounts/{account}/aliases",
      "/computeMetadata/v1/instance/service-accounts/{account}/email",
      "/computeMetadata/v1/instance/service-accounts/{account}/scopes",
      // Tokens work - but are a security risk to display
      //     "/computeMetadata/v1/instance/service-accounts/{account}/token"
  };

  private final String metadata = "http://metadata.google.internal";
  private TemplateEngine templateEngine;

  // Use OkHttp from Square as it's quite easy to use for simple fetches.
  private final OkHttpClient ok = new OkHttpClient.Builder()
      .readTimeout(500, TimeUnit.MILLISECONDS)  // Don't dawdle
      .writeTimeout(500, TimeUnit.MILLISECONDS)
      .build();

  // Setup to pretty print returned json
  private final Gson gson = new GsonBuilder()
      .setPrettyPrinting()
      .create();
  private final JsonParser jp = new JsonParser();

  // Fetch Metadata
  String fetchMetadata(String key) throws IOException {
    Request request = new Request.Builder()
        .url(metadata + key)
        .addHeader("Metadata-Flavor", "Google")
        .get()
        .build();

    Response response = ok.newCall(request).execute();
    return response.body().string();
  }

  String fetchJsonMetadata(String prefix) throws IOException {
    Request request = new Request.Builder()
        .url(metadata + prefix)
        .addHeader("Metadata-Flavor", "Google")
        .get()
        .build();

    Response response = ok.newCall(request).execute();

    // Convert json to prety json
    return gson.toJson(jp.parse(response.body().string()));
  }

  @Override
  public void init() {
    // Setup ThymeLeaf
    ServletContextTemplateResolver templateResolver =
        new ServletContextTemplateResolver(this.getServletContext());

    templateResolver.setPrefix("/WEB-INF/templates/");
    templateResolver.setSuffix(".html");
    templateResolver.setCacheTTLMs(Long.valueOf(1200000L)); // TTL=20m

    // Cache is set to true by default. Set to false if you want templates to
    // be automatically updated when modified.
    templateResolver.setCacheable(true);

    templateEngine = new TemplateEngine();
    templateEngine.setTemplateResolver(templateResolver);
  }

  @Override
  public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
    String defaultServiceAccount = "";
    WebContext ctx = new WebContext(req, resp, getServletContext(), req.getLocale());

    resp.setContentType("text/html");

    String environment =
        (String) System.getProperties().get("com.google.appengine.runtime.environment");
    ctx.setVariable("production", environment);

    // The metadata server is only on a production system
    if (environment.equals("Production")) {

      TreeMap<String, String> m = new TreeMap<>();

      for (String key : metaPath) {
        m.put(key, fetchMetadata(key));
        if (key.contains("default/email")) {
          defaultServiceAccount = m.get(key);
        }
      }

      ctx.setVariable("Metadata", m.descendingMap());

      m = new TreeMap<>();
      for (String key : metaServiceAcct) {
        // substitute a service account for {account}
        key = key.replace("{account}", defaultServiceAccount);
        m.put(key, fetchMetadata(key));
      }
      ctx.setVariable("sam", m.descendingMap());

      // Recursivly get all info about service accounts -- Note tokens are leftout by default.
      ctx.setVariable("rsa",
          fetchJsonMetadata("/computeMetadata/v1/instance/service-accounts/?recursive=true"));
      // Recursivly get all data on Metadata server.
      ctx.setVariable("ram", fetchJsonMetadata("/?recursive=true"));
    }

    templateEngine.process("index", ctx, resp.getWriter());

  }
}

在範例程式碼中,請注意檢查確保應用程式在生產環境中執行。若應用程式在本機執行,則不會從要求中傳回任何中繼資料。

此外,請注意使用 Google Gson JSON 序列化 / 反序列化 OkHttp HTTP 和 HTTP2 用戶端,以及 Thymeleaf 範本系統。這些程序並非必須,但對您的專案有所幫助。

在本機執行

中繼資料伺服器可用於已部署的應用程式:不支援在開發伺服器上的本機執行。您可以在程式碼中新增環境檢查,以確保應用程式僅在實際工作環境中執行時,才能取得中繼資料結果,如上述範例程式碼所示:

String environment =
      (String) System.getProperties().get("com.google.appengine.runtime.environment");
  ctx.setVariable("production", environment);

  // The metadata server is only on a production system
  if (environment.equals("Production")) {
     ... //show metadata results
   }
本頁內容對您是否有任何幫助?請提供意見:

傳送您對下列選項的寶貴意見...

這個網頁
Java 適用的 App Engine 標準環境