14 Terraform을 사용하여 Azure 배포 슬롯으로 인프라 프로비전
<참조>
https://docs.microsoft.com/ko-kr/azure/terraform/terraform-slot-walkthru
https://docs.microsoft.com/en-us/azure/terraform/terraform-slot-walkthru
이번 자습서에서는 GitHub 및 Azure를 통해 두 개의 앱을 배포하는 과정을 안내하면서 배포 슬롯을 사용하는 예를 보여준다. 하나의 앱이 프로덕션 슬롯에 호스트되고 두 번째 앱은 스테이징 슬롯에 호스트된다. 배포 슬롯을 구성한 후 Terraform을 사용하여 두 슬롯 사이를 전환한다.
필수 조건
-
Azure 구독: Azure 구독이 아직 없는 경우 시작하기 전에 무료 계정을 만든다.
-
GitHub 계정: 테스트 GitHub 리포지토리를 fork하고 사용하려면 GitHub 계정이 필요하다.
Terraform 계획 만들기 및 적용
실습할 디렉토리를 생성하고 마우스 오른쪽 버튼을 클릭하여 "Code(으)로 열기"를 선택한다.
다음과 같이 생성한 실습 디렉토리 이하에 deploy, swap의 이름을 가지는 두 개의 디렉토리를 생성한다.
deploy 디렉토리 내 deploy.tf 파일을 만들고 다음 코드를 붙여 넣는다.
이때, azurerm_app_service의 name은 각자 고유의 값으로 변경해야 한다.
# Configure the Azure provider provider "azurerm" { }
resource "azurerm_resource_group" "slotDemo" { name = "slotDemoResourceGroup" location = "koreacentral" }
resource "azurerm_app_service_plan" "slotDemo" { name = "slotAppServicePlan" location = azurerm_resource_group.slotDemo.location resource_group_name = azurerm_resource_group.slotDemo.name sku { tier = "Standard" size = "S1" } }
resource "azurerm_app_service" "slotDemo" { name = "zeroslotAppService" location = azurerm_resource_group.slotDemo.location resource_group_name = azurerm_resource_group.slotDemo.name app_service_plan_id = azurerm_app_service_plan.slotDemo.id }
resource "azurerm_app_service_slot" "slotDemo" { name = "slotAppServiceSlotOne" location = azurerm_resource_group.slotDemo.location resource_group_name = azurerm_resource_group.slotDemo.name app_service_plan_id = azurerm_app_service_plan.slotDemo.id app_service_name = azurerm_app_service.slotDemo.name } |
파일을 저장( Ctrl + S)하고 새로운 bash용 Terminal을 연다.
작업에 앞서, 혹시나 Azure 구독이 여러 개인 경우 az account list와 az account set 명령을 통해 작업환경을 준비한다.
zerobig@ZEROBIG-NT800:/mnt/c/AzureDevOps-Exercise/20200112$ az account list
A few accounts are skipped as they don't have 'Enabled' state. Use '--all' to display them.
[
{
"cloudName": "AzureCloud",
"id": "2e5d848e-xxxx-xxx-xxxx-fd25ae915bcd",
"isDefault": false,
"name": "Visual Studio Enterprise 2019",
"state": "Enabled",
"tenantId": "54a472fb-1510-4554-922c-fe808f9e6e64",
"user": {
"name": "zerobig.devops@gmail.com",
"type": "user"
}
},
{
"cloudName": "AzureCloud",
"id": "f8764f39-xxxx-xxxx-xxxx-77b286ed971b",
"isDefault": true,
"name": "Visual Studio Enterprise 201907",
"state": "Enabled",
"tenantId": "917bfe84-0ca6-488d-ad3a-236e41ceafe9",
"user": {
"name": "zerobig.kim@gmail.com",
"type": "user"
}
},
{
"cloudName": "AzureCloud",
"id": "2dce383a-9126-496c-a9a6-5fc758f9cf1d",
"isDefault": false,
"name": "Visual Studio Enterprise – MPN",
"state": "Enabled",
"tenantId": "22921252-b61a-4ab3-ac9a-8f160db61f8d",
"user": {
"name": "zerobig@sptek.co.kr",
"type": "user"
}
}
zerobig@ZEROBIG-NT800:/mnt/c/AzureDevOps-Exercise/20200112$ az account set --subscription f8764f39-xxxx-xxxx-xxxx-77b286ed971b
zerobig@ZEROBIG-NT800:/mnt/c/AzureDevOps-Exercise/20200112$ az account show
{
"environmentName": "AzureCloud",
"id": "f8764f39-xxxx-xxxx-xxxx-77b286ed971b",
"isDefault": true,
"name": "Visual Studio Enterprise 201907",
"state": "Enabled",
"tenantId": "917bfe84-0ca6-488d-ad3a-236e41ceafe9",
"user": {
"name": "zerobig.kim@gmail.com",
"type": "user"
}
}
deploy 디렉토리로 이동하여 terraform init을 통해 초기화를 하고 이어 terraform plan을 통해 계획을 만든다.
zerobig@ZEROBIG-NT800:/mnt/c/AzureDevOps-Exercise/20200112$ cd deploy/
zerobig@ZEROBIG-NT800:/mnt/c/AzureDevOps-Exercise/20200112/deploy$ ls -rlht
total 4.0K
-rwxrwxrwx 1 zerobig zerobig 1.2K Jan 12 11:49 deploy.tf
zerobig@ZEROBIG-NT800:/mnt/c/AzureDevOps-Exercise/20200112/deploy$ terraform init
Initializing the backend...
Initializing provider plugins...
- Checking for available provider plugins...
- Downloading plugin for provider "azurerm" (hashicorp/azurerm) 1.40.0...
The following providers do not have any version constraints in configuration,
so the latest version was installed.
To prevent automatic upgrades to new major versions that may contain breaking
changes, it is recommended to add version = "..." constraints to the
corresponding provider blocks in configuration, with the constraint strings
suggested below.
* provider.azurerm: version = "~> 1.40"
Terraform has been successfully initialized!
You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.
If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
zerobig@ZEROBIG-NT800:/mnt/c/AzureDevOps-Exercise/20200112/deploy$ terraform plan
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.
------------------------------------------------------------------------
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# azurerm_app_service.slotDemo will be created
+ resource "azurerm_app_service" "slotDemo" {
+ app_service_plan_id = (known after apply)
+ app_settings = (known after apply)
+ client_affinity_enabled = (known after apply)
+ default_site_hostname = (known after apply)
+ enabled = true
+ https_only = false
+ id = (known after apply)
+ location = "koreacentral"
+ name = "slotAppService"
+ outbound_ip_addresses = (known after apply)
+ possible_outbound_ip_addresses = (known after apply)
+ resource_group_name = "slotDemoResourceGroup"
+ site_credential = (known after apply)
+ source_control = (known after apply)
+ tags = (known after apply)
<중략>
# azurerm_resource_group.slotDemo will be created
+ resource "azurerm_resource_group" "slotDemo" {
+ id = (known after apply)
+ location = "koreacentral"
+ name = "slotDemoResourceGroup"
+ tags = (known after apply)
}
Plan: 4 to add, 0 to change, 0 to destroy.
------------------------------------------------------------------------
Note: You didn't specify an "-out" parameter to save this plan, so Terraform
can't guarantee that exactly these actions will be performed if
"terraform apply" is subsequently run.
이상이 없다면, deploy.tf 구성 파일에 정의된 리소스를 프로비전한다. (프롬프트에 yes를 입력하여 작업을 확인한다.)
zerobig@ZEROBIG-NT800:/mnt/c/AzureDevOps-Exercise/20200112/deploy$ terraform apply
azurerm_resource_group.slotDemo: Refreshing state... [id=/subscriptions/f8764f39-xxxx-xxxx-xxxx-77b286ed971b/resourceGroups/slotDemoResourceGroup]
azurerm_app_service_plan.slotDemo: Refreshing state... [id=/subscriptions/f8764f39-xxxx-xxxx-xxxx-77b286ed971b/resourceGroups/slotDemoResourceGroup/providers/Microsoft.Web/serverfarms/slotAppServicePlan]
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# azurerm_app_service.slotDemo will be created
+ resource "azurerm_app_service" "slotDemo" {
+ app_service_plan_id = "/subscriptions/f8764f39-xxxx-xxxx-xxxx-77b286ed971b/resourceGroups/slotDemoResourceGroup/providers/Microsoft.Web/serverfarms/slotAppServicePlan"
+ app_settings = (known after apply)
+ client_affinity_enabled = (known after apply)
+ default_site_hostname = (known after apply)
+ enabled = true
+ https_only = false
+ id = (known after apply)
+ location = "koreacentral"
+ name = "zeroslotAppService"
+ outbound_ip_addresses = (known after apply)
+ possible_outbound_ip_addresses = (known after apply)
+ resource_group_name = "slotDemoResourceGroup"
+ site_credential = (known after apply)
+ source_control = (known after apply)
+ tags = (known after apply)
<중략>
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
azurerm_app_service.slotDemo: Creating...
azurerm_app_service.slotDemo: Still creating... [10s elapsed]
azurerm_app_service.slotDemo: Still creating... [20s elapsed]
azurerm_app_service.slotDemo: Creation complete after 25s [id=/subscriptions/f8764f39-xxxx-xxxx-xxxx-77b286ed971b/resourceGroups/slotDemoResourceGroup/providers/Microsoft.Web/sites/zeroslotAppService]
azurerm_app_service_slot.slotDemo: Creating...
azurerm_app_service_slot.slotDemo: Still creating... [10s elapsed]
azurerm_app_service_slot.slotDemo: Still creating... [20s elapsed]
azurerm_app_service_slot.slotDemo: Creation complete after 24s [id=/subscriptions/f8764f39-xxxx-xxxx-xxxx-77b286ed971b/resourceGroups/slotDemoResourceGroup/providers/Microsoft.Web/sites/zeroslotAppService/slots/slotAppServiceSlotOne]
Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
Azure Portal의 slotDemoResourceGroup 리소스 그룹을 선택하여 결과를 확인한다.
테스트 프로젝트 Fork
배포 슬롯 생성 및 배포 슬롯과 교환을 테스트하려면 그 전에 GitHub에서 테스트 프로젝트를 Fork해야 한다.
1. GitHub의 awesome-terraform 리포지토리로 이동한다.
2. awesome-terraform 리포지토리를 Fork 한다.
3. 프롬프트에 따라 환경을 fork한다.
GitHub에서 배포 슬롯으로 배포
먼저 진행에 앞서 Azure DevOps에 "awesome-terraform"이라는 프로젝트를 기본값으로 생성한다.
이후 Azure Portal에서 다음 단계를 통해 배포 슬롯을 구성한다.
1. Azure Portal의 주 메뉴에서 리소스 그룹을 선택한다.
2. slotDemoResourceGroup을 선택한다.
3. 각자 상황에 맞는 zeroslotAppService를 선택한다.
4. Deployment Center를 선택한다. (원문에는 Deployment options으로 가이드 되어있어 더 이상 없는 UI다.)
5. Deployment Center - SOURCE CONTROL 화면에서 GitHub를 선택하고 Continue를 누른다.
6. Deployment Center - BUILD PROVIDER 화면에서 Azure Pipelines (Preview)를 선택하고 Continue를 누른다.
7. Deployment Center - CONFIGURE 화면에서 조직, 리포지토리 및 브랜치(master)를 선택하고 Continue를 누른다.
8. Deployment Center - SUMMARY 화면에서 내용을 검토하고 Finish를 누른다.
잠시 후 "Successfully setup Continuous Delivery and triggered build" 메시지가 화면에 전시된다.
이 시점에 Azure DevOps의 CI/CD가 순차적으로 진행된다.
성공적으로 작업이 이루어 진 것이 확인되면, 이번에는 slotappserviceslotone에 대해 위 4번 과정의 Deployment Center 선택부터 동일한 작업을 진행한다.
단, 7. Deployment Center - CONFIGURE 화면에서 브랜치를 appServiceSlot_Working_DO_NOT_MERGE으로 선택해야 한다.
앱 배포 테스트
zerolotAppService과 slotAppServiceSlotOne 두 개 웹앱에 대한 배포 결과를 확인한다.
- zeroslotAppService 웹앱 - 페이지 제목이 Slot Demo App 1인 파란색 페이지다.
- slotAppServiceSlotOne 웹앱 - 페이지 제목이 Slot Demo App 2인 녹색 페이지다.
두 개의 배포 슬롯 교환
두 개의 배포 슬롯 교환을 테스트하려면 다음 단계를 수행한다.
1. zeroslotAppService(파란색 페이지가 있는 앱)가 실행 중인 브라우저 탭으로 전환한다.
2. swap 디렉터리로 내 swap.tf 파일을 만들고 다음 내용을 붙여 넣는다.
# Configure the Azure provider
|
3. 파일을 저장( Ctrl + S)한다.
4. terraform init을 통해 초기화를 하고, 이어 terraform plan을 통해 계획을 만든다.
zerobig@ZEROBIG-NT800:/mnt/c/AzureDevOps-Exercise/20200112/swap$ terraform init
Initializing the backend...
Initializing provider plugins...
- Checking for available provider plugins...
- Downloading plugin for provider "azurerm" (hashicorp/azurerm) 1.40.0...
The following providers do not have any version constraints in configuration,
so the latest version was installed.
To prevent automatic upgrades to new major versions that may contain breaking
changes, it is recommended to add version = "..." constraints to the
corresponding provider blocks in configuration, with the constraint strings
suggested below.
* provider.azurerm: version = "~> 1.40"
Terraform has been successfully initialized!
You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.
If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
zerobig@ZEROBIG-NT800:/mnt/c/AzureDevOps-Exercise/20200112/swap$ terraform plan
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.
------------------------------------------------------------------------
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# azurerm_app_service_active_slot.slotDemoActiveSlot will be created
+ resource "azurerm_app_service_active_slot" "slotDemoActiveSlot" {
+ app_service_name = "zeroslotAppService"
+ app_service_slot_name = "slotappServiceSlotOne"
+ id = (known after apply)
+ resource_group_name = "slotDemoResourceGroup"
}
Plan: 1 to add, 0 to change, 0 to destroy.
------------------------------------------------------------------------
Note: You didn't specify an "-out" parameter to save this plan, so Terraform
can't guarantee that exactly these actions will be performed if
"terraform apply" is subsequently run.
5. 이상이 없다면, swap.tf 구성 파일에 정의된 리소스를 프로비전한다. (프롬프트에 yes를 입력하여 작업을 확인한다.)
zerobig@ZEROBIG-NT800:/mnt/c/AzureDevOps-Exercise/20200112/swap$ terraform apply
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# azurerm_app_service_active_slot.slotDemoActiveSlot will be created
+ resource "azurerm_app_service_active_slot" "slotDemoActiveSlot" {
+ app_service_name = "zeroslotAppService"
+ app_service_slot_name = "slotappServiceSlotOne"
+ id = (known after apply)
+ resource_group_name = "slotDemoResourceGroup"
}
Plan: 1 to add, 0 to change, 0 to destroy.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
azurerm_app_service_active_slot.slotDemoActiveSlot: Creating...
azurerm_app_service_active_slot.slotDemoActiveSlot: Still creating... [10s elapsed]
azurerm_app_service_active_slot.slotDemoActiveSlot: Still creating... [20s elapsed]
azurerm_app_service_active_slot.slotDemoActiveSlot: Still creating... [30s elapsed]
azurerm_app_service_active_slot.slotDemoActiveSlot: Still creating... [40s elapsed]
azurerm_app_service_active_slot.slotDemoActiveSlot: Still creating... [50s elapsed]
azurerm_app_service_active_slot.slotDemoActiveSlot: Still creating... [1m0s elapsed]
azurerm_app_service_active_slot.slotDemoActiveSlot: Creation complete after 1m3s [id=/subscriptions/f8764f39-xxxx-xxxx-xxxx-77b286ed971b/resourceGroups/slotDemoResourceGroup/providers/Microsoft.Web/sites/zeroslotAppService]
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
6. Terraform에서 슬롯을 바꾼 후 브라우저로 돌아간다. 페이지를 새로 고친다.
zeroslotAppServiceSlotOne 스테이징 슬롯의 웹앱이 프로덕션 슬롯으로 교환되고 녹색으로 렌더링된다.
7. 앱의 원래 프로덕션 버전으로 돌아가려면 swap.tf 구성 파일에서 만든 Terraform 계획을 다시 적용한다.
zerobig@ZEROBIG-NT800:/mnt/c/AzureDevOps-Exercise/20200112/swap$ terraform apply
azurerm_app_service_active_slot.slotDemoActiveSlot: Refreshing state... [id=/subscriptions/f8764f39-xxxx-xxxx-xxxx-77b286ed971b/resourceGroups/slotDemoResourceGroup/providers/Microsoft.Web/sites/zeroslotAppService]
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
~ update in-place
Terraform will perform the following actions:
# azurerm_app_service_active_slot.slotDemoActiveSlot will be updated in-place
~ resource "azurerm_app_service_active_slot" "slotDemoActiveSlot" {
app_service_name = "zeroslotAppService"
~ app_service_slot_name = "slotAppServiceSlotOne" -> "slotappServiceSlotOne"
id = "/subscriptions/f8764f39-xxxx-xxxx-xxxx-77b286ed971b/resourceGroups/slotDemoResourceGroup/providers/Microsoft.Web/sites/zeroslotAppService"
resource_group_name = "slotDemoResourceGroup"
}
Plan: 0 to add, 1 to change, 0 to destroy.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
azurerm_app_service_active_slot.slotDemoActiveSlot: Modifying... [id=/subscriptions/f8764f39-xxxx-xxxx-xxxx-77b286ed971b/resourceGroups/slotDemoResourceGroup/providers/Microsoft.Web/sites/zeroslotAppService]
azurerm_app_service_active_slot.slotDemoActiveSlot: Still modifying... [id=/subscriptions/f8764f39-01ee-4631-9941-...Microsoft.Web/sites/zeroslotAppService, 10s elapsed]
azurerm_app_service_active_slot.slotDemoActiveSlot: Still modifying... [id=/subscriptions/f8764f39-01ee-4631-9941-...Microsoft.Web/sites/zeroslotAppService, 20s elapsed]
azurerm_app_service_active_slot.slotDemoActiveSlot: Still modifying... [id=/subscriptions/f8764f39-01ee-4631-9941-...Microsoft.Web/sites/zeroslotAppService, 30s elapsed]
azurerm_app_service_active_slot.slotDemoActiveSlot: Still modifying... [id=/subscriptions/f8764f39-01ee-4631-9941-...Microsoft.Web/sites/zeroslotAppService, 40s elapsed]
azurerm_app_service_active_slot.slotDemoActiveSlot: Still modifying... [id=/subscriptions/f8764f39-01ee-4631-9941-...Microsoft.Web/sites/zeroslotAppService, 50s elapsed]
azurerm_app_service_active_slot.slotDemoActiveSlot: Still modifying... [id=/subscriptions/f8764f39-01ee-4631-9941-...Microsoft.Web/sites/zeroslotAppService, 1m0s elapsed]
azurerm_app_service_active_slot.slotDemoActiveSlot: Modifications complete after 1m2s [id=/subscriptions/f8764f39-xxxx-xxxx-xxxx-77b286ed971b/resourceGroups/slotDemoResourceGroup/providers/Microsoft.Web/sites/zeroslotAppService]
Apply complete! Resources: 0 added, 1 changed, 0 destroyed.
앱이 교환되면 원래 구성이 표시된다.