Cloud Run Functions 실행 환경

Cloud Run Functions는 Google에서 인프라, 운영체제, 런타임 환경을 처리하는 완전 관리형 서버리스 환경에서 실행됩니다. 각 함수는 고유한 분리된 보안 실행 컨텍스트에서 실행되고 자동으로 확장되며 다른 함수와 독립된 수명 주기를 갖습니다.

런타임

Cloud Run Functions에서 지원하는 언어 런타임은 다음과 같습니다. 각 항목에는 표준 시스템 패키지와 해당 언어에 필요한 도구 및 라이브러리가 포함되어 있습니다. 명령줄에서 또는 Terraform을 통해 함수를 배포하는 경우 런타임 ID 값이 필요합니다.

보안 및 유지보수 업데이트는 모든 Cloud Run Functions 및 Cloud Run Functions(1세대) 실행 환경에서 사용할 수 있습니다. 이러한 업데이트는 환경과 구성 방법에 따라 자동 또는 수동으로 적용됩니다. 실행 환경 업데이트에 대한 자세한 내용은 Cloud Run Functions 보호를 참조하세요.

런타임 이미지는 Artifact Registry를 사용할 수 있는 모든 리전에서 호스팅됩니다. URI의 첫 번째 부분을 원하는 리전으로 바꾸면 런타임 이미지 경로를 맞춤설정할 수 있습니다.

REGION-docker.pkg.dev/serverless-runtimes/STACK/runtimes/RUNTIME_ID

다음과 같이 바꿉니다.

  • REGION을 선호하는 리전으로 바꿉니다(예: us-central1).
  • STACK을 선호하는 운영체제 스택으로 바꿉니다(예: google-22-full).
  • RUNTIME_ID를 함수에서 사용하는 런타임 ID로 바꿉니다(예: python310).

예를 들어 us-central1에 호스팅되고 google-22-full 스택을 사용하는 최신 Node.js 20 기본 이미지는 다음 URL로 참조됩니다. us-central1-docker.pkg.dev/serverless-runtimes/google-22-full/runtimes/nodejs22

Node.js

런타임 생성 런타임 ID 스택 런타임 기본 이미지
Node.js 22 Run Functions nodejs22 google-22-full google-22-full/nodejs22
Node.js 20 1세대, Run Functions nodejs20 google-22-full google-22-full/nodejs20
Node.js 18 1세대, Run Functions nodejs18 google-22-full google-22-full/nodejs18
Node.js 16 1세대, Run Functions nodejs16 google-18-full google-18-full/nodjes16
Node.js 14 1세대, Run Functions nodejs14 google-18-full google-18-full/nodjes14
Node.js 12 1세대, Run Functions nodejs12 google-18-full google-18-full/nodjes14
Node.js 10 1세대, Run Functions nodejs10 google-18-full google-18-full/nodjes10
Node.js 8 1세대, Run Functions nodejs8 사용 중단됨 사용 중단됨
Node.js 6 1세대, Run Functions nodejs6 사용 중단됨 사용 중단됨

Python

런타임 생성 런타임 ID 스택 런타임 기본 이미지
Python 3.12 1세대, Run Functions python312 google-22-full google-22-full/python312
Python 3.11 1세대, Run Functions python311 google-22-full google-22-full/python311
Python 3.10 1세대, Run Functions python310 google-22-full google-22-full/python310
Python 3.9 1세대, Run Functions python39 google-18-full google-18-full/python39
Python 3.8 1세대, Run Functions python38 google-18-full google-18-full/python38
Python 3.7 1세대, Run Functions python37 google-18-full google-18-full/python37

Go

런타임 생성 런타임 ID 스택 런타임 기본 이미지
Go 1.23
(미리보기 전용)
Run Functions go123 google-22-full google-22-full/go123
Go 1.22 Run Functions go122 google-22-full google-22-full/go122
Go 1.21 Run Functions go121 google-22-full google-22-full/go121
Go 1.20 Run Functions go120 google-22-full google-22-full/go120
Go 1.19 1세대, Run Functions go119 google-22-full google-22-full/go119
Go 1.18 1세대, Run Functions go118 google-22-full google-22-full/go120
Go 1.16 1세대, Run Functions go116 google-18-full google-18-full/go116
Go 1.13 1세대, Run Functions go113 google-18-full google-18-full/go113
Go 1.11 1세대, Run Functions go111 사용 중단됨 사용 중단됨

Java

런타임 생성 런타임 ID 스택 런타임 기본 이미지
자바 21 Run Functions java21 google-22-full google-22-full/java21
자바 17 1세대, Run Functions java17 google-22-full google-22-full/java17
자바 11 1세대, Run Functions java11 google-18 google-18/java11

Ruby

런타임 생성 런타임 ID 스택 런타임 기본 이미지
Ruby 3.3 1세대, Run Functions ruby33 google-22-full google-22-full/ruby33
Ruby 3.2 1세대, Run Functions ruby32 google-22-full google-22-full/ruby32
Ruby 3.0 1세대, Run Functions ruby30 google-18-full google-18-full/ruby30
Ruby 2.7 1세대, Run Functions ruby27 google-18-full google-18-full/ruby27
Ruby 2.6 1세대, Run Functions ruby26 google-18-full google-18-full/ruby26

PHP

런타임 생성 런타임 ID 스택 런타임 기본 이미지
PHP 8.3 Run Functions php83 google-22-full google-22-full/php83
PHP 8.2 1세대, Run Functions php82 google-22-full google-22-full/php82
PHP 8.1 1세대, Run Functions php81 google-18-full google-18-full/php81
PHP 7.4 1세대, Run Functions php74 google-18-full google-18-full/php74

.NET Core

런타임 생성 런타임 ID 스택 런타임 기본 이미지
.NET Core 8 Run Functions dotnet8 google-22-full google-22-full/dotnet8
.NET Core 6 1세대, Run Functions dotnet6 google-22-full google-22-full/dotnet6
.NET Core 3 1세대, Run Functions dotnet3 google-18-full google-18-full/dotnet3

자동 확장 동작

Cloud Run Functions는 서버리스 패러다임을 구현합니다. 즉 서버 또는 가상 머신과 같은 기반 인프라에 대한 걱정 없이 코드를 실행할 수 있습니다. 배포된 함수는 자동으로 관리되고 확장됩니다.

Cloud Run Functions는 수신받은 요청을 함수의 instances에 할당하여 처리합니다. 요청의 양과 기존 함수 인스턴스의 개수에 따라 Cloud Run Functions는 기존 인스턴스에 요청을 할당하거나 새 인스턴스를 만들 수 있습니다.

인바운드 요청의 양이 기존 인스턴스의 개수를 초과하는 경우 Cloud Run Functions는 여러 개의 새로운 인스턴스를 시작하여 요청을 처리할 수 있습니다. 이러한 자동 확장을 통해 Cloud Run Functions는 함수의 다른 인스턴스를 사용하여 여러 요청을 동시에 처리할 수 있습니다.

무제한으로 확장하는 것이 바람직하지 않을 수도 있습니다. 이를 해결하려면 Cloud Run Functions를 사용해 특정 함수에 특정 시점에 공존할 수 있는 최대 인스턴스 수를 구성할 수 있습니다.

스테이트리스(Stateless)

함수의 자동 관리 및 확장을 사용 설정하려면 함수가 스테이트리스(Stateless)여야 합니다. 즉 하나의 함수 호출은 이전 호출에서 설정한 인메모리 상태에 의존해서는 안 됩니다. 전역 변수, 메모리, 파일 시스템 또는 다른 상태를 공유하지 않는 여러 함수 인스턴스에서 호출을 처리할 수도 있습니다.

함수 호출 전반에서 상태를 공유해야 하는 경우 함수는 Memorystore, Datastore, Firestore, Cloud Storage 같은 서비스를 사용하여 데이터를 유지해야 합니다. Google Cloud에서 제공하는 데이터베이스 및 스토리지 옵션에 대한 상세 설명은 Google Cloud 데이터베이스Google Cloud Storage 제품을 참조하세요.

동시 실행

Cloud Run Functions

Cloud Run Functions는 단일 함수 인스턴스에서 동시 요청 여러 개를 처리할 수 있습니다. 이는 이미 준비된 인스턴스가 동시에 요청 여러 개를 처리하여 전체 지연 시간이 단축될 수 있으므로 콜드 스타트를 방지하는 데 유용합니다. 자세한 내용은 동시 실행을 참조하세요.

Cloud Run Functions(1세대)

Cloud Run Functions(1세대)에서 함수의 각 인스턴스는 한 번에 하나의 동시 요청만을 처리합니다. 즉, 코드가 요청을 처리하는 동안에는 다른 요청이 동일한 인스턴스로 라우팅되지 않습니다. 따라서 원래 요청이 사용자가 할당한 전체 리소스(메모리 및 CPU)를 사용할 수 있습니다.

Cloud Run Functions(1세대)의 동시 요청은 서로 다른 함수 인스턴스에 의해 처리되므로 변수 또는 로컬 메모리를 공유하지 않습니다. 자세한 내용은 스테이트리스(Stateless)함수 인스턴스 수명을 참조하세요.

콜드 스타트

다음 두 가지 경우 새로운 함수 인스턴스가 시작됩니다.

  • 함수를 배포하는 경우

  • 새로운 함수 인스턴스가 자동으로 생성되어 부하에 맞게 수직 확장되거나 간혹 기존 인스턴스를 대체하는 경우

새로운 함수 인스턴스를 시작하려면 런타임과 코드를 로드해야 합니다. 함수 인스턴스 시작(콜드 스타트)를 포함하는 요청은 기존 함수 인스턴스로 라우팅된 요청보다 느릴 수 있습니다. 하지만 함수가 일정한 부하를 받는 경우 함수가 자주 충돌하여 함수 환경을 재시작해야 하는 것이 아니라면 완전 시작 횟수는 일반적으로 무시해도 됩니다.

함수 코드에서 포착되지 않은 예외가 발생하거나 현재 프로세스가 비정상적으로 종료되면 함수 인스턴스가 다시 시작될 수 있습니다. 이렇게 되면 콜드 스타트가 더 많이 발생되어 지연 시간이 길어질 수 있으므로 예외를 포착하고 그렇지 않으면 현재 프로세스가 종료되지 않도록 하는 것이 좋습니다. Cloud Run Functions의 오류를 처리하고 보고하는 방법에 대한 자세한 내용은 오류 보고를 참조하세요.

함수가 지연 시간에 민감한 경우 최소 인스턴스 수를 설정하여 콜드 스타트를 방지하세요.

함수 인스턴스 수명

진행 중인 트래픽 부족으로 인해 인스턴스의 수가 줄어들거나 함수가 충돌하지 않는 한 일반적으로 함수 인스턴스는 복원력이 우수하며 후속 함수 호출에 의해 재사용됩니다. 즉 하나의 함수 실행이 끝나면 다른 함수 호출이 동일한 함수 인스턴스에 의해 처리될 수 있습니다.

함수 범위와 전역 범위 비교

단일 함수 호출 시 진입점으로 선언된 함수의 본문만 실행하게 됩니다. 함수 소스 코드의 전역 범위는 콜드 스타트에서만 실행되며 이미 초기화된 인스턴스에서는 실행되지 않습니다.

Node.js

const functions = require('@google-cloud/functions-framework');

// TODO(developer): Define your own computations
const {lightComputation, heavyComputation} = require('./computations');

// Global (instance-wide) scope
// This computation runs once (at instance cold-start)
const instanceVar = heavyComputation();

/**
 * HTTP function that declares a variable.
 *
 * @param {Object} req request context.
 * @param {Object} res response context.
 */
functions.http('scopeDemo', (req, res) => {
  // Per-function scope
  // This computation runs every time this function is called
  const functionVar = lightComputation();

  res.send(`Per instance: ${instanceVar}, per function: ${functionVar}`);
});

Python

import time

import functions_framework


# Placeholder
def heavy_computation():
    return time.time()


# Placeholder
def light_computation():
    return time.time()


# Global (instance-wide) scope
# This computation runs at instance cold-start
instance_var = heavy_computation()


@functions_framework.http
def scope_demo(request):
    """
    HTTP Cloud Function that declares a variable.
    Args:
        request (flask.Request): The request object.
        <http://flask.pocoo.org/docs/1.0/api/#flask.Request>
    Returns:
        The response text, or any set of values that can be turned into a
        Response object using `make_response`
        <http://flask.pocoo.org/docs/1.0/api/#flask.Flask.make_response>.
    """

    # Per-function scope
    # This computation runs every time this function is called
    function_var = light_computation()
    return f"Instance: {instance_var}; function: {function_var}"

Go


// h is in the global (instance-wide) scope.
var h string

// init runs during package initialization. So, this will only run during an
// an instance's cold start.
func init() {
	h = heavyComputation()
	functions.HTTP("ScopeDemo", ScopeDemo)
}

// ScopeDemo is an example of using globally and locally
// scoped variables in a function.
func ScopeDemo(w http.ResponseWriter, r *http.Request) {
	l := lightComputation()
	fmt.Fprintf(w, "Global: %q, Local: %q", h, l)
}

자바


import com.google.cloud.functions.HttpFunction;
import com.google.cloud.functions.HttpRequest;
import com.google.cloud.functions.HttpResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;

public class Scopes implements HttpFunction {
  // Global (instance-wide) scope
  // This computation runs at instance cold-start.
  // Warning: Class variables used in functions code must be thread-safe.
  private static final int INSTANCE_VAR = heavyComputation();

  @Override
  public void service(HttpRequest request, HttpResponse response)
      throws IOException {
    // Per-function scope
    // This computation runs every time this function is called
    int functionVar = lightComputation();

    var writer = new PrintWriter(response.getWriter());
    writer.printf("Instance: %s; function: %s", INSTANCE_VAR, functionVar);
  }

  private static int lightComputation() {
    int[] numbers = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    return Arrays.stream(numbers).sum();
  }

  private static int heavyComputation() {
    int[] numbers = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    return Arrays.stream(numbers).reduce((t, x) -> t * x).getAsInt();
  }
}

Ruby

# Global (instance-wide) scope.
# This block runs on cold start, before any function is invoked.
#
# Note: It is usually best to run global initialization in an on_startup block
# instead at the top level of the Ruby file. This is because top-level code
# could be executed to verify the function during deployment, whereas an
# on_startup block is run only when an actual function instance is starting up.
FunctionsFramework.on_startup do
  instance_data = perform_heavy_computation

  # To pass data into function invocations, the best practice is to set a
  # key-value pair using the Ruby Function Framework's built-in "set_global"
  # method. Functions can call the "global" method to retrieve the data by key.
  # (You can also use Ruby global variables or "toplevel" local variables, but
  # they can make it difficult to isolate global data for testing.)
  set_global :my_instance_data, instance_data
end

FunctionsFramework.http "tips_scopes" do |_request|
  # Per-function scope.
  # This method is called every time this function is called.
  invocation_data = perform_light_computation

  # Retrieve the data computed by the on_startup block.
  instance_data = global :my_instance_data

  "instance: #{instance_data}; function: #{invocation_data}"
end

전역 변수를 성능 최적화로 사용할 수 있지만 이전 함수 호출로 전역 범위에 설정된 상태에 의존하지 않아야 합니다. 자세한 내용은 스테이트리스(Stateless)를 참조하세요.

각 함수 인스턴스에 대해 함수 코드가 호출되기 전에 전역 범위가 정확히 한 번 실행되었다고 가정할 수 있습니다. 그러나 전역 범위 실행의 총 횟수 또는 시점은 자동 확장 활동에 따라 달라질 수 있으므로 이를 신뢰해서는 안 됩니다.

함수 실행 타임라인

함수는 함수가 실행되는 동안에만 할당된 리소스(메모리 및 CPU)에 액세스할 수 있습니다. 실행 기간이 아닌 시점에 실행되는 코드는 실행이 보장되지 않으며 언제든지 중단될 수 있습니다. 따라서 항상 함수 실행의 끝을 정확히 알리고 그 이후에는 코드를 실행하지 않아야 합니다. 자세한 내용은 HTTP 함수, 백그라운드 함수, CloudEvent 함수를 참조하세요.

또한 함수 실행에는 함수의 제한 시간이 적용됩니다. 자세한 내용은 함수 제한 시간을 참조하세요.

애플리케이션을 초기화할 때는 실행 타임라인을 고려하세요. 백그라운드 태스크는 요청 기간이 아닌 시간에 실행되므로 초기화 중에 전역 범위에서 생성하면 안 됩니다.

실행 보장

일반적으로 함수는 수신 이벤트가 있을 때마다 한 번씩 호출됩니다. 그러나 오류 시나리오가 다양하기 때문에 Cloud Run Functions는 항상 단일 호출을 보장하지 않습니다.

단일 이벤트에 대한 함수의 최대 또는 최소 호출 횟수는 함수 유형에 따라 다릅니다.

  • HTTP 함수는 최대 한 번만 호출됩니다. 이는 HTTP 호출의 동기식 특성 때문이며 함수 호출 중에 발생하는 오류가 재시도 없이 반환됩니다. HTTP 함수 호출자는 필요한 경우 오류를 처리하고 재시도합니다.

  • 이벤트 기반 함수는 최소 한 번 이상 호출됩니다. 이는 응답을 기다리는 호출자가 없는 이벤트의 비동기적인 특성 때문입니다. 이벤트 전달을 위해 시스템에서 이벤트 기반 함수를 두 번 이상 호출하는 경우도 있습니다. 이벤트 기반 함수 호출이 오류로 인해 실패하는 경우 해당 함수에 실패 시 재시도가 사용 설정되어 있지 않으면 다시 호출되지 않습니다.

실행을 재시도할 때 함수가 제대로 작동하도록 하려면 함수가 멱등성을 갖도록 구현하여 이벤트가 여러 번 전송되더라도 원하는 결과(부작용 포함)를 내도록 해야 합니다. 즉 HTTP 함수의 경우 호출자가 HTTP 함수 엔드포인트에 호출을 다시 시도하더라도 원하는 값을 반환합니다. 함수가 멱등성을 갖도록 하는 방법에 대한 자세한 내용은 이벤트 기반 함수 재시도를 참조하세요.

메모리 및 파일 시스템

각 함수에는 메모리 할당에 일정한 양의 메모리가 있습니다. 배포 시 메모리 양을 구성할 수 있습니다. 자세한 내용은 메모리 한도를 참조하세요.

함수 실행 환경은 함수와 함께 배포된 소스 파일 및 디렉터리를 포함하는 인메모리 파일 시스템을 포함합니다(소스 코드 구조화 참조). 소스 파일이 포함된 디렉터리는 읽기 전용이지만, 나머지 파일 시스템은 쓰기가 가능합니다(운영체제에서 사용되는 파일 제외). 파일 시스템 사용은 함수의 메모리 사용량에 포함됩니다.

함수는 각 프로그래밍 언어의 표준 메서드를 사용하여 파일 시스템과 상호작용할 수 있습니다.

네트워크

함수는 런타임에서 제공하는 기본 제공 라이브러리 또는 종속 항목으로 포함된 제3자 라이브러리를 통해 각 프로그래밍 언어의 표준 메서드를 사용하여 공개 인터넷에 액세스할 수 있습니다.

네트워킹 최적화에 설명된 대로 함수 호출 시 네트워크 연결을 재사용하세요 하지만 연결을 10분간 사용하지 않으면 시스템에 의해 종료될 수 있으며 이후 종료된 연결을 사용하려고 시도하면 '연결 재설정' 오류가 발생합니다. 코드는 종료된 연결을 제대로 처리하는 라이브러리를 사용하거나 하위 수준의 네트워킹 구조를 사용하는 경우 이를 명시적으로 처리해야 합니다.

함수 격리

배포된 각 함수는 동일한 소스 파일에서 배포된 함수를 포함하여 다른 모든 함수와 격리됩니다. 특히 메모리, 전역 변수, 파일 시스템 또는 다른 상태를 공유하지 않습니다.

배포된 함수 간에 데이터를 공유하기 위해 Memorystore, Datastore, Firestore 또는 Cloud Storage와 같은 서비스를 사용할 수 있습니다. 또는 적절한 트리거를 사용하여 한 함수에서 다른 함수를 호출하고 필요한 데이터를 전달할 수 있습니다. 예를 들어 HTTP 함수의 엔드포인트에 HTTP를 요청하거나 Pub/Sub 주제에 메시지를 게시하여 Pub/Sub 함수를 트리거합니다.