Мне было поручено придумать способ настроить облачную функцию в GCP, которая делает следующее:
Отслеживает корзину Google Cloud Storage для новых файлов
Срабатывает при обнаружении нового файла в корзине
Копирует этот файл в каталог внутри вычислительного экземпляра (Ubuntu).
Я проводил некоторые исследования и ничего не понял. Я знаю, что могу легко настроить задание cron, которое синхронизирует корзину/каталог каждую минуту или что-то в этом роде, но одна из философий проектирования системы, которую мы создаем, заключается в работе с триггерами, а не с таймерами.
Возможно ли то, о чем я прошу?





Вы можете активировать облачную функцию из корзины Google Cloud Storage, и, выбрав тип события Завершить/Создать, каждый раз, когда файл загружается в корзину, будет вызываться облачная функция.
Каждый раз, когда в корзине создается новый объект, облачная функция получает уведомление с Формат объекта облачного хранилища.
Теперь, что касается второго шага, я не смог найти API, который мог бы загружать файлы из облачного хранилища в виртуальную машину экземпляра. Однако я сделал следующее в качестве обходного пути, предполагая, что в вашем экземпляре виртуальной машины настроен сервер, который может получать 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(data['bucket'])
blob = bucket.get_blob(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"
требования.txt
google-cloud-storage
requests
Скорее всего, было бы лучше просто отправить имя объекта и имя корзины на вашу серверную конечную точку, а оттуда загрузить файлы с помощью Облачная клиентская библиотека.
Теперь вы можете спросить...
Как заставить экземпляр Compute Engine обрабатывать запрос?
Создайте виртуальную машину экземпляра Compute Engine. Убедитесь, что он находится в том же регионе, что и облачная функция, и при его создании разрешите HTTP-подключения к нему. Документация. Для этого теста я использовал образ debian-9.
SSH в экземпляр и выполните следующие команды:
Установить сервер апач
sudo apt-get update
sudo apt-get install apache2
sudo apt-get install libapache2-mod-wsgi
Установите также эти библиотеки Python:
sudo apt-get install python-pip
sudo pip install flask
Настройте среду для вашего приложения:
cd ~/
mkdir app
sudo ln -sT ~/app /var/www/html/app
Последняя строка должна указывать на путь к папке, из которой apache обслуживает файл index.html.
/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()
main.wsgi
import sys
sys.path.insert(0, '/var/www/html/app')
from main import app as application
Добавьте следующую строку в /etc/apache2/sites-enabled/000-default.conf после тега DocumentRoot:
WSGIDaemonProcess flaskapp threads=5
WSGIScriptAlias / /var/www/html/app/main.wsgi
<Directory app>
WSGIProcessGroup main
WSGIApplicationGroup %{GLOBAL}
Order deny,allow
Allow from all
</Directory>
Запустите sudo apachectl restart. Вы должны иметь возможность отправлять почтовые запросы в ваше приложение на внутренний 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"
весьма спорный вопрос, но вместо того, чтобы поддерживать два фрагмента кода (один для облачной функции и один для конечной точки для загрузки файлов), вы можете опубликовать объектное событие на pub/sub topic, и он вызовет (подпишется) https://your-instance-server/endpoint-to-download-files и загрузит файл на сервер.
Я отредактировал ответ, объясняющий, как настроить конечную точку в экземпляре Compute Engine. Пожалуйста, дайте мне знать, если я что-то пропустил, или если у вас есть какие-либо вопросы.
Есть ли другой способ вызвать функцию в вычислительном движке из облачной функции вместо создания конечной точки сервера в вычислительном движке?
Спасибо за ваш ответ, Джоан. Извините, но я новичок в GCP, и мне было интересно, как узнать, что такое конечная точка моего сервера и как отправлять на нее объекты?