Azure DevOps 변수 템플릿을 코드로 구성

15442 단어
twelve-factor app 방법의 원칙 중 하나는 strict separation between code and config이다. 그 중에서 설정은 배치 간에 변화가 발생할 수 있는 모든 것을 의미하고, 코드는 변화가 일어나지 않는 모든 것을 의미한다. 역사적으로 보면 그것은 적합하지 않다.NET Framework 응용 프로그램, web.config transformation, Slow Cheetah 등 도구에 의존하여 구축할 때 응용 프로그램 프로필에 변환을 적용합니다.이러한 변환은 원본 Repo의 응용 프로그램 코드와 함께 저장된 환경별 프로필을 기반으로 합니다.과거에 이로 인해 일부 평론가들은 12가지 요소의 일부분just not applicable to .NET applications이라는 결론을 얻었다.1 그때부터 세계와 세계는 모두 앞으로 발전하고 있다.NET 프레임워크, 코드와 설정의 분리가 더욱 쉽다.본고는 Azure DevOpsvariable templates를 사용하여 버전 제어의 설정 데이터를 관리하는 기술을 기술하고자 한다. 이 기술은 우리의 응용 프로그램 코드와 함께 사용되지만 응용 프로그램 코드와 분리된다.

예제


예제 항목은 예제 ASP입니다.Cosmos DB의 NET Core MVC 응용 프로그램은 atutorial on docs.microsoft.com에 설명되어 있으며 download from GitHub에 사용할 수 있습니다.요컨대, 이 사이트는 Azure Cosmos DB에 저장된'대기사항 목록'에 CRUD2 조작을 제공하는 간단한 사이트로 구성되어 있다.나는 이 특수한 예를 선택했다. 왜냐하면 그것은 몇 가지 설정 항목이 필요하기 때문이다. 그 중 하나인 Cosmos DB API 키는 비밀이기 때문이다.대부분의 현실 생활에서의 프로젝트는 적어도 내가 일한 프로젝트이기 때문에 대량의 변수를 설정해야 한다.
기본적으로 ASP입니다.NET Core 웹 응용 프로그램은 예약된 순서대로 여러 원본에서 설정을 읽을 수 있는 default configuration builder 을 제공합니다.여기서 알아야 할 중요한 점은 환경 변수가 appsettings.json 의 값보다 우선한다는 것이다.이는 appsettings.json 및 그 근친appsettings.dev.json, appsettings.test.json 등이 개발자의 데스크톱에서 설정 값을 제공하는 것으로 강등될 수 있음을 의미하며 모든 다른 환경은 환경 변수를 통해 설정된다.공교롭게도 개원된nuget 패키지 DotNetEnv 가 하나 있는데, 이것은 전혀 사용하지 않는 appsettings.json를 더욱 쉽게 만들었지만, 예시 항목이 그것을 사용하지 않았기 때문에 나는 여기서 더 이상 토론하지 않을 것이다.appsettings.json의 단점은 당연히 끝내기 쉽다는 것이다this kind of thing.

리셋 구성


project 두 번의 환매를 포함한다. sample-app-code sample-app-config .sample-app-code GitHub 공용 재구매의 한 부분일 뿐, azure-pipelines.yml 파일을 추가하여 응용 프로그램을 구축하고 발표한다.sample-app-config 환경마다 .yml 파일이 있습니다. 저는 환경으로 명명되었습니다.

환경당 템플릿 파일 1개
이 파일들 .ymlpipeline templates 이라고 합니다.파이핑에서 파이핑 템플릿을 참조하면 템플릿 파일의 모든 내용이 이 점에 삽입됩니다.파이핑 템플릿은 단계, 작업, 단계 등 많은 파이핑 객체를 정의하고 재사용할 수 있으며 이 예에서는 변수도 있습니다.

In general you can’t mix different types of objects, such as variables and steps for example, in a single template - they would end up being inserted at the “wrong” place in the pipeline.


모든 템플릿 파일은 배치 사이나 설정 사이에서 변경될 수 있는 모든 내용을 나타내는 변수를 포함합니다.이 변수들은 우리의 파이프에 사용할 수도 있고, 환경 변수로 우리의 스크립트에 사용할 수도 있다3.
# This is a comment. Take that, appsettings.json!
variables:
#deployment config
serviceConnectionName: myNonProdServiceConnection
resourceGroupName: rg-todo-staging
resourceGroupLocation: uksouth
#Cosmos DB Config
cosmosAccountName: cosmos-ac-todo-staging
keyVaultName: kv-todo-staging-fdkjiwh
#Web app config
appServicePlanName: asp-todo-staging
servicePlanSku: S1
# need single quotes around double quotes to pass the pipe and the double quotes!
runtimeVersion: '"DOTNETCORE|3.1"'
webAppName: todo-staging-vdorpsbzaoiku

만약 당신이'현실 생활'에서 이렇게 한다면, 당신은 모든 코드repo를 위한 설정repo를 만들 것인가, 아니면 여러 코드repo 사이에서 설정repo를 공유할 것인가, 이것은 당신 자신에게 달려 있다.다음 경우에는 폴더 구조 및/또는 명명 규칙을 제시해야 합니다. 예를 들어.
.
├── app1
│ ├── production.yml
│ └── staging.yml
└── app2
├── otherenv.yml
├── production.yml
└── staging.yml

또는
.
├── app1-production.yml
├── app1-staging.yml
├── app2-otherenv.yml
├── app2-production.yml
└── app2-staging.yml

파이프


pipeline file는 매우 짧기 때문에 나는 이곳에서 그것을 완전하게 소개했다.구축 단계에서 우리는 dotnet publish 을 실행하고 생성된 패키지를 pipeline artifact 로 발표하여 나중에 사용할 수 있도록 한다.배치 단계는 이미 두 개의 매개 변수를 사용하는 작업 템플릿에 봉인되었다.첫 번째는 우리가 배치해야 할 환경의 이름이고, 두 번째는 추가 비밀 변수를 포함하는 변수 그룹의 이름입니다. 왜냐하면 우리는 설정repo에 비밀 변수를 저장하고 싶지 않기 때문입니다.

Azure 파이핑의 환경
나는 생산 환경 비준using the UI을 만들었다.
세심한 독자들은 우리가 stageName 매개 변수에서 전달한 값이 설정repo의yml 파일 이름과 Azure 파이프에서 정의한 환경 이름과 일치한다는 것을 알게 될 것이다.이것은 매우 중요하다. 왜냐하면 우리는 이 매개 변수를 사용하여 어느 변수 템플릿을 사용하고 어느 환경에 배치해야 하는지를 확정하기 때문이다.물론, 이 이름들이 다르기를 원한다면, 추가 매핑 논리를 통해 이 점에 적응할 수 있습니다.변수 템플릿과 달리 작업 템플릿pipelineTemplates/doTheDevOps.yml은 코드와 같은repo에 저장됩니다. 왜냐하면 서로 다른 환경에서 변화가 없기 때문입니다.
이렇게 한 결과, 우리 파이프의 각 단계는 모두 같은 배치였다.우리는 같은 템플릿을 사용하여 배치를 하고 템플릿이 어디에서 그 설정을 검색하는지 알려 줍니다.이것은 우리가 생산 환경에 배치할 자신감을 크게 높일 것이다. 왜냐하면 우리는 어디에서나 같은 코드를 사용하기 때문에 생산 환경을 배치하기 전에 우리는 많은 기회를 가지고 연습할 수 있다.
trigger:
- master
pool:
vmImage: 'ubuntu-latest'
resources:
repositories:
- repository: config
type: git
name: sample-app-config
stages:
- stage: buildAndPublish
displayName: Build project and publish artifact
jobs:
- job: buildAndPublish
displayName: Build and Publish
steps:
- task: DotNetCoreCLI@2
displayName: dotnet publish
inputs:
command: 'publish'
publishWebProjects: true
arguments: '-c Release -o $(Build.ArtifactStagingDirectory)/todo'
modifyOutputPath: false
- task: PublishPipelineArtifact@1
displayName: Publish todo.zip as Pipeline Artifact
inputs:
targetPath: '$(Build.ArtifactStagingDirectory)/todo/todo.zip'
artifact: 'todozip'
publishLocation: 'pipeline'
- stage: deployStaging
displayName: Deploy Staging Environment
jobs:
- template: pipelineTemplates/doTheDevOps.yml
parameters:
stageName : sample_app_staging
variableGroupForSecrets : SecretVarsForStaging
- stage: deployProduction
displayName: Deploy Production Environment
jobs:
- template: pipelineTemplates/doTheDevOps.yml
parameters:
stageName : sample_app_production
variableGroupForSecrets : SecretVarsForProduction

배치 작업


말 그대로 this file 행동이 일어난 곳이다.한 마디로 하면 우리는 우리의 지원 인프라 시설4-CosmosDB 계정을 만들고 CosmosDB 키를 저장하는 키 라이브러리, 응용 프로그램 서비스 계획을 세운 다음에 적당한 설정으로 우리의 웹 응용 프로그램을 배치했다.
YAML 파이프의 비밀 변수를 저장하기 위해 변수 그룹을 사용하는 방법을 보여 주기 위해서, 나는 응용 프로그램에서 사용하지 않았던 추가 민감한 설정을 추가했다.파이프 로그 출력에서 차단해야 할 비밀을 저장하는 것 외에 변수 템플릿을 사용하여 변수 그룹에 대한 수요를 없앴다고 생각합니다.마찬가지로 템플릿 파일이 매우 짧아서 여기에서 완전하게 복사할 수 있습니다.
parameters:
- name: stageName
type: string
- name: variableGroupForSecrets
type: string
jobs:
- deployment: deploy${{ parameters.stageName }}
displayName: Deploy ${{ parameters.stageName }} Environment
environment: ${{ parameters.stageName }}
variables:
- template: ${{ parameters.stageName }}.yml@config
- group: ${{parameters.variableGroupForSecrets}}
strategy:
runOnce:
deploy:
steps:
- task: AzureCLI@2
inputs:
azureSubscription: ${{ variables.serviceConnectionName }}
scriptType: 'bash'
scriptLocation: 'inlineScript'
inlineScript: |
 az group create --name $(resourceGroupName) --location $(resourceGroupLocation)
az appservice plan create --name $(appServicePlanName) --resource-group $(resourceGroupName) \
--sku $(servicePlanSku) --is-linux
az webapp create --resource-group $(resourceGroupName) --plan $(appServicePlanName) --name $(webAppName) \
--runtime $(runtimeVersion)
az webapp identity assign --name $(webAppName) --resource-group $(resourceGroupName)
# Grant the web app identity permission to read secrets from the vault
az keyvault create --resource-group $(resourceGroupName) --location $(resourceGroupLocation) --name $(keyVaultName)
principal=$(az webapp identity show --resource-group $(resourceGroupName) --name $(webAppName) | jq -r .principalId)
az keyvault set-policy --name $(keyVaultName) --secret-permissions get --object-id $principal
# Add our secret var to the key vault
az keyvault secret set --vault-name $(keyVaultName) --name PointlessSecret --value $(PointlessSecret)
# Create cosmosdb account and retrieve uri and key for app settings
az cosmosdb create --name $(cosmosAccountName) --resource-group $(resourceGroupName)
cosmosUri=$(az cosmosdb show --name $(cosmosAccountName) --resource-group $(resourceGroupName) | jq -r .documentEndpoint)
cosmosAccountKey=$(az cosmosdb keys list --name $(cosmosAccountName) --resource-group $(resourceGroupName) | jq -r .primaryMasterKey)
# Add cosmos key to key vault 
az keyvault secret set --vault-name $(keyVaultName) --name cosmosAccountKey --value $cosmosAccountKey
# Get Secret Uris to add to app settings
cosmosKeyKvUri=$(az keyvault secret list-versions --name cosmosAccountKey --vault-name $(keyVaultName) --maxresults 1 | jq -r .[0].id)
pointlessSecretUri=$(az keyvault secret list-versions --name PointlessSecret --vault-name $(keyVaultName) --maxresults 1 | jq -r .[0].id)
# Set up app settings
az webapp config appsettings set --resource-group $(resourceGroupName) --name $(webAppName) \
--settings Logging __LogLevel__ Default=Warning \
AllowedHosts="*" \
CosmosDb__Account=$cosmosUri \
CosmosDb__Key="@Microsoft.KeyVault(SecretUri=$cosmosKeyKvUri)" \
CosmosDb__DatabaseName=Tasks \
CosmosDb__ContainerName=Item \
PointlessSecret="@Microsoft.KeyVault(SecretUri=$pointlessSecretUri)"
# set web app to mount zip file read-only https://docs.microsoft.com/en-us/azure/app-service/deploy-run-package
az webapp config appsettings set --resource-group $(resourceGroupName) --name $(webAppName) --settings WEBSITE_RUN_FROM_PACKAGE="1"
az webapp deployment source config-zip --resource-group $(resourceGroupName) --name $(webAppName) --src $(Pipeline.Workspace)/todozip/todo.zip

여기에 많은 내용이 없습니다. 우리는 응용 서비스 계획과 웹 응용 프로그램, 그리고 코스모스 키를 저장하는 키 라이브러리, 그리고 변수 그룹에서 읽고 있는 비밀을 만들었습니다.이 웹 프로그램은 키 라이브러리에 대한 접근 권한을 부여하기 위해 위탁 관리 신분으로 만듭니다.이제 Cosmos DB 계정을 만들고 계정 키를 키 저장소에 저장합니다.마지막으로, 우리는 관건적인vault 인용을 포함하여 모든 응용 프로그램 설정을 설정하고, 웹 응용 프로그램을 배치합니다.이 응용 프로그램은 로컬 경로에 어떤 내용도 쓰지 않기 때문에 mount our zipped deployment package directly as a read-only filesystem 기능을 이용했습니다.
파이핑을 실행할 때 애플리케이션을 구축하고 단계별로 배치합니다.

완료된 파이프 실행
로그를 검사하면 마스터 azure-pipelines.yml 파일에 정의된 것처럼 템플릿의 단계가 포함되어 있습니다.

파이프 로그

보답


비록 이런 방법은 약간의 일을 세워야 하지만, 그것은 많은 이익을 제공했다.
  • 우리가 배치한 환경에 따라 우리의 원본 환매에는 어떠한 논리도 필요 없다.
  • 응용 프로그램 설정에 대한 변경은 우리가 응용 프로그램 코드를 재건해야 한다는 것을 의미하지 않는다. 우리는 새로운 설정으로 같은 버전을 재배치할 수 있다.
  • 설정repo는 버전 제어를 할 수 있기 때문에 서로 다른 코드repo는 설정의 다른 버전에 고정할 수 있다.
  • 구성 재구매는 일반적으로 특정 환경에 배치된 가상 시스템의 수량이나 크기와 같은 비용 민감성을 포함한다.이를 Azure Repos에 저장하면 일반적인 소스 코드 관리 및 감사 기술을 사용하여 이러한 변수에 대한 변경 사항을 제어할 수 있습니다
  • .
  • 우리는 config repo에서 새로운 프로필을 만들고 발표 파이프에 다음 형식의 절을 만들면 발표 파이프에 새로운 환경을 추가할 수 있습니다.
  •  - stage: deployWhatever
    displayName: Deploy Whatever Environment
    jobs:
    - template: pipelineTemplates/doTheDevOps.yml
    parameters:
    stageName : sample_app_whatever
    variableGroupForSecrets : SecretVarsForWhatever
    
    

    이 stackoverflow 라인은 2012년에서 왔습니다.참여자에 대한 비판이 아니라 당시 유행했던 관점에 대한 비판이다.이 게시물에 따르면 12가지 요인 작성자는 ".NET의 프로필 사용을 분명히 이해하지 못한다"며 50점의'현상'을 받았다.↩︎
    https://en.wikipedia.org/wiki/Create,_read,_update_and_delete ↩︎
    Azure DevOps의 괴벽은 variable names are upper-cased when being exposed as environment variables 입니다.↩︎
    간결하게 보기 위해 본 예는 Azure CLI 를 사용하여 모든 기초 구조를 만듭니다.실제 프로젝트에서, 나는 이 점을 실현하기 위해 다른 도구를 사용할 수 있지만, 변수 템플릿은 파이프의 다른 부분과 같다.↩︎

    좋은 웹페이지 즐겨찾기