다음을 통해 공유


GitHub Actions를 사용하여 App Service에 Python 웹앱 배포(Linux)

이 문서에서는 GitHub Actions에서 CI/CD(지속적인 통합 및 지속적인 업데이트) 플랫폼을 사용하여 Linux의 Azure App Service에 Python 웹앱을 배포하는 방법을 설명합니다. GitHub Actions 워크플로는 리포지토리에 커밋이 있을 때마다 코드를 자동으로 빌드하고 App Service 인스턴스에 배포합니다. GitHub Actions 워크플로에서 테스트 스크립트, 보안 검사 및 다단계 배포와 같은 다른 자동화를 추가할 수 있습니다.

앱 코드에 대한 리포지토리 만들기

이 문서의 절차를 완료하려면 GitHub 리포지토리에 커밋된 Python 웹앱이 필요합니다.

비고

앱에서 DjangoSQLite 데이터베이스를 사용하는 경우 이러한 절차에서는 작동하지 않습니다. SQLite는 로컬 파일 기반 스토리지 제한으로 인해 대부분의 클라우드 호스팅 환경에서 지원되지 않습니다. PostgreSQL 또는 Azure Cosmos DB와 같은 클라우드 호환 데이터베이스로 전환하는 것이 좋습니다. 자세한 내용은 이 문서의 뒷부분에 있는 Django 고려 사항 검토를 참조하세요.

대상 App Service 인스턴스 만들기

App Service 인스턴스를 만드는 가장 빠른 방법은 대화형 Azure Cloud Shell을 통해 Azure CLI(명령줄 인터페이스)를 사용하는 것입니다. Cloud Shell에는 Git 및 Azure CLI가 포함됩니다. 다음 절차에서는 az webapp up 명령을 사용하여 App Service 인스턴스를 만들고 앱의 초기 배포를 수행합니다.

  1. https://portal.azure.com에서 Azure Portal에 로그인합니다.

  2. 포털 도구 모음에서 Cloud Shell 옵션을 선택하여 Azure CLI를 엽니다.

    Azure Portal 도구 모음에서 아이콘 작업을 사용하여 Azure Cloud Shell을 여는 방법을 보여 주는 스크린샷

  3. Cloud Shell의 드롭다운 메뉴에서 Bash 옵션을 선택합니다.

    Cloud Shell에서 Bash 옵션을 선택하는 방법을 보여 주는 스크린샷

  4. Cloud Shell에서 git clone 명령을 사용하여 리포지토리를 복제합니다.

    팁 (조언)

    명령 또는 텍스트를 Cloud Shell에 붙여넣려면 Ctrl+Shift+V 바로 가기 키를 사용하거나 마우스 오른쪽 단추를 클릭하고 상황에 맞는 메뉴에서 붙여넣 기를 선택합니다.

    • Flask 샘플 앱의 경우 다음 명령을 사용할 수 있습니다. 부분을 <github-user> 리포지토리를 포크한 GitHub 계정의 이름으로 바꿉다.

      git clone https://github.com/<github-user>/python-sample-vscode-flask-tutorial.git
      
    • 앱이 다른 리포지토리에 있는 경우 특정 리포지토리에 대한 GitHub Actions를 설정합니다. 부분을 <github-user> 리포지토리를 포크한 GitHub 계정의 이름으로 바꾸고 자리 표시자에 실제 리포지토리 이름을 <repo-name> 제공합니다.

      git clone https://github.com/<github-user>/<repo-name>.git
      

    비고

    Cloud Shell은 cloud-shell-storage-your-region이라는 리소스 그룹의 Azure Storage< 계정으로 지원됩니다>. 해당 스토리지 계정에는 복제된 리포지토리를 저장하는 Cloud Shell 파일 시스템의 이미지가 포함되어 있습니다. 이 스토리지에는 약간의 비용이 듭니다. 이 문서를 완료한 후 만든 다른 리소스와 함께 스토리지 계정을 삭제할 수 있습니다.

  5. Cloud Shell에서 디렉터리를 Python 앱의 리포지토리 폴더로 변경하여 az webapp up 명령이 앱을 Python으로 인식합니다. Flask 샘플 앱의 경우 다음 명령을 사용합니다.

    cd python-sample-vscode-flask-tutorial
    
  6. Cloud Shell에서 az webapp up 명령을 사용하여 App Service 인스턴스를 만들고 앱에 대한 초기 배포를 수행합니다.

    az webapp up --name <app-service-name> --runtime "PYTHON:3.9"
    
    • <app-service-name> 자리 표시자의 경우 Azure에서 고유한 App Service 이름을 지정합니다. 이름은 3~60자여야 하며 문자, 숫자 및 하이픈만 포함할 수 있습니다. 이름은 문자로 시작하고 문자 또는 숫자로 끝나야 합니다.

    • 시스템에서 사용 가능한 런타임 목록을 보려면 이 명령을 사용합니다 az webapp list-runtimes .

    • 명령에 런타임 값을 입력할 때 Python 주 버전 및 부 버전인 X.Y 형식을 사용합니다PYTHON:X.Y.

    • 매개 변수를 사용하여 --___location App Service 인스턴스의 지역 위치를 지정할 수도 있습니다. 사용 가능한 위치 목록을 보려면 이 명령을 사용합니다 az account list-locations --output table .

  7. 앱에 사용자 지정 시작 스크립트가 있는 경우 az webapp config 명령을 사용하여 스크립트를 시작합니다.

    • 앱에 사용자 지정 시작 스크립트가 없는 경우 다음 단계를 계속 진행합니다.

    • Flask 샘플 앱의 경우 다음 명령을 실행하여 startup.txt 파일의 시작 스크립트에 액세스해야 합니다.

      az webapp config set \
         --resource-group <resource-group-name> \
         --name <app-service-name> \
         --startup-file startup.txt
      

      리소스 그룹 이름 및 App Service 인스턴스 이름을 <resource-group-name><app-service-name> 자리 표시자에 제공합니다. 리소스 그룹 이름을 찾으려면 이전 az webapp up 명령의 출력을 확인합니다. 리소스 그룹 이름에는 azure-account-name>_rg_와 같이< azure 계정 이름 뒤에 _rg 접미사가 포함됩니다.

  8. 실행 중인 앱을 보려면 브라우저를 열고 App Service 인스턴스의 배포 엔드포인트로 이동합니다. 다음 URL에서 <app-service-name> 자리 표시자를 App Service 인스턴스 이름으로 바꿉니다.

    http://<app-service-name>.azurewebsites.net
    

    일반 페이지가 표시되면 App Service 인스턴스가 시작될 때까지 몇 초 정도 기다렸다가 페이지를 새로 고칩니다.

    • 제네릭 페이지가 계속 표시되면 올바른 폴더에서 배포했는지 확인합니다.
    • Flask 샘플 앱의 경우 python-sample-vscode-flask-tutorial 폴더에서 배포했는지 확인합니다. 또한 시작 명령을 올바르게 설정했는지 확인합니다.

App Service에서 연속 배포 설정

다음 절차에서는 CD(지속적인 업데이트)를 설정합니다. 즉, 워크플로가 트리거할 때마다 새 코드 배포가 발생합니다. 문서 예제에서의 트리거는 PR(끌어오기 요청)과 같이 리포지토리의 main 브랜치의 변경입니다.

  1. Cloud Shell에서 python-sample-vscode-flask-tutorial과 같은 앱 하위 폴더가 아닌 시스템(~)의 루트 디렉터리에 있는지 확인합니다.

  2. az webapp deployment github-actions add 명령을 사용하여 GitHub Actions를 추가합니다. 자리 표시자를 특정 값으로 대체합니다.

    az webapp deployment github-actions add \
      --repo "<github-user>/<github-repo>" \
      --resource-group <resource-group-name> \
      --branch <branch-name> \
      --name <app-service-name> \
      --login-with-github
    
    • 매개 변수는 --login-with-github 대화형 메서드를 사용하여 개인 액세스 토큰을 검색합니다. 프롬프트에 따라 인증을 완료합니다.

    • 시스템에서 동일한 App Service 인스턴스 이름을 가진 기존 워크플로 파일이 발견되면 프롬프트에 따라 워크플로를 덮어쓸지 여부를 선택합니다. 명령과 --force 함께 매개 변수를 사용하여 충돌하는 워크플로를 자동으로 덮어쓸 수 있습니다.

    add 명령은 다음 작업을 완료합니다.

    • 리포지토리의 .github/workflows/<workflow-name>.yml 경로에 새 워크플로 파일을 만듭니다. 파일 이름에는 App Service 인스턴스의 이름이 포함됩니다.
    • App Service 인스턴스에 대한 비밀이 포함된 게시 프로필을 가져와서 GitHub 작업 비밀로 추가합니다. 비밀의 이름은 AZUREAPPSERVICE_PUBLISHPROFILE_ 시작합니다. 이 비밀은 워크플로 파일에서 참조됩니다.
  3. az webapp deployment source show 명령을 사용하여 소스 제어 배포 구성의 세부 정보를 가져옵니다. 자리 표시자 매개 변수를 특정 값으로 바꿉다.

    az webapp deployment source show \
      --name <app-service-name> \
      --resource-group <resource-group-name>
    
  4. 명령 출력에서 repoUrl 속성과 branch 속성의 값을 확인합니다. 이러한 값은 명령으로 지정한 값과 add 일치해야 합니다.

GitHub 워크플로 및 작업 검사

워크플로 정의는 리포지토리의 /.github/workflows/ 경로에 있는 YAML(.yml) 파일에 지정됩니다. 이 YAML 파일에는 GitHub 리포지토리와 연결된 자동화된 프로세스인 워크플로를 구성하는 다양한 단계와 매개 변수가 포함되어 있습니다. 워크플로를 사용하여 GitHub에서 모든 프로젝트를 빌드, 테스트, 패키지, 릴리스 및 배포할 수 있습니다.

각 워크플로는 하나 이상의 작업으로 구성되며 각 작업은 일련의 단계입니다. 각 단계는 셸 스크립트 또는 작업입니다. 각 작업에는 워크플로 파일에 작업 섹션이 있습니다.

Azure App Service에 배포하기 위해 Python 코드로 설정된 워크플로와 관련하여 워크플로에는 다음과 같은 작업이 있습니다.

조치 설명
체크아웃 리포지토리를 러너, GitHub Actions 에이전트에서 확인하세요.
setup-python 실행기에서 Python을 설치합니다.
앱서비스-빌드 웹앱을 빌드합니다.
webapps-deploy 게시 프로필 자격 증명을 사용하여 웹앱을 배포하여 Azure에서 인증합니다. 자격 증명은 GitHub 비밀에 저장됩니다.

워크플로를 만드는 데 사용되는 워크플로 템플릿은 Azure/actions-workflow-samples입니다.

워크플로는 지정된 분기에 대한 푸시 이벤트에서 트리거됩니다. 이벤트 및 분기는 워크플로 파일의 시작 부분에 정의됩니다. 예를 들어 다음 코드 조각은 분기에 대한 푸시 이벤트에서 워크플로가 트리거됨을 보여 줍니다.

on:
  push:
    branches:
    - main

OAuth 권한 있는 앱

지속적인 배포를 설정할 때 GitHub 계정에 대한 권한 있는 OAuth 앱으로 Azure App Service에 권한을 부여합니다. App Service는 권한 있는 액세스를 사용하여 리포지토리의 .github/workflows/<workflow-name>.yml 경로에 GitHub 작업 YAML 파일을 만듭니다.

권한 있는 앱을 보고 GitHub 계정에서 권한을 취소하려면 설정>통합/애플리케이션으로 이동합니다.

GitHub 계정에 대해 권한이 부여된 OAuth 앱을 보는 방법을 보여 주는 스크린샷

워크플로우 게시 프로필 비밀번호

리포지토리에 추가된 .github/workflows/<workflow-name>.yml 워크플로 파일에는 워크플로의 배포 작업에 필요한 게시 프로필 자격 증명의 자리 표시자가 있습니다. 게시 프로필 정보는 리포지토리에 암호화되어 저장됩니다.

비밀을 보려면 설정>보안>비밀 및 변수 작업으로> 이동합니다.

GitHub에서 리포지토리에 대한 작업 비밀을 보는 방법을 보여 주는 스크린샷

이 문서에서 GitHub 작업은 게시 프로필 자격 증명을 사용하여 인증합니다. 서비스 주체 또는 OpenID Connect와 같이 인증하는 다른 방법이 있습니다. 자세한 내용은 GitHub Actions를 사용하여 App Service에 배포를 참조하세요.

워크플로 실행 및 테스트

마지막 단계는 리포지토리를 변경하여 워크플로를 테스트하는 것입니다.

  1. 브라우저에서 샘플 리포지토리(또는 사용한 리포지토리)의 포크로 이동한 후, 트리거로 설정한 브랜치를 선택합니다.

    GitHub Actions 워크플로가 정의된 리포지토리 및 분기로 이동하는 방법을 보여 주는 스크린샷

  2. Python 웹앱을 약간 변경합니다.

    Flask 자습서의 경우 다음과 같은 간단한 변경 사항이 있습니다.

    1. 트리거 분기의 /hello-app/templates/home.html 파일로 이동합니다.
    2. 편집(연필)을 선택합니다.
    3. 편집기에서 인쇄 <p> 문을 찾아 "재배포됨!" 텍스트를 추가합니다.
  3. 작업 중인 분기에 직접 변경 내용을 커밋합니다.

    1. 편집기에서 오른쪽 위에서 변경 내용 커밋 을 선택합니다. 변경 내용 커밋 창이 열립니다.
    2. 변경 내용 커밋 창에서 커밋 메시지를 원하는 대로 수정하고 변경 내용 커밋을 선택합니다.

    커밋 프로세스는 GitHub Actions 워크플로를 트리거합니다.

워크플로를 수동으로 트리거할 수도 있습니다.

  1. 연속 배포를 위해 설정된 리포지토리의 작업 탭으로 이동합니다.

  2. 워크플로 목록에서 워크플로를 선택한 다음 워크플로 실행을 선택합니다.

실패한 워크플로 문제 해결

앱 리포지토리에 대한 작업 탭에서 워크플로의 상태를 확인할 수 있습니다. 이 문서에서 만든 워크플로 파일을 검사하면 빌드배포라는 두 가지 작업이 표시됩니다. 미리 알림으로 워크플로는 Azure/actions-workflow-samples 템플릿을 기반으로 합니다.

실패한 작업의 경우 작업 태스크의 출력을 확인하여 실패의 표시를 확인합니다.

다음은 조사할 몇 가지 일반적인 문제입니다.

  • 종속성 누락으로 인해 앱이 실패하는 경우 배포 중에requirements.txt 파일이 처리되지 않습니다. 이 동작은 이 문서에 표시된 대로 명령을 사용하는 az webapp up 대신 포털에서 직접 웹앱을 만든 경우에 발생합니다.

  • 포털을 통해 앱 서비스를 프로비전한 경우 빌드 작업 SCM_DO_BUILD_DURING_DEPLOYMENT 설정이 설정되지 않을 수 있습니다. 이 설정은 true로 설정해야 합니다. 이 az webapp up 명령은 빌드 작업을 자동으로 설정합니다.

  • "TLS 핸드셰이크 시간 제한"에 대한 오류 메시지가 표시되면 앱 리포지토리의 작업 탭에서 트리거 자동 배포를 선택하여 워크플로를 수동으로 실행합니다. 시간 제한이 일시적인 문제인지 확인할 수 있습니다.

  • 이 문서에 표시된 대로 컨테이너 앱에 대한 지속적인 배포를 설정하는 경우 초기 워크플로 파일 .github/workflows/<workflow-name>.yml 자동으로 만들어집니다. 파일을 수정한 경우 수정 내용을 제거하여 오류가 발생하는지 확인합니다.

배포 후 스크립트 실행

배포 후 스크립트는 앱 코드에서 예상하는 환경 변수 정의와 같은 여러 작업을 완료할 수 있습니다. 앱 코드의 일부로 스크립트를 추가하고 시작 명령을 사용하여 스크립트를 실행합니다.

워크플로 YAML 파일에서 변수 값을 하드 코딩하지 않도록 하려면 GitHub에서 변수를 구성하고 스크립트에서 변수 이름을 참조하는 것이 좋습니다. 리포지토리 또는 환경(계정 리포지토리)에 대해 암호화된 비밀을 만들 수 있습니다. 자세한 내용은 GitHub Actions에서 비밀 사용을 참조하세요.

Django 고려 사항 검토

이 문서의 앞부분에서 설명한 것처럼 별도의 데이터베이스를 사용하는 경우 GitHub Actions를 사용하여 Linux의 Azure App Service에 Django 앱을 배포할 수 있습니다. App Service에서 db.sqlite3 파일을 잠가 읽기 및 쓰기를 모두 차단하므로 SQLite 데이터베이스를 사용할 수 없습니다. 이 동작은 외부 데이터베이스에 영향을 주지 않습니다.

App Service에서 Python 앱 구성 - 컨테이너 시작 프로세스 문서에서는 App Service가 앱 코드 내에서 일반적으로 앱 개체를 포함하는 wsgi.py 파일을 자동으로 찾는 방법을 설명합니다. 이 명령을 사용하여 webapp config set 시작 명령을 설정한 경우 매개 변수를 --startup-file 사용하여 앱 개체가 포함된 파일을 지정했습니다. 웹앱 배포 작업에서는 이 webapp config set 명령을 사용할 수 없습니다. 대신 매개 변수를 startup-command 사용하여 시작 명령을 지정할 수 있습니다. 예를 들어 다음 코드는 워크플로 파일에서 시작 명령을 지정하는 방법을 보여줍니다.

startup-command: startup.txt

Django를 사용하는 경우 일반적으로 앱 코드를 배포한 후 명령을 사용하여 python manage.py migrate 데이터 모델을 마이그레이션하려고 합니다. 배포 후 스크립트에서 마이그레이션 명령을 실행할 수 있습니다.

GitHub Actions 연결 끊기

App Service 인스턴스에서 GitHub Actions의 연결을 끊으면 앱 배포를 다시 구성할 수 있습니다. 연결을 끊은 후 워크플로 파일에 발생하는 작업과 파일을 저장하거나 삭제할지 여부를 선택할 수 있습니다.

다음 Azure CLI az webapp deployment github-actions remove 명령을 사용하여 GitHub Actions 연결을 끊 습니다. 자리 표시자를 특정 값으로 대체합니다.

az webapp deployment github-actions remove \
  --repo "<github-username>/<github-repo>" \
  --resource-group <resource-group-name> \
  --branch <branch-name> \
  --name <app-service-name> \
  --login-with-github

자원을 정리하세요

이 문서에서 만든 Azure 리소스에 대한 요금이 발생하지 않도록 하려면 App Service 인스턴스 및 App Service 계획을 포함하는 리소스 그룹을 삭제합니다.

Azure Cloud Shell을 포함하여 Azure CLI가 설치된 모든 곳에서 az group delete 명령을 사용하여 리소스 그룹을 삭제할 수 있습니다.

az group delete --name <resource-group-name>

스토리지 계정 삭제

약간의 월별 요금이 발생하는 Cloud Shell에 대한 파일 시스템을 유지하는 스토리지 계정을 삭제하려면 cloud-shell-storage-로 시작하는 리소스 그룹을 삭제합니다. 그룹의 유일한 사용자인 경우 리소스 그룹을 삭제해도 안전합니다. 다른 사용자가 있는 경우 리소스 그룹에서 스토리지 계정을 삭제할 수 있습니다.

GitHub 계정 및 리포지토리 업데이트

Azure 리소스 그룹을 삭제하는 경우 지속적인 배포를 위해 연결된 GitHub 계정 및 리포지토리를 다음과 같이 수정하는 것이 좋습니다.

  • 앱 리포지토리에서 .github/workflows/<workflow-name>.yml 파일을 제거합니다.
  • 앱 리포지토리 설정에서 워크플로에 대해 만든 AZUREAPPSERVICE_PUBLISHPROFILE_ 비밀 키를 제거합니다.
  • GitHub 계정 설정에서 Azure App Service를 GitHub 계정에 대한 권한 있는 Oauth 앱으로 제거합니다.