Keyboard shortcuts

Press ← or → to navigate between chapters

Press ? to show this help

Press Esc to hide this help

Compute Module 컨테이너와 환경 변수

이미지는 코드와 의존성 및 시작 설정을 담은 실행 템플릿이며, 컨테이너는 그 이미지로 실행한 인스턴스입니다. Compute Module은 호환되는 이미지를 Foundry Artifacts에 게시한 뒤 실행합니다.

함수 구현은 Python, Java, TypeScript SDK를 사용합니다. 외부 연결은 소스, 같은 복제본 안의 파일 공유는 볼륨으로 구성합니다.

이미지 조건

  • linux/amd64 대상으로 빌드합니다.
  • root가 아닌 숫자 UID로 실행합니다.
  • digest 또는 latest 이외의 태그를 지정합니다.
  • 노출하는 포트는 1024~65535 범위이며 8945와 8946은 제외합니다.

Docker를 설치하고 docker info로 daemon 상태를 확인할 수 있습니다. Cannot connect to the Docker daemon이면 Docker daemon과 Desktop 실행 상태를 해결한 뒤 빌드합니다.

Dockerfile 명령역할
FROM빌드 단계의 기반 이미지
WORKDIR뒤따르는 작업의 기본 디렉터리
RUN이미지 빌드 중 설치, 컴파일 등 실행
COPY빌드 컨텍스트의 파일을 이미지로 복사
USER실행 UID 설정
ENTRYPOINT컨테이너 시작 명령
EXPOSE앱이 수신하는 포트 명시
ENV런타임 환경 변수의 기본값 설정

Python 이미지 예제

프로젝트에 Dockerfile, requirements.txt와 src/application.py를 둡니다. requirements.txt에는 실제 앱 의존성을, application.py에는 모듈 구현을 넣습니다. Python SDK의 add 함수를 사용한다면 requirements.txt에 foundry-compute-modules를 넣습니다.

FROM python:3.12
WORKDIR /app
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
COPY src/application.py ./
USER 5001
ENTRYPOINT ["python", "application.py"]

숫자 UID로 실행할 수 있으므로 이름 있는 OS 사용자를 만들 필요는 없습니다. 의존성과 앱 코드를 별도 COPY 단계로 나누면 코드만 바꿀 때 의존성 설치 레이어를 재사용할 수 있습니다.

docker build --platform linux/amd64 -t myimage:0.0.0 .

Foundry에서 Artifacts 저장소를 만들고 Publish > Docker를 선택합니다. 해당 저장소가 표시하는 로그인과 push 명령으로 이미지를 게시한 뒤 Compute Module의 컨테이너로 선택합니다.

로그 수집

Configure의 Containers에서 컨테이너 행을 선택하면 로그 수집을 켜거나 끄고 형식과 소스를 정할 수 있습니다.

SLS

SLS는 메시지와 메타데이터를 구조화한 JSON 로그 형식입니다. service.1 로그에는 level, time, origin, thread, message 및 params 같은 필드가 들어갑니다. 아래 값은 형식을 보여 주는 가상 예입니다.

{
  "type": "service.1",
  "level": "INFO",
  "time": "2024-01-15T12:00:00.000Z",
  "origin": "com.example.MyClass",
  "thread": "main",
  "message": "Processing request",
  "params": {"requestId": "example-request"},
  "uid": "example-log-id",
  "sid": "example-session-id"
}

SLS를 선택하면 일반 System.out.println 출력은 SLS 로그로 수집하지 않습니다. Java SDK의 SafeLogger 또는 Python SDK의 get_logger처럼 형식에 맞는 로거를 사용합니다.

이전 DeployedAppRuntime을 사용하는 앱에서는 다음과 같이 기록할 수 있습니다. 해당 SDK는 Include runtime을 OFF로 설정해야 합니다.

package myproject;

import com.palantir.interactive.module.api.SafeArg;
import com.palantir.interactive.module.api.UnsafeArg;
import com.palantir.interactive.module.tasks.deployedapps.DeployedAppRuntime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

final class DeployedApp {
    private static final Logger LOG = LoggerFactory.getLogger(DeployedApp.class);

    public static void main(String[] args) {
        DeployedAppRuntime.builder()
                .addQueryRunner(DeployedApp::hello, String.class, String.class, "hello")
                .buildAndStart();
    }

    static String hello(String name) {
        LOG.info("Greeting requested", SafeArg.of("operation", "hello"));
        LOG.info("Greeting recipient", UnsafeArg.of("name", name));
        return "Hello, " + name + "!";
    }

    private DeployedApp() {}
}

SafeArg는 비민감 값, UnsafeArg는 민감할 수 있는 값에 사용합니다. 비밀 자체를 로그에 기록하는 방식으로 사용하지 않습니다. Python은 get_logger(__name__)와 logger.setLevel(logging.INFO)로 로거를 만들고 set_internal_log_level()로 SDK 내부의 상세 정도를 조절합니다. 수준은 DEBUG, INFO, WARNING, ERROR, CRITICAL 순서입니다.

Plaintext

Plaintext 형식은 출력을 SLS 로그의 message 필드에 넣습니다. 일반 텍스트를 그대로 읽을 수 있으며, 입력에 SLS JSON이 있어도 JSON 문자열이 message에 나타납니다. 일반 출력과 구조화 출력을 함께 수집해야 할 때 사용할 수 있습니다.

STDOUT 또는 파일

소스조건
Standard output/bin/sh 실행 파일과 set, tee 명령을 지원해야 함
stderr 포함true이면 stdout과 stderr를 동기화하여 한 스트림으로 합침
Log filesDirectory path와 File path patterns 지정. 각 패턴에 디렉터리 경로 포함

예를 들어 Directory path가 /var/log이면 패턴으로 /var/log/foo/*.log 및 /var/log/bar.txt를 지정할 수 있습니다. 로그 파일 방식을 쓸 때 지정한 기본 디렉터리는 모듈 시작 시 비어 있어야 합니다.

사용자 환경 변수

환경 변수는 이미지를 다시 빌드하지 않고 앱 설정을 바꿀 때 사용합니다. 예를 들어 production 변수를 true로 지정하면 INFO, 그 밖의 경우에는 DEBUG 로그를 사용하는 코드를 작성할 수 있습니다.

import logging
import os

logging.basicConfig(
    level=logging.INFO if os.environ.get("production") == "true" else logging.DEBUG
)

비밀은 이미지의 ENV나 코드에 넣지 않고 소스 자격 증명 또는 애플리케이션 권한의 제공 경로를 사용합니다.

예약 환경 변수

다음 변수는 플랫폼이 제공하므로 덮어쓸 수 없습니다. 파일 경로인 변수를 토큰 값 자체로 전송하지 않도록 구분합니다.

변수값과 용도
CLIENT_IDFunctions 모드의 Application permissions에 연결한 앱의 client ID
CLIENT_SECRET위 앱의 client secret. client credentials 토큰 교환에 사용
RUNTIME_HOST내부 Compute Module 서비스의 호스트
RUNTIME_PORT내부 서비스 포트. 예: 8945
RUNTIME_API호스트와 포트를 포함한 내부 서비스 주소
GET_JOB_PATH작업 조회 URI 경로
GET_JOB_URI작업 조회 전체 URI
POST_RESULT_PATH결과 전송 URI 경로
POST_RESULT_URI결과 전송 기본 URI. 뒤에 jobId를 붙여 사용
POST_SCHEMA_URI함수 명세 게시 전체 URI
MAX_CONCURRENT_TASKS복제본당 최대 작업 수. 시작 시 읽으며 실행 중 값 변경을 반영하지 않음
SOURCE_CREDENTIALS소스 API 이름을 최상위 키로 갖는 비밀 JSON 파일 경로. 소스를 연결했을 때 제공
SOURCE_CONFIGURATIONS_PATH소스별 비밀 및 연결 메타데이터를 담은 JSON 파일 경로
DEFAULT_CA_PATH내부 서비스 연결의 CA PEM 파일 경로. 사용자 클라이언트의 TLS 검증에 사용
BUILD2_TOKENPipeline 입력/출력으로 범위가 제한된 토큰 파일 경로
COMPUTE_SESSION_ID컨테이너가 실행되는 복제본의 세션 식별자. 복제본마다 다름
FOUNDRY_COMPUTE_MODULE_RIDCompute Module의 RID
MODULE_AUTH_TOKEN내부 서비스 요청의 Module-Auth-Token 헤더에 넣을 토큰 파일 경로
FOUNDRY_ONTOLOGY_RIDMarketplace 설치 프로젝트의 대상 온톨로지 RID

내부 경로의 예는 /interactive-module/api/internal-query/job, /interactive-module/api/internal-query/results, /interactive-module/api/internal-query/schemas입니다. 사용자 클라이언트는 실제 제공된 URI를 사용합니다.

import os
from pathlib import Path

module_auth_token = Path(os.environ["MODULE_AUTH_TOKEN"]).read_text().strip()
ca_path = os.environ["DEFAULT_CA_PATH"]
job_uri = os.environ["GET_JOB_URI"]

소스 JSON의 최상위 키는 소스 API 이름입니다. 연결 URL과 secrets도 해당 소스 항목 안에서 읽습니다. 소스별 파일 구조를 따릅니다.

Marketplace에서 FOUNDRY_ONTOLOGY_RID는 원본 프로젝트가 아니라 설치 대상 프로젝트의 온톨로지입니다. 생성 OSDK를 초기화할 때 이 값을 사용해야 하며 온톨로지 엔터티 API 이름은 원본과 대상에서 일치해야 합니다.

컨테이너 준비 상태는 probe, 복제본 자원 규모와 비용은 사용량에서 설정 결과를 확인합니다.