1. 소개
워크플로를 사용하여 일련의 서버리스 작업을 사용자가 정의한 순서대로 연결하는 서버리스 워크플로를 만들 수 있습니다. 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. 설정 및 요구사항
자습형 환경 설정
- Cloud Console에 로그인하고 새 프로젝트를 만들거나 기존 프로젝트를 다시 사용합니다. (Gmail 또는 G Suite 계정이 없으면 만들어야 합니다.)
모든 Google Cloud 프로젝트에서 고유한 이름인 프로젝트 ID를 기억하세요(위의 이름은 이미 사용되었으므로 사용할 수 없습니다). 이 ID는 나중에 이 Codelab에서 PROJECT_ID
라고 부릅니다.
- 그런 후 Google Cloud 리소스를 사용할 수 있도록 Cloud Console에서 결제를 사용 설정해야 합니다.
이 Codelab 실행에는 많은 비용이 들지 않습니다. 이 가이드를 마친 후 비용이 결제되지 않도록 리소스 종료 방법을 알려주는 '삭제' 섹션의 안내를 따르세요. Google Cloud 새 사용자에게는 $300USD 상당의 무료 체험판 프로그램 참여 자격이 부여됩니다.
Cloud Shell 시작
Google Cloud를 노트북에서 원격으로 실행할 수 있지만, 이 Codelab에서는 Cloud에서 실행되는 명령줄 환경인 Google Cloud Shell을 사용합니다.
GCP 콘솔에서 오른쪽 상단 툴바의 Cloud Shell 아이콘을 클릭합니다.
환경을 프로비저닝하고 연결하는 데 몇 분 정도 소요됩니다. 완료되면 다음과 같이 표시됩니다.
가상 머신에는 필요한 개발 도구가 모두 들어있습니다. 영구적인 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
출력에는 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 콘솔을 사용해 워크플로를 업데이트합니다. Google Cloud 콘솔에서 Workflows
를 찾습니다.
워크플로를 찾아 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
의 로그 함수 호출에 제공합니다.
UI에서 워크플로를 수정하고 배포하는 방법을 안내합니다. 배포되면 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
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
출력에는 정수 result
및 state
가 포함됩니다.
result: '{"body":"5","code":200 ... } ... state: SUCCEEDED
10. 축하합니다.
축하합니다. Codelab을 완료했습니다.
학습한 내용
- Workflows의 기본사항
- 공개 Cloud Functions를 Workflows와 연결하는 방법을 설명합니다.
- Workflows에 비공개 Cloud Run 서비스를 연결하는 방법을 설명합니다.
- Workflows에 외부 HTTP API를 연결하는 방법을 설명합니다.