Cloud Run 및 Cloud Run 함수에서 Workflows 사용 튜토리얼

이 튜토리얼에서는 Workflows를 사용하여 일련의 서비스를 함께 연결하는 방법을 보여줍니다. Cloud Run Functions를 사용하는 두 공개 HTTP 서비스, 외부 REST API, 비공개 Cloud Run 서비스를 연결하면 유연한 서버리스 애플리케이션을 만들 수 있습니다.

첫 번째 Cloud Run 함수 배포

HTTP 요청을 수신하면 이 HTTP 함수가 1에서 100 사이의 난수를 생성한 후 숫자를 JSON 형식으로 반환합니다.

  1. randomgen이라는 디렉터리를 만들어 변경합니다.

    mkdir ~/randomgen
    cd ~/randomgen
  2. 다음 Python 코드가 포함된 main.py라는 파일 이름의 텍스트 파일을 만듭니다.

    import functions_framework
    import random
    from flask import jsonify
    
    
    @functions_framework.http
    def randomgen(request):
        randomNum = random.randint(1, 100)
        output = {"random": randomNum}
        return jsonify(output)
  3. HTTP 처리를 위해 Flask에 대한 종속 항목을 지원하려면 pip 패키지 관리자용 텍스트 파일을 만듭니다. 파일 이름을 requirements.txt로 지정하고 다음을 추가합니다.

    flask>=1.0.2
    functions-framework==3.0.0
  4. HTTP 트리거를 사용하여 함수를 배포하고 인증되지 않은 액세스를 허용합니다.

    gcloud functions deploy randomgen-function \
        --gen2 \
        --runtime python310 \
        --entry-point=randomgen \
        --trigger-http \
        --allow-unauthenticated

    함수를 배포하는 데 몇 분 정도 걸릴 수 있습니다. 또는 Google Cloud 콘솔에서 Cloud Run Functions 인터페이스를 사용하여 함수를 배포할 수 있습니다.

  5. randomgen 함수가 배포되면 httpsTrigger.url 속성을 확인할 수 있습니다.

    gcloud functions describe randomgen-function \
        --gen2 \
        --format="value(serviceConfig.uri)"
  6. URL을 저장합니다. 이후 실습에서 워크플로 소스 파일에 추가해야 합니다.

  7. 다음 curl 명령어를 통해 함수를 사용해 볼 수 있습니다.

    curl $(gcloud functions describe randomgen-function \
        --gen2 \
        --format="value(serviceConfig.uri)")

    숫자가 무작위로 생성되어 반환됩니다.

두 번째 Cloud Run 함수 배포

HTTP 요청을 수신하면 이 HTTP 함수가 JSON 본문에서 input을 추출하여 2를 곱한 후 결과를 JSON 형식으로 반환합니다.

  1. 홈 디렉터리로 다시 이동합니다.

    cd ~
  2. multiply라는 디렉터리를 만들어 변경합니다.

    mkdir ~/multiply
    cd ~/multiply
  3. 다음 Python 코드가 포함된 main.py라는 파일 이름의 텍스트 파일을 만듭니다.

    import functions_framework
    from flask import jsonify
    
    
    @functions_framework.http
    def multiply(request):
        request_json = request.get_json()
        output = {"multiplied": 2 * request_json['input']}
        return jsonify(output)
  4. HTTP 처리를 위해 Flask에 대한 종속 항목을 지원하려면 pip 패키지 관리자용 텍스트 파일을 만듭니다. 파일 이름을 requirements.txt로 지정하고 다음을 추가합니다.

    flask>=1.0.2
    functions-framework==3.0.0
  5. HTTP 트리거를 사용하여 함수를 배포하고 인증되지 않은 액세스를 허용합니다.

    gcloud functions deploy multiply-function \
        --gen2 \
        --runtime python310 \
        --entry-point=multiply \
        --trigger-http \
        --allow-unauthenticated

    함수를 배포하는 데 몇 분 정도 걸릴 수 있습니다. 또는 Google Cloud 콘솔에서 Cloud Run Functions 인터페이스를 사용하여 함수를 배포할 수 있습니다.

  6. multiply 함수가 배포되면 httpsTrigger.url 속성을 확인할 수 있습니다.

    gcloud functions describe multiply-function \
        --gen2\
        --format="value(serviceConfig.uri)"
  7. URL을 저장합니다. 이후 실습에서 워크플로 소스 파일에 추가해야 합니다.

  8. 다음 curl 명령어를 통해 함수를 사용해 볼 수 있습니다.

    curl -X POST MULTIPLY_FUNCTION_URL \
        -H "Authorization: Bearer $(gcloud auth print-identity-token)" \
        -H "Content-Type: application/json" \
        -d '{"input": 5}'

    숫자 10이 반환되어야 합니다.

워크플로에서 두 Cloud Run 함수 서비스 연결

워크플로 정의는 YAML 또는 JSON 형식으로 작성할 수 있는 Workflows 구문을 사용하여 기술되는 일련의 단계들로 구성됩니다. 이것이 워크플로의 정의입니다. 자세한 내용은 구문 참조 페이지를 참조하세요.

  1. 홈 디렉터리로 다시 이동합니다.

    cd ~
  2. 다음 콘텐츠를 포함하며 파일 이름이 workflow.yaml인 텍스트 파일을 만듭니다.

    - randomgen_function:
        call: http.get
        args:
            url: RANDOMGEN_FUNCTION_URL
        result: randomgen_result
    - multiply_function:
        call: http.post
        args:
            url: MULTIPLY_FUNCTION_URL
            body:
                input: ${randomgen_result.body.random}
        result: multiply_result
    - return_result:
        return: ${multiply_result}
    

    이 소스 파일에서는 두 HTTP 함수가 함께 연결되어 최종 결과가 반환됩니다.

  3. 워크플로를 만들면 배포할 수 있으므로 실행이 가능합니다.

    gcloud workflows deploy WORKFLOW_NAME \
        --source=workflow.yaml \
        --service-account=${SERVICE_ACCOUNT}@PROJECT_ID.iam.gserviceaccount.com

    WORKFLOW_NAME을 워크플로의 이름으로 바꿉니다.

  4. 워크플로를 실행합니다.

    gcloud workflows run WORKFLOW_NAME

    실행은 워크플로 정의에 포함된 논리의 단일 실행을 의미합니다. 모든 워크플로 실행은 독립적이며 Workflows의 빠른 확장 덕분에 다수의 동시 실행이 가능합니다.

    워크플로가 실행되면 다음과 유사한 결과가 출력됩니다.

    result: '{"body":{"multiplied":120},"code":200,"headers":{"Alt-Svc":"h3-29=\":443\";
    ...
    startTime: '2021-05-05T14:17:39.135251700Z'
    state: SUCCEEDED
    ...
    

워크플로에서 공개 REST 서비스 연결

기존 워크플로를 업데이트하고 수학 표현식을 평가할 수 있는 공개 REST API(math.js)를 연결합니다. 예를 들면 curl https://api.mathjs.org/v4/?'expr=log(56)'입니다.

워크플로를 배포했으므로 Google Cloud 콘솔의 Workflows 페이지를 통해 워크플로를 수정할 수도 있습니다.

  1. 워크플로의 소스 파일을 수정하여 다음 콘텐츠로 바꿉니다.

    - randomgen_function:
        call: http.get
        args:
            url: RANDOMGEN_FUNCTION_URL
        result: randomgen_result
    - multiply_function:
        call: http.post
        args:
            url: MULTIPLY_FUNCTION_URL
            body:
                input: ${randomgen_result.body.random}
        result: multiply_result
    - log_function:
        call: http.get
        args:
            url: https://api.mathjs.org/v4/
            query:
                expr: ${"log(" + string(multiply_result.body.multiplied) + ")"}
        result: log_result
    - return_result:
        return: ${log_result}
    

    이렇게 하면 외부 REST 서비스가 Cloud Run 함수에 연결되어 최종 결과가 반환됩니다.

  2. 수정된 워크플로를 배포합니다.

    gcloud workflows deploy WORKFLOW_NAME \
        --source=workflow.yaml \
        --service-account=${SERVICE_ACCOUNT}@PROJECT_ID.iam.gserviceaccount.com

Cloud Run 서비스 배포

HTTP 요청을 수신하면 JSON 본문에서 input을 추출하고 math.floor를 계산하여 결과를 반환하는 Cloud Run 서비스를 배포합니다.

  1. floor라는 디렉터리를 만들어 변경합니다.

    mkdir ~/floor
    cd ~/floor
  2. 다음 Python 코드가 포함된 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)))

  3. 같은 디렉터리에서 다음 콘텐츠로 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

  4. Docker 컨테이너 이미지를 저장할 수 있는 Artifact Registry 표준 저장소를 만듭니다.

    gcloud artifacts repositories create REPOSITORY \
        --repository-format=docker \
        --location=${REGION}

    REPOSITORY를 저장소의 고유한 이름으로 바꿉니다.

  5. 컨테이너 이미지를 빌드합니다.

    export SERVICE_NAME=floor
    gcloud builds submit --tag ${REGION}-docker.pkg.dev/PROJECT_ID/REPOSITORY/${SERVICE_NAME}
  6. Cloud Run에 컨테이너 이미지를 배포하여 인증된 호출만 수락하도록 합니다.

    gcloud run deploy ${SERVICE_NAME} \
        --image ${REGION}-docker.pkg.dev/PROJECT_ID/REPOSITORY/${SERVICE_NAME}:latest \
        --no-allow-unauthenticated

서비스 URL이 표시되면 배포가 완료된 것입니다. 워크플로 정의를 업데이트하는 경우 해당 URL을 지정해야 합니다.

워크플로에서 Cloud Run 서비스 연결

기존 워크플로를 업데이트하고 Cloud Run 서비스의 URL을 지정합니다.

  1. 홈 디렉터리로 다시 이동합니다.

    cd ~
  2. 워크플로의 소스 파일을 수정하여 다음 콘텐츠로 바꿉니다.

    - randomgen_function:
        call: http.get
        args:
            url: RANDOMGEN_FUNCTION_URL
        result: randomgen_result
    - multiply_function:
        call: http.post
        args:
            url: MULTIPLY_FUNCTION_URL
            body:
                input: ${randomgen_result.body.random}
        result: multiply_result
    - log_function:
        call: http.get
        args:
            url: https://api.mathjs.org/v4/
            query:
                expr: ${"log(" + string(multiply_result.body.multiplied) + ")"}
        result: log_result
    - floor_function:
        call: http.post
        args:
            url: CLOUD_RUN_SERVICE_URL
            auth:
                type: OIDC
            body:
                input: ${log_result.body}
        result: floor_result
    - create_output_map:
        assign:
          - outputMap:
              randomResult: ${randomgen_result}
              multiplyResult: ${multiply_result}
              logResult: ${log_result}
              floorResult: ${floor_result}
    - return_output:
        return: ${outputMap}
    
    • RANDOMGEN_FUNCTION_URLrandomgen 함수의 URL로 바꿉니다.
    • MULTIPLY_FUNCTION_URLmultiply 함수의 URL로 바꿉니다.
    • CLOUD_RUN_SERVICE_URL을 Cloud Run 서비스 URL로 바꿉니다.

    그러면 워크플로의 Cloud Run 서비스가 연결됩니다. auth 키는 Cloud Run 서비스 호출 시 인증 토큰이 전달되도록 합니다. 자세한 내용은 워크플로에서 인증된 요청 수행을 참조하세요.

  3. 수정된 워크플로를 배포합니다.

    gcloud workflows deploy WORKFLOW_NAME \
        --source=workflow.yaml \
        --service-account=${SERVICE_ACCOUNT}@PROJECT_ID.iam.gserviceaccount.com
  4. 최종 워크플로를 실행합니다.

    gcloud workflows run WORKFLOW_NAME

    출력은 다음과 비슷하게 표시됩니다.

    result: '{"floorResult":{"body":"4","code":200
      ...
      "logResult":{"body":"4.02535169073515","code":200
      ...
      "multiplyResult":{"body":{"multiplied":56},"code":200
      ...
      "randomResult":{"body":{"random":28},"code":200
      ...
    startTime: '2023-11-13T21:22:56.782669001Z'
    state: SUCCEEDED
    

수고하셨습니다. 일련의 서비스를 연결하는 워크플로를 배포하고 실행했습니다.

표현식, 조건부 건너뛰기, Base64 인코딩 또는 디코딩, 하위 워크플로 등을 사용하는 더 복잡한 워크플로를 만들려면 워크플로 구문 참조표준 라이브러리 개요를 참조하세요.