연습 - 워크플로에 여러 환경 추가

완료됨

이제 테스트 및 프로덕션 환경에 모두 배포하도록 워크플로를 업데이트할 준비가 되었습니다. 이 단원에서는 환경 간에 작업을 다시 사용할 수 있도록 호출된 워크플로를 사용하도록 워크플로를 업데이트합니다.

프로세스 중에 다음을 수행합니다.

  • 린팅 작업에 재사용 가능한 워크플로를 추가합니다.
  • 환경에 배포하는 데 필요한 작업을 정의하는 재사용 가능한 워크플로를 추가합니다.
  • 호출된 워크플로를 사용하도록 워크플로를 업데이트합니다.
  • 워크플로를 실행하고 결과를 확인합니다.

린트 작업에 다시 사용할 수 있는 워크플로 추가

워크플로가 배포되는 환경 수에 관계없이 린트 작업은 워크플로 실행 중에 한 번만 발생합니다. 따라서 실제로는 린트 작업에 대해 호출된 워크플로를 사용할 필요가 없습니다. 그러나 기본 워크플로 정의 파일을 간단하고 읽기 쉽게 유지하기 위해 린트 작업을 별도의 워크플로 파일에서 정의하려고 합니다.

  1. Visual Studio Code에서 github/workflows 폴더에 lint.yml이라는 새 파일을 만듭니다.

    .github/workflows 폴더와 lint.YML 파일이 있는 Visual Studio Code 탐색기의 스크린샷

  2. 다음 워크플로 정의를 파일에 복사합니다.

    name: lint
    
    on:
      workflow_call:
    
    jobs:
      lint:
        name: Lint code
        runs-on: ubuntu-latest
        steps:
        - uses: actions/checkout@v3
    
        - name: Lint code
          run: |
            az bicep build --file deploy/main.bicep
    

    린트 작업은 이미 워크플로에 있는 린트 작업과 동일하지만 이제는 별도의 워크플로 파일에 있습니다.

  3. 변경 내용을 저장하고 파일을 닫습니다.

배포를 위해 재사용 가능한 워크플로 추가

각 환경을 배포하는 데 필요한 모든 작업을 정의하는 재사용 가능한 워크플로를 만듭니다. 입력과 비밀을 사용하여 환경 간에 다를 수 있는 설정을 지정합니다.

  1. .github/workflows 폴더에 deploy.yml이라는 새 파일을 만듭니다.

    .github/workflows 폴더와 deploy.YML 파일이 있는 Visual Studio Code 탐색기의 스크린샷

    이 파일은 각 환경에 대해 실행되는 모든 배포 작업을 나타냅니다.

  2. 다음 워크플로 이름, 트리거, 입력, 비밀을 파일에 붙여넣습니다.

    name: deploy
    
    on:
      workflow_call:
        inputs:
          environmentType:
            required: true
            type: string
          resourceGroupName:
            required: true
            type: string
        secrets:
          AZURE_CLIENT_ID:
            required: true
          AZURE_TENANT_ID:
            required: true
          AZURE_SUBSCRIPTION_ID:
            required: true
    

    참고

    Visual Studio Code 내 YAML 파일 작업을 시작할 때 문제가 있음을 알리는 빨간색 물결선이 표시될 수 있습니다. YAML 파일의 Visual Studio Code 확장이 파일의 스키마를 잘못 추측하기 때문입니다.

    확장에서 보고하는 문제를 무시할 수 있습니다. 또는 원하는 경우 파일 상단에 다음 코드를 추가하여 확장의 추측을 억제할 수 있습니다.

    # yaml-language-server: $schema=./deploy.yml
    
  3. 비밀 아래에 유효성 검사 작업의 정의를 붙여넣습니다.

    jobs:
      validate:
         runs-on: ubuntu-latest
         steps:
         - uses: actions/checkout@v3
         - uses: azure/login@v1
           name: Sign in to Azure
           with:
            client-id: ${{ secrets.AZURE_CLIENT_ID }}
            tenant-id: ${{ secrets.AZURE_TENANT_ID }}
            subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
         - if: inputs.environmentType != 'Production'
           uses: azure/arm-deploy@v1
           name: Run preflight validation
           with:
             deploymentName: ${{ github.run_number }}
             resourceGroupName: ${{ inputs.resourceGroupName }}
             template: ./deploy/main.bicep
             parameters: >
               environmentType=${{ inputs.environmentType }}
             deploymentMode: Validate
         - if: inputs.environmentType == 'Production'
           uses: azure/arm-deploy@v1
           name: Run what-if
           with:
             failOnStdErr: false
             resourceGroupName: ${{ inputs.resourceGroupName }}
             template: ./deploy/main.bicep
             parameters: >
               environmentType=${{ inputs.environmentType }}
             additionalArguments: --what-if
    

    작업에 조건이 적용됩니다. 실행 전 유효성 검사는 비프로덕션 환경에서만 실행됩니다. 가상 작업은 프로덕션 환경에서만 실행됩니다. 학습 경로의 이전 모듈에서는 이러한 작업에 대해 별도의 작업을 사용했지만 여기에서는 해당 작업을 결합하여 워크플로를 단순화합니다.

    YAML 파일은 들여쓰기를 구분합니다. 이 코드를 입력하든 아니면 붙여넣든, 들여쓰기가 정확해야 합니다. 이 연습 뒷부분에서 파일의 일치 여부를 확인할 수 있도록 전체 YAML 워크플로 정의가 표시됩니다.

  4. 유효성 검사 작업 아래에서 배포 작업의 정의를 붙여넣습니다.

    deploy:
      needs: validate
      environment: ${{ inputs.environmentType }}
      runs-on: ubuntu-latest
      outputs:
        appServiceAppHostName: ${{ steps.deploy.outputs.appServiceAppHostName }}
      steps:
      - uses: actions/checkout@v3
      - uses: azure/login@v1
        name: Sign in to Azure
        with:
          client-id: ${{ secrets.AZURE_CLIENT_ID }}
          tenant-id: ${{ secrets.AZURE_TENANT_ID }}
          subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
      - uses: azure/arm-deploy@v1
        id: deploy
        name: Deploy Bicep file
        with:
          failOnStdErr: false
          deploymentName: ${{ github.run_number }}
          resourceGroupName: ${{ inputs.resourceGroupName }}
          template: ./deploy/main.bicep
          parameters: >
            environmentType=${{ inputs.environmentType }}
    
  5. 배포 작업 아래에 스모크 테스트 작업의 정의를 붙여넣습니다.

    smoke-test:
      runs-on: ubuntu-latest
      needs: deploy
      steps:
      - uses: actions/checkout@v3
      - run: |
          $container = New-PesterContainer `
            -Path 'deploy/Website.Tests.ps1' `
            -Data @{ HostName = '${{needs.deploy.outputs.appServiceAppHostName}}' }
          Invoke-Pester `
            -Container $container `
            -CI
        name: Run smoke tests
        shell: pwsh
    
  6. deploy.yml 파일이 다음 예시와 같은지 확인합니다.

    name: deploy
    
    on:
      workflow_call:
        inputs:
          environmentType:
            required: true
            type: string
          resourceGroupName:
            required: true
            type: string
        secrets:
          AZURE_CLIENT_ID:
            required: true
          AZURE_TENANT_ID:
            required: true
          AZURE_SUBSCRIPTION_ID:
            required: true
    
    jobs:
      validate:
         runs-on: ubuntu-latest
         steps:
         - uses: actions/checkout@v3
         - uses: azure/login@v1
           name: Sign in to Azure
           with:
            client-id: ${{ secrets.AZURE_CLIENT_ID }}
            tenant-id: ${{ secrets.AZURE_TENANT_ID }}
            subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
         - if: inputs.environmentType != 'Production'
           uses: azure/arm-deploy@v1
           name: Run preflight validation
           with:
             deploymentName: ${{ github.run_number }}
             resourceGroupName: ${{ inputs.resourceGroupName }}
             template: ./deploy/main.bicep
             parameters: >
               environmentType=${{ inputs.environmentType }}
             deploymentMode: Validate
         - if: inputs.environmentType == 'Production'
           uses: azure/arm-deploy@v1
           name: Run what-if
           with:
             failOnStdErr: false
             resourceGroupName: ${{ inputs.resourceGroupName }}
             template: ./deploy/main.bicep
             parameters: >
               environmentType=${{ inputs.environmentType }}
             additionalArguments: --what-if
    
      deploy:
        needs: validate
        environment: ${{ inputs.environmentType }}
        runs-on: ubuntu-latest
        outputs:
          appServiceAppHostName: ${{ steps.deploy.outputs.appServiceAppHostName }}
        steps:
        - uses: actions/checkout@v3
        - uses: azure/login@v1
          name: Sign in to Azure
          with:
            client-id: ${{ secrets.AZURE_CLIENT_ID }}
            tenant-id: ${{ secrets.AZURE_TENANT_ID }}
            subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
        - uses: azure/arm-deploy@v1
          id: deploy
          name: Deploy Bicep file
          with:
            failOnStdErr: false
            deploymentName: ${{ github.run_number }}
            resourceGroupName: ${{ inputs.resourceGroupName }}
            template: ./deploy/main.bicep
            parameters: >
              environmentType=${{ inputs.environmentType }}
    
      smoke-test:
        runs-on: ubuntu-latest
        needs: deploy
        steps:
        - uses: actions/checkout@v3
        - run: |
            $container = New-PesterContainer `
              -Path 'deploy/Website.Tests.ps1' `
              -Data @{ HostName = '${{needs.deploy.outputs.appServiceAppHostName}}' }
            Invoke-Pester `
              -Container $container `
              -CI
          name: Run smoke tests
          shell: pwsh
    
  7. 파일의 변경 내용을 저장합니다.

템플릿을 사용하도록 워크플로 정의 업데이트

  1. .github/workflows 폴더에서 workflow.yml 파일을 엽니다.

  2. 두 환경 변수를 포함하여 env: 섹션의 콘텐츠를 제거합니다. 곧 환경별 변수로 바꿀 예정입니다.

  3. lint: 작업 정의의 콘텐츠를 제거하고 다음 코드로 바꿔서 앞에서 만든 lint.yml 파일을 사용합니다.

    # Lint the Bicep file.
    lint:
      uses: ./.github/workflows/lint.yml
    
  4. 파일의 업데이트한 린트 작업 아래에서 모든 것을 삭제합니다.

  5. 파일의 아래쪽에 다음 코드를 추가하여 테스트 환경에 배포합니다.

    # Deploy to the test environment.
    deploy-test:
      uses: ./.github/workflows/deploy.yml
      needs: lint
      with:
        environmentType: Test
        resourceGroupName: ToyWebsiteTest
      secrets:
        AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID_TEST }}
        AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
        AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
    
  6. 방금 추가한 코드 아래에 다음 코드를 추가하여 프로덕션 환경에 배포합니다.

    # Deploy to the production environment.
    deploy-production:
      uses: ./.github/workflows/deploy.yml
      needs: deploy-test
      with:
        environmentType: Production
        resourceGroupName: ToyWebsiteProduction
      secrets:
        AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID_PRODUCTION }}
        AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
        AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
    

    업데이트된 워크플로는 린트 작업을 한 번 실행합니다. 그런 다음, 호출된 워크플로 deploy.yml을 환경별로 한 번씩 두 번 사용합니다. 이렇게 하면 워크플로 정의를 명확하고 쉽게 이해할 수 있습니다. YAML 파일의 주석은 각 작업의 대상 환경을 식별합니다.

  7. workflow.yml 파일이 다음 예제와 같이 표시되는지 확인합니다.

    name: deploy-toy-website-environments
    concurrency: toy-company
    
    on:
      push:
        branches:
          - main
      workflow_dispatch:
    
    permissions:
      id-token: write
      contents: read
    
    jobs:
    
      # Lint the Bicep file.
      lint:
        uses: ./.github/workflows/lint.yml
    
      # Deploy to the test environment.
      deploy-test:
        uses: ./.github/workflows/deploy.yml
        needs: lint
        with:
          environmentType: Test
          resourceGroupName: ToyWebsiteTest
        secrets:
          AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID_TEST }}
          AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
          AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
    
      # Deploy to the production environment.
      deploy-production:
        uses: ./.github/workflows/deploy.yml
        needs: deploy-test
        with:
          environmentType: Production
          resourceGroupName: ToyWebsiteProduction
        secrets:
          AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID_PRODUCTION }}
          AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
          AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
    
  8. 변경 내용을 저장합니다.

  9. Visual Studio Code 터미널에서 다음 명령을 실행하여 변경 내용을 커밋하고 Git 리포지토리에 푸시합니다.

    git add .
    git commit -m "Add reusable workflows"
    git push
    
  10. 리포지토리에 푸시하는 것이 처음이므로 로그인하라는 메시지가 표시될 수 있습니다.

    Windows에서는 1을 입력하여 웹 브라우저로 인증하고 Enter를 선택합니다.

    macOS에서는 권한 부여를 선택합니다.

  11. 브라우저 창이 표시됩니다. GitHub에 다시 로그인해야 할 수도 있습니다. 권한 부여를 선택합니다.

워크플로 실행 보기

  1. 브라우저에서 작업으로 이동합니다.

    ‘초기 커밋’이라는 레이블이 지정된 워크플로의 첫 번째 실행은 실패로 표시됩니다. GitHub는 리포지토리를 만들 때 워크플로를 자동으로 실행했습니다. 암호는 해당 시점에 준비되지 않았기 때문에 실패했습니다. 이 오류는 무시해도 됩니다.

  2. deploy-toy-website-environments 워크플로를 선택합니다.

  3. 가장 최근에 실행한 워크플로를 선택합니다.

    이제 YAML 파일에서 정의한 모든 작업이 워크플로 실행에 표시됩니다.

    일부 경고는 주석 패널에 나열됩니다. 이러한 경고는 Bicep가 워크플로 로그에 정보 메시지를 쓰는 방식 때문에 발생합니다. 이러한 경고는 무시하면 됩니다.

  4. deploy-production / deploy 작업 전에 워크플로가 일시 중지될 때까지 기다립니다. 워크플로가 이 지점에 도달하는 데는 몇 분 정도 걸릴 수 있습니다.

    승인을 위해 일시 중지된 워크플로 실행을 보여 주는 GitHub의 스크린샷

  5. 배포 검토 단추를 선택하여 프로덕션 환경에 대한 배포를 승인합니다.

  6. 프로덕션 환경을 선택한 다음, 승인 및 배포 단추를 선택합니다.

    워크플로 승인 페이지와 승인 및 배포 단추를 보여 주는 GitHub 인터페이스의 스크린샷

    워크플로의 실행이 완료될 때까지 기다립니다. 워크플로가 성공적으로 완료됩니다.

  7. 코드를 선택합니다.

  8. 프로덕션 배포를 선택합니다.

    프로덕션 환경이 강조 표시된 코드 페이지 환경을 보여 주는 GitHub의 스크린샷

  9. 배포 화면에 프로덕션 환경의 배포 기록에 대한 개요가 표시됩니다.

    단일 배포를 표시하는 배포 기록이 있는 프로덕션 환경을 보여 주는 GitHub의 스크린샷

  10. 커밋 식별자를 선택합니다.

    GitHub는 배포에 포함된 커밋 목록을 보여 줍니다. 이렇게 하면 시간이 지남에 따른 환경 내 변경 사항을 확인할 수 있습니다.

    커밋 목록이 포함된 프로덕션 환경의 배포 세부 정보를 보여 주는 GitHub의 스크린샷

  11. 브라우저에서 Azure Portal로 이동합니다.

  12. ToyWebsiteProduction 리소스 그룹으로 이동합니다.

  13. 리소스 목록에서 Azure App Service 앱을 엽니다.

    App Services 토이 웹 사이트 프로덕션 앱 및 App Service 요금제 SKU 세부 정보를 보여주는 Azure Portal의 스크린샷.

    App Service 요금제 유형은 S1입니다.

  14. ToyWebsiteTest 리소스 그룹의 App Service 앱으로 이동합니다.

    App Service 요금제 유형은 F1입니다. Bicep 파일에서 정의한 대로 두 환경에서 서로 다른 설정을 사용합니다.