Compute > Cloud Functions > 코드 템플릿 가이드 > Python

이 문서는 NHN Cloud의 Cloud Functions 서비스에서 Python을 사용하여 함수를 개발하는 방법을 상세히 설명합니다.

템플릿 정보

항목 값
지원 버전 3.11, 3.12, 3.13
파일명 user.py
Entry Point user.main

기본 템플릿

Hello World 예시

가장 기본적인 함수 형태입니다.

import sys
import yaml

document = """
  a: 1
  b:
    c: 3
    d: 4
"""

def main():
    return yaml.dump(yaml.safe_load(document))

Context 객체

Python 함수에서는 Flask의 request 객체로 HTTP 요청 정보에 접근할 수 있습니다.

from flask import request
import json

def main():
    # HTTP 요청 정보
    method = request.method
    headers = dict(request.headers)
    args = request.args.to_dict()

    # 요청 본문(POST/PUT 등)
    data = None
    if request.is_json:
        data = request.get_json()
    elif request.data:
        data = request.data.decode('utf-8')

    return {
        'method': method,
        'headers': headers,
        'query_params': args,
        'body': data
    }

템플릿 파일 다운로드 및 활용

템플릿 다운로드

Cloud Functions에서 제공하는 Python 템플릿을 다운로드하여 로컬 환경에서 개발할 수 있습니다.

템플릿 다운로드 링크: python.zip

템플릿 파일 구조

다운로드한 템플릿 파일의 구조는 다음과 같습니다.

python.zip
├── user.py          # 메인 함수 파일
└── requirements.txt # 의존성 관리 파일

user.py

기본 YAML 처리 함수가 포함되어 있습니다.

import sys
import yaml

document = """
  a: 1
  b:
    c: 3
    d: 4
"""

def main():
    return yaml.dump(yaml.safe_load(document))

requirements.txt

pyyaml

로컬 개발 과정

1. 압축 해제

# 압축 해제
unzip python.zip -d my-function

# 작업 디렉터리 이동
cd my-function

2. 함수 코드 수정

user.py 파일을 원하는 로직으로 수정합니다.

# user.py - 간단한 수정 예시
from flask import request
import json
from datetime import datetime

def main():
    try:
        # 쿼리 파라미터에서 이름 가져오기
        name = request.args.get('name', 'World')

        # POST 요청인 경우 body에서 메시지 가져오기
        custom_message = ''
        if request.method == 'POST':
            try:
                data = request.get_json()
                if data:
                    custom_message = data.get('message', '')
            except Exception:
                # JSON 파싱 실패 시 무시
                pass

        result = {
            'greeting': f'Hello, {name}!',
            'message': custom_message,
            'method': request.method,
            'timestamp': str(datetime.now())
        }

        return json.dumps(result, ensure_ascii=False)

    except Exception as e:
        return json.dumps({
            'error': 'Internal Server Error',
            'details': str(e)
        }, ensure_ascii=False)

3. ZIP 파일로 압축

수정된 코드를 다시 ZIP 파일로 압축합니다.

# Windows (PowerShell)
Compress-Archive -Path .\user.py, .\requirements.txt -DestinationPath my-function.zip

# Windows (7-Zip 사용 시)
7z a my-function.zip user.py requirements.txt

# macOS/Linux
zip my-function.zip user.py requirements.txt

# 모든 파일 포함(추가 파일이 있는 경우)
zip -r my-function.zip . -x "*.git*" "__pycache__/*" "*.pyc" "test.py"

Cloud Functions 콘솔에서 업로드

함수를 생성하거나 수정할 때 사용자 로컬 환경의 파일을 업로드하는 경우에 사용합니다. 자세한 내용은 콘솔 사용 가이드를 참고하세요.

업로드 시 주의사항

ZIP 파일 구조

  • ZIP 파일의 루트에 직접 .py 파일과 requirements.txt가 위치해야 합니다.
  • 불필요한 폴더 구조는 피할 것을 권장합니다.

올바른 구조:

my-function.zip
├── user.py
├── requirements.txt
└── utils.py (추가 파일이 있는 경우)

잘못된 구조:

my-function.zip
└── my-function/
    ├── user.py
    └── requirements.txt

파일 크기 제한

  • ZIP 파일 크기는 100MiB 이하로 제한됩니다.
  • __pycache__ 폴더는 포함하지 마세요.

제외할 파일들

# .gitignore와 유사하게 다음 파일들은 제외
zip -r my-function.zip . -x \
  "__pycache__/*" \
  "*.pyc" \
  ".git/*" \
  "*.log" \
  "test.py" \
  ".env" \
  "*.zip"

HTTP 메서드별 처리

GET 요청 처리

from flask import request
import json
from datetime import datetime

def main():
    if request.method != 'GET':
        return json.dumps({'error': 'Method Not Allowed'}, ensure_ascii=False), 405

    # 쿼리 파라미터 가져오기
    name = request.args.get('name', 'World')
    greeting = request.args.get('greeting', 'Hello')

    result = {
        'message': f'{greeting}, {name}!',
        'timestamp': datetime.now().isoformat(),
        'method': 'GET'
    }

    return json.dumps(result, ensure_ascii=False)

POST 요청 처리

from flask import request
import json
from datetime import datetime
import uuid

def main():
    if request.method != 'POST':
        return json.dumps({'error': 'Method Not Allowed'}, ensure_ascii=False), 405

    try:
        # JSON 형태의 request body 파싱
        request_body = request.get_json()

        # 필수 필드 검증
        if not request_body or 'name' not in request_body:
            return json.dumps({
                'error': 'Missing required field: name'
            }, ensure_ascii=False), 400

        name = request_body['name']
        email = request_body.get('email', 'not provided')
        message = request_body.get('message', 'No message')

        # 처리 로직
        response = {
            'id': str(uuid.uuid4())[:8],
            'name': name,
            'email': email,
            'message': message,
            'processed_at': datetime.now().isoformat()
        }

        return json.dumps(response, ensure_ascii=False)

    except Exception as e:
        return json.dumps({
            'error': 'Invalid JSON format',
            'details': str(e)
        }, ensure_ascii=False), 400

패키지 관리

requirements.txt 작성

의존성 관리를 위해 requirements.txt 파일을 작성합니다.

pyyaml
requests>=2.28.0
python-dateutil>=2.8.0

외부 API 호출 예시

from flask import request
import json
import requests
from datetime import datetime

def main():
    try:
        user_id = request.args.get('userId')

        if not user_id:
            return json.dumps({'error': 'userId is required'}, ensure_ascii=False), 400

        # 외부 API 호출
        response = requests.get(f'https://jsonplaceholder.typicode.com/users/{user_id}')

        if response.status_code == 404:
            return json.dumps({'error': 'User not found'}, ensure_ascii=False), 404

        response.raise_for_status()
        user_data = response.json()

        result = {
            'user': user_data,
            'fetched_at': datetime.now().isoformat()
        }

        return json.dumps(result, ensure_ascii=False)

    except requests.RequestException as e:
        return json.dumps({
            'error': 'External API error',
            'details': str(e)
        }, ensure_ascii=False), 500
    except Exception as e:
        return json.dumps({
            'error': 'Internal server error',
            'details': str(e)
        }, ensure_ascii=False), 500

데이터 처리 예시

from flask import request
import json
from datetime import datetime
import uuid
import re

def main():
    try:
        request_body = request.get_json()
        data = request_body.get('data', [])

        if not isinstance(data, list):
            return json.dumps({'error': 'Data must be an array'}, ensure_ascii=False), 400

        # 데이터 처리
        processed_data = []
        for item in data:
            if 'name' in item:
                processed_item = {
                    'id': str(uuid.uuid4())[:8],
                    **item,
                    'processed_at': datetime.now().isoformat(),
                    'normalized_name': normalize_name(item['name'])
                }
                processed_data.append(processed_item)

        # 데이터 정렬 및 필터링
        valid_data = [item for item in processed_data if item['normalized_name']]
        valid_data.sort(key=lambda x: x['normalized_name'])

        result = {
            'total_processed': len(processed_data),
            'valid_items': len(valid_data),
            'data': valid_data
        }

        return json.dumps(result, ensure_ascii=False)

    except Exception as e:
        return json.dumps({
            'error': 'Data processing failed',
            'details': str(e)
        }, ensure_ascii=False), 400

def normalize_name(name):
    """이름 정규화 함수"""
    if not name:
        return ''
    # 공백 제거 및 첫 글자 대문자화
    return name.strip().title()

환경 변수 사용

함수에 등록한 환경 변수는 os.environ(또는 os.getenv)으로 접근할 수 있습니다. 환경 변수는 함수 생성 및 수정의 코드 작성 단계에서 등록합니다. 자세한 내용은 콘솔 사용 가이드를 참고하세요.

from flask import request
import os
import json

def main():
    # 환경 변수 읽기
    db_host = os.environ.get('DB_HOST')
    api_key = os.getenv('API_KEY')

    if not api_key:
        return json.dumps({'error': 'API_KEY is not set'}, ensure_ascii=False), 500

    return json.dumps({'db_host': db_host}, ensure_ascii=False)

참고

보안상 다음 키·접두사는 환경 변수로 등록할 수 없습니다.

공통(모든 런타임)

  • 셸/subprocess: PATH, IFS, HOME, BASH_ENV, ENV, SHELLOPTS
  • 로더/라이브러리: LD_PRELOAD, LD_LIBRARY_PATH, LD_AUDIT
  • glibc 동적 로딩: GCONV_PATH, LOCPATH, HOSTALIASES
  • 프록시: HTTP_PROXY, HTTPS_PROXY, ALL_PROXY(소문자 포함)
  • TLS 신뢰 저장소: SSL_CERT_FILE, SSL_CERT_DIR, REQUESTS_CA_BUNDLE, CURL_CA_BUNDLE
  • 플랫폼 내부: RUNTIME_PORT, USERFUNCVOL, WSGI_FRAMEWORK, SENTRY_DSN, SENTRY_RELEASE, TIMEOUT, BODY_PARSER_LIMIT
  • 접두사: LD_, DYLD_, KUBERNETES_, FISSION_, CORECLR_, COMPLUS_, DOTNET_, ASPNETCORE_, PYTHON, NODE_, RUBY

Python

  • PYTHONPATH, PYTHONSTARTUP, PYTHONHOME, PYTHONEXECUTABLE

Entry Point 설정

단일 함수

파일명.함수명을 Entry Point로 사용합니다.

파일명: user.py 함수명: main Entry Point: user.main

다중 함수

하나의 파일에서 여러 함수를 정의할 수 있습니다.

# handlers.py
from flask import request
import json

def get_user():
    # 사용자 조회 로직
    return json.dumps({'message': 'Get user'}, ensure_ascii=False)

def create_user():
    # 사용자 생성 로직
    return json.dumps({'message': 'User created'}, ensure_ascii=False)

def update_user():
    # 사용자 수정 로직
    return json.dumps({'message': 'User updated'}, ensure_ascii=False)

Entry Point 설정: - handlers.get_user - handlers.create_user - handlers.update_user

주의사항

지원하지 않는 패키지

현재 아래 특징이 있는 복잡한 패키지는 지원하지 않습니다.

지원하지 않는 패키지 예시: - numpy, pandas (C/C++ 확장 모듈 필수) - scipy (시스템 라이브러리 의존성) - tensorflow, pytorch (복잡한 초기화 과정)

지원 가능한 패키지 예시: - requests (HTTP 클라이언트) - pyyaml (YAML 처리) - python-dateutil (날짜/시간 처리) - pillow (이미지 처리 - 기본 기능)

메모리 및 실행 시간 고려사항

  • 함수는 제한된 메모리와 실행 시간 내에서 동작해야 합니다.
  • 대용량 데이터 처리 시 제너레이터나 스트림 처리를 고려하세요.
  • 장시간 실행되는 작업은 적절히 분할하세요.
TOP