如何使用Google Cloud Function将文件从Cloud Storage存储桶中推送到实例中?

Cam*_*Cam 2 python-3.x google-cloud-storage google-compute-engine google-cloud-platform google-cloud-functions

我已经分配了一项任务,以考虑一种在GCP中设置云功能的方法,该方法可以执行以下操作:

  • 监视Google Cloud Storage存储桶中的新文件

  • 在检测到存储桶中的新文件时触发

  • 将该文件复制到Compute Instance(Ubuntu)内的目录中

我一直在做一些研究,但很快就空了。我知道我可以轻松地建立一个cron作业,该作业每分钟或类似的时间同步存储桶/目录,但是我们正在构建的系统的设计理念之一是使用触发器而不是计时器。

我要问的可能吗?

Joa*_*oël 8

您可以从Google Cloud Storage存储桶中触发Cloud Function,然后通过将事件类型选择为Finalize / Create完成,每次在存储桶中上传文件时,都会调用Cloud Function。

每次在存储桶中创建新对象时,云功能都会收到带有Cloud Storage对象格式的通知。

现在,进入第二步,我找不到任何可以将文件从Cloud Storage上传到实例VM的API。但是,假设您的实例VM的服务器配置为可以接收HTTP请求(例如Apache或Nginx),我将以下操作作为解决方法:

main.py

import requests
from google.cloud import storage

def hello_gcs(data, context):
    """Background Cloud Function to be triggered by Cloud Storage.  
    Args:
        data (dict): The Cloud Functions event payload.
        context (google.cloud.functions.Context): Metadata of triggering event.
    Returns:
        None; the file is sent as a request to 
    """
    print('Bucket: {}'.format(data['bucket']))
    print('File: {}'.format(data['name']))

    client = storage.Client()
    bucket = client.get_bucket(format(data['bucket']))
    blob = bucket.get_blob(format(data['name']))

    contents = blob.download_as_string()

    headers = {
        'Content-type': 'text/plain',
    }

    data = '{"text":"{}"}'.format(contents)
    response = requests.post('https://your-instance-server/endpoint-to-download-files', headers=headers, data=data)
    return "Request sent to your instance with the data of the object"
Run Code Online (Sandbox Code Playgroud)

requirements.txt

google-cloud-storage
requests
Run Code Online (Sandbox Code Playgroud)

最有可能的是,最好只是将对象名称和存储桶名称发送到您的服务器端点,然后使用Cloud Client Library从那里下载文件。

现在你可能会问...

如何使Compute Engine实例处理请求?

  1. 创建Compute Engine实例VM。确保它与云功能位于同一区域,并在创建它时允许HTTP连接。文件资料。我debian-9为此测试使用了一张图片。

  2. SSH进入实例,并运行以下命令:

  3. 为您的应用程序设置环境:

    cd ~/
    mkdir app
    sudo ln -sT ~/app /var/www/html/app
    
    Run Code Online (Sandbox Code Playgroud)

最后一行应指向apache用来提供index.html文件的文件夹路径。

  1. /home/<user_name>/app以下位置创建您的应用:

main.py

from flask import Flask, request
app = Flask(__name__)

@app.route('/', methods=['POST'])
def receive_file():
    file_content = request.form['data']
    # TODO
    # Implement process to save this data onto a file
    return 'Hello from Flask!'

if __name__ == '__main__':
  app.run()
Run Code Online (Sandbox Code Playgroud)
  1. 在同一目录中创建wsgi服务器入口点:

main.wsgi

import sys
sys.path.insert(0, '/var/www/html/app')

from main import app as application
Run Code Online (Sandbox Code Playgroud)
  1. /etc/apache2/sites-enabled/000-default.confDocumentRoot标记后,将以下行添加到:

        WSGIDaemonProcess flaskapp threads=5
        WSGIScriptAlias / /var/www/html/app/main.wsgi
    
        <Directory app>
                WSGIProcessGroup main
                WSGIApplicationGroup %{GLOBAL}
                Order deny,allow
                Allow from all
        </Directory>
    
    Run Code Online (Sandbox Code Playgroud)
  2. 运行sudo apachectl restart。您应该能够将发布请求发送到您的应用程序,VM实例的内部IP(可以在控制台的Compute Engine部分中看到它)。在拥有它之后,在您的云功能中,您应该将响应行更改为:

    response = requests.post('<INTERNAL_INSTANCE_IP>/', headers=headers, data=data)
    
    return "Request sent to your instance with the data of the object"
    
    Run Code Online (Sandbox Code Playgroud)