Visual Studio에서 만든 GitHub Actions 워크플로를 사용하여 Azure에 애플리케이션 배포

Visual Studio 2019 버전 16.11부터 GitHub.com에서 호스팅되는 .NET 프로젝트에 대한 새로운 GitHub Actions 워크플로를 만들 수 있습니다.

필수 조건

GitHub 작업을 사용하여 단일 프로젝트를 Azure에 배포하기

솔루션 탐색기에서 GitHub.com 호스트 프로젝트를 마우스 오른쪽 단추로 클릭하고 게시를 선택합니다.

> 게시를 마우스 오른쪽 단추로 클릭

다음 화면에서 Azure, 다음을 차례로 선택합니다.

Azure 선택

프로젝트 형식에 따라 선택할 수 있는 다른 Azure 서비스 목록이 표시됩니다. 요구 사항에 맞는 지원되는 Azure 서비스 중 하나를 선택합니다.

프로젝트에 적합한 Azure 서비스 선택

마법사의 마지막 단계에서 GitHub Actions 워크플로를 사용한 CI/CD(yml 파일을 생성함)를 선택한 다음, 마침을 선택합니다.

GitHub Actions 워크플로를 사용한 CI/CD(yml 파일을 생성함)

Visual Studio에서는 새 GitHub Actions 워크플로를 생성한 다음, 사용자에게 커밋하고 GitHub.com에 푸시하도록 요청합니다.

커밋 후 푸시

기본 제공 Git 도구를 사용하여 이 단계를 완료하면 Visual Studio에서 워크플로의 실행을 검색합니다.

워크플로 실행 중

GitHub 비밀 설정

생성된 워크플로를 Azure에 성공적으로 배포하려면 게시 프로필에 대한 액세스 권한이 필요할 수 있습니다.

하나의 GitHub 비밀

성공적으로 배포하려면 서비스 주체에 대한 액세스 권한도 필요할 수 있습니다.

두 개의 GitHub 비밀

모든 경우에 Visual Studio는 사용자 대신 올바른 값으로 GitHub 비밀을 설정하려고 시도합니다. 실패할 경우 사용자에게 이를 알리고 다시 시도할 수 있는 기회를 제공합니다.

GitHub 비밀 누락

비밀을 다시 설정하지 못하면 Visual Studio는 비밀에 수동으로 액세스할 수 있는 기회를 제공하므로, 사용자는 GitHub.com의 리포지토리 페이지를 통해 프로세스를 완료할 수 있습니다.

누락된 GitHub 비밀 설정

GitHub 동작을 사용하여 여러 프로젝트를 Azure 컨테이너 앱에 배포하기

이 단계는 Docker 컨테이너를 사용하는 프로젝트가 두 개 이상이고 이를 멀티프로젝트 앱으로 배포하려는 경우에 적합합니다. 마이크로 서비스를 구현하는 앱과 같은 멀티프로젝트 앱을 Azure Container Apps 또는 Azure Kubernetes Service(AKS)에 배포할 수 있습니다. 이 문서에서는 Azure Container Apps에 대해 설명합니다.

  1. 솔루션 탐색기에서 GitHub 작업 노드를 마우스 오른쪽 버튼으로 클릭하고 새 워크플로를 선택합니다. GitHub 작업 워크플로 마법사가 나타납니다.

    GitHub Actions 노드 메뉴의 스크린샷

  2. GitHub Actions 워크플로우 대상 화면에서 Azure를 선택합니다.

  3. 특정 대상의 경우 Azure 컨테이너 앱를 선택합니다. 마법사가 컨테이너 앱 화면으로 진행됩니다.

    기존 Azure Container Apps를 보여 주는 스크린샷

  4. 기존 Azure 컨테이너 앱을 선택하거나 새로 만들기를 선택합니다.

    기존 Azure Container Apps를 보여 주는 스크린샷

    새 계정을 만들면 이 화면이 표시됩니다. 테스트하거나 학습할 때는 일반적으로 새 리소스 그룹을 만들어 나중에 모든 것을 쉽게 삭제할 수 있도록 하는 것이 가장 좋습니다. 컨테이너 앱 환경은 동일한 가상 네트워크를 공유하고 동일한 로깅 대상에 로그를 기록하는 컨테이너 앱 그룹을 둘러싼 안전한 경계입니다. Azure 컨테이너 앱 환경를 참조하세요. 이 인스턴스가 무엇인지 모르거나 이전에 생성한 적이 없다면 이 인스턴스에 대해 새로 생성하세요.

    새 Azure Container Apps 인스턴스 만들기를 보여주는 스크린샷

    생성되면 새 Azure 컨테이너 앱 인스턴스가 표시됩니다.

    새로 생성된 Azure Container Apps 인스턴스를 보여주는 스크린샷

  5. 다음를 선택하여 레지스트리 화면으로 이동합니다. 기존 Azure 컨테이너 레지스트리를 선택하거나 새 레지스트리를 만듭니다.

    Azure Container Registry 화면의 스크린샷

    새로 만들기를 선택하면 다음과 같은 화면이 표시됩니다. 리소스 그룹, SKU를 입력하고 가능하면 이전과 동일한 지역을 선택합니다. Azure 컨테이너 레지스트리의 SKU에 대한 자세한 내용은 Azure 컨테이너 레지스트리 서비스 티어를 참조하세요.

    방금 생성된 새 Azure Container Registry를 보여주는 스크린샷

    생성되면 새 레지스트리가 화면에 표시됩니다.

    새 Azure Container Registry 만들기를 보여주는 스크린샷

  6. 솔루션에서 배포 가능한 프로젝트가 표시되며, 동일한 Azure 컨테이너 앱 인스턴스에서 함께 배포할 프로젝트를 선택합니다.

    배포할 프로젝트의 선택을 보여 주는 스크린샷

  7. 마침을 선택합니다. Azure에서 에셋을 만들고 인증을 설정하는 명령이 실행되는 것을 볼 수 있습니다. 실패하는 경우 CLI에서 다시 시도할 수 있으므로 사용된 명령줄을 기록해 두세요. 이 단계에서 인증에 실패하더라도 너무 걱정하지 마세요. 나중에 Visual Studio에서 인증을 설정할 수도 있습니다.

  8. 완료되면 요약 화면이 나타납니다. 요약 화면에는 자격 증명이 표시되며, 이 자격 증명은 Visual Studio가 GitHub 리포지토리에 GitHub 작업 비밀 아래에 만든 항목과 일치합니다. 노란색 경고 표시가 있는지 확인하세요. 생성 과정에서 인증 단계 중 하나라도 실패한 경우 여기에서 경고 표시가 있는 링크를 클릭하고 몇 가지 단계를 따라 수정할 수 있습니다.

  9. 워크플로 파일을 열어 Visual Studio에서 생성된 내용을 확인합니다. Visual Studio는 사용자의 상황에 맞는 워크플로를 생성하기 위해 최선을 다하지만 모든 앱과 리포지토리는 고유하므로 Visual Studio에서 생성한 워크플로 YML 파일을 수동으로 편집해야 성공적으로 실행되는 경우가 많습니다. 열려면 솔루션 탐색기에서 GitHub Actions 노드를 확장하고 방금 생성한 워크플로우를 마우스 오른쪽 버튼으로 클릭한 다음 편집를 선택합니다.

다음은 배포 가능한 두 개의 프로젝트, WebAPI 및 WebFrontEnd가 있는 솔루션에 대해 Visual Studio에서 만든 워크플로 파일의 예입니다.

on:
push:
  branches:
  - main
env:
CONTAINER_REGISTRY_LOGIN_SERVER: registry20230810121555.azurecr.io
CONTAINER_APP_NAME: containerapp20230810121017
CONTAINER_APP_RESOURCE_GROUP_NAME: webfrontend-container-app-1234
CONTAINER_APP_CONTAINER_NAME: containerapp
jobs:
WebApi_buildImageAndDeploy:
  runs-on: ubuntu-latest
  steps:
  - name: Checkout source code
    uses: actions/checkout@v3
  - name: Set up Docker Buildx
    uses: docker/setup-buildx-action@v2
  - name: Login to Docker registry
    uses: docker/login-action@v2
    with:
      registry: ${{ env.CONTAINER_REGISTRY_LOGIN_SERVER }}
      username: ${{ secrets.registry20230810121555_USERNAME_6891 }}
      password: ${{ secrets.registry20230810121555_PASSWORD_6891 }}
  - name: Build and push Docker image to Azure container registry
    uses: docker/build-push-action@v4
    with:
      push: true
      tags: ${{ env.CONTAINER_REGISTRY_LOGIN_SERVER }}/webapi:${{ github.sha }}
      file: WebApi\Dockerfile
  - name: Azure login
    uses: azure/login@v1
    with:
      creds: ${{ secrets.containerapp20230810121017_SPN }}
  - name: Deploy to Azure container app
    uses: azure/CLI@v1
    with:
      inlineScript: >-
        az config set extension.use_dynamic_install=yes_without_prompt
        az containerapp registry set --name ${{ env.CONTAINER_APP_NAME }} --resource-group ${{ env.CONTAINER_APP_RESOURCE_GROUP_NAME }} --server ${{ env.CONTAINER_REGISTRY_LOGIN_SERVER }} --username ${{ secrets.registry20230810121555_USERNAME_2047 }} --password ${{ secrets.registry20230810121555_PASSWORD_2047 }}
        az containerapp update --name ${{ env.CONTAINER_APP_NAME }} --container-name ${{ env.CONTAINER_APP_CONTAINER_NAME }} --resource-group ${{ env.CONTAINER_APP_RESOURCE_GROUP_NAME }} --image ${{ env.CONTAINER_REGISTRY_LOGIN_SERVER }}/webapi:${{ github.sha }}
  - name: Azure logout
    run: az logout
WebFrontEnd_buildImageAndDeploy:
  runs-on: ubuntu-latest
  needs: WebApi_buildImageAndDeploy
  steps:
  - name: Checkout source code
    uses: actions/checkout@v3
  - name: Set up Docker Buildx
    uses: docker/setup-buildx-action@v2
  - name: Login to Docker registry
    uses: docker/login-action@v2
    with:
      registry: ${{ env.CONTAINER_REGISTRY_LOGIN_SERVER }}
      username: ${{ secrets.registry20230810121555_USERNAME_2047 }}
      password: ${{ secrets.registry20230810121555_PASSWORD_2047 }}
  - name: Build and push Docker image to Azure container registry
    uses: docker/build-push-action@v4
    with:
      push: true
      tags: ${{ env.CONTAINER_REGISTRY_LOGIN_SERVER }}/webfrontend:${{ github.sha }}
      file: WebFrontEnd\Dockerfile
  - name: Azure login
    uses: azure/login@v1
    with:
      creds: ${{ secrets.containerapp20230810121017_SPN }}
  - name: Deploy to Azure container app
    uses: azure/CLI@v1
    with:
      inlineScript: >-
        az config set extension.use_dynamic_install=yes_without_prompt
        az containerapp registry set --name ${{ env.CONTAINER_APP_NAME }} --resource-group ${{ env.CONTAINER_APP_RESOURCE_GROUP_NAME }} --server ${{ env.CONTAINER_REGISTRY_LOGIN_SERVER }} --username ${{ secrets.registry20230810121555_USERNAME_2047 }} --password ${{ secrets.registry20230810121555_PASSWORD_2047 }}
        az containerapp update --name ${{ env.CONTAINER_APP_NAME }} --container-name ${{ env.CONTAINER_APP_CONTAINER_NAME }} --resource-group ${{ env.CONTAINER_APP_RESOURCE_GROUP_NAME }} --image ${{ env.CONTAINER_REGISTRY_LOGIN_SERVER }}/webfrontend:${{ github.sha }}
  - name: Azure logout
    run: az logout

워크플로의 주요 기능은 올바른 인증을 통해 Azure 서비스에 로그인하고 명령을 실행하여 앱을 빌드 및 배포하는 것입니다.

워크플로 편집 및 테스트

위의 절차에 따라 워크플로 YML 파일이 생성되지만 일반적으로 배포에 사용하기 전에 검토하고 사용자 지정해야 합니다. 워크플로 동작 작성에 대한 GitHub의 지침을 참조해야 할 수도 있습니다(사용자 지정 동작 정보 참조). 워크플로 파일에는 환경 변수 설정, 비밀 번호 이름 등 구성 가능한 많은 요소가 포함되어 있습니다. Docker파일의 위치, Azure 컨테이너 앱의 이름, 워크플로 실행을 트리거하는 데 사용할 리포지토리의 브랜치 및 GitHub의 시크릿에 대한 참조를 볼 수 있습니다. ${{ secrets.SECRET_NAME }}시크릿은 구문을 사용하여 참조합니다. GitHub 액션 시크릿를 참조하세요.

프로젝트가 리포지토리의 루트에 있지 않은 경우 워크플로를 변경하여 Docker파일을 찾을 수 있는 경로를 지정해야 합니다. 두 프로젝트 모두에서 Docker파일의 상대 경로에 대한 환경 변수를 추가합니다.

DOCKER_FILEPATH_WEBAPI: docker/ComposeSample/WebApi/Dockerfile
DOCKER_FILEPATH_WEBFRONTEND: docker/ComposeSample/WebFrontend/Dockerfile

file 매개변수에는 다음과 같이 환경 변수 값을 사용합니다:

- name: Build and push Docker image to Azure container registry
  uses: docker/build-push-action@v4
  with:
    push: true
    tags: ${{ env.CONTAINER_REGISTRY_LOGIN_SERVER }}/webfrontend:${{ github.sha }}
    file: ${{ env.DOCKER_FILEPATH_WEBFRONTEND }}

도커파일을 변경해야 하는 경우 변경 내용을 저장하고 커밋한 후 원격 리포지토리에 푸시합니다. Visual Studio에서 생성하는 워크플로에는 지정된 브랜치에서 업데이트되면 트리거가 실행되도록 하는 트리거가 포함되어 있습니다. working 브랜치에 푸시하는 경우 다음 코드와 비슷해야 합니다:

on:
  push:
  branches:
  - working

변경 사항을 테스트하려면 변경 사항을 커밋하고 트리거 코드에 지정된 리포지토리의 브랜치에 푸시합니다. PR(끌어오기 요청)을 생성할 필요가 없습니다. push워크플로는 트리거가 올바른 브랜치로 설정되어 있는 한 실행됩니다.

GitHub.com 리포지토리의 Actions 탭에서 워크플로 실행을 찾습니다. Visual Studio의 GitHub 작업 요약 탭에 있는 링크를 사용하여 바로 이동할 수 있습니다. GitHub에서 워크플로 실행을 열어 로그를 볼 수 있습니다.

문제 해결

워크플로가 성공적으로 실행되지 않는 경우 다음 문제 해결 팁이 도움이 될 수 있습니다.

이슈: 빌드 단계가 빌드되지 않음

Docker파일에서 발생할 수 있는 한 가지 문제는 빌드 단계가 Visual Studio에서와 같이 작동하지 않는다는 것입니다. Visual Studio에서 프로젝트에 대해 생성하는 기본 Docker파일을 보면 이 문제를 확인할 수 있습니다. 이러한 도커파일이 있는 경우 빌드 단계에서 다음과 같이 수정하는 것을 고려하세요. 다음은 프로젝트가 리포지토리의 docker/ComposeSample/WebApi에 있는 예입니다. 워크플로 빌드 컨테이너의 Docker파일 컨텍스트가 리포지토리의 루트로 설정되어 있기 때문에 전체 경로가 제공되지만, Visual Studio에서는 프로젝트 폴더 위의 폴더로 설정되어 있습니다. 여기에 접미사 _build을 추가하여 빌드 폴더를 만들고 프로젝트 파일만 복사하는 대신 전체 폴더를 복사합니다. Visual Studio에서 생성된 기본 Docker파일과 비교하면, COPY 명령의 첫 번째 인수에 있는 경로의 파일 부분이 제거되어 프로젝트 파일만 복사하는 것이 아니라 전체 폴더를 복사합니다. 이러한 변경이 없으면 이 단계에서 MSBuild 오류가 발생합니다.

FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY ["docker/ComposeSample/WebApi/", "WebApi_build/"]
RUN dotnet restore "WebApi_build/WebApi.csproj"
COPY . .
WORKDIR "/src/WebApi_build"
RUN dotnet build "WebApi.csproj" -c Release -o /app/build

이슈: 인증 자격 증명

워크플로를 사용하려면 Azure 액세스를 위해 올바른 사용자 이름 및 암호 비밀을 설정해야 합니다. Visual Studio는 Azure 에셋을 만들 때 또는 Microsoft Visual Studio IDE의 GitHub 작업 화면에서 이 작업을 자동으로 시도합니다. 리포지토리의 설정 섹션을 사용하여 GitHub에서 시크릿을 확인하고 있는지 확인하거나, 필요한 경우 다시 생성하여 GitHub에 다시 추가할 수 있습니다. 워크플로우의 각 섹션에서 참조된 것과 비교하여 비밀 ID를 확인합니다. 필요한 경우 Azure 포털의 컨테이너 레지스트리로 이동하여 컨테이너 레지스트리의 사용자 이름과 비밀번호를 가져와서 해당 값을 사용하여 GitHub에서 비밀을 업데이트할 수 있습니다.

az ad sp create-for-rbac 명령을 실행하여 서비스 주체를 설정하고 클라이언트 ID, 클라이언트 비밀 및 테넌트 ID를 얻은 경우 GitHub 리포지토리의 GitHub 작업 비밀 섹션에 클라이언트 ID와 클라이언트 비밀을 비밀로 추가합니다 Azure 컨테이너 앱 인증을 위해 사용자 이름(앱의 클라이언트 ID) 및 암호(클라이언트 암호)의 형태로 Azure 로그인 자격 증명을 제공할 수 있습니다. 이렇게 하려면 Azure login 단계를 다음 코드로 바꾸면 됩니다. 클라이언트 ID와 클라이언트 시크릿에 직접 만든 GitHub 시크릿 이름을 사용하고, 같은 명령의 출력에 있는 테넌트 ID를 사용하세요.

- name: Azure login
  uses: azure/CLI@v1
  with:
    inlineScript: |
      az login --service-principal -u ${{ secrets.GITHUB_SECRETID_FOR_USERNAME }} -p ${{ secrets.GITHUB_SECRETID_FOR_PASSWORD }} --tenant {your tenant ID}
      az account list

도커파일이 올바르게 작동하고 인증이 올바른데도 워크플로에 문제가 계속 발생하는 경우 다음 리소스를 참조하세요.

지원되는 프로젝트 형식은 무엇인가요?

  • ASP.NET Core
  • ASP.NET 5 이상
  • Azure 기능

어떤 Azure 서비스가 지원되나요?

  • Azure Web Apps
  • Azure 기능
  • Azure API Management