مقدمه ای بر ارکستراسیون بدون سرور با Workflows

۱. مقدمه

c9b0cc839df0bb8f.png

شما می‌توانید از Workflowها برای ایجاد گردش‌های کاری بدون سرور استفاده کنید که مجموعه‌ای از وظایف بدون سرور را به ترتیبی که شما تعریف می‌کنید، به هم پیوند می‌دهند. می‌توانید قدرت APIهای Google Cloud، محصولات بدون سرور مانند Cloud Functions و Cloud Run و فراخوانی‌های APIهای خارجی را برای ایجاد برنامه‌های بدون سرور انعطاف‌پذیر ترکیب کنید.

گردش‌های کاری نیازی به مدیریت زیرساخت ندارند و به طور یکپارچه با تقاضا، از جمله کاهش مقیاس به صفر، مقیاس‌پذیر هستند. با مدل قیمت‌گذاری پرداخت به ازای هر استفاده، شما فقط برای زمان اجرا هزینه پرداخت می‌کنید.

در این آزمایشگاه کد، شما یاد خواهید گرفت که چگونه سرویس‌های مختلف گوگل کلود و APIهای HTTP خارجی را با Workflowها متصل کنید. به طور خاص، شما دو سرویس Cloud Functions عمومی، یک سرویس Cloud Run خصوصی و یک HTTP API عمومی خارجی را به یک Workflow متصل خواهید کرد.

آنچه یاد خواهید گرفت

  • مبانی گردش‌های کاری.
  • نحوه اتصال توابع ابری عمومی با گردش‌های کاری.
  • نحوه اتصال سرویس‌های خصوصی Cloud Run به Workflows.
  • نحوه اتصال APIهای HTTP خارجی با Workflowها.

۲. تنظیمات و الزامات

تنظیم محیط خودتنظیم

  1. وارد Cloud Console شوید و یک پروژه جدید ایجاد کنید یا از یک پروژه موجود دوباره استفاده کنید. (اگر از قبل حساب Gmail یا G Suite ندارید، باید یکی ایجاد کنید .)

H_hgylo4zxOllHaAbPKJ7VyqCKPDUnDhkr-BsBIFBsrB6TYSisg6LX-uqmMhh4sXUy_hoa2Qv87C2nFmkg-QAcCiZZp0qtpf6VPaNEEfP_iqt29KVLD-gklBWugQVeOWsFnJmNjHDw

dcCPqfBIwNO4R-0fNQLUC4aYXOOZhKhjUnakFLZJGeziw2ikOxGjGkCHDwN5x5kCbPFB8fiOzZnX-GfuzQ8Ox-UU15BwHirkVPR_0RJwl0oXrhZMaJbZwH50RJwHirkVPR_0RJwl0oXrhZMaJbZwH5MGQZwZw5

jgLzVCxk93d6E2bbonzATKA4jFZReoQ-fORxZZLEi5C3D-ubnv6nL-eP-iyh7qAsWyq_nyzzuEoPFD1wFOFZOe4FWhPBJjUDncnTxTImT3Ts9TM54f4nPpsAp52O0y3Cb19IceAEgQ

شناسه پروژه را به خاطر بسپارید، یک نام منحصر به فرد در تمام پروژه‌های Google Cloud (نام بالا قبلاً گرفته شده و برای شما کار نخواهد کرد، متاسفیم!). بعداً در این آزمایشگاه کد به آن PROJECT_ID گفته خواهد شد.

  1. در مرحله بعد، برای استفاده از منابع گوگل کلود، باید پرداخت را در Cloud Console فعال کنید .

اجرای این آزمایشگاه کد، اگر اصلاً هزینه‌ای نداشته باشد، نباید هزینه زیادی داشته باشد. حتماً دستورالعمل‌های بخش «پاکسازی» را که به شما نحوه خاموش کردن منابع را آموزش می‌دهد، دنبال کنید تا پس از این آموزش، متحمل هزینه نشوید. کاربران جدید Google Cloud واجد شرایط برنامه آزمایشی رایگان ۳۰۰ دلاری هستند.

شروع پوسته ابری

اگرچه می‌توان از راه دور و از طریق لپ‌تاپ، گوگل کلود را مدیریت کرد، اما در این آزمایشگاه کد، از گوگل کلود شل ، یک محیط خط فرمان که در فضای ابری اجرا می‌شود، استفاده خواهید کرد.

از کنسول GCP روی آیکون Cloud Shell در نوار ابزار بالا سمت راست کلیک کنید:

STgwiN06Y0s_gL7i9bTed8duc9tWOIaFw0z_4QOjc-jeOmuH2TBK8l4udei56CKPloM_i1yEF6pn5Ga88eniJQoEh8cAiTH79gWUHJdKOw0oiBZfBpOdcEOl6p29i4mvPe_A6UMJBQ

آماده‌سازی و اتصال به محیط فقط چند لحظه طول می‌کشد. وقتی تمام شد، باید چیزی شبیه به این را ببینید:

r6WRHJDzL-GdB5VDxMWa67_cQxRR_x_xCG5xdt9Nilfuwe9fTGAwM9XSZbNPWvDSFtrZ7 DDecKqR5_pIq2IJJ9puAMkC3Kt4JbN9jfMX3gAwTNHNqFmqOJ-3iIX5HSePO4dNVZUkNA

این ماشین مجازی مجهز به تمام ابزارهای توسعه مورد نیاز شماست. این ماشین یک دایرکتوری خانگی دائمی ۵ گیگابایتی ارائه می‌دهد و روی فضای ابری گوگل اجرا می‌شود که عملکرد شبکه و احراز هویت را تا حد زیادی بهبود می‌بخشد. تمام کارهای شما در این آزمایشگاه را می‌توان به سادگی با یک مرورگر انجام داد.

۳. مرور کلی گردش‌های کاری

مبانی

یک گردش کار از مجموعه‌ای از مراحل تشکیل شده است که با استفاده از سینتکس مبتنی بر YAML گردش‌های کار شرح داده شده‌اند. این تعریف گردش کار است. برای توضیح دقیق سینتکس YAML گردش‌های کار، به صفحه مرجع سینتکس مراجعه کنید.

وقتی یک گردش کار ایجاد می‌شود، مستقر می‌شود که گردش کار را برای اجرا آماده می‌کند. اجرا، یک اجرای واحد از منطق موجود در تعریف گردش کار است. همه اجراهای گردش کار مستقل هستند و محصول از تعداد زیادی اجراهای همزمان پشتیبانی می‌کند.

فعال کردن سرویس‌ها

در این آزمایشگاه کد، شما توابع ابری و سرویس‌های Cloud Run را با گردش‌های کاری متصل خواهید کرد. همچنین در طول ساخت سرویس‌ها از Cloud Build و Cloud Storage استفاده خواهید کرد.

فعال کردن تمام سرویس‌های لازم:

gcloud services enable \
  cloudfunctions.googleapis.com \
  run.googleapis.com \
  workflows.googleapis.com \
  cloudbuild.googleapis.com \
  storage.googleapis.com

در مرحله بعد، دو تابع ابری را در یک گردش کار به هم متصل خواهید کرد.

۴. اولین عملکرد ابری را مستقر کنید

تابع اول یک مولد اعداد تصادفی در پایتون است.

یک دایرکتوری برای کد تابع ایجاد کنید و به آن بروید:

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 دریافت می‌کند، این تابع یک عدد تصادفی بین ۱ تا ۱۰۰ تولید می‌کند و آن را در قالب JSON به فراخواننده برمی‌گرداند.

این تابع برای پردازش HTTP به Flask متکی است و ما باید آن را به عنوان یک وابستگی اضافه کنیم. وابستگی‌ها در پایتون با 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 نمایش داده می‌شود، مشاهده کنید.

همچنین می‌توانید با دستور curl زیر به آن URL تابع دسترسی پیدا کنید:

curl $(gcloud functions describe randomgen --format='value(url)')

این تابع برای گردش کار آماده است.

۵. دومین عملکرد ابری را مستقر کنید

تابع دوم یک ضرب‌کننده است. ورودی دریافتی را در ۲ ضرب می‌کند.

یک دایرکتوری برای کد تابع ایجاد کنید و به آن بروید:

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 استخراج می‌کند، آن را در ۲ ضرب می‌کند و در قالب JSON به فراخواننده برمی‌گرداند.

همان فایل requirements.txt را در همان دایرکتوری با محتوای زیر ایجاد کنید:

flask>=1.0.2

تابع را با یک تریگر HTTP و با درخواست‌های احراز هویت نشده مجاز با این دستور مستقر کنید:

gcloud functions deploy multiply \
    --runtime python312 \
    --trigger-http \
    --allow-unauthenticated

پس از استقرار تابع، می‌توانید با دستور curl زیر به آن URL تابع نیز دسترسی پیدا کنید:

curl $(gcloud functions describe multiply --format='value(url)') \
-X POST \
-H "content-type: application/json" \
-d '{"input": 5}'

این تابع برای گردش کار آماده است.

۶. دو تابع ابری را به هم متصل کنید

در اولین گردش کار، دو تابع را به هم متصل کنید.

یک فایل 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

۷. اتصال یک HTTP API خارجی

در مرحله بعد، math.js را به عنوان یک سرویس خارجی در گردش کار متصل خواهید کرد.

در math.js ، می‌توانید عبارات ریاضی را به این صورت ارزیابی کنید:

curl https://api.mathjs.org/v4/?'expr=log(56)'

این بار، شما از Cloud Console برای به‌روزرسانی گردش کار ما استفاده خواهید کرد. Workflows در Google Cloud Console بیابید:

7608a7991b33bbb0.png

گردش کار خود را پیدا کنید و روی تب Definition کلیک کنید:

f3c8c4d3ffa49b1b.png

تعریف گردش کار را ویرایش کنید و فراخوانی 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}

اکنون گردش کار، خروجی تابع multiply را به یک فراخوانی تابع log در math.js ارسال می‌کند.

رابط کاربری شما را برای ویرایش و استقرار گردش کار راهنمایی می‌کند. پس از استقرار، برای اجرای گردش کار Execute کلیک کنید. جزئیات اجرا را مشاهده خواهید کرد:

b40c76ee43a1ce65.png

به کد وضعیت 200 و body حاوی خروجی تابع log توجه کنید.

شما همین الان یک سرویس خارجی را در گردش کار ما ادغام کردید، خیلی عالی!

۸. یک سرویس 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 env متصل شود، از این رو کد بالا را داریم.

وقتی یک درخواست 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

پس از استقرار، سرویس برای گردش کار آماده است.

۹. سرویس Cloud Run را وصل کنید

قبل از اینکه بتوانید Workflows را برای فراخوانی سرویس خصوصی Cloud Run پیکربندی کنید، باید یک حساب کاربری سرویس برای استفاده از Workflows ایجاد کنید:

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 نیز اضافه می‌کنید تا مطمئن شوید Workflows در فراخوانی‌های خود به سرویس 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}

گردش کار را به‌روزرسانی کنید. این بار service-account را وارد کنید:

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

۱۰. تبریک می‌گویم!

تبریک می‌گویم که آزمایشگاه کد را تمام کردی.

آنچه ما پوشش داده‌ایم

  • مبانی گردش‌های کاری.
  • نحوه اتصال توابع ابری عمومی با گردش‌های کاری.
  • نحوه اتصال سرویس‌های خصوصی Cloud Run به Workflows.
  • نحوه اتصال APIهای HTTP خارجی با Workflowها.