예전에 애저 DevOps 파이프라인을 효과적으로 리팩토링하는 전략에 대해 논의해 본 적이 있었다. 깃헙 액션도 꽤 효율적이긴 한데, 애저 DevOps만큼 효과적으로 구현하려면 고민해야 할 지점이 상당히 많은 편이다. 그 중에서 최근에 출시한 "재활용 워크플로우" 기능을 이용하면 이런 고민들을 상당히 많이 덜어낼 수 있다. 이 포스트에서는 이 "재활용 워크플로우" 기능을 이용해서 애저 정적 웹 앱에서 자동으로 생성해 주는 CI/CD 파이프라인을 리팩토링해 보기로 한다.
애저 정적 웹 앱 워크플로우
애저 정적 웹 앱 인스턴스를 프로비저닝할 때 별다른 설정을 하지 않으면 자동으로 깃헙 액션 워크플로우가 생성된다. 아래는 자동으로 생성되는 워크플로우 파일의 예이다.
### original workflow: azure-static-web-apps-xxxx-xxxx-xxxx.yml ### | |
name: Azure Static Web Apps CI/CD | |
on: | |
push: | |
branches: | |
- main | |
pull_request: | |
types: [opened, synchronize, reopened, closed] | |
branches: | |
- main | |
jobs: | |
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_XXXX_XXXX_XXXX }} | |
repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for Github integrations (i.e. PR comments) | |
action: "upload" | |
###### Repository/Build Configurations - These values can be configured to match your app requirements. ###### | |
# For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig | |
app_location: "webapp" # App source code path | |
api_location: "apiapp" # Api source code path - optional | |
output_location: "wwwroot" # Built app content directory - optional | |
###### End of Repository/Build Configurations ###### | |
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_XXXX_XXXX_XXXX }} | |
action: "close" |
문제는 한 번 생성된 워크플로우 파일은 파일 이름을 변경할 수가 없기 때문에 워크플로우를 수정하려면 항상 이 파일 안에서만 수정해야 한다.
어떤 상황을 한 번 가정해 보자. 회사에서 애저 정적 웹 앱으로 배포하는 코드가 있고, 개발용, 테스트용, 라이브용 인스턴스가 따로 있다고 가정을 해 보자. 굳이 모노리포 방식까지 언급을 하지 않더라도 충분히 나올 수 있는 상황이다. 이런 경우에는 인스턴스 수 만큼 자동으로 깃헙 액션 워크플로우가 생성된다. 하지만, 그 안의 내용은 변수값을 제외하고는 차이가 없다. 동일한 코드를 굳이 여러 파일에서 나눠서 관리하기 보다는 리팩토링을 해서 하나로 합친 후 이를 각자 호출하면 훨씬 더 간결해 질 것이다.
얼마전까지만 해도 이 리팩토링을 위해 workflow_dispatch
이벤트를 활용해야 했다. 이 이벤트를 자동으로 호출하기 위해서는 웹훅 이벤트까지 동원해야 한다. 한 번 구성을 해 놓으면 웹훅을 위한 액세스 토큰이 유효한 이상 계속 사용할 수 있다. 하지만, 어느 순간 액세스 토큰 유효기간이 지났다거나, 노출됐다거나 하는 등의 이유로 토큰을 사용하지 못하는 상황이 생긴다면? 이런 부분을 좀 해결할 수 있는 방법이 없을까?
재활용 워크플로우
이번에 새롭게 소개된 workflow_call
이벤트를 활용하면 워크플로우를 job 수준에서 좀 더 편리하게 재활용 할 수 있게 된다. 위 코드를 살짝 리팩토링해 보자. 우선 위에 정의해 놓은 두 build_and_deploy_job
, close_pull_request_job
을 그대로 복사해 온다. 이 워크플로우를 "재활용 워크플로우"라고 하자.
### reusable workflow: build-aswa.yaml ### | |
name: Azure Static Web Apps | |
jobs: | |
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_XXXX_XXXX_XXXX }} | |
repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for Github integrations (i.e. PR comments) | |
action: "upload" | |
###### Repository/Build Configurations - These values can be configured to match your app requirements. ###### | |
# For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig | |
app_location: "webapp" # App source code path | |
api_location: "apiapp" # Api source code path - optional | |
output_location: "dist" # Built app content directory - optional | |
###### End of Repository/Build Configurations ###### | |
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_XXXX_XXXX_XXXX }} | |
action: "close" |
위 워크플로우에 보면 이벤트 개체에서 받아오는 값과 시크릿 변수값, 웹 앱 소스 위치값이 있는데, 이를 나열해 보면 아래와 같다. 이 값은 변경 가능한 변수값이다.
-
이벤트 개체
- 이벤트 이름:
github.event_name
- 이벤트 액션:
github.event.action
- 이벤트 이름:
-
시크릿
- 애저 정적 웹 앱 배포 API 토큰:
secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_XXXX_XXXX_XXXX
- 깃헙 토큰:
secrets.GITHUB_TOKEN
- 애저 정적 웹 앱 배포 API 토큰:
-
애저 정적 웹 앱 위치
- 웹 앱 위치:
app_location
- API 앱 위치:
api_location
- 웹 앱 아티팩트 위치:
output_location
- 웹 앱 위치:
하지만, 재활용 워크플로우에서는 이 값들에 직접 접근할 수 없으므로 변수 처리를 해서 항상 "호출 워크플로우"를 통해 받아와야 한다. 재활용 워크플로우에 있던 여러 값들을 아래와 같이 변수형태로 바꿔보자 (line #7-8, 20-21, 23-24, 30-31, 33-34, 36-37, 43-44, 54-55).
### reusable workflow: build-aswa.yaml ### | |
name: Azure Static Web Apps | |
jobs: | |
build_and_deploy_job: | |
# if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed') | |
if: inputs.event_name == 'push' || (inputs.event_name == 'pull_request' && inputs.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_XXXX_XXXX_XXXX }} | |
azure_static_web_apps_api_token: ${{ secrets.aswa_token }} | |
# repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for Github integrations (i.e. PR comments) | |
repo_token: ${{ secrets.github_token }} # Used for Github integrations (i.e. PR comments) | |
action: "upload" | |
###### Repository/Build Configurations - These values can be configured to match your app requirements. ###### | |
# For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig | |
# app_location: "webapp" # App source code path | |
app_location: ${{ inputs.app_location }} # App source code path | |
# api_location: "apiapp" # Api source code path - optional | |
api_location: ${{ inputs.api_location }} # Api source code path - optional | |
# output_location: "dist" # Built app content directory - optional | |
output_location: ${{ inputs.output_location }} # Built app content directory - optional | |
###### End of Repository/Build Configurations ###### | |
close_pull_request_job: | |
# if: github.event_name == 'pull_request' && github.event.action == 'closed' | |
if: inputs.event_name == 'pull_request' && inputs.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_XXXX_XXXX_XXXX }} | |
azure_static_web_apps_api_token: ${{ secrets.aswa_token }} | |
action: "close" |
위와 같이 변수 처리를 했다면, 이제 이 변수들에 대해 정의를 해야 한다. 재활용 워크플로우에서 변수 정의는 아래와 같이 workflow_call
이벤트에 붙여서 하면 된다. 일반 변수는 inputs
어트리뷰트 아래에 (line #6-21), 시크릿 변수는 secrets
어트리뷰트 아래에 (line #23-27) 정의한다.
### reusable workflow: build-aswa.yaml ### | |
name: Azure Static Web Apps | |
on: | |
workflow_call: | |
inputs: | |
event_name: | |
required: true | |
type: string | |
event_action: | |
required: true | |
type: string | |
app_location: | |
required: true | |
type: string | |
api_location: | |
required: true | |
type: string | |
output_location: | |
required: true | |
type: string | |
secrets: | |
github_token: | |
required: true | |
aswa_token: | |
required: true | |
jobs: | |
... |
이렇게 재활용 워크플로우에 대한 리팩토링이 끝났다.
호출 워크플로우
이제 애저 정적 웹 앱 워크플로우를 수정해 보자. 기존 jobs
노드 아래에 있던 내용은 더이상 필요없으므로 지우고 아래와 같이 "재활용 워크플로우"를 설정한다.
- 재활용 워크플로우 (line #14-15):
<org_name>/<repo_name>/.github/workflows/<reusable_workflow_filename>@<branch_or_tag>
- 변수 (line #17-22):
with
속성 - 시크릿 (line #24-26):
secrets
속성
### caller workflow: azure-static-web-apps-xxxx-xxxx-xxxx.yml ### | |
name: Azure Static Web Apps CI/CD | |
on: | |
push: | |
branches: | |
- main | |
pull_request: | |
types: [opened, synchronize, reopened, closed] | |
branches: | |
- main | |
jobs: | |
call_aswa_flow: | |
uses: <org_name>/<repo_name>/.github/workflows/build-aswa.yaml@main | |
with: | |
event_name: ${{ github.event_name }} | |
event_action: ${{ github.event.action }} | |
app_location: "webapp" | |
api_location: "apiapp" | |
output_location: "dist" | |
secrets: | |
github_token: ${{ secrets.GITHUB_TOKEN }} | |
aswa_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_XXXX_XXXX_XXXX }} |
이제 "호출 워크플로우"가 몇개가 됐든, 위와 같이 리팩토링을 해 놓으면 더이상 "호출 워크플로우"는 수정할 필요 없이 "재활용 워크플로우"만 수정하면 모든 "호출 워크플로우"로 한 번에 변경사항을 반영할 수 있어 무척이나 편리해진다.
지금까지 애저 정적 웹 앱 인스턴스 배포를 위한 깃헙 액션 워크플로우를 재활용 워크플로우 기능을 이용해 리팩토링해 봤다. 이 아이디어를 기반으로 좀 더 다양한 빌드/배포 시나리오에서 활용할 수 있을 것이다.