본문 바로가기

클라우드

[Azure Function] Azure Function 배포 문제

Outline

우리 회사는 클라우드로 Azure를 사용한다. Azure Function을 배포하는 방법은 정말 많다. 

문제는 기존 방식대로, 새로운 서비스를 Azure Function에 올리려고 하였는데, 동작하지 않았다.

로컬에서는 디버깅하거나, 함수를 실행을 시켜도, 정상적으로 동작하고 기능 상으로도 문제가 없는데, 배포만 하면 함수가 로드되지 않았다. 환경변수, 설정파일 등 많은 부분을 다시 확인했음에도 불구 하고, 동작하지 않았다.

급한 대로, Azure Core tools를 이용해서 배포 하였고, 이를 정리하고자 한다.

 

Spec

문제가 발생한 Azure Function은 다음과 같다.

  • python3.11
  • host.json
  • python azure function v2 방식
{
  "version": "2.0",
  "logging": {
    "applicationInsights": {
      "samplingSettings": {
        "isEnabled": true,
        "excludedTypes": "Request"
      }
    }
  },
  "extensionBundle": {
    "id": "Microsoft.Azure.Functions.ExtensionBundle",
    "version": "[4.*, 5.0.0)"
  }
}

 

Contents

기존 배포 방식

기존의 배포 방식은 Azure github CI/CD를 이용했었다.

Azure Function에는 Deploy Center를 통해서, Azure github에 배포가 가능하도록 github workflow(github action)을 설정해준다.

 

다음은, Azure Portal에서 Azure Function의 Deploy Center를 통해서, github workflow를 생성하면, 만들어지는 yml파일이다.

 

# Docs for the Azure Web Apps Deploy action: https://github.com/azure/functions-action
# More GitHub Actions for Azure: https://github.com/Azure/actions
# More info on Python, GitHub Actions, and Azure Functions: https://aka.ms/python-webapps-actions

name: Build and deploy Python project to Azure Function App - test-app

on:
  push:
    branches:
      - dev
  workflow_dispatch:

env:
  AZURE_FUNCTIONAPP_PACKAGE_PATH: '.' # set this to the path to your web app project, defaults to the repository root
  PYTHON_VERSION: '3.11' # set this to the python version to use (supports 3.6, 3.7, 3.8)

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Setup Python version
        uses: actions/setup-python@v5
        with:
          python-version: ${{ env.PYTHON_VERSION }}

      - name: Create and start virtual environment
        run: |
          python -m venv venv
          source venv/bin/activate

      - name: Install dependencies
        run: pip install -r requirements.txt

      # Optional: Add step to run tests here

      - name: Zip artifact for deployment
        run: zip release.zip ./* -r

      - name: Upload artifact for deployment job
        uses: actions/upload-artifact@v4
        with:
          name: python-app
          path: |
            release.zip
            !venv/

  deploy:
    runs-on: ubuntu-latest
    needs: build
    
    
    steps:
      - name: Download artifact from build job
        uses: actions/download-artifact@v4
        with:
          name: python-app

      - name: Unzip artifact for deployment
        run: unzip release.zip     
        
      - name: 'Deploy to Azure Functions'
        uses: Azure/functions-action@v1
        id: deploy-to-function
        with:
          app-name: 'test-app'
          slot-name: 'dev'
          package: ${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}
          publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_98F3 }}

 

Azure Function을 code방식 만들고, github workflow를 만들면, 자동으로 배포가 되는 서비스를 Azure에서 제공해준다.

그리고, 지금까지는 이 방식이 잘 되었다.

 

문제점

정말 많은 시간을 쏟아부어서 무엇이 근본적인 원인인지를 알아냈다.

근본적으로는 "python의 외부 모듈 미설치" 문제였다. 분명히 pip install -r requirements 처럼 외부 모듈들을 다운로드 받아서 사용함에도 불구하고, 배포만 하면 적용이 되지 않는 문제를 발견했다.

 

디버깅

이 문제를 해결하기 위해서, 원인을 찾기 위한 기나긴 디버깅 여정을 떠났다.

이 문제의 열받게 하는 점은, "local"에서는 정말 잘되는데, "remote"에 올리면 함수 조차 뜨지 않아서, 디버깅하기가 쉽지 않다는 것이다.

 

 

  • 환경변수 확인
    • python code에서 필요로 하는 환경변수 등을 Azure Function App에서 설정을 했는지 확인한다.
  • AzureWebJobsStorage 확인
    • 올바른 Storage Account 주소가 작성되어있어야 한다.
  • Azure Function 런타임 확인
    • Azure Function의 런타임 버전이 배포한 코드와 호환되는지 확인한다.
  • 배포 파일 확인
    • Azure Function의 ssh를 통해서 /home/site/wwwroot 위치에 python 코드가 존재하는지 확인한다.
  • Python dependencies 확인
    • ssh를 통해서 python 패키지가 제대로 설치되어 있는지 확인한다.

 

추가적으로, 커뮤니티에서 도움받은 체크 리스트 이다.

  • Gtihub Action 배포 yml 확인(아래 부분이 있는지 확인한다)
- name: 'Deploy to Azure Functions'
        uses: Azure/functions-action@v1
        id: deploy-to-function
        with:
          app-name: 'test-app'
          slot-name: 'dev'
          package: ${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}
          publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_98F3 }}
  • Blob Trigger는 path 설정이 정확해야된다.

 

보통은, 환경변수, AzureWebJobsStorage 레벨에서 이 문제가 해결되었었다. 그래서 가볍게 고치면 되겠지라고 생각하고, 작업을 시작했고, 정말 많은 시간을 들이게 되었다.

 

해결법

문제는 위에서 언급한대로, Python dependencies가 제대로 설치 되지 않았다는 것이다.

이 사실을 ssh를 통해서 python 패키지가 제대로 설치 되지 않는다는 것을 알고 있었다.

그러나, 의심을 하지 않았다. 왜냐하면, 그 동안 동일한 구성으로 잘 사용하고 있었고, 설마 외부 모듈을 설치 하지 못할 것이라고는 생각을 못했다.

 

결국 모든 코드를 무(無)로 돌리고, 하나씩 추가하면서, 외부 모듈을 import하는 순간 문제가 발생한다는 것을 알았다.

import azure.functions as func
import logging

app = func.FunctionApp()


@app.blob_trigger(
    arg_name="myblob",
    path="test1-container",
    connection="AzureWebJobsStorage",
)
def test(myblob: func.InputStream):
    logging.info("===================================")
    logging.info(f"Python blob trigger function processed blobName: {myblob.name}")

더 화가 나는 것은, 위와 같은 기본 코드는 "remote"에서 제대로 함수가 활성화 된다는 것이다.

requirements도 github action도 모든 부분에서 문제가 없었고, 로컬에서도 개발하는데 문제가 없었기 때문에, 더 믿기 힘들었다.

 

급하게 Azure Function이 필요했기 때문에, 최대한 빨리 고칠 수 있는 방법을 찾아 나섰고, Azure Core tools를 이용해서 배포를 했다.

 

이 방법이 좋은 방법은 아닌 이유가, 로컬에서 배포를 진행하는 방식이라는 것이다. 개발자들의 실수로 심지어 운영에 배포가 될 수 있다.

pip install -r requirements.txt --target="./.python_packages/lib/site-packages"

func azure functionapp publish test-app --slot dev

 

위와 같이, 로컬의 터미널에 사용하면, python code를 해당 slot에 배포를 하게 되고, 로그를 확인하면, 외부 모듈이 제대로 설치가 된다는 것을 알 수 있다.

최종적으로, Azure Function이 로드된다.

 

더 좋은 방법

위의 배포 방식은 정상적으로 동작하지만, 개발자의 실수가 운영에도 영향을 미칠 수 있으므로 좋은 방식은 아니다.

정말 급한 상황에서 사용할 수 있을 것 같다.

 

그래서, Azure Function의 code 배포를 사용하는 것이 아니라, container 배포를 사용하면 더 좋을 것 같다.

Azure Function은 애초에 동작을 docker를 이용한 container배포를 하게 되는데, 그렇기 때문에 docker container로 배포를 이용하면, 위의 문제도 더 명시적으로 발견하기 쉽지 않을까 싶다.