Workflows를 사용한 서버리스 조정 소개

1. 소개

c9b0cc839df0bb8f.png

워크플로를 사용하여 일련의 서버리스 작업을 사용자가 정의한 순서대로 연결하는 서버리스 워크플로를 만들 수 있습니다. Google Cloud의 API, Cloud Functions 및 Cloud Run과 같은 서버리스 제품, 외부 API 호출을 결합하여 유연한 서버리스 애플리케이션을 만들 수 있습니다.

워크플로에는 인프라 관리가 필요하지 않으며 0으로 축소하는 등 수요에 따라 원활하게 확장됩니다. 종량제 요금 가격 책정 모델을 적용하여 실행 시간에 대해서만 비용을 지불하면 됩니다.

이 Codelab에서는 Workflows를 사용하여 다양한 Google Cloud 서비스와 외부 HTTP API를 연결하는 방법을 알아봅니다. 더 구체적으로 설명하자면, 2개의 퍼블릭 Cloud Functions 서비스, 즉 비공개 Cloud Run 서비스와 외부 공개 HTTP API를 워크플로에 연결합니다.

학습할 내용

  • Workflows의 기본사항
  • 공개 Cloud Functions를 Workflows와 연결하는 방법을 설명합니다.
  • Workflows에 비공개 Cloud Run 서비스를 연결하는 방법을 설명합니다.
  • Workflows에 외부 HTTP API를 연결하는 방법을 설명합니다.

2. 설정 및 요구사항

자습형 환경 설정

  1. Cloud Console에 로그인하고 새 프로젝트를 만들거나 기존 프로젝트를 다시 사용합니다. (Gmail 또는 G Suite 계정이 없으면 만들어야 합니다.)

H_hgylo4zxOllHaAbPKJ7VyqCKPDUnDhkr-BsBIFBsrB6TYSisg6LX-uqmMhh4sXUy_hoa2Qv87C2nFmkg-QAcCiZZp0qtpf6VPaNEEfP_iqt29KVLD-gklBWugQVeOWsFnJmNjHDw

dcCPqfBIwNO4R-0fNQLUC4aYXOOZhKhjUnakFLZJGeziw2ikOxGjGkCHDwN5x5kCbPFB8fiOzZnX-GfuzQ8Ox-UU15BwHirkVPR_0RJwl0oXrhqZmMIvZMa_uwHugBJIdx5-bZ6Z8Q

jgLzVCxk93d6E2bbonzATKA4jFZReoQ-fORxZZLEi5C3D-ubnv6nL-eP-iyh7qAsWyq_nyzzuEoPFD1wFOFZOe4FWhPBJjUDncnTxTImT3Ts9TM54f4nPpsAp52O0y3Cb19IceAEgQ

모든 Google Cloud 프로젝트에서 고유한 이름인 프로젝트 ID를 기억하세요(위의 이름은 이미 사용되었으므로 사용할 수 없습니다). 이 ID는 나중에 이 Codelab에서 PROJECT_ID라고 부릅니다.

  1. 그런 후 Google Cloud 리소스를 사용할 수 있도록 Cloud Console에서 결제를 사용 설정해야 합니다.

이 Codelab 실행에는 많은 비용이 들지 않습니다. 이 가이드를 마친 후 비용이 결제되지 않도록 리소스 종료 방법을 알려주는 '삭제' 섹션의 안내를 따르세요. Google Cloud 새 사용자에게는 $300USD 상당의 무료 체험판 프로그램 참여 자격이 부여됩니다.

Cloud Shell 시작

Google Cloud를 노트북에서 원격으로 실행할 수 있지만, 이 Codelab에서는 Cloud에서 실행되는 명령줄 환경인 Google Cloud Shell을 사용합니다.

GCP 콘솔에서 오른쪽 상단 툴바의 Cloud Shell 아이콘을 클릭합니다.

STgwiN06Y0s_gL7i9bTed8duc9tWOIaFw0z_4QOjc-jeOmuH2TBK8l4udei56CKPLoM_i1yEF6pn5Ga88eniJQoEh8cAiTH79gWUHJdKOw0oiBZfBpOdcEOl6p29i4mvPe_A6UMJBQ

환경을 프로비저닝하고 연결하는 데 몇 분 정도 소요됩니다. 완료되면 다음과 같이 표시됩니다.

r6WRHJDzL-GdB5VDxMWa67_cQxRR_x_xCG5xdt9Nilfuwe9fTGAwM9XSZbNPWvDSFtrZ7DDecKqR5_pIq2IJJ9puAMkC3Kt4JbN9jfMX3gAwTNHNqFmqOJ-3iIX5HSePO4dNVZUkNA

가상 머신에는 필요한 개발 도구가 모두 들어있습니다. 영구적인 5GB 홈 디렉토리를 제공하고 Google Cloud에서 실행되므로 네트워크 성능과 인증이 크게 개선됩니다. 이 실습의 모든 작업은 브라우저만으로 수행할 수 있습니다.

3. Workflows 개요

기본사항

워크플로는 Workflows YAML 기반 구문을 사용하여 설명된 일련의 단계로 구성됩니다. 이것이 워크플로의 정의입니다. Workflows YAML 구문에 대한 자세한 설명은 구문 참조 페이지를 참조하세요.

워크플로가 생성되면 배포되어 워크플로를 실행할 수 있도록 준비됩니다. 실행은 워크플로 정의에 포함된 논리의 단일 실행을 의미합니다. 모든 워크플로 실행은 독립적이며 제품이 많은 수의 동시 실행을 지원합니다.

서비스 사용 설정

이 Codelab에서는 Cloud Run 서비스인 Cloud Functions를 Workflows와 연결합니다. 서비스를 빌드하는 동안에도 Cloud Build 및 Cloud Storage를 사용하게 됩니다.

필요한 모든 서비스를 사용 설정합니다.

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

다음 단계에서는 워크플로에서 두 개의 Cloud Functions를 함께 연결합니다.

4. 첫 번째 Cloud 함수 배포

첫 번째 함수는 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 형식으로 호출자에게 반환합니다.

이 함수는 HTTP 처리를 위해 Flask를 사용하므로 이를 종속 항목으로 추가해야 합니다. Python의 종속 항목은 pip로 관리되며 requirements.txt라는 메타데이터 파일로 표현됩니다.

동일한 디렉터리에 다음 콘텐츠가 포함된 requirements.txt 파일을 만듭니다.

flask>=1.0.2

HTTP 트리거와 다음 명령어로 허용되는 인증되지 않은 요청을 사용하여 함수를 배포합니다.

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

함수가 배포되면 콘솔에 표시되거나 gcloud functions describe 명령어를 사용하여 httpsTrigger.url 속성에서 함수의 URL을 확인할 수 있습니다.

다음 curl 명령어를 사용하여 함수의 URL을 방문할 수도 있습니다.

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

이제 함수를 워크플로에서 사용할 수 있습니다.

5. 두 번째 Cloud 함수 배포

두 번째 함수는 승수입니다. 수신된 입력에 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 요청을 수신하면 JSON 본문에서 input를 추출하여 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 Functions 연결

첫 번째 워크플로에서 두 함수를 함께 연결합니다.

다음 콘텐츠로 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

워크플로가 실행되면 이전 단계에서 제공된 실행 ID를 전달하여 결과를 볼 수 있습니다.

gcloud workflows executions describe <your-execution-id> --workflow workflow

출력에는 resultstate가 포함됩니다.

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 콘솔을 사용해 워크플로를 업데이트합니다. Google Cloud 콘솔에서 Workflows를 찾습니다.

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}

이제 워크플로는 곱하기 함수의 출력을 math.js의 로그 함수 호출에 제공합니다.

UI에서 워크플로를 수정하고 배포하는 방법을 안내합니다. 배포되면 Execute를 클릭하여 워크플로를 실행합니다. 실행 세부정보가 표시됩니다.

b40c76ee43a1ce65.png

상태 코드 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.0PORT env 변수에 결합되어야 하므로 위의 코드를 사용해야 합니다.

이 함수는 HTTP 요청을 수신하면 JSON 본문에서 input를 추출하고 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 서비스를 호출하도록 Workflows를 구성하려면 먼저 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"

Cloud Run 서비스를 포함하도록 workflow.yaml의 워크플로 정의를 업데이트합니다. Workflows가 Cloud Run 서비스 호출에 인증 토큰을 전달하도록 auth 필드도 포함하는 방법을 확인합니다.

- 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

출력에는 정수 resultstate가 포함됩니다.

result: '{"body":"5","code":200 ... } 

...
state: SUCCEEDED

10. 축하합니다.

축하합니다. Codelab을 완료했습니다.

학습한 내용

  • Workflows의 기본사항
  • 공개 Cloud Functions를 Workflows와 연결하는 방법을 설명합니다.
  • Workflows에 비공개 Cloud Run 서비스를 연결하는 방법을 설명합니다.
  • Workflows에 외부 HTTP API를 연결하는 방법을 설명합니다.