如何以编程方式在谷歌云运行 api 中获取当前项目 ID

Posted

技术标签:

【中文标题】如何以编程方式在谷歌云运行 api 中获取当前项目 ID【英文标题】:How to programmatically get current project id in Google cloud run api 【发布时间】:2020-04-12 11:10:12 【问题描述】:

我有一个容器化并在云运行中运行的 API。如何获取正在执行云运行的当前项目 ID?我试过了:

我在日志中的 textpayload 中看到它,但我不确定如何在 post 函数中读取 textpayload?我收到的 pub sub 消息缺少此信息。 我已经阅读了查询元数据 api 的内容,但是关于如何从 api 中再次执行此操作还不是很清楚。有链接吗?

还有其他方法吗?

编辑:

在下面的一些 cmets 之后,我最终在 Cloud Run 中运行我的 .net API 中的这段代码。

        private string GetProjectid()
        
            var projectid = string.Empty;
            try 
                var PATH = "http://metadata.google.internal/computeMetadata/v1/project/project-id";
                using (var client = new HttpClient())
                
                    client.DefaultRequestHeaders.Add("Metadata-Flavor", "Google");
                    projectid = client.GetStringAsync(PATH).Result.ToString();
                

                Console.WriteLine("PROJECT: " + projectid);
            
            catch (Exception ex) 
                Console.WriteLine(ex.Message + " --- " + ex.ToString());
            
            return projectid;
        

更新,它有效。我的构建推送失败了,我没有看到。感谢大家。

【问题讨论】:

http://metadata.google.internal/computeMetadata/v1/project/project-id发出HTTP GET请求 我得到(响应状态码不表示成功:403(尝试执行此操作时禁止。 您从哪里提出请求?您的 Compute Engine 实例启用了哪些范围?您添加了哪些 HTTP 标头?请参阅 Steren 向元数据服务器发出请求的答案,其中必须包含 Metadata-Flavor:Google 标头。 我没有!如何获得 ACCESS_TOKEN? 我更改了我的评论,因为元数据服务器仅在您的代码在 Compute Engine 实例中运行且不需要访问令牌时才可用。如果您在其他地方(例如 Web 浏览器)运行代码,则无法调用此端点。使用有关如何调用此端点的确切详细信息编辑您的问题并包含错误消息。 【参考方案1】:

    我按照教程Using Pub/Sub with Cloud Run tutorial

    我在requirements.txt 中添加了模块gcloud

       Flask==1.1.1
       pytest==5.3.0; python_version > "3.0"
       pytest==4.6.6; python_version < "3.0"
       gunicorn==19.9.0
       gcloud
    

    我在 main.py 中更改了index 函数:

       def index():
         envelope = request.get_json()
         if not envelope:
            msg = 'no Pub/Sub message received'
            print(f'error: msg')
            return f'Bad Request: msg', 400
         if not isinstance(envelope, dict) or 'message' not in envelope:
            msg = 'invalid Pub/Sub message format'
            print(f'error: msg')
            return f'Bad Request: msg', 400
         pubsub_message = envelope['message']
         name = 'World'
         if isinstance(pubsub_message, dict) and 'data' in pubsub_message:
            name = base64.b64decode(pubsub_message['data']).decode('utf-8').strip()
         print(f'Hello name!')
    
         #code added 
         from gcloud import pubsub  # Or whichever service you need
         client = pubsub.Client()
         print('This is the project '.format(client.project))
    
         # Flush the stdout to avoid log buffering.
         sys.stdout.flush()
         return ('', 204)
    

      我检查了日志:

        Hello (pubsub message).
        This is the project my-project-id.
      

【讨论】:

【参考方案2】:

您可以通过向 http://metadata.google.internal/computeMetadata/v1/project/project-id 发送带有 Metadata-Flavor:Google 标头的 GET 请求来获取项目 ID。

见this documentation

以 Node.js 为例:

index.js:

const express = require('express');
const axios = require('axios');
const app = express();

const axiosInstance = axios.create(
  baseURL: 'http://metadata.google.internal/',
  timeout: 1000,
  headers: 'Metadata-Flavor': 'Google'
);

app.get('/', (req, res) => 
  let path = req.query.path || 'computeMetadata/v1/project/project-id';
  axiosInstance.get(path).then(response => 
    console.log(response.status)
    console.log(response.data);
    res.send(response.data);
  );
);

const port = process.env.PORT || 8080;
app.listen(port, () => 
  console.log('Hello world listening on port', port);
);

package.json:


  "name": "metadata",
  "version": "1.0.0",
  "description": "Metadata server",
  "main": "app.js",
  "scripts": 
    "start": "node index.js"
  ,
  "author": "",
  "license": "Apache-2.0",
  "dependencies": 
    "axios": "^0.18.0",
    "express": "^4.16.4"
  

【讨论】:

我正在尝试同样的事情,但没有运气。尝试 var PATH = "metadata.google.internal/computeMetadata/v1/project/project-id";使用 (var client = new HttpClient()) client.DefaultRequestHeaders.Add("Metadata-Flavor", "Google"); projectid = client.GetStringAsync(PATH).Result.ToString(); Console.WriteLine("项目:" + projectid); 【参考方案3】:

应该可以使用Google.Api.Gax (https://github.com/googleapis/gax-dotnet/blob/master/Google.Api.Gax/Platform.cs) 中的Platform 类。 Google.Api.Gax 包通常作为其他 Google .NET 包的依赖项安装,例如 Google.Cloud.Storage.V1

var projectId = Google.Api.Gax.Platform.Instance().ProjectId;

在GAE平台上,也可以简单查看环境变量GOOGLE_CLOUD_PROJECTGCLOUD_PROJECT

var projectId = Environment.GetEnvironmentVariable("GOOGLE_CLOUD_PROJECT")
             ?? Environment.GetEnvironmentVariable("GCLOUD_PROJECT");

【讨论】:

【参考方案4】:

这是获取当前项目 ID 的 Java 代码的 sn-p:

            String url = "http://metadata.google.internal/computeMetadata/v1/project/project-id";
            HttpURLConnection conn = (HttpURLConnection)(new URL(url).openConnection());
            conn.setRequestProperty("Metadata-Flavor", "Google");
            try 
                InputStream in = conn.getInputStream();
                projectId = new String(in.readAllBytes(), StandardCharsets.UTF_8);
             finally 
                conn.disconnect();
                           

【讨论】:

【参考方案5】:

其他人已经展示了如何通过 HTTP API 获取项目名称,但在我看来,这里更容易、更简单、更高效的做法是将项目 ID 设置为 run-time environment variable。为此,在部署函数时:

gcloud functions deploy myFunction --set-env-vars PROJECT_ID=my-project-name

然后您可以使用以下代码访问它:

exports.myFunction = (req, res) => 
  console.log(process.env.PROJECT_ID);

您只需为部署函数的每个环境设置适当的值。这有一个非常小的缺点,即每个环境都需要一个一次性的命令行参数,而不让你的函数依赖于成功验证和解析 API 响应的主要优点。这也提供了代码可移植性,因为几乎所有托管环境都支持环境变量,包括您的本地开发环境。

【讨论】:

一些较旧的运行时(例如 nodejs8)会自动填充 process.env. GCP_PROJECT,但在撰写本文时已被弃用一段时间【参考方案6】:

@Steren 在 python 中的回答

import os

def get_project_id():
    # In python 3.7, this works
    project_id = os.getenv("GCP_PROJECT")

    if not project_id:  # > python37
        # Only works on runtime.
        import urllib.request

        url = "http://metadata.google.internal/computeMetadata/v1/project/project-id"
        req = urllib.request.Request(url)
        req.add_header("Metadata-Flavor", "Google")
        project_id = urllib.request.urlopen(req).read().decode()

    if not project_id:  # Running locally
        with open(os.environ["GOOGLE_APPLICATION_CREDENTIALS"], "r") as fp:
            credentials = json.load(fp)
        project_id = credentials["project_id"]

    if not project_id:
        raise ValueError("Could not get a value for PROJECT_ID")

    return project_id

【讨论】:

以上是关于如何以编程方式在谷歌云运行 api 中获取当前项目 ID的主要内容,如果未能解决你的问题,请参考以下文章

如何在谷歌云数据流中停止流式传输管道

如何在谷歌云上安排 docker 运行

在 android 中获取意外的响应代码 403,同时在谷歌云控制台中将 API 密钥限制为 Android 应用程序

如何以编程方式从其中一个集群中获取当前的 GKE 项目 ID?

如何在谷歌云功能中使用谷歌表格 API

在谷歌云视觉 API 中调用 client.text_detection() 获取 TypeError: type object got multiple values for keyword arg