Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (seongtaejeong at gmail.com)
홈페이지
첨부 파일
 

파이썬 - Azure App Service에 응용 프로그램 배포 후의 환경

지난 글에서 Azure App Service의 초기 환경 구성을 살펴봤는데요,

파이썬 - Azure App Service에 응용 프로그램 배포하기 전의 환경
; https://www.sysnet.pe.kr/2/0/13946

그렇다면 파이썬 웹 앱을 배포한 경우에는 어떤 식으로 바뀔까요? ^^




간단하게 예제 프로젝트를 다음과 같이 배포하는 걸 가정해 보겠습니다. 우선, SCM_DO_BUILD_DURING_DEPLOYMENT 설정을 true로 변경하고,

c:\temp> az login

c:\temp> az webapp config appsettings set --resource-group pywebapp_group --name pywebapp --settings SCM_DO_BUILD_DURING_DEPLOYMENT=true

이후 파이썬 (예제) 소스 코드를 압축해 배포합니다.

E:\git_clone> git clone https://github.com/Azure-Samples/msdocs-python-fastapi-webapp-quickstart.git

E:\git_clone> cd msdocs-python-fastapi-webapp-quickstart

E:\git_clone\msdocs-python-fastapi-webapp-quickstart> ucompressarchive test.zip .

E:\git_clone\msdocs-python-fastapi-webapp-quickstart> az webapp deploy --resource-group pywebapp_group --name pywebapp --src-path test.zip

배포가 완료된 후 웹 사이트를 방문해 보면, (기대와는 달리) Azure의 기본 웹 앱이 여전히 실행되고 있습니다. ^^; 단지, 화면의 메시지만 살짝 바뀌었는데요, application.py의 코드에서,

# cat /opt/defaultsite/application.py 
from flask import Flask
import os
app = Flask(__name__, static_folder='/opt/defaultsite')

@app.route('/')
def root():
    if os.path.isdir('/home/site/deployments') and len(next(os.walk('/home/site/deployments'))[1]) > 1:
        return app.send_static_file('hostingstart_dep.html')
    else:
        return app.send_static_file('hostingstart.html')

(배포로 인해) /home/site/deployments 디렉터리가 생성됐기 때문에 hostingstart_dep.html 페이지가 보이기 때문입니다. 이에 더해 한 가지 변화가 더 있는데요, 배포 후에 SSH 접속을 해보면 "-bash: antenv/bin/activate: No such file or directory" 오류가 발생하지 않고 오히려 파이썬 가상 환경에 진입한 상태의 프롬프트와 함께 시작 디렉터리도 다르게 나옵니다.

((antenv) ) root@pywebapp-532e70cd:/tmp/8dd91f1ff178df3#

당연하겠지만, 배포 후에는 (App Service 인스턴스 구동 후 제일 먼저 실행되는) /opt/startup/startup.sh 파일이 다음과 같이 바뀌었기 때문입니다.

# cat /opt/startup/startup.sh
#!/bin/sh

echo 'export APP_PATH="/tmp/8dd91f1ff178df3"' >> ~/.bashrc
echo 'cd $APP_PATH' >> ~/.bashrc

# Enter the source directory to make sure the script runs where the user expects
cd /tmp/8dd91f1ff178df3

export APP_PATH="/tmp/8dd91f1ff178df3"
if [ -z "$HOST" ]; then
                export HOST=0.0.0.0
fi

if [ -z "$PORT" ]; then
                export PORT=80
fi

export PATH="/opt/python/3.12.10/bin:${PATH}"
echo 'export VIRTUALENVIRONMENT_PATH="/tmp/8dd91f1ff178df3/antenv"' >> ~/.bashrc
echo '. antenv/bin/activate' >> ~/.bashrc
PYTHON_VERSION=$(python -c "import sys; print(str(sys.version_info.major) + '.' + str(sys.version_info.minor))")
echo Using packages from virtual environment 'antenv' located at '/tmp/8dd91f1ff178df3/antenv'.
export PYTHONPATH=$PYTHONPATH:"/tmp/8dd91f1ff178df3/antenv/lib/python$PYTHON_VERSION/site-packages"
echo "Updated PYTHONPATH to '$PYTHONPATH'"
. antenv/bin/activate
GUNICORN_CMD_ARGS="--timeout 600 --access-logfile '-' --error-logfile '-' -c /opt/startup/gunicorn.conf.py --chdir=/opt/defaultsite" gunicorn application:app

그러니까, Azure App Service에 파이썬 배포를 하면 가상 환경(virtualenv)을 자동으로 구성해 그 내부에, 위의 경우 ""/tmp/8dd91f1ff178df3" 디렉터리 하위에 ZIP 파일의 압축을 해제하는 것입니다.

그런데 문제는, gunicorn을 실행하는 부분에서 application:app을 찾는 디렉터리가 여전히 "--chdir=/opt/defaultsite" 옵션으로 인해 Azure의 기본 웹 앱 디렉터리로 설정돼 있다는 점입니다.
GUNICORN_CMD_ARGS="--timeout 600 --access-logfile '-' --error-logfile '-' -c /opt/startup/gunicorn.conf.py --chdir=/opt/defaultsite"

따라서, 배포 후에 우리가 원하는 웹 앱이 동작하게 만들려면 "Startup Command"를 설정해야 하는 것입니다. (문서에는 "optional"로 나오지만, 현실적으로는 필수 설정 항목입니다.)

Configure a Linux Python app for Azure App Service
; https://learn.microsoft.com/en-us/azure/app-service/configure-language-python

결국, App Service에 대해서는 (Azure Portal의 콘솔 화면에서 하거나, 또는) 다음과 같이 스크립트 설정 명령을 (자신의 환경에 맞게) 실행해 줘야 합니다.

// msdocs-python-fastapi-webapp-quickstart 예제의 경우라면!
// (지정한 sh 파일은 반드시 LF 형식으로 저장해야 합니다.)

c:\temp> az webapp config set --resource-group pywebapp_group --name pywebapp --startup-file "$APP_PATH/startup.sh"

// 또는, 어차피 현재 디렉터리가 "$APP_PATH"이므로 "./startup.sh"로 대체해도 됩니다.

Azure App Service는 "Startup Command"에 명령어가 있다면 기존의 "/opt/startup/startup.sh"에서 마지막 명령어만 다음과 같은 식으로 대체합니다.

# cat /opt/startup/startup.sh
#!/bin/sh

echo 'export APP_PATH="/tmp/8dd91f1ff178df3"' >> ~/.bashrc
echo 'cd $APP_PATH' >> ~/.bashrc

# ...[생략]...

export PATH="/opt/python/3.12.10/bin:${PATH}"
echo 'export VIRTUALENVIRONMENT_PATH="/tmp/8dd91f1ff178df3/antenv"' >> ~/.bashrc
echo '. antenv/bin/activate' >> ~/.bashrc
PYTHON_VERSION=$(python -c "import sys; print(str(sys.version_info.major) + '.' + str(sys.version_info.minor))")
echo Using packages from virtual environment 'antenv' located at '/tmp/8dd91f1ff178df3/antenv'.
export PYTHONPATH=$PYTHONPATH:"/tmp/8dd91f1ff178df3/antenv/lib/python$PYTHON_VERSION/site-packages"
echo "Updated PYTHONPATH to '$PYTHONPATH'"
. antenv/bin/activate
PATH="$PATH:/tmp/8dd91f1ff178df3" $APP_PATH/startup.sh

이제서야 대충 돌아가는 상황이 정리된 것 같습니다. ^^




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]







[최초 등록일: ]
[최종 수정일: 6/9/2025]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 




1  2  3  4  5  6  7  8  [9]  10  11  12  13  14  15  ...
NoWriterDateCnt.TitleFile(s)
13748정성태9/29/20246556닷넷: 2301. C# - BigInteger 타입이 byte 배열로 직렬화하는 방식
13747정성태9/28/20247186닷넷: 2300. C# - OpenSSH의 공개키 파일에 대한 "BEGIN OPENSSH PUBLIC KEY" / "END OPENSSH PUBLIC KEY" PEM 포맷파일 다운로드1
13746정성태9/28/20246426오류 유형: 924. Python - LocalProtocolError("Illegal header value ...")
13745정성태9/28/20246256Linux: 80. 리눅스 - 실행 중인 프로세스 내부의 환경변수 설정을 구하는 방법 (lldb)
13744정성태9/27/20246757닷넷: 2299. C# - Windows Hello 사용자 인증 다이얼로그 표시하기파일 다운로드1
13743정성태9/26/20247368닷넷: 2298. C# - Console 프로젝트에서의 await 대상으로 Main 스레드 활용하는 방법 [1]
13742정성태9/26/20247443닷넷: 2297. C# - ssh-keygen으로 생성한 ecdsa 유형의 Public Key 파일 해석 [1]파일 다운로드1
13741정성태9/25/20246738디버깅 기술: 202. windbg - ASP.NET MVC Web Application (.NET Framework) 응용 프로그램의 덤프 분석 시 요령
13740정성태9/24/20246484기타: 86. RSA 공개키 등의 modulus 값에 0x00 선행 바이트가 있는 이유(ASN.1 인코딩)
13739정성태9/24/20246689닷넷: 2297. C# - ssh-keygen으로 생성한 Public Key 파일 해석과 fingerprint 값(md5, sha256) 생성 [1]파일 다운로드1
13738정성태9/22/20246360C/C++: 174. C/C++ - 윈도우 운영체제에서의 file descriptor, FILE*파일 다운로드1
13737정성태9/21/20246878개발 환경 구성: 727. Visual C++ - 리눅스 프로젝트를 위한 빌드 서버의 msbuild 구성
13736정성태9/20/20246875오류 유형: 923. Visual Studio Code - Could not establish connection to "...": Port forwarding is disabled.
13735정성태9/20/20246727개발 환경 구성: 726. ARM 플랫폼용 Visual C++ 리눅스 프로젝트 빌드
13734정성태9/19/20246361개발 환경 구성: 725. ssh를 이용한 원격 docker 서비스 사용
13733정성태9/19/20246864VS.NET IDE: 194. Visual Studio - Cross Platform / "Authentication Type: Private Key"로 접속하는 방법
13732정성태9/17/20246986개발 환경 구성: 724. ARM + docker 환경에서 .NET 8 설치
13731정성태9/15/20247526개발 환경 구성: 723. C# / Visual C++ - Control Flow Guard (CFG) 활성화 [1]파일 다운로드2
13730정성태9/10/20247786오류 유형: 922. docker - RULE_APPEND failed (No such file or directory): rule in chain DOCKER
13729정성태9/9/20248491C/C++: 173. Windows / C++ - AllocConsole로 할당한 콘솔과 CRT 함수 연동 [1]파일 다운로드1
13728정성태9/7/20248215C/C++: 172. Windows - C 런타임에서 STARTUPINFO의 cbReserved2, lpReserved2 멤버를 사용하는 이유파일 다운로드1
13727정성태9/6/20248872개발 환경 구성: 722. ARM 플랫폼 빌드를 위한 미니 PC(?) - Khadas VIM4 [1]
13726정성태9/5/20248099C/C++: 171. C/C++ - 윈도우 운영체제에서의 file descriptor와 HANDLE파일 다운로드1
13725정성태9/4/20246707디버깅 기술: 201. WinDbg - sos threads 명령어 실행 시 "Failed to request ThreadStore"
13724정성태9/3/20249359닷넷: 2296. Win32/C# - 자식 프로세스로 HANDLE 상속파일 다운로드1
13723정성태9/2/20248912C/C++: 170. Windows - STARTUPINFO의 cbReserved2, lpReserved2 멤버 사용자 정의파일 다운로드2
1  2  3  4  5  6  7  8  [9]  10  11  12  13  14  15  ...