1. Введение

С помощью Workflows можно создавать бессерверные рабочие процессы, которые связывают ряд бессерверных задач в заданном вами порядке. Вы можете объединить возможности API Google Cloud, бессерверных продуктов, таких как Cloud Functions и Cloud Run, и вызовов внешних API для создания гибких бессерверных приложений.
Workflows не требует управления инфраструктурой и масштабируется без проблем в зависимости от спроса, включая масштабирование до нуля. Благодаря модели ценообразования с оплатой по факту использования вы платите только за время выполнения.
В этом практическом занятии вы узнаете, как связать различные сервисы Google Cloud и внешние HTTP API с помощью рабочих процессов. В частности, вы подключите два общедоступных сервиса Cloud Functions, один частный сервис Cloud Run и внешний общедоступный HTTP API к рабочему процессу.
Что вы узнаете
- Основы рабочих процессов.
- Как связать общедоступные облачные функции с рабочими процессами.
- Как подключить частные облачные сервисы Cloud Run к рабочим процессам.
- Как подключить внешние HTTP API к рабочим процессам.
2. Настройка и требования
Настройка среды для самостоятельного обучения
- Войдите в Cloud Console и создайте новый проект или используйте существующий. (Если у вас еще нет учетной записи Gmail или G Suite, вам необходимо ее создать .)
Запомните идентификатор проекта (Project ID) — уникальное имя для всех проектов Google Cloud (указанное выше имя уже занято и вам не подойдёт, извините!). В дальнейшем в этом практическом занятии оно будет обозначаться как PROJECT_ID .
- Далее вам потребуется включить оплату в Cloud Console, чтобы использовать ресурсы Google Cloud.
Выполнение этого практического задания не должно стоить дорого, если вообще что-либо. Обязательно следуйте инструкциям в разделе «Очистка», где указано, как отключить ресурсы, чтобы избежать дополнительных расходов после завершения этого урока. Новые пользователи Google Cloud имеют право на бесплатную пробную версию стоимостью 300 долларов США .
Запустить Cloud Shell
Хотя Google Cloud можно управлять удаленно с ноутбука, в этом практическом занятии вы будете использовать Google Cloud Shell — среду командной строки, работающую в облаке.
В консоли GCP щелкните значок Cloud Shell на панели инструментов в правом верхнем углу:
Подготовка и подключение к среде займут всего несколько минут. После завершения вы должны увидеть что-то подобное:
Эта виртуальная машина оснащена всеми необходимыми инструментами разработки. Она предоставляет постоянный домашний каталог размером 5 ГБ и работает в облаке Google, что значительно повышает производительность сети и аутентификацию. Всю работу в этой лаборатории можно выполнять с помощью обычного браузера.
3. Обзор рабочих процессов
Основы
Рабочий процесс состоит из ряда шагов, описанных с использованием синтаксиса Workflows на основе YAML. Это определение рабочего процесса. Подробное объяснение синтаксиса Workflows YAML см. на странице справочника по синтаксису .
При создании рабочего процесса он развертывается, что делает его готовым к выполнению. Выполнение — это однократный запуск логики, содержащейся в определении рабочего процесса. Все выполнения рабочих процессов независимы друг от друга, и продукт поддерживает большое количество одновременных выполнений.
Включить службы
В этом практическом занятии вы будете подключать сервисы Cloud Functions и Cloud Run к рабочим процессам. Вы также будете использовать Cloud Build и Cloud Storage при создании сервисов.
Включите все необходимые службы:
gcloud services enable \ cloudfunctions.googleapis.com \ run.googleapis.com \ workflows.googleapis.com \ cloudbuild.googleapis.com \ storage.googleapis.com
На следующем шаге вы объедините две облачные функции в единый рабочий процесс.
4. Разверните первую облачную функцию.
Первая функция — это генератор случайных чисел на языке Python.
Создайте директорию и перейдите в неё, чтобы сохранить код функции:
mkdir ~/randomgen cd ~/randomgen
Создайте в указанной директории файл main.py со следующим содержимым:
import random, json
from flask import jsonify
def randomgen(request):
randomNum = random.randint(1,100)
output = {"random":randomNum}
return jsonify(output)
При получении HTTP-запроса эта функция генерирует случайное число от 1 до 100 и возвращает его вызывающей стороне в формате JSON.
Эта функция использует Flask для обработки HTTP-запросов, и нам необходимо добавить его в качестве зависимости. В Python зависимости управляются с помощью pip и описываются в файле метаданных под названием requirements.txt .
Создайте в той же директории файл requirements.txt со следующим содержимым:
flask>=1.0.2
Разверните функцию с HTTP-триггером и разрешите неаутентифицированные запросы с помощью этой команды:
gcloud functions deploy randomgen \
--runtime python312 \
--trigger-http \
--allow-unauthenticated
После развертывания функции вы можете увидеть ее URL-адрес в свойстве url , отображаемом в консоли или с помощью команды gcloud functions describe .
Вы также можете перейти по указанному URL-адресу функции с помощью следующей команды curl :
curl $(gcloud functions describe randomgen --format='value(url)')
Функция готова к использованию в рабочем процессе.
5. Развертывание второй облачной функции.
Вторая функция — это умножитель. Он умножает полученный входной сигнал на 2.
Создайте директорию и перейдите в неё, чтобы сохранить код функции:
mkdir ~/multiply cd ~/multiply
Создайте в указанной директории файл main.py со следующим содержимым:
import random, json
from flask import jsonify
def multiply(request):
request_json = request.get_json()
output = {"multiplied":2*request_json['input']}
return jsonify(output)
При получении HTTP-запроса эта функция извлекает input из тела JSON-запроса, умножает их на 2 и возвращает результат в формате JSON вызывающей стороне.
Создайте аналогичный файл requirements.txt в той же директории со следующим содержимым:
flask>=1.0.2
Разверните функцию с HTTP-триггером и разрешите неаутентифицированные запросы с помощью этой команды:
gcloud functions deploy multiply \
--runtime python312 \
--trigger-http \
--allow-unauthenticated
После развертывания функции вы также можете перейти по указанному URL-адресу функции с помощью следующей команды curl :
curl $(gcloud functions describe multiply --format='value(url)') \
-X POST \
-H "content-type: application/json" \
-d '{"input": 5}'
Функция готова к использованию в рабочем процессе.
6. Соедините две облачные функции.
В первом варианте выполнения задачи соедините две функции.
Создайте файл workflow.yaml со следующим содержимым.
- randomgenFunction:
call: http.get
args:
url: https://<region>-<project-id>.cloudfunctions.net/randomgen
result: randomgenResult
- multiplyFunction:
call: http.post
args:
url: https://<region>-<project-id>.cloudfunctions.net/multiply
body:
input: ${randomgenResult.body.random}
result: multiplyResult
- returnResult:
return: ${multiplyResult}
В этом алгоритме вы получаете случайное число из первой функции и передаете его во вторую функцию. Результатом является умноженное случайное число.
Разверните первый рабочий процесс:
gcloud workflows deploy workflow --source=workflow.yaml
Выполните первый рабочий процесс:
gcloud workflows execute workflow
После выполнения рабочего процесса вы можете увидеть результат, передав идентификатор выполнения, указанный на предыдущем шаге:
gcloud workflows executions describe <your-execution-id> --workflow workflow
В выходных данных будут указаны result и state :
result: '{"body":{"multiplied":108},"code":200 ... }
...
state: SUCCEEDED
7. Подключите внешний HTTP API.
Далее вы подключите math.js в качестве внешнего сервиса в рабочем процессе.
В math.js можно вычислять математические выражения следующим образом:
curl https://api.mathjs.org/v4/?'expr=log(56)'
На этот раз вы воспользуетесь Cloud Console для обновления нашего рабочего процесса. Найдите Workflows в Google Cloud Console:

Найдите свой рабочий процесс и перейдите на вкладку Definition :

Отредактируйте определение рабочего процесса и добавьте вызов math.js
- randomgenFunction:
call: http.get
args:
url: https://<region>-<project-id>.cloudfunctions.net/randomgen
result: randomgenResult
- multiplyFunction:
call: http.post
args:
url: https://<region>-<project-id>.cloudfunctions.net/multiply
body:
input: ${randomgenResult.body.random}
result: multiplyResult
- logFunction:
call: http.get
args:
url: https://api.mathjs.org/v4/
query:
expr: ${"log(" + string(multiplyResult.body.multiplied) + ")"}
result: logResult
- returnResult:
return: ${logResult}
Теперь в процессе работы результат функции умножения передается в вызов функции логирования в файле math.js
Интерфейс пользователя поможет вам отредактировать и развернуть рабочий процесс. После развертывания нажмите кнопку Execute , чтобы запустить рабочий процесс. Вы увидите подробную информацию о выполнении:

Обратите внимание на код состояния 200 и body с выводом функции логирования.
Вы только что интегрировали внешний сервис в наш рабочий процесс, это просто здорово!
8. Разверните сервис Cloud Run.
В заключительной части завершите рабочий процесс вызовом частного сервиса Cloud Run. Это означает, что для вызова сервиса Cloud Run необходимо пройти аутентификацию.
Сервис Cloud Run возвращает результат math.floor для переданного числа.
Создайте директорию с кодом сервиса и перейдите в неё:
mkdir ~/floor cd ~/floor
Создайте в указанной директории файл app.py со следующим содержимым:
import json
import logging
import os
import math
from flask import Flask, request
app = Flask(__name__)
@app.route('/', methods=['POST'])
def handle_post():
content = json.loads(request.data)
input = float(content['input'])
return f"{math.floor(input)}", 200
if __name__ != '__main__':
# Redirect Flask logs to Gunicorn logs
gunicorn_logger = logging.getLogger('gunicorn.error')
app.logger.handlers = gunicorn_logger.handlers
app.logger.setLevel(gunicorn_logger.level)
app.logger.info('Service started...')
else:
app.run(debug=True, host='0.0.0.0', port=int(os.environ.get('PORT', 8080)))
Cloud Run развертывает контейнеры, поэтому вам нужен Dockerfile , и ваш контейнер должен быть привязан к переменной окружения 0.0.0.0 и PORT , отсюда и приведенный выше код.
При получении HTTP-запроса эта функция извлекает input из тела JSON-запроса, вызывает метод math.floor и возвращает результат вызывающей стороне.
В той же директории создайте следующий Dockerfile :
# Use an official lightweight Python image. # https://hub.docker.com/_/python FROM python:3.7-slim # Install production dependencies. RUN pip install Flask gunicorn # Copy local code to the container image. WORKDIR /app COPY . . # Run the web service on container startup. Here we use the gunicorn # webserver, with one worker process and 8 threads. # For environments with multiple CPU cores, increase the number of workers # to be equal to the cores available. CMD exec gunicorn --bind 0.0.0.0:8080 --workers 1 --threads 8 app:app
Создайте контейнер:
export SERVICE_NAME=floor
gcloud builds submit --tag gcr.io/${GOOGLE_CLOUD_PROJECT}/${SERVICE_NAME}
После сборки контейнера разверните его в Cloud Run. Обратите внимание на флаг no-allow-unauthenticated . Он гарантирует, что сервис будет принимать только аутентифицированные вызовы:
gcloud run deploy ${SERVICE_NAME} \
--image gcr.io/${GOOGLE_CLOUD_PROJECT}/${SERVICE_NAME} \
--platform managed \
--no-allow-unauthenticated
После развертывания сервис готов к работе.
9. Подключите сервис Cloud Run.
Прежде чем настраивать рабочие процессы для вызова частной службы Cloud Run, необходимо создать учетную запись службы, которую будут использовать рабочие процессы:
export SERVICE_ACCOUNT=workflows-sa
gcloud iam service-accounts create ${SERVICE_ACCOUNT}
Предоставьте учетной записи службы роль run.invoker . Это позволит учетной записи службы вызывать аутентифицированные службы Cloud Run:
gcloud projects add-iam-policy-binding ${GOOGLE_CLOUD_PROJECT} \
--member "serviceAccount:${SERVICE_ACCOUNT}@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com" \
--role "roles/run.invoker"
Обновите определение рабочего процесса в workflow.yaml , добавив службу Cloud Run. Обратите внимание, что вы также включаете поле auth , чтобы убедиться, что рабочие процессы передают токен аутентификации в своих вызовах к службе Cloud Run:
- randomgenFunction:
call: http.get
args:
url: https://<region>-<project-id>.cloudfunctions.net/randomgen
result: randomgenResult
- multiplyFunction:
call: http.post
args:
url: https://<region>-<project-id>.cloudfunctions.net/multiply
body:
input: ${randomgenResult.body.random}
result: multiplyResult
- logFunction:
call: http.get
args:
url: https://api.mathjs.org/v4/
query:
expr: ${"log(" + string(multiplyResult.body.multiplied) + ")"}
result: logResult
- floorFunction:
call: http.post
args:
url: https://floor-<random-hash>.run.app
auth:
type: OIDC
body:
input: ${logResult.body}
result: floorResult
- returnResult:
return: ${floorResult}
Обновите рабочий процесс. На этот раз передав учетную запись службы:
gcloud workflows deploy workflow \
--source=workflow.yaml \
--service-account=${SERVICE_ACCOUNT}@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com
Выполните рабочий процесс:
gcloud workflows execute workflow
Через несколько секунд вы сможете взглянуть на выполнение рабочего процесса и увидеть результат:
gcloud workflows executions describe <your-execution-id> --workflow workflow
В результате будет получено целочисленное result и state :
result: '{"body":"5","code":200 ... }
...
state: SUCCEEDED
10. Поздравляем!
Поздравляем с завершением практического занятия!
Что мы рассмотрели
- Основы рабочих процессов.
- Как связать общедоступные облачные функции с рабочими процессами.
- Как подключить частные облачные сервисы Cloud Run к рабочим процессам.
- Как подключить внешние HTTP API к рабочим процессам.