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

1. مقدمه

c9b0cc839df0bb8f.png

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

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

در این کد لبه، نحوه اتصال سرویس های مختلف Google Cloud و API های HTTP خارجی با Workflows را یاد خواهید گرفت. به طور خاص، شما دو سرویس عمومی Cloud Function، یک سرویس Cloud Run خصوصی و یک API عمومی HTTP خارجی را به یک گردش کار متصل خواهید کرد.

چیزی که یاد خواهید گرفت

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

2. راه اندازی و الزامات

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

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

H_hgylo4zxOllHaAbPKJ7VyqCKPDUnDhkr-BsBIFBsrB6TYSisg6LX-uqmMhh4sXUy_hoa2Qv87C2nFmkg-QAcCiZZp0qtpf6VPaNEEfP_iqt29KWs

dcCPqfBIwNO4R-0fNQLUC4aYXOOZhKhjUnakFLZJGeziw2ikOxGjGkCHDwN5x5kCbPFB8fiOzZnX-GfuzQ8Ox-UU15BwHirkVPR_0RJwl0oXrhZMaJbZwH50RJwHirkVPR_0RJwl0oXrhZMaJbZwH5MGQZwZw5

jgLzVCxk93d6E2bbonzATKA4jFZReoQ-forxZZLEi5C3D-ubnv6nL-eP-iyh7qAsWyq_nyzzuEoPFD1wFOFZOe4FWhPBJjUDncnTxTImT4p5EC29Ts

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

  1. در مرحله بعد، برای استفاده از منابع Google Cloud، باید صورت‌حساب را در Cloud Console فعال کنید .

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

Cloud Shell را راه اندازی کنید

در حالی که Google Cloud را می توان از راه دور از لپ تاپ شما کار کرد، در این کد لبه از Google Cloud Shell استفاده خواهید کرد، یک محیط خط فرمان که در Cloud اجرا می شود.

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

STgwiN06Y0s_gL7i9bTed8duc9tWOIaFw0z_4QOjc-jeOmuH2TBK8l4udei56CKPLoM_i1yEF6pn5Ga88eniJQoEh8cAiTH79gWUHJdKOw0vOdP2QEiF

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

r6WRHJDzL-GdB5VDxMWa67_cQxRR_x_xCG5xdt9Nilfuwe9fTGAwM9XSZbNPWvDSFtrZ7DDecKqR5_pIq2IJJ9puAMkC3Kt4JbN9jfMIXOVSQe UkNA

این ماشین مجازی با تمام ابزارهای توسعه که شما نیاز دارید بارگذاری شده است. این یک فهرست اصلی 5 گیگابایتی دائمی را ارائه می دهد و در Google Cloud اجرا می شود و عملکرد و احراز هویت شبکه را تا حد زیادی افزایش می دهد. تمام کارهای شما در این آزمایشگاه به سادگی با یک مرورگر قابل انجام است.

3. بررسی اجمالی گردش کار

مبانی

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

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

فعال کردن خدمات

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

فعال کردن تمام خدمات لازم:

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

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

4. اولین تابع Cloud را اجرا کنید

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

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

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 به تماس گیرنده برمی گردد.

این تابع برای پردازش HTTP به Flask متکی است و ما باید آن را به عنوان یک وابستگی اضافه کنیم. وابستگی ها در پایتون با پیپ مدیریت می شوند و در یک فایل ابرداده به نام requirements.txt بیان می شوند.

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

flask>=1.0.2

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

gcloud functions deploy randomgen \
    --runtime python37 \
    --trigger-http \
    --allow-unauthenticated

پس از استقرار تابع، می‌توانید URL تابع را تحت خاصیت httpsTrigger.url مشاهده کنید که در کنسول نمایش داده می‌شود یا با دستور gcloud functions describe نمایش داده می‌شود.

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

curl $(gcloud functions describe randomgen --format='value(httpsTrigger.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 python37 \
    --trigger-http \
    --allow-unauthenticated

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

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

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

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

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

یک فایل 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. یک API HTTP خارجی وصل کنید

بعد، 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}

گردش کار اکنون خروجی تابع ضرب را به یک فراخوانی تابع log در math.js تغذیه می کند.

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

b40c76ee43a1ce65.png

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

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

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 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

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

9. سرویس 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}

گردش کار را به روز کنید. این زمان در حساب سرویس می گذرد:

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 با Workflows.
  • نحوه اتصال سرویس های خصوصی Cloud Run با Workflows.
  • نحوه اتصال APIهای HTTP خارجی با Workflows.