티스토리 뷰

<참조> https://azuredevopslabs.com/labs/vstsextend/releasegates/

 

 

 

 


이 랩은 진행과정에 해결해야 할 이슈가 많아 정리하는데 많은 시간이 걸렸다. 이에 3
편에 걸쳐 분리하여 포스팅 하고자 한다. 먼저 1편을 정리한다.

 

 

 

알고 있는 바과 같이, 릴리즈 파이프라인은 애플리케이션이 다양한 환경에 배포 될 수 있도록 종단간 릴리즈 프로세스를 지정한다. 각 환경에 대한 배포는 잡 및 태스크를 사용하여 완전히 자동화 된다. 이상적으로는 애플리케이션에 대한 새 업데이트가 모든 사용자에게 동시에 노출되는 것을 원하지 않는다. 업데이트를 단계적으로 노출하는 것이 가장 좋은 관행이다. 사용자들의 부분집합에 노출되고, 사용자들의 사용을 모니터링하며, 사용자들의 초기 집합이 가진 경험에 기초하여 다른 사용자들에게 노출된다.

승인 및 게이트를 통해 릴리즈에서 배포의 시작 및 완료를 제어 할 수 있다. 승인이 있으면 사용자가 배포를 수동으로 승인하거나 거부 할 때까지 기다릴 수 있다. 릴리즈 게이트를 사용하면 릴리즈가 다음 환경으로 승격되기 전에 충족되어야 하는 애플리케이션 상태 기준을 지정할 수 있다. 환경 배포 이전 또는 이후에 지정된 모든 게이트는 모두 통과하거나 정의된 제한 시간에 도달하여 실패 할 때까지 자동으로 평가된다.

pre-deployment conditions 또는 post-deployment conditions 패널에서 릴리즈 정의의 환경에 게이트를 추가 할 수 있다. 릴리즈에 대한 모든 입력이 성공적으로 이루어 지도록 여러 게이트를 환경 조건에 추가 할 수 있다.

예를 들면 다음과 같가.

Pre-deployment gates는 빌드를 환경에 배포하기 전에 작업 항목 또는 이슈 관리 시스템에 활성 문제가 없는지 확인한다.

Post-deployment gates는 배포를 다음 환경으로 승격하기 전에 앱이 배포 된 후 앱의 모니터링 또는 사고 관리 시스템에서 사고가 발생하지 않도록한다.

모든 계정에 기본적으로 4 가지 유형의 게이트가 포함되어 있다.

 

1. Azure 함수 호출 : Azure 함수 실행을 트리거하고 성공적인 완료를 보장한다. 자세한 내용은 Azure 함수 태스크를 참조한다.

 

2. Azure 모니터 경고 쿼리 : 활성 경고에 대해 구성된 Azure 모니터 경고 규칙을 관찰한다. 자세한 내용은 Azure Monitor 태스크를 참조한다.

 

3. REST API 호출 : REST API를 호출하고 성공적인 응답을 반환하면 계속한다. 자세한 내용은 HTTP REST API 태스크를 참조한다.

 

4. 쿼리 작업 항목 : 쿼리에서 반환 된 일치하는 작업 항목의 수가 임계 값 내에 있는지 확인한다. 자세한 내용은 작업 항목 쿼리 태스크를 참조한다. 

 

 

 

 

본 랩에서 다루는 내용

이 랩에서는 배포 게이트의 구성과 Azure 파이프라인에 컨트롤을 추가하는 방법에 대해 자세히 설명한다. Azure Web App에 대한 두 가지 환경으로 릴리즈 정의를 구성한다. 앱에 대한 차단 버그가 없는 경우에만 Canary 환경에 배포하고 Azure Monitor (Application Insights)에 활성 경고가 없는 경우에만 Canary 환경을 완료로 표시한다.

 

 

 

시작하기 전에

1. 다음 실습을 수행하기 전에 시작하기 페이지를 참조한다.

2. Azure DevOps 데모 생성기를 사용하여 Azure DevOps 조직에 프로젝트를 프로비저닝 한다.

 

 

 

타겟 환경 설정하기

Azure에서 두 개의 Web Apps를 만들어 애플리케이션을 배포하기위한 Canary 및 Production의 두 환경을 설명한다.

1. Azure Portal에서 Azure Cloud Shell을 시작하고 Bash를 선택한다.

2. 리소스 그룹을 만든다. <region>을 선택한 지역 (예 : koreacentral)으로 바꾼다.


az group create 
-n MyResourceGroup -l <region>

kim@Azure:~$ az group create -n azdoho-rg -l koreacentral
{
  "id": "/subscriptions/1199xxxx-xxxx-xxxx-xxxx-cabaxxxxee88/resourceGroups/azdoho-rg",
  "location": "koreacentral",
  "managedBy": null,
  "name": "azdoho-rg",
  "properties": {
    "provisioningState": "Succeeded"
  },
  "tags": null,
  "type": "Microsoft.Resources/resourceGroups"
}

 

3. 앱 서비스 계획을 만든다.

 


az group create 
-n MyResourceGroup -l <region>

kim@Azure:~$ az appservice plan create -g azdoho-rg -n zeroasp-azdoho --sku S1
{- Finished ..
  "freeOfferExpirationTime": null,
  "geoRegion": "Korea Central",
  "hostingEnvironmentProfile": null,
  "hyperV": false,
  "id": "/subscriptions/1199xxxx-xxxx-xxxx-xxxx-cabaxxxxee88/resourceGroups/azdoho-rg/providers/Microsoft.Web/serverfarms/zeroasp-azdoho",
  "isSpot": false,
  "isXenon": false,
  "kind": "app",
  "location": "koreacentral",
  "maximumElasticWorkerCount": 1,
  "maximumNumberOfWorkers": 0,
  "name": "zeroasp-azdoho",
  "numberOfSites": 0,
  "perSiteScaling": false,
  "provisioningState": "Succeeded",
  "reserved": false,
  "resourceGroup": "azdoho-rg",
  "sku": {
    "capabilities": null,
    "capacity": 1,
    "family": "S",
    "locations": null,
    "name": "S1",
    "size": "S1",
    "skuCapacity": null,
    "tier": "Standard"
  },
  "spotExpirationTime": null,
  "status": "Ready",
  "subscription": "1199xxxx-xxxx-xxxx-xxxx-cabaxxxxee88",
  "tags": null,
  "targetWorkerCount": 0,
  "targetWorkerSizeId": 0,
  "type": "Microsoft.Web/serverfarms",
  "workerTierName": null
}

 

 

4. 고유 한 앱 이름으로 두 개의 웹앱을 만든다. (앱 이름은 고유한 이름으로 변경하여 입력 한다.)


az webapp create -g MyResourceGroup -p MyPlan -n PartsUnlimited-Canary

kim@Azure:~$ az webapp create -g azdoho-rg -p zeroasp-azdoho -n PartsUnlimited-Canary-zerobig
{- Finished ..
  "availabilityState": "Normal",
  "clientAffinityEnabled": true,
  "clientCertEnabled": false,
  "clientCertExclusionPaths": null,
  "cloningInfo": null,
  "containerSize": 0,
  "dailyMemoryTimeQuota": 0,
  "defaultHostName": "partsunlimited-canary-zerobig.azurewebsites.net",
  "enabled": true,
  "enabledHostNames": [
    "partsunlimited-canary-zerobig.azurewebsites.net",
    "partsunlimited-canary-zerobig.scm.azurewebsites.net"
  ],
  "ftpPublishingUrl": "ftp://waws-prod-se1-005.ftp.azurewebsites.windows.net/site/wwwroot",
  "hostNameSslStates": [
    {
      "hostType": "Standard",
      "ipBasedSslResult": null,
      "ipBasedSslState": "NotConfigured",
      "name": "partsunlimited-canary-zerobig.azurewebsites.net",
      "sslState": "Disabled",
      "thumbprint": null,
      "toUpdate": null,
      "toUpdateIpBasedSsl": null,
      "virtualIp": null
    },
    {
      "hostType": "Repository",
      "ipBasedSslResult": null,
      "ipBasedSslState": "NotConfigured",
      "name": "partsunlimited-canary-zerobig.scm.azurewebsites.net",
      "sslState": "Disabled",
      "thumbprint": null,
      "toUpdate": null,
      "toUpdateIpBasedSsl": null,
      "virtualIp": null
    }
  ],
  "hostNames": [
    "partsunlimited-canary-zerobig.azurewebsites.net"
  ],
  "hostNamesDisabled": false,
  "hostingEnvironmentProfile": null,
  "httpsOnly": false,
  "hyperV": false,
  "id": "/subscriptions/1199xxxx-xxxx-xxxx-xxxx-cabaxxxxee88/resourceGroups/azdoho-rg/providers/Microsoft.Web/sites/PartsUnlimited-Canary-zerobig",
  "identity": null,
  "inProgressOperationId": null,
  "isDefaultContainer": null,
  "isXenon": false,
  "kind": "app",
  "lastModifiedTimeUtc": "2021-02-20T00:44:00.656666",
  "location": "Korea Central",
  "maxNumberOfWorkers": null,
  "name": "PartsUnlimited-Canary-zerobig",
  "outboundIpAddresses": "52.231.77.58,52.231.73.183,52.231.71.204,52.231.66.104,52.231.77.171",
  "possibleOutboundIpAddresses": "52.231.77.58,52.231.73.183,52.231.71.204,52.231.66.104,52.231.77.171,52.231.69.238,52.231.78.172,52.231.69.251",
  "redundancyMode": "None",
  "repositorySiteName": "PartsUnlimited-Canary-zerobig",
  "reserved": false,
  "resourceGroup": "azdoho-rg",
  "scmSiteAlsoStopped": false,
  "serverFarmId": "/subscriptions/1199xxxx-xxxx-xxxx-xxxx-cabaxxxxee88/resourceGroups/azdoho-rg/providers/Microsoft.Web/serverfarms/zeroasp-azdoho",
  "siteConfig": {
    "acrUseManagedIdentityCreds": false,
    "acrUserManagedIdentityId": null,
    "alwaysOn": null,
    "apiDefinition": null,
    "apiManagementConfig": null,
    "appCommandLine": null,
    "appSettings": null,
    "autoHealEnabled": null,
    "autoHealRules": null,
    "autoSwapSlotName": null,
    "azureMonitorLogCategories": null,
    "azureStorageAccounts": null,
    "connectionStrings": null,
    "cors": null,
    "customAppPoolIdentityAdminState": null,
    "customAppPoolIdentityTenantState": null,
    "defaultDocuments": null,
    "detailedErrorLoggingEnabled": null,
    "documentRoot": null,
    "experiments": null,
    "fileChangeAuditEnabled": null,
    "ftpsState": null,
    "functionAppScaleLimit": null,
    "functionsRuntimeScaleMonitoringEnabled": null,
    "handlerMappings": null,
    "healthCheckPath": null,
    "http20Enabled": null,
    "httpLoggingEnabled": null,
    "ipSecurityRestrictions": [
      {
        "action": "Allow",
        "description": "Allow all access",
        "ipAddress": "Any",
        "name": "Allow all",
        "priority": 1,
        "subnetMask": null,
        "subnetTrafficTag": null,
        "tag": null,
        "vnetSubnetResourceId": null,
        "vnetTrafficTag": null
      }
    ],
    "javaContainer": null,
    "javaContainerVersion": null,
    "javaVersion": null,
    "limits": null,
    "linuxFxVersion": null,
    "loadBalancing": null,
    "localMySqlEnabled": null,
    "logsDirectorySizeLimit": null,
    "machineKey": null,
    "managedPipelineMode": null,
    "managedServiceIdentityId": null,
    "metadata": null,
    "minTlsVersion": null,
    "minimumElasticInstanceCount": 0,
    "netFrameworkVersion": null,
    "nodeVersion": null,
    "numberOfWorkers": null,
    "phpVersion": null,
    "powerShellVersion": null,
    "preWarmedInstanceCount": null,
    "publishingPassword": null,
    "publishingUsername": null,
    "push": null,
    "pythonVersion": null,
    "remoteDebuggingEnabled": null,
    "remoteDebuggingVersion": null,
    "requestTracingEnabled": null,
    "requestTracingExpirationTime": null,
    "routingRules": null,
    "runtimeADUser": null,
    "runtimeADUserPassword": null,
    "scmIpSecurityRestrictions": [
      {
        "action": "Allow",
        "description": "Allow all access",
        "ipAddress": "Any",
        "name": "Allow all",
        "priority": 1,
        "subnetMask": null,
        "subnetTrafficTag": null,
        "tag": null,
        "vnetSubnetResourceId": null,
        "vnetTrafficTag": null
      }
    ],
    "scmIpSecurityRestrictionsUseMain": null,
    "scmMinTlsVersion": null,
    "scmType": null,
    "tracingOptions": null,
    "use32BitWorkerProcess": null,
    "virtualApplications": null,
    "vnetName": null,
    "vnetPrivatePortsCount": null,
    "vnetRouteAllEnabled": null,
    "webSocketsEnabled": null,
    "websiteTimeZone": null,
    "winAuthAdminState": null,
    "winAuthTenantState": null,
    "windowsFxVersion": null,
    "xManagedServiceIdentityId": null
  },
  "slotSwapStatus": null,
  "state": "Running",
  "suspendedTill": null,
  "tags": null,
  "targetSwapSlot": null,
  "trafficManagerHostNames": null,
  "type": "Microsoft.Web/sites",
  "usageState": "Normal"
}

 


az group create 
-n MyResaz webapp create -g MyResourceGroup -p MyPlan -n PartsUnlimited-Prod

kim@Azure:~$ az webapp create -g azdoho-rg -p zeroasp-azdoho -n PartsUnlimited-Prod-zerobig
{- Finished ..
  "availabilityState": "Normal",
  "clientAffinityEnabled": true,
  "clientCertEnabled": false,
  "clientCertExclusionPaths": null,
  "cloningInfo": null,
  "containerSize": 0,
  "dailyMemoryTimeQuota": 0,
  "defaultHostName": "partsunlimited-prod-zerobig.azurewebsites.net",
  "enabled": true,
  "enabledHostNames": [
    "partsunlimited-prod-zerobig.azurewebsites.net",
    "partsunlimited-prod-zerobig.scm.azurewebsites.net"
  ],
  "ftpPublishingUrl": "ftp://waws-prod-se1-005.ftp.azurewebsites.windows.net/site/wwwroot",
  "hostNameSslStates": [
    {
      "hostType": "Standard",
      "ipBasedSslResult": null,
      "ipBasedSslState": "NotConfigured",
      "name": "partsunlimited-prod-zerobig.azurewebsites.net",
      "sslState": "Disabled",
      "thumbprint": null,
      "toUpdate": null,
      "toUpdateIpBasedSsl": null,
      "virtualIp": null
    },
    {
      "hostType": "Repository",
      "ipBasedSslResult": null,
      "ipBasedSslState": "NotConfigured",
      "name": "partsunlimited-prod-zerobig.scm.azurewebsites.net",
      "sslState": "Disabled",
      "thumbprint": null,
      "toUpdate": null,
      "toUpdateIpBasedSsl": null,
      "virtualIp": null
    }
  ],
  "hostNames": [
    "partsunlimited-prod-zerobig.azurewebsites.net"
  ],
  "hostNamesDisabled": false,
  "hostingEnvironmentProfile": null,
  "httpsOnly": false,
  "hyperV": false,
  "id": "/subscriptions/1199xxxx-xxxx-xxxx-xxxx-cabaxxxxee88/resourceGroups/azdoho-rg/providers/Microsoft.Web/sites/PartsUnlimited-Prod-zerobig",
  "identity": null,
  "inProgressOperationId": null,
  "isDefaultContainer": null,
  "isXenon": false,
  "kind": "app",
  "lastModifiedTimeUtc": "2021-02-20T00:45:43.220000",
  "location": "Korea Central",
  "maxNumberOfWorkers": null,
  "name": "PartsUnlimited-Prod-zerobig",
  "outboundIpAddresses": "52.231.77.58,52.231.73.183,52.231.71.204,52.231.66.104,52.231.77.171",
  "possibleOutboundIpAddresses": "52.231.77.58,52.231.73.183,52.231.71.204,52.231.66.104,52.231.77.171,52.231.69.238,52.231.78.172,52.231.69.251",
  "redundancyMode": "None",
  "repositorySiteName": "PartsUnlimited-Prod-zerobig",
  "reserved": false,
  "resourceGroup": "azdoho-rg",
  "scmSiteAlsoStopped": false,
  "serverFarmId": "/subscriptions/1199xxxx-xxxx-xxxx-xxxx-cabaxxxxee88/resourceGroups/azdoho-rg/providers/Microsoft.Web/serverfarms/zeroasp-azdoho",
  "siteConfig": {
    "acrUseManagedIdentityCreds": false,
    "acrUserManagedIdentityId": null,
    "alwaysOn": null,
    "apiDefinition": null,
    "apiManagementConfig": null,
    "appCommandLine": null,
    "appSettings": null,
    "autoHealEnabled": null,
    "autoHealRules": null,
    "autoSwapSlotName": null,
    "azureMonitorLogCategories": null,
    "azureStorageAccounts": null,
    "connectionStrings": null,
    "cors": null,
    "customAppPoolIdentityAdminState": null,
    "customAppPoolIdentityTenantState": null,
    "defaultDocuments": null,
    "detailedErrorLoggingEnabled": null,
    "documentRoot": null,
    "experiments": null,
    "fileChangeAuditEnabled": null,
    "ftpsState": null,
    "functionAppScaleLimit": null,
    "functionsRuntimeScaleMonitoringEnabled": null,
    "handlerMappings": null,
    "healthCheckPath": null,
    "http20Enabled": null,
    "httpLoggingEnabled": null,
    "ipSecurityRestrictions": [
      {
        "action": "Allow",
        "description": "Allow all access",
        "ipAddress": "Any",
        "name": "Allow all",
        "priority": 1,
        "subnetMask": null,
        "subnetTrafficTag": null,
        "tag": null,
        "vnetSubnetResourceId": null,
        "vnetTrafficTag": null
      }
    ],
    "javaContainer": null,
    "javaContainerVersion": null,
    "javaVersion": null,
    "limits": null,
    "linuxFxVersion": null,
    "loadBalancing": null,
    "localMySqlEnabled": null,
    "logsDirectorySizeLimit": null,
    "machineKey": null,
    "managedPipelineMode": null,
    "managedServiceIdentityId": null,
    "metadata": null,
    "minTlsVersion": null,
    "minimumElasticInstanceCount": 0,
    "netFrameworkVersion": null,
    "nodeVersion": null,
    "numberOfWorkers": null,
    "phpVersion": null,
    "powerShellVersion": null,
    "preWarmedInstanceCount": null,
    "publishingPassword": null,
    "publishingUsername": null,
    "push": null,
    "pythonVersion": null,
    "remoteDebuggingEnabled": null,
    "remoteDebuggingVersion": null,
    "requestTracingEnabled": null,
    "requestTracingExpirationTime": null,
    "routingRules": null,
    "runtimeADUser": null,
    "runtimeADUserPassword": null,
    "scmIpSecurityRestrictions": [
      {
        "action": "Allow",
        "description": "Allow all access",
        "ipAddress": "Any",
        "name": "Allow all",
        "priority": 1,
        "subnetMask": null,
        "subnetTrafficTag": null,
        "tag": null,
        "vnetSubnetResourceId": null,
        "vnetTrafficTag": null
      }
    ],
    "scmIpSecurityRestrictionsUseMain": null,
    "scmMinTlsVersion": null,
    "scmType": null,
    "tracingOptions": null,
    "use32BitWorkerProcess": null,
    "virtualApplications": null,
    "vnetName": null,
    "vnetPrivatePortsCount": null,
    "vnetRouteAllEnabled": null,
    "webSocketsEnabled": null,
    "websiteTimeZone": null,
    "winAuthAdminState": null,
    "winAuthTenantState": null,
    "windowsFxVersion": null,
    "xManagedServiceIdentityId": null
  },
  "slotSwapStatus": null,
  "state": "Running",
  "suspendedTill": null,
  "tags": null,
  "targetSwapSlot": null,
  "trafficManagerHostNames": null,
  "type": "Microsoft.Web/sites",
  "usageState": "Normal"
}

 

5. 5. 생성한 리소스 그룹으로 이동하면 그림과 같이 리소스가 표시된다.

 

 

6. 이제 Canary 웹 앱을 선택하고 Settings Application insights 설정을 클릭한다. Turn on Application Insights를 선택한다.

 

 

7. 기본 설정으로 Apply를 클릭하여 애플리케이션 인사이트 리소스를 만들고 Canary 웹앱에 연결한다.

 

 

8. 이제 리소스 그룹으로 돌아가서 생성된 애플리케이션 인사이트 리소스를 선택한다.

 

 

 

9. 여기에서 모니터 알림을 생성하고 이 실습의 후반부에서 사용할 것이다. Alerts를 선택하고 New alert rule을 클릭한다.

 

 

10. Create alert rule 창이 나타난다. Select condition을 선택한다. Failed Requests 규칙을 검색하고 선택한다.

 

결과 창에서 아래와 같이 Alert logic을 구성하고 Done을 클릭한다.

 

 

11. 이제 Create alert rule 창에서 아래와 같이 경고 규칙 세부 정보를 입력한다.

 

PartsUnlimited_FailedRequests

 

 

 

12. 규칙이 생성되면 Alerts 아래에서 해당 규칙을 볼 수 있다.

 

 

다음과 같은 서로 다른 메트릭에 대해 여러 경고 규칙을 만들 수 있다.

 

Availability < 99 Percent

Server response time > 5 Seconds

Server exceptions > 0 Count

 

이 실습에서는 Whenever the count requests/failed is greater than 0 조건에 따라 트리거 할 하나의 모니터 알림을 만들었다.

 

 

2편에서 계속

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함