Вывод конвейера SWA DevOps на новый уровень

Одна из вещей, которые мне больше всего нравятся в Azure Static Web Apps, также известной как SWA, заключается в том, что она генерирует для вас файл рабочего процесса GitHub Actions, гарантируя, что у вас есть CI/CD конвейер, который будет развертывать код по мере внесения изменений, делая повторяющиеся развертывания запланированными. Если вы не используете GitHub Actions, нет проблем, вы можете использовать Azure Pipelines, GitLab, Bitbucket или недавно выпущенную команду cli deploy и добиться того же повторяющегося рабочего процесса, а не возвращаться к копированию файлов на удаленный сервер.

В этой статье я буду использовать GitHub Actions, поскольку именно их я использую для своего блога (на котором основана эта статья), но шаблоны будут такими же и для других платформ сборки.

Чтобы освежить в памяти или для тех, кто не знаком с SWA, вот задание, которое будет сгенерировано, чтобы собрать и развернуть ваше приложение в Azure:

build_and_deploy_job:
  if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed')
  runs-on: ubuntu-latest
  name: Build and Deploy Job
  steps:
    - uses: actions/checkout@v2
      with:
        submodules: true
    - name: Build And Deploy
      id: builddeploy
      uses: Azure/static-web-apps-deploy@v1
      with:
        azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN }}
        repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for GitHub integrations (i.e. PR comments)
        action: "upload"
        ###### Repository/Build Configurations ######
        app_location: "src" # App source code path relative to repository root
        api_location: "api" # Api source code path relative to repository root - optional
        output_location: "public" # Built app content directory, relative to app_location - optional
        ###### End of Repository/Build Configurations ######
Войти в полноэкранный режим Выход из полноэкранного режима

Действительно важной частью этого процесса является задание Build And Deploy, поскольку оно отвечает за две задачи: создание фронт-энда (и Functions API, если он существует), а затем загрузку его в Azure.

Хотя этот рабочий процесс охватывает многие случаи использования, вы можете захотеть выйти за его пределы. Возможно, вы хотите запускать тесты как часть конвейера, или добавить процесс утверждения для развертывания, или что-то еще, что означает, что объединение этапа сборки с этапом развертывания может усложнить задачу.

Выход за рамки стандартного

Давайте рассмотрим, как выйти за рамки стандартного, и проиллюстрируем сложный конвейер GitHub Actions, который в конечном итоге развертывается на SWA:

Это изображение рабочего процесса для моего блога, который состоит из семи заданий, выполняемых с помощью почти 40 шагов. Некоторые из этих заданий выполняются параллельно, некоторые — последовательно, но в целом именно так я развертываю свой блог.

Итак, почему все так сложно? Ну, мой сайт создан для трех разных платформ: Hugo для самого блога, .NET для поиска на основе Blazor и TypeScript для API (о котором я скоро расскажу отдельно). Из-за этого стандартное действие SWA не работает; оно не знает, что строить!

Из-за этого у меня есть три основных параллельных задания, build_hugo, build_api и build_search_ui, и каждое из них будет генерировать артефакты для развертывания. В этом посте я опишу гораздо более простой процесс, но вы можете посмотреть мой полный (и, возможно, слишком сложный…) рабочий процесс в build-and-deploy.yml.

Сначала сборка, потом развертывание

Первое, что мы хотим сделать, это отделить этап сборки от остальной части конвейера. Фактические шаги, которые вы будете выполнять в GitHub Actions, будут зависеть от того, что вы собираете, давайте возьмем приложение JavaScript:

job:
  build:
    if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed')
    runs-on: ubuntu-latest
    environment: build
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
          with:
            node-version: 16
      - run: npm ci
      - run: npm run build
Войти в полноэкранный режим Выйти из полноэкранного режима

Важная часть здесь — знать, куда будет отправлен вывод, и в данном случае мы просто предполагаем, что он находится в папке build этого гипотетического приложения.

Но как мы получим их позже? Превратив их в артефакт работы, используя действие actions/upload-artifact:

- name: Publish website output
  uses: actions/upload-artifact@v3
  with:
    name: website
    path: ${{ github.workspace }}/build
Войти в полноэкранный режим Выйти из полноэкранного режима

Это упакует выходное содержимое нашего шага сборки и загрузит его в рабочий процесс, который мы сможем использовать позже.

Артефакты с большим количеством файлов

Если вы работаете с результатом, который будет содержать много файлов, например, папку node_modules (потому что это приложение без пакета), вы можете захотеть упаковать их в архив, а затем загрузить этот архив (как я делаю с моим API):

- run: npm ci
- run: npm run build
- run: mkdir ${{ github.workspace }}/${{ env.OUTPUT_FOLDER }}
- run: tar -cvf ${{ github.workspace }}/${{ env.OUTPUT_FOLDER }}/api.tar .

- name: Publish API output
  uses: actions/upload-artifact@v1
  with:
    name: api
    path: ${{ github.workspace }}/${{ env.OUTPUT_FOLDER }}/api.tar
Вход в полноэкранный режим Выйти из полноэкранного режима

Это происходит потому, что при загрузке он будет загружать файл за файлом, а когда файлов много, это может занять ооооочень много времени (что делает сборку медленнее), но если мы создадим архив, он будет загружать только один файл, что требует гораздо меньше IO.

Развертывание из артефактов

Теперь, когда мы отделили нашу фазу сборки от SWA Action, как нам ее использовать?

Начните с определения нового задания в нашем рабочем процессе, deploy, и добавьте к нему раздел needs, говорящий о том, что ему необходимо, чтобы задание build было выполнено первым, иначе это задание будет выполняться параллельно, и мы не сможем развернуть, пока не выполним сборку!

job:
  build:
    # snip
  deploy:
    runs-on: ubuntu-latest
    environment: production
    needs: [build]
    steps:
      # todo
Вход в полноэкранный режим Выход из полноэкранного режима

В отличие от задания build, нам не понадобится actions/checkout, потому что нам не нужен исходный код для нашего приложения, мы будем использовать предварительно собранный артефакт, который мы получим из actions/download-artifact:

job:
  build:
    # snip
  deploy:
    runs-on: ubuntu-latest
    environment: production
    needs: [build]
    steps:
      - name: Download website
        uses: actions/download-artifact@v1
        with:
          name: website
          path: ${{ github.workspace }}
Вход в полноэкранный режим Выйти из полноэкранного режима

Укажите место, куда вы хотите загрузить артефакт. В данном случае мы поместим его в корень агента, так как мы знаем, что это новый агент для этой работы, нет других файлов, о которых нам нужно беспокоиться.

Далее мы подключим действие azure/static-web-apps-deploy, чтобы мы могли развернуть в Azure:

job:
  build:
    # snip
  deploy:
    runs-on: ubuntu-latest
    environment: production
    needs: [build]
    steps:
      - name: Download website
        uses: actions/download-artifact@v1
        with:
          name: website
          path: ${{ github.workspace }}

      - name: Build And Deploy
        id: builddeploy
        uses: Azure/static-web-apps-deploy@v1
        with:
          azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN }}
          repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for GitHub integrations (i.e. PR comments)
          action: "upload"
          ###### Repository/Build Configurations ######
          app_location: "" # App source code path relative to repository root
          api_location: "api" # Api source code path relative to repository root - optional
          skip_app_build: true
          ###### End of Repository/Build Configurations ######
Вход в полноэкранный режим Выход из полноэкранного режима

Здесь нужны два секрета: GITHUB_TOKEN, который предоставляется GitHub, и AZURE_STATIC_WEB_APPS_API_TOKEN, который является маркером развертывания, который генерируется при первом подключении репозитория к SWA, может быть получен через портал или через Azure CLI (и который я сливал в своих логах, что послужило поводом для этой записи в блоге).

Другие параметры, которые нам нужно изменить для действия, это то, что мы установим app_location в место относительно ${{ github.workspace }} (которое в нашем случае пустое) и затем установим skip_app_build в true, так как мы уже создали, все, что нам нужно сделать, это развернуть.

Резюме

Итак, у нас есть завершенный многоэтапный рабочий процесс, который выглядит следующим образом для сборки и развертывания SWA (я исключил триггеры для простоты):

job:
  build:
    if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed')
    runs-on: ubuntu-latest
    environment: build
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
          with:
            node-version: 16
      - run: npm ci
      - run: npm run build
      - name: Publish website output
        uses: actions/upload-artifact@v3
        with:
          name: website
          path: ${{ github.workspace }}/build

  deploy:
    runs-on: ubuntu-latest
    environment: production
    needs: [build]
    steps:
      - name: Download website
        uses: actions/download-artifact@v1
        with:
          name: website
          path: ${{ github.workspace }}

      - name: Build And Deploy
        id: builddeploy
        uses: Azure/static-web-apps-deploy@v1
        with:
          azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN }}
          repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for GitHub integrations (i.e. PR comments)
          action: "upload"
          ###### Repository/Build Configurations ######
          app_location: "" # App source code path relative to repository root
          api_location: "api" # Api source code path relative to repository root - optional
          skip_app_build: true
          ###### End of Repository/Build Configurations ######
Вход в полноэкранный режим Выход из полноэкранного режима

Мы видели, как мы можем использовать артефакты для перемещения результатов от одного задания к другому, что позволяет четко определить фазы сборки и развертывания в нашем рабочем процессе.

С помощью этой настройки мы можем ввести в рабочий процесс любые дополнительные шаги, такие как запуск тестов, развертывание SWA с помощью Bicep или запуск параллельных заданий для ускорения выполнения рабочего процесса.

У меня в блоге используется более сложная форма этого процесса, которую вы можете увидеть в моем рабочем процессе в build-and-deploy.yml.

Бонус — разделение управления PR

SWA автоматически генерирует среду предварительного просмотра из PR, и часть этого требует второго задания для очистки, когда PR закрывается:

close_pull_request_job:
  if: github.event_name == 'pull_request' && github.event.action == 'closed'
  runs-on: ubuntu-latest
  name: Close Pull Request Job
  steps:
    - name: Close Pull Request
      id: closepullrequest
      uses: Azure/static-web-apps-deploy@v1
      with:
        azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN }}
        action: "close"
Вход в полноэкранный режим Выход из полноэкранного режима

Это задание включается в создаваемый файл рабочего процесса, и из-за этого у нас есть некоторые if проверки на заданиях, поскольку рабочий процесс запускается на PR, но нам нужно выборочно запускать задания в зависимости от того, какое событие вызвало PR.

Но мы также можем разделить это, чтобы у нас был рабочий процесс «закрыть PR», который не зависит от нашего задания «сборка и развертывание», и мы можем сделать это, изменив триггеры для рабочего процесса.

Давайте начнем с рабочего процесса сборки и развертывания:

on:
  push:
    branches:
      - main
  pull_request:
    types: [opened, synchronize, reopened]
    branches:
      - main
Вход в полноэкранный режим Выход из полноэкранного режима

Этот рабочий процесс все еще будет выполняться на PR, но он будет выполняться только в том случае, если PR открыт, синхронизирован (на него выкладываются файлы) или открыт. Это означает, что мы можем удалить проверку if из нашего задания build.

Затем создайте другой файл рабочего процесса и переместите в него задание close_pull_request_job:

name: Close PR

on:
  pull_request:
    types: [closed]
    branches:
      - main
jobs:
  close_pull_request_job:
    runs-on: ubuntu-latest
    name: Close Pull Request Job
    environment: production
    steps:
      - name: Close Pull Request
        id: closepullrequest
        uses: Azure/static-web-apps-deploy@v1
        with:
          azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN }}
          action: "close"
Вход в полноэкранный режим Выйти из полноэкранного режима

Этот процесс срабатывает только при событии closed для PR, и выполняет один шаг для уничтожения среды предварительного просмотра.

Конечно, это означает наличие дополнительного файла рабочего процесса (и некоторый потенциал для дублирования кода), но я предпочитаю более чистый вид и то, что понятно, какие рабочие процессы когда будут выполняться.

Оцените статью
devanswers.ru
Добавить комментарий