Theory
인프라
Azure
Functions Python Guide

Azure Functions Python Guide

개요

Azure Functions를 사용하여 Python으로 개발하는 방법에 대한 가이드입니다. 이 문서는 Azure Functions 개발자 가이드 (opens in a new tab)를 이미 읽었다고 가정합니다.

Azure Functions는 서버리스 컴퓨팅 플랫폼으로, Python을 사용하여 이벤트 기반 애플리케이션을 구축할 수 있습니다.

프로그래밍 모델

Azure Functions Python에는 두 가지 프로그래밍 모델이 있습니다:

v1 모델 (기존)

  • functions.json 파일을 사용하여 함수 정의
  • 파일 기반 구성 방식

v2 모델 (권장) ⭐

  • 데코레이터 기반 접근 방식
  • 더 간단한 파일 구조
  • 코드 중심적 개발

개발 옵션

로컬 개발 환경

지원되는 개발 환경:

  • Visual Studio Code (권장)
  • 터미널/명령 프롬프트 (Azure Functions Core Tools 사용)
  • Azure Portal (온라인 개발)

중요한 참고사항:

Windows에서 로컬 개발은 가능하지만, Azure에서 실행 시에는 Linux 기반 호스팅 플랜만 지원됩니다.

프로그래밍 모델 상세

v1 모델 (functions.json 기반)

폴더 구조
<project_root>/
├── .venv/
├── .vscode/
├── my_first_function/
│   ├── __init__.py
│   └── function.json
├── my_second_function/
│   ├── __init__.py
│   └── function.json
├── shared_code/
│   ├── __init__.py
│   ├── my_first_helper_function.py
│   └── my_second_helper_function.py
├── tests/
├── .funcignore
├── host.json
├── local.settings.json
├── requirements.txt
└── Dockerfile
function.json 예시
{
    "scriptFile": "__init__.py",
    "bindings": [
        {
            "authLevel": "function",
            "type": "httpTrigger",
            "direction": "in",
            "name": "req",
            "methods": ["get", "post"]
        },
        {
            "type": "http",
            "direction": "out",
            "name": "$return"
        }
    ]
}
Python 코드 (init.py)
import azure.functions
 
def main(req: azure.functions.HttpRequest) -> str:
    user = req.params.get('user')
    return f'Hello, {user}!'

v2 모델 (데코레이터 기반) ⭐

폴더 구조
<project_root>/
├── .venv/
├── .vscode/
├── function_app.py          ## 모든 함수가 여기에
├── additional_functions.py  ## 선택적 추가 함수들
├── tests/
├── .funcignore
├── host.json
├── local.settings.json
├── requirements.txt
└── Dockerfile
function_app.py 예시
import azure.functions as func
 
app = func.FunctionApp()
 
@app.function_name(name="HttpTrigger1")
@app.route(route="req")
def main(req: func.HttpRequest) -> str:
    user = req.params.get("user")
    return f"Hello, {user}!"

주요 파일 설명

필수 파일

파일명설명
function_app.pyv2: 모든 함수와 트리거/바인딩이 정의되는 메인 파일
requirements.txtPython 패키지 의존성 목록
host.json함수 앱 인스턴스의 전역 구성 옵션
local.settings.json로컬 개발용 앱 설정 및 연결 문자열

선택적 파일

파일명설명
.funcignoreAzure에 배포하지 않을 파일들 정의
.vscode/Visual Studio Code 구성
.venv/Python 가상환경
Dockerfile커스텀 컨테이너로 배포 시 사용
tests/테스트 케이스들

대체 진입점 설정

v1 모델에서 커스텀 진입점

{
  "scriptFile": "main.py",
  "entryPoint": "customentry",
  "bindings": [...]
}
## main.py
def customentry(req):
    return "Custom entry point!"

v2 모델에서는 blueprint 사용

## function_app.py
import azure.functions as func
from additional_functions import bp
 
app = func.FunctionApp()
app.register_blueprint(bp)

Python Worker 확장

확장 기능이란?

  • 함수 실행 생명주기 동안 추가 기능을 제공하는 서드파티 라이브러리
  • 애플리케이션 레벨 또는 함수 레벨에서 동작

확장 사용 방법

  1. requirements.txt에 확장 패키지 추가
application-level-extension==1.0.0
  1. 환경 변수 설정
// local.settings.json
{
  "Values": {
    "PYTHON_ENABLE_WORKER_EXTENSIONS": "1"
  }
}
  1. 함수에서 확장 사용
from application_level_extension import AppExtension
 
AppExtension.configure(key=value)
 
def main(req, context):
    ## context.app_ext_attributes 사용
    pass

확장 타입

애플리케이션 레벨 확장
  • 전체 앱 범위에서 동작
  • AppExtensionBase 클래스를 상속
  • 앱 시작 시 한 번 초기화
함수 레벨 확장
  • 특정 함수 트리거에서만 동작
  • FuncExtensionBase 클래스를 상속
  • 각 함수마다 개별 인스턴스

고급 기능

CORS (Cross-Origin Resource Sharing)

## Azure Portal 또는 Azure CLI에서 설정
## 함수 앱 레벨에서 CORS 설정 적용

비동기 처리

import asyncio
import azure.functions as func
 
app = func.FunctionApp()
 
@app.function_name(name="AsyncFunction")
@app.route(route="async")
async def main(req: func.HttpRequest) -> str:
    ## 비동기 I/O 작업으로 성능 향상
    await asyncio.sleep(1)
    return "Async response"

장점:

  • 단일 스레드 Python 런타임에서 더 나은 성능
  • I/O 바운드 작업에 효과적
  • 대량의 I/O 이벤트 처리에 적합

공유 메모리 (미리 보기)

설정 방법:

// 앱 설정
{
  "FUNCTIONS_WORKER_SHARED_MEMORY_DATA_TRANSFER_ENABLED": "1",
  "DOCKER_SHM_SIZE": "268435456"  // 256MB
}

사용 시나리오:

  • 1MB 이상의 큰 페이로드 처리 시
  • Blob Storage 바인딩 사용 시
  • Premium 또는 Dedicated 플랜에서만 사용 가능

타입 힌팅 및 IntelliSense

타입 어노테이션 활용

import azure.functions as func
 
app = func.FunctionApp()
 
@app.function_name(name="TypedFunction")
@app.route(route="typed")
def main(req: func.HttpRequest) -> func.HttpResponse:
    ## 타입 힌팅으로 IntelliSense 지원
    user: str = req.params.get('user', 'Guest')
    
    return func.HttpResponse(
        f"Hello, {user}!",
        status_code=200,
        headers={"Content-Type": "application/json"}
    )

모범 사례

1. 프로젝트 구조

## function_app.py
import azure.functions as func
from shared_code import helpers
 
app = func.FunctionApp()
 
@app.function_name(name="WellStructuredFunction")
@app.route(route="api/users/{user_id}")
def get_user(req: func.HttpRequest) -> func.HttpResponse:
    user_id = req.route_params.get('user_id')
    user_data = helpers.get_user_by_id(user_id)
    
    return func.HttpResponse(
        user_data,
        mimetype="application/json"
    )

2. 환경 변수 관리

import os
import azure.functions as func
 
app = func.FunctionApp()
 
@app.function_name(name="ConfiguredFunction")
@app.route(route="config")
def main(req: func.HttpRequest) -> str:
    ## 환경 변수 사용
    api_key = os.environ.get('API_KEY')
    database_url = os.environ.get('DATABASE_CONNECTION_STRING')
    
    return f"Configuration loaded successfully"

3. 에러 처리

import azure.functions as func
import logging
 
app = func.FunctionApp()
 
@app.function_name(name="ErrorHandlingFunction")
@app.route(route="safe")
def main(req: func.HttpRequest) -> func.HttpResponse:
    try:
        ## 비즈니스 로직
        result = process_request(req)
        return func.HttpResponse(result, status_code=200)
    
    except ValueError as e:
        logging.error(f"Validation error: {e}")
        return func.HttpResponse("Bad Request", status_code=400)
    
    except Exception as e:
        logging.error(f"Unexpected error: {e}")
        return func.HttpResponse("Internal Server Error", status_code=500)

알려진 이슈 및 문제 해결

일반적인 문제들

  1. ModuleNotFoundError 및 ImportError

    • requirements.txt에 의존성이 누락된 경우
    • 가상환경 설정 문제
  2. 'cygrpc'를 import할 수 없음

    • gRPC 관련 의존성 문제

v2 모델 관련 이슈

  1. 파일이나 어셈블리를 로드할 수 없음

    • 패키지 호환성 문제
  2. Azure Storage 연결을 해결할 수 없음

    • 연결 문자열 설정 문제

디버깅 팁

import logging
 
## 로깅 설정
logging.basicConfig(level=logging.INFO)
 
@app.function_name(name="DebugFunction")
@app.route(route="debug")
def main(req: func.HttpRequest) -> str:
    logging.info(f"Request received: {req.url}")
    logging.info(f"Request method: {req.method}")
    logging.info(f"Request headers: {dict(req.headers)}")
    
    return "Debug info logged"

다음 단계

추가 학습 리소스

  • Azure Functions 패키지 API 문서
  • Azure Functions 모범 사례
  • 트리거 및 바인딩 가이드
  • Blob Storage 바인딩
  • HTTP 및 웹훅 바인딩
  • Queue Storage 바인딩
  • Timer 트리거

실용적인 시나리오

  • 머신러닝 & AI: PyTorch, TensorFlow, Azure OpenAI 연동
  • 자동화: Azure 리소스 관리 자동화
  • 서버리스 워크플로우: 상태 저장 함수로 오케스트레이션

출처: Microsoft Learn - Azure Functions Python developer guide (opens in a new tab)

Python Azure Function App 동시성 및 인스턴스, 워커, 랭귀지 워커의 차이

참고: Microsoft Q&A - Python Azure Function App concurrency and differences between instance, worker and language worker (opens in a new tab)

주요 용어 정리

  • Host(호스트): Azure Functions 앱 전체를 관리하는 프로세스(컨트롤러 역할)
  • Instance(인스턴스): Azure에서 할당된 VM(머신) 또는 컨테이너. 하나의 인스턴스에 여러 워커 프로세스가 실행될 수 있음
  • Worker(워커 프로세스): 실제로 함수 코드를 실행하는 프로세스. Python의 경우 별도의 Python 워커 프로세스가 생성됨
  • Language Worker(랭귀지 워커): 특정 언어(Python, Node.js 등)로 함수 실행을 담당하는 프로세스. Python Functions는 Python 워커 프로세스가 랭귀지 워커임
  • Thread(스레드): 워커 프로세스 내에서 동시 실행을 위한 OS 레벨의 스레드

구조 요약

  • 하나의 인스턴스(머신/VM) 안에 여러 워커 프로세스가 있을 수 있음
  • 각 워커 프로세스는 여러 스레드를 가질 수 있음
  • Python Functions는 기본적으로 싱글 스레드이지만, ThreadPoolExecutor 등으로 병렬 처리 가능

주요 설정 변수

  • FUNCTIONS_WORKER_PROCESS_COUNT

    • 한 호스트(인스턴스) 내에서 실행할 워커 프로세스 수 (1~10)
    • 워커 프로세스가 많을수록 더 많은 함수 실행을 병렬로 처리 가능
  • PYTHON_THREADPOOL_THREAD_COUNT

    • 각 Python 워커 프로세스가 사용할 스레드 수
    • ThreadPoolExecutor 등에서 병렬 처리 시 사용
  • maxConcurrentActivityFunctions, maxConcurrentOrchestratorFunctions

    • Durable Functions에서 동시 실행할 Activity/Orchestrator 함수 개수 제한
    • TaskHub(외부 스토리지)에 등록된 작업을 얼마나 동시에 처리할지 결정

동작 예시 및 주의점

  • 비동기(async) 함수만 사용할 경우, PYTHON_THREADPOOL_THREAD_COUNT를 늘려도 효과가 없음 (스레드가 추가로 생성되지 않음)
  • 동기 함수를 많이 실행할 때는 스레드 수를 늘리면 여러 작업을 동시에 처리 가능
  • FUNCTIONS_WORKER_PROCESS_COUNT를 늘리면 워커 프로세스가 여러 개 생성되어, 각 프로세스가 독립적으로 함수 실행
  • Durable Functions의 동시성 제한(throttle)은 "VM(인스턴스) 단위"로 적용됨 (즉, 한 머신에서 동시에 처리할 함수 개수 제한)
  • 워커/스레드/인스턴스 개수 설정이 실제 처리량과 리소스 사용에 큰 영향을 미침

실전 팁

  • CPU/메모리 리소스를 늘리기 전에, 워커/스레드/동시성 설정을 최적화하는 것이 중요
  • 비동기 함수만 쓴다면 스레드 수 조정보다는 워커 프로세스 수 조정이 더 효과적일 수 있음
  • Durable Functions에서는 TaskHub의 작업이 여러 VM/워커에 고르게 분배되도록 설정 필요

참고

  • "worker"라는 용어는 문맥에 따라 VM, 워커 프로세스, 랭귀지 워커 등 여러 의미로 쓰이니 주의
  • 실제 동작 구조와 설정값의 관계를 잘 이해하고, 워크로드에 맞게 조정해야 최적의 성능을 낼 수 있음

출처: Microsoft Q&A - Python Azure Function App concurrency and differences between instance, worker and language worker (opens in a new tab)