티스토리 뷰
[특집 시리즈] Azure Kubernetes Service 워크샵 - 10. 수요에 맞게 애플리케이션 크기 조정 2편
zerobig-k8s 2021. 6. 14. 07:47클러스터 자동 크기 조정
HPA는 필요에 따라 새 Pod로 확장된다. 결국에는 클러스터 리소스는 모두 소진되고 예약된 Pod는 보류 상태가 된다.
클러스터 자동 크기 조정기란?
클러스터 자동 크기 조정기는 리소스 제약으로 인해 노드에서 예약할 수 없는 Pod를 감시한다. 그러면 클러스터에서 클러스터의 노드 수가 자동으로 늘어난다.
클러스터에 부하를 도입하여 자동 크기 조정을 강제로 적용해 보겠다. ratings-api 배포에서 인위적으로 CPU의 리소스 request와 limit를 cpu: "1000m"으로 증가하여 이러한 상황을 시뮬레이션하고 다시 배포할 수 있다. 이렇게 하면 Pod가 실제로 사용할 수 있는 것보다 더 많은 리소스를 클러스터 전체에 요청할 수밖에 없다. 그런 다음, 자동 크기 조정을 사용하도록 설정하고 Pod를 실행하는 데 사용할 수 있는 사용 가능한 노드를 늘릴 수 있다.
1. 통합 편집기를 사용하여 ratings-api-deployment.yaml이라는 이름의 파일을 편집한다.
code ratings-api-deployment.yaml
2. 컨테이너의 resources.requests와 resources.limits가 1000m이 되도록 변경한다(이는 1 코어를 의미). 이제 섹션이 다음과 같이 표시된다.
resources:
requests: # minimum resources required
cpu: 1000m
memory: 64Mi
limits: # maximum resources allocated
cpu: 1000m
memory: 256Mi
3. kubectl apply 명령을 사용하여 구성을 적용한다. ratingsapp 네임스페이스에 리소스 업데이트를 배포한다.
kubectl apply \
--namespace ratingsapp \
-f ratings-api-deployment.yaml
다음 예제와 비슷한 출력이 표시된다.
kim@Azure:~$ kubectl apply \
> --namespace ratingsapp \
> -f ratings-api-deployment.yaml
deployment.apps/ratings-api configured
4. 롤아웃한 새로운 Pod를 검토한다. app=ratings-api로 레이블이 지정된 ratingsapp 네임스페이스의 Pod를 쿼리한다.
kubectl get pods \
--namespace ratingsapp \
-l app=ratings-api -w
이제 새 Pod를 예약하기에는 클러스터의 용량이 충분하지 않아서 Pod가 Pending 상태에 걸려 있는 것을 확인할 수 있다.
kim@Azure:~$ kubectl get pods \
> --namespace ratingsapp \
> -l app=ratings-api -w
NAME READY STATUS RESTARTS AGE
ratings-api-7b8fd97cfd-2q88v 1/1 Running 0 8m7s
ratings-api-7b8fd97cfd-44vct 1/1 Running 0 20m
ratings-api-7b8fd97cfd-4xq6n 1/1 Running 0 65m
ratings-api-7b8fd97cfd-4zm2x 1/1 Running 0 15m
ratings-api-7b8fd97cfd-5mltv 1/1 Running 0 15m
ratings-api-7b8fd97cfd-fpkct 1/1 Running 0 21m
ratings-api-7b8fd97cfd-kdv9b 0/1 Terminating 0 5m5s
ratings-api-7b8fd97cfd-s5cww 0/1 Terminating 0 5m5s
ratings-api-7b8fd97cfd-vx7w6 1/1 Running 0 21m
ratings-api-7b8fd97cfd-wmwq6 1/1 Running 0 20m
ratings-api-f4d56dc78-44k9n 0/1 Pending 0 5s
ratings-api-f4d56dc78-5fbct 0/1 Pending 0 5s
ratings-api-f4d56dc78-bmgdz 0/1 Pending 0 5s
ratings-api-f4d56dc78-mwzv7 0/1 Pending 0 5s
ratings-api-f4d56dc78-wzhw2 0/1 Pending 0 5s
Pending 중인 Pod 문제를 해결하려면 클러스터 자동 크기 조정기를 활성화하여 클러스터의 규모를 자동으로 조정하면 된다.
5. 클러스터 자동 크기 조정기를 구성한다. 클러스터 사용률에 따라 노드를 동적으로 추가하고 제거하는 것을 확인할 수 있다. az aks update 명령을 사용하여 클러스터 자동 크기 조정기를 사용하도록 설정한다. 노드 수에 대한 최소값 및 최대값을 지정한다. 앞서 사용한 것과 동일한 리소스 그룹(예: aksworkshop)을 사용해야 한다.
다음 예에서는 --min-count를 _3_으로, --max-count를 _5_로 설정했다.
az aks update \
--resource-group $RESOURCE_GROUP \
--name $AKS_CLUSTER_NAME \
--enable-cluster-autoscaler \
--min-count 3 \
--max-count 5
kim@Azure:~/mslearn-aks-workshop-ratings-web$ az aks update \
> --resource-group $RESOURCE_GROUP \
> --name $AKS_CLUSTER_NAME \
> --enable-cluster-autoscaler \
> --min-count 3 \
> --max-count 5
{
"aadProfile": null,
"addonProfiles": null,
"agentPoolProfiles": [
{
"availabilityZones": null,
"count": 2,
"enableAutoScaling": true,
"enableEncryptionAtHost": false,
"enableFips": false,
"enableNodePublicIp": false,
"gpuInstanceProfile": null,
"kubeletConfig": null,
"kubeletDiskType": "OS",
"linuxOsConfig": null,
"maxCount": 5,
"maxPods": 30,
"minCount": 3,
"mode": "System",
"name": "nodepool1",
"nodeImageVersion": "AKSUbuntu-1804gen2containerd-2021.05.19",
"nodeLabels": {},
"nodePublicIpPrefixId": null,
"nodeTaints": null,
"orchestratorVersion": "1.20.7",
"osDiskSizeGb": 128,
"osDiskType": "Managed",
"osSku": "Ubuntu",
"osType": "Linux",
"podSubnetId": null,
"powerState": {
"code": "Running"
},
"provisioningState": "Succeeded",
"proximityPlacementGroupId": null,
"scaleSetEvictionPolicy": null,
"scaleSetPriority": null,
"spotMaxPrice": null,
"tags": null,
"type": "VirtualMachineScaleSets",
"upgradeSettings": null,
"vmSize": "Standard_DS2_v2",
"vnetSubnetId": "/subscriptions/1199b626-xxxx-xxxx-xxxx-caba7859ee88/resourceGroups/aksworkshop4zerobig/providers/Microsoft.Network/virtualNetworks/aks-vnet/subnets/aks-subnet"
}
],
"apiServerAccessProfile": null,
"autoScalerProfile": {
"balanceSimilarNodeGroups": "false",
"expander": "random",
"maxEmptyBulkDelete": "10",
"maxGracefulTerminationSec": "600",
"maxNodeProvisionTime": "15m",
"maxTotalUnreadyPercentage": "45",
"newPodScaleUpDelay": "0s",
"okTotalUnreadyCount": "3",
"scaleDownDelayAfterAdd": "10m",
"scaleDownDelayAfterDelete": "10s",
"scaleDownDelayAfterFailure": "3m",
"scaleDownUnneededTime": "10m",
"scaleDownUnreadyTime": "20m",
"scaleDownUtilizationThreshold": "0.5",
"scanInterval": "10s",
"skipNodesWithLocalStorage": "false",
"skipNodesWithSystemPods": "true"
},
"autoUpgradeProfile": null,
"azurePortalFqdn": "aksworksho-aksworkshop4zero-1199b6-50bedfce.portal.hcp.koreacentral.azmk8s.io",
"disableLocalAccounts": null,
"diskEncryptionSetId": null,
"dnsPrefix": "aksworksho-aksworkshop4zero-1199b6",
"enablePodSecurityPolicy": null,
"enableRbac": true,
"extendedLocation": null,
"fqdn": "aksworksho-aksworkshop4zero-1199b6-50bedfce.hcp.koreacentral.azmk8s.io",
"fqdnSubdomain": null,
"httpProxyConfig": null,
"id": "/subscriptions/1199b626-xxxx-xxxx-xxxx-caba7859ee88/resourcegroups/aksworkshop4zerobig/providers/Microsoft.ContainerService/managedClusters/aksworkshop-31951",
"identity": {
"principalId": "94537d8f-52a1-4d70-b9cd-35f46337f2bb",
"tenantId": "917bfe84-0ca6-488d-ad3a-236e41ceafe9",
"type": "SystemAssigned",
"userAssignedIdentities": null
},
"identityProfile": {
"kubeletidentity": {
"clientId": "e054549d-d3ff-45d9-bce1-27e0231b7a62",
"objectId": "d2c1e42d-e5da-4b00-bf29-90747e907898",
"resourceId": "/subscriptions/1199b626-xxxx-xxxx-xxxx-caba7859ee88/resourcegroups/MC_aksworkshop4zerobig_aksworkshop-31951_koreacentral/providers/Microsoft.ManagedIdentity/userAssignedIdentities/aksworkshop-31951-agentpool"
}
},
"kubernetesVersion": "1.20.7",
"linuxProfile": {
"adminUsername": "azureuser",
"ssh": {
"publicKeys": [
{
"keyData": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDNv2eLCX5Bkdn3zt0uG3CfL6hWaM5feriY4K8qTDrO64jOAPRyFrKgfrZKP7f85SAaK5QDoM//5niYYHMqoV8n0+x4qsXfYrODzly4z7TLocHJl/Osb1lxCxdgx64HZYWhVXmRarfJ0ffDOhAhUIKcpKIf2HR9YmMdbj4UYT2YTYUCR7AE8QsD2hzr53fHc7TSxIGe8tFGJ+N+dumqT/y8XKDK9VDWN1h8tt+MuHYB4JWrKsA8NqIdNFrgqAzNDxLX7XHwDV7GsBKkz5CcZmQpD4Hq2LjL+EeQf7WFxokpsXJRnoX74y4ozeVggXnEAOfTzD5jXel+L39zn+xJIK8D kim@cc-80381d60-cbc8669fb-s87xb\n"
}
]
}
},
"location": "koreacentral",
"maxAgentPools": 100,
"name": "aksworkshop-31951",
"networkProfile": {
"dnsServiceIp": "10.2.0.10",
"dockerBridgeCidr": "172.17.0.1/16",
"loadBalancerProfile": {
"allocatedOutboundPorts": null,
"effectiveOutboundIps": [
{
"id": "/subscriptions/1199b626-xxxx-xxxx-xxxx-caba7859ee88/resourceGroups/MC_aksworkshop4zerobig_aksworkshop-31951_koreacentral/providers/Microsoft.Network/publicIPAddresses/22a75a86-19e4-4c85-9c59-101720949adc",
"resourceGroup": "MC_aksworkshop4zerobig_aksworkshop-31951_koreacentral"
}
],
"idleTimeoutInMinutes": null,
"managedOutboundIps": {
"count": 1
},
"outboundIpPrefixes": null,
"outboundIps": null
},
"loadBalancerSku": "Standard",
"networkMode": null,
"networkPlugin": "azure",
"networkPolicy": null,
"outboundType": "loadBalancer",
"podCidr": null,
"serviceCidr": "10.2.0.0/24"
},
"nodeResourceGroup": "MC_aksworkshop4zerobig_aksworkshop-31951_koreacentral",
"podIdentityProfile": null,
"powerState": {
"code": "Running"
},
"privateFqdn": null,
"privateLinkResources": null,
"provisioningState": "Succeeded",
"resourceGroup": "aksworkshop4zerobig",
"servicePrincipalProfile": {
"clientId": "msi",
"secret": null
},
"sku": {
"name": "Basic",
"tier": "Free"
},
"tags": null,
"type": "Microsoft.ContainerService/ManagedClusters",
"windowsProfile": {
"adminPassword": null,
"adminUsername": "azureuser",
"enableCsiProxy": true,
"licenseType": null
}
}
몇 분 후에 클러스터 자동 크기 조정기가 클러스터를 구성한다. 노드 수가 증가하는 것을 볼 수 있다.
6. 노드 수가 증가했는지 확인한다.
kubectl get nodes -w
kim@Azure:~$ kubectl get nodes --watch
NAME STATUS ROLES AGE VERSION
aks-nodepool1-24183474-vmss000000 Ready agent 118m v1.20.7
aks-nodepool1-24183474-vmss000001 Ready agent 118m v1.20.7
aks-nodepool1-24183474-vmss000000 Ready agent 118m v1.20.7
aks-nodepool1-24183474-vmss000004 NotReady <none> 0s v1.20.7
aks-nodepool1-24183474-vmss000004 NotReady <none> 0s v1.20.7
aks-nodepool1-24183474-vmss000004 NotReady <none> 0s v1.20.7
aks-nodepool1-24183474-vmss000003 NotReady <none> 0s v1.20.7
aks-nodepool1-24183474-vmss000003 NotReady <none> 0s v1.20.7
aks-nodepool1-24183474-vmss000003 NotReady <none> 0s v1.20.7
aks-nodepool1-24183474-vmss000004 NotReady <none> 1s v1.20.7
aks-nodepool1-24183474-vmss000002 NotReady <none> 0s v1.20.7
aks-nodepool1-24183474-vmss000002 NotReady <none> 0s v1.20.7
aks-nodepool1-24183474-vmss000002 NotReady <none> 0s v1.20.7
aks-nodepool1-24183474-vmss000004 Ready <none> 10s v1.20.7
aks-nodepool1-24183474-vmss000004 Ready <none> 10s v1.20.7
aks-nodepool1-24183474-vmss000004 Ready <none> 10s v1.20.7
aks-nodepool1-24183474-vmss000003 Ready <none> 11s v1.20.7
aks-nodepool1-24183474-vmss000003 Ready <none> 11s v1.20.7
aks-nodepool1-24183474-vmss000004 Ready <none> 11s v1.20.7
aks-nodepool1-24183474-vmss000003 Ready <none> 11s v1.20.7
aks-nodepool1-24183474-vmss000002 Ready <none> 10s v1.20.7
몇 분 후에 새로운 노드 몇 개가 표시되고 Ready 상태로 전환된다. Ctrl+C를 사용하여 확인을 중지한다.
클러스터 자동 크기 조정 테스트 (추가)
보다 직관적이고 쉬운 이해를 위해 다시 한번 클러스터 자동 크기에 대해 테스트를 시행해 보겠다.
현재 실행 중인 ratings-api 파드 수를 1개로 스케일링 한다.
참고로 여러 개가 실행 중인 경우 다음 명령을 활용한다.
kubectl scale deployment ratings-api --replicas=1
kim@Azure:~$ kubectl get pods -n ratingsapp
NAME READY STATUS RESTARTS AGE
ratings-api-ccf847b54-29jqk 1/1 Running 0 12h
ratings-mongodb-5688d575c8-vgszs 1/1 Running 0 14h
ratings-web-64b65fcd6d-x6hzw 1/1 Running 0 14h
다음 ratings-api-deployment.yaml 파일에서 컨테이너의 resources.requests와 resources.limits가 500m으로 변경한다.
resources:
requests: # minimum resources required
cpu: 1000m
memory: 64Mi
limits: # maximum resources allocated
cpu: 1000m
memory: 256Mi
현재 실행 중인 ratings-api 파드 수를 1개로 스케일링 한다.
현재 여러 개의 파드가 실행 중인 경우라면 다음 명령을 활용한다.
kubectl scale deployment ratings-api --replicas=1
참고로 실행 중인 파드가 1개이고 부하가 없으므로 현재 동작 중인 노드 수는 3개이다. 이제 막 스케일링을 시행한 경우라면 노드가 최소 수로 스케일 아웃되기까지 조금 기다려야 할 수도 있다.
kim@Azure:~$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
aks-nodepool1-24183474-vmss000000 Ready agent 14h v1.20.7
aks-nodepool1-24183474-vmss000001 Ready agent 14h v1.20.7
aks-nodepool1-24183474-vmss000002 Ready agent 12h v1.20.7
이제 ratings-api 파드의 갯수를 5개로 스케일 아웃 한다.
kubectl scale deployment ratings-api --replicas=5
현재 3개의 노드 상에서 파드 스케줄링을 시도하지만 일부 파드는 노드 상의 CPU 리소스 부족으로 Pending 상태가 된다.
kim@Azure:~$ kubectl scale deployment ratings-api --replicas=5 -n ratingsapp
deployment.apps/ratings-api scaled
kim@Azure:~$ kubectl get pods -n ratingsapp
NAME READY STATUS RESTARTS AGE
ratings-api-ccf847b54-29jqk 1/1 Running 0 12h
ratings-api-ccf847b54-4f2jd 0/1 Pending 0 3s
ratings-api-ccf847b54-dj4qx 0/1 Running 0 3s
ratings-api-ccf847b54-hknl6 0/1 Pending 0 3s
ratings-api-ccf847b54-nmz7n 0/1 Running 0 3s
ratings-mongodb-5688d575c8-vgszs 1/1 Running 0 14h
ratings-web-64b65fcd6d-x6hzw 1/1 Running 0 14h
Pending 상태의 파드를 대상으로 describe 명령해보면 "0/3 nodes are available: 3 Insufficient cpu" 라는 이벤트 메시지를 확인할 수 있다.
kim@Azure:~$ kubectl describe pod ratings-api-ccf847b54-4f2jd -n ratingsapp
Name: ratings-api-ccf847b54-4f2jd
Namespace: ratingsapp
Priority: 0
<중략>
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal TriggeredScaleUp 93s cluster-autoscaler pod triggered scale-up: [{aks-nodepool1-24183474-vmss 3->5 (max: 5)}]
Warning FailedScheduling 11s (x3 over 97s) default-scheduler 0/3 nodes are available: 3 Insufficient cpu.
몇분 후 노드(vmss000007, vmss000008)가 자동으로 스케일 아웃되는 것을 확인할 수 있다.
kim@Azure:~$ kubectl get nodes --watch
NAME STATUS ROLES AGE VERSION
aks-nodepool1-24183474-vmss000000 Ready agent 15h v1.20.7
aks-nodepool1-24183474-vmss000001 Ready agent 15h v1.20.7
aks-nodepool1-24183474-vmss000002 Ready agent 13h v1.20.7
aks-nodepool1-24183474-vmss000001 Ready agent 15h v1.20.7
aks-nodepool1-24183474-vmss000008 NotReady <none> 0s v1.20.7
aks-nodepool1-24183474-vmss000008 NotReady <none> 0s v1.20.7
aks-nodepool1-24183474-vmss000008 NotReady <none> 0s v1.20.7
aks-nodepool1-24183474-vmss000007 NotReady <none> 0s v1.20.7
aks-nodepool1-24183474-vmss000007 NotReady <none> 0s v1.20.7
aks-nodepool1-24183474-vmss000007 NotReady <none> 0s v1.20.7
aks-nodepool1-24183474-vmss000008 Ready <none> 10s v1.20.7
aks-nodepool1-24183474-vmss000008 Ready <none> 10s v1.20.7
aks-nodepool1-24183474-vmss000007 NotReady <none> 9s v1.20.7
aks-nodepool1-24183474-vmss000007 NotReady <none> 10s v1.20.7
aks-nodepool1-24183474-vmss000007 Ready <none> 10s v1.20.7
aks-nodepool1-24183474-vmss000007 Ready <none> 10s v1.20.7
aks-nodepool1-24183474-vmss000008 Ready <none> 11s v1.20.7
이제 노드의 갯수는 총 5개로 스케일링 되었다.
kim@Azure:~$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
aks-nodepool1-24183474-vmss000000 Ready agent 15h v1.20.7
aks-nodepool1-24183474-vmss000001 Ready agent 15h v1.20.7
aks-nodepool1-24183474-vmss000002 Ready agent 13h v1.20.7
aks-nodepool1-24183474-vmss000007 Ready agent 7m7s v1.20.7
aks-nodepool1-24183474-vmss000008 Ready agent 7m8s v1.20.7
따라서 Pending 상태의 모든 ratings-api 파드는 이제 정상적으로 Running 상태가 된다.
kim@Azure:~$ kubectl get pods -n ratingsapp --watch
NAME READY STATUS RESTARTS AGE
ratings-api-ccf847b54-29jqk 1/1 Running 0 13h
ratings-api-ccf847b54-4f2jd 1/1 Running 0 2m37s
ratings-api-ccf847b54-dj4qx 1/1 Running 0 2m37s
ratings-api-ccf847b54-hknl6 1/1 Running 0 2m37s
ratings-api-ccf847b54-nmz7n 1/1 Running 0 2m37s
ratings-mongodb-5688d575c8-vgszs 1/1 Running 0 14h
ratings-web-64b65fcd6d-x6hzw 1/1 Running 0 14h
이제 다시 ratings-api 파드가 1로 줄어들면, 임의의 시간 후 전체 노드 갯수는 다시 3개로 줄어드는 것을 확인할 수 있다.
요약
이번 실습에서는 Horizontal Pod Autoscaler를 만들고 부하 테스트를 실행하여 클러스터에서 Pod를 스케일 아웃했다. 그런 다음, 클러스터 자동 크기 조정기를 통해 클러스터의 컴퓨팅 용량을 늘려 AKS 클러스터에 노드를 추가했다. 이제 사용자 트래픽의 변동에 대한 응답으로 Fruit Smoothies AKS 환경의 크기 조정을 할 수 있는지 확인하는 지식을 갖추게 되었다.
지금까지 배운 내용을 살펴보겠다.
요약 및 정리
이 워크샵에서는 AKS(Azure Kubernetes Service)에 다중 컨테이너 애플리케이션을 배포했다. 컨테이너 이미지를 저장하는 데 Azure Container Registry를 사용했다. Helm으로 MongoDB를 배포했고, 배포를 용이하게 하고 애플리케이션과 서비스 간의 통신을 지원하는 주요 Kubernetes 개념에 대해 알아보았다. 통신이 암호화되도록 TSL/SSL을 설정하고 트래픽 변동을 처리할 자동 크기 조정도 설정했다.
이제 배운 내용을 활용하여 사용자 환경의 컨테이너 기반 애플리케이션을 AKS에 배포할 수 있다.
리소스 정리
이 모듈에서는 Azure 구독을 사용하여 리소스를 만들었다. 이러한 리소스로 인해 계정에 요금이 계속 청구되지 않도록 리소스를 정리한다.
1. Azure Portal을 연다.
2. 왼쪽에서 리소스 그룹을 선택한다.
3. aksworkshop 리소스 그룹 또는 사용한 리소스 그룹 이름을 찾아 선택한다.
4. 리소스 그룹의 개요 탭에서 리소스 그룹 삭제를 선택한다.
5. 확인할 리소스 그룹의 이름을 입력한다. 삭제를 선택하여 이 모듈에서 만든 모든 리소스를 삭제한다.
6. 마지막으로, kubectl config delete-context 명령을 실행하여 삭제된 클러스터 컨텍스트를 제거한다. 다음은 전체 명령의 예이다. 클러스터 이름을 사용자의 클러스터 이름으로 바꾸어야 한다.
kubectl config delete-context aksworkshop
몇 분 후에 새로운 노드 몇 개가 표시되고 Ready 상태로 전환된다. Ctrl+C를 사용하여 확인을 중지한다.
kim@Azure:~$ kubectl config delete-context aksworkshop-11290
warning: this removed your active context, use "kubectl config use-context" to select a different one
deleted context aksworkshop-11290 from /home/zerobig/.kube/config