빠른 시작: Terraform을 사용하여 AKS(Azure Kubernetes Service) 클러스터 배포

AKS(Azure Kubernetes Service)는 클러스터를 빠르게 배포하고 관리할 수 있는 관리형 Kubernetes 서비스입니다. 이 빠른 시작에서 관련 정보는 다음과 같습니다.

  • Terraform을 사용하여 AKS 클러스터를 배포합니다.
  • 소매 시나리오를 시뮬레이션하는 마이크로 서비스 및 웹 프런트 엔드 그룹을 사용하여 샘플 다중 컨테이너 애플리케이션을 실행합니다.

참고 항목

AKS 클러스터 프로비전을 빠르게 시작하기 위해 이 문서에는 평가 목적으로만 기본 설정으로 클러스터를 배포하는 단계가 포함되어 있습니다. 프로덕션에 즉시 사용 가능한 클러스터를 배포하기 전에 기본 참조 아키텍처를 숙지하여 비즈니스 요구 사항에 어떻게 부합하는지 고려하는 것이 좋습니다.

시작하기 전에

참고 항목

이제 Azure Linux 노드 풀은 GA(일반 공급)됩니다. 이점과 배포 단계에 대해 알아보려면 AKS용 Azure Linux 컨테이너 호스트 소개를 참조하세요.

Azure 계정에 로그인합니다.

먼저 Azure 계정에 로그인하고 다음 섹션에 설명된 방법 중 하나를 사용하여 인증합니다.

Terraform 및 Azure 인증 시나리오

Terraform은 Azure CLI를 통한 Azure 인증만 지원합니다. Azure PowerShell을 사용한 인증은 지원되지 않습니다. 따라서 Terraform 작업을 수행할 때 Azure PowerShell 모듈을 사용할 수 있지만 먼저 Azure CLI를 사용하여 Azure에 인증해야 합니다.

이 문서에서는 다음 시나리오에서 Terraform을 Azure에 인증하는 방법을 설명합니다. Terraform을 Azure로 인증하는 옵션에 대한 자세한 내용은 Azure CLI를 사용하여 인증을 참조하세요.

Microsoft 계정을 통해 Azure에 인증

Microsoft 계정은 Azure와 같은 Microsoft 서비스에 로그인하는 데 사용되는 사용자 이름(이메일 및 해당 자격 증명과 연결)입니다. Microsoft 계정은 하나 이상의 Azure 구독과 연결될 수 있으며, 이러한 구독 중 하나가 기본값입니다.

다음 단계는 다음 작업을 수행할 수 있는 방법을 보여 줍니다.

  • Microsoft 계정을 사용하여 대화형으로 Azure에 로그인
  • 계정과 연결된 Azure 구독 나열(기본값 포함)
  • 현재 구독을 설정합니다.
  1. Azure CLI에 액세스하는 명령줄을 엽니다.

  2. 매개 변수 없이 az login을 실행하고 지침에 따라 Azure에 로그인합니다.

    az login
    

    주요 정보:

    • 로그인에 성공하면 az login은 기본 구독을 포함하여 로그인 Microsoft 계정에 연결된 Azure 구독 목록을 표시합니다.
  3. 현재 Azure 구독을 확인하려면 az account show를 실행합니다.

    az account show
    
  4. 특정 Microsoft 계정의 모든 Azure 구독 이름 및 ID를 보려면 az account list를 실행합니다.

    az account list --query "[?user.name=='<microsoft_account_email>'].{Name:name, ID:id, Default:isDefault}" --output Table
    

    주요 정보:

    • <microsoft_account_email> 자리 표시자를 나열하려는 Azure 구독이 있는 Microsoft 계정 이메일 주소로 바꿉니다.
    • hotmail 또는 outlook과 같은 라이브 계정을 사용하면 정규화된 이메일 주소를 지정해야 할 수 있습니다. 예를 들어 이메일 주소가 admin@hotmail.com인 경우 자리 표시자를 live.com#admin@hotmail.com으로 바꾸어야 할 수 있습니다.
  5. 특정 Azure 구독을 사용하려면 az account set을 실행합니다.

    az account set --subscription "<subscription_id_or_subscription_name>"
    

    주요 정보:

    • <subscription_id_or_subscription_name> 자리 표시자를 사용하려는 구독의 ID 또는 이름으로 바꿉니다.
    • az account set를 호출해도 지정된 Azure 구독으로 전환한 결과가 표시되지 않습니다. 그러나 az account show를 사용하여 현재 Azure 구독이 변경되었는지 확인할 수 있습니다.
    • 이전 단계에서 az account list 명령을 실행하면 기본 Azure 구독이 az account set으로 지정한 구독으로 변경된 것을 알 수 있습니다.

서비스 주체 만들기

Azure 서비스를 배포하거나 사용하는 자동화된 도구(예: Terraform)에는 항상 제한된 권한이 있어야 합니다. 애플리케이션이 완전한 권한이 있는 사용자로 로그인하는 대신 Azure는 서비스 주체를 제공합니다.

가장 일반적인 패턴은 Azure에 대화형으로 로그인하고, 서비스 주체를 만들고, 서비스 주체를 테스트한 다음, 향후 인증을 위해 해당 서비스 주체를 사용하는 것입니다(대화형 또는 스크립트에서).

  1. 서비스 주체를 만들려면 Azure에 로그인합니다. Microsoft 계정을 통해 Azure에 인증한 후 여기로 돌아갑니다.

  2. Git Bash에서 서비스 주체를 만드는 경우 MSYS_NO_PATHCONV 환경 변수를 설정합니다. (Cloud Shell을 사용하는 경우에는 이 단계가 필요하지 않습니다.)

    export MSYS_NO_PATHCONV=1    
    

    주요 정보:

    • MSYS_NO_PATHCONV 환경 변수를 전역(모든 터미널 세션의 경우) 또는 로컬(현재 세션에만 해당)로 설정할 수 있습니다. 서비스 주체를 만드는 것은 자주 있는 일이 아니기 때문에 샘플은 현재 세션의 값을 설정합니다. 이 환경 변수를 전역적으로 설정하려면 설정을 ~/.bashrc 파일에 추가합니다.
  3. 서비스 주체를 만들려면 az ad sp create-for-rbac를 실행합니다.

    az ad sp create-for-rbac --name <service_principal_name> --role Contributor --scopes /subscriptions/<subscription_id>
    

    주요 정보:

    • <service-principal-name>을 환경의 사용자 지정 이름으로 바꾸거나 매개 변수를 완전히 생략할 수 있습니다. 매개 변수를 생략하면 현재 날짜 및 시간을 기반으로 서비스 사용자 이름이 생성됩니다.
    • 성공적으로 완료되면 az ad sp create-for-rbac에서 여러 값을 표시합니다. appId, passwordtenant 값은 다음 단계에서 사용됩니다.
    • 분실한 암호는 복구할 수 없습니다. 따라서 암호를 안전한 장소에 저장해야 합니다. 암호를 잊어버린 경우 서비스 주체 자격 증명을 다시 설정할 수 있습니다.
    • 이 문서에서는 기여자 역할을 사용하여 서비스 주체가 사용됩니다. RBAC(역할 기반 액세스 제어) 역할에 대한 자세한 내용은 RBAC: 기본 제공 역할을 참조하세요.
    • 서비스 주체를 만들 때의 출력에는 중요한 자격 증명이 포함됩니다. 이러한 자격 증명을 코드에 포함하지 않도록 하거나 소스 제어에 자격 증명을 확인해야 합니다.
    • Azure CLI를 사용하여 서비스 주체를 만들 때 옵션에 대한 자세한 내용은 Azure CLI로 Azure 서비스 주체 만들기 문서를 참조하세요.

환경 변수에서 서비스 주체 자격 증명 지정

서비스 주체를 만든 후에는 환경 변수를 통해 Terraform에 대한 자격 증명을 지정할 수 있습니다.

  1. 다음 환경 변수를 추가하여 ~/.bashrc 파일을 수정합니다.

    export ARM_SUBSCRIPTION_ID="<azure_subscription_id>"
    export ARM_TENANT_ID="<azure_subscription_tenant_id>"
    export ARM_CLIENT_ID="<service_principal_appid>"
    export ARM_CLIENT_SECRET="<service_principal_password>"
    
  2. ~/.bashrc 스크립트를 실행하려면 source ~/.bashrc(또는 이에 상응하는 약어 . ~/.bashrc)를 실행합니다. 스크립트가 자동으로 실행되도록 Cloud Shell을 종료하고 다시 열 수도 있습니다.

    . ~/.bashrc
    
  3. 환경 변수를 설정한 후에는 다음과 같이 해당 값을 확인할 수 있습니다.

    printenv | grep ^ARM*
    

주요 정보:

  • 모든 환경 변수와 마찬가지로 Terraform 스크립트 내에서 Azure 구독 값에 액세스하려면 ${env.<environment_variable>} 구문을 사용합니다. 예를 들어 ARM_SUBSCRIPTION_ID 값에 액세스하려면 ${env.ARM_SUBSCRIPTION_ID}를 지정합니다.
  • Terraform 실행 계획을 만들고 적용하면 서비스 주체와 연결된 Azure 구독이 변경됩니다. 하나의 Azure 구독에 로그인하고 환경 변수가 두 번째 Azure 구독을 가리키는 경우 이 팩트가 혼동될 수 있습니다. 설명을 위해 다음 예제를 살펴보겠습니다. 두 개의 Azure 구독(SubA 및 SubB)이 있다고 가정해 보겠습니다. 현재 Azure 구독이 SubA(az account show를 통해 결정됨)인 경우 환경 변수가 SubB를 가리키면 Terraform의 모든 변경 내용이 SubB에 있게 됩니다. 따라서 Azure CLI 명령 또는 Azure PowerShell 명령을 실행하여 변경 내용을 보려면 SubB 구독에 로그인해야 합니다.

Terraform 공급자 블록에서 서비스 주체 자격 증명 지정

Azure 공급자 블록은 Azure 구독의 인증 정보를 지정할 수 있는 구문을 정의합니다.

terraform {
  required_providers {
    azurerm = {
      source = "hashicorp/azurerm"
      version = "~>2.0"
    }
  }
}

provider "azurerm" {
  features {}

  subscription_id   = "<azure_subscription_id>"
  tenant_id         = "<azure_subscription_tenant_id>"
  client_id         = "<service_principal_appid>"
  client_secret     = "<service_principal_password>"
}

# Your code goes here

주의

Terraform 구성 파일에서 Azure 구독 자격 증명을 지정하는 기능은 특히 테스트할 때 편리할 수 있습니다. 그러나 신뢰할 수 없는 사용자가 볼 수 있는 일반 텍스트 파일에는 자격 증명을 저장하지 않는 것이 좋습니다.

Terraform 코드 구현

  1. 샘플 Terraform 코드를 테스트할 수 있는 디렉터리를 만들고, 이를 현재 디렉터리로 만듭니다.

  2. providers.tf라는 파일을 만들고 다음 코드를 삽입합니다.

    terraform {
      required_version = ">=1.0"
    
      required_providers {
        azapi = {
          source  = "azure/azapi"
          version = "~>1.5"
        }
        azurerm = {
          source  = "hashicorp/azurerm"
          version = "~>3.0"
        }
        random = {
          source  = "hashicorp/random"
          version = "~>3.0"
        }
        time = {
          source  = "hashicorp/time"
          version = "0.9.1"
        }
      }
    }
    
    provider "azurerm" {
      features {}
    }
    
  3. ssh.tf라는 파일을 만들고 다음 코드를 삽입합니다.

    resource "random_pet" "ssh_key_name" {
      prefix    = "ssh"
      separator = ""
    }
    
    resource "azapi_resource_action" "ssh_public_key_gen" {
      type        = "Microsoft.Compute/sshPublicKeys@2022-11-01"
      resource_id = azapi_resource.ssh_public_key.id
      action      = "generateKeyPair"
      method      = "POST"
    
      response_export_values = ["publicKey", "privateKey"]
    }
    
    resource "azapi_resource" "ssh_public_key" {
      type      = "Microsoft.Compute/sshPublicKeys@2022-11-01"
      name      = random_pet.ssh_key_name.id
      location  = azurerm_resource_group.rg.location
      parent_id = azurerm_resource_group.rg.id
    }
    
    output "key_data" {
      value = jsondecode(azapi_resource_action.ssh_public_key_gen.output).publicKey
    }
    
  4. main.tf라는 파일을 만들고 다음 코드를 삽입합니다.

    # Generate random resource group name
    resource "random_pet" "rg_name" {
      prefix = var.resource_group_name_prefix
    }
    
    resource "azurerm_resource_group" "rg" {
      location = var.resource_group_location
      name     = random_pet.rg_name.id
    }
    
    resource "random_pet" "azurerm_kubernetes_cluster_name" {
      prefix = "cluster"
    }
    
    resource "random_pet" "azurerm_kubernetes_cluster_dns_prefix" {
      prefix = "dns"
    }
    
    resource "azurerm_kubernetes_cluster" "k8s" {
      location            = azurerm_resource_group.rg.location
      name                = random_pet.azurerm_kubernetes_cluster_name.id
      resource_group_name = azurerm_resource_group.rg.name
      dns_prefix          = random_pet.azurerm_kubernetes_cluster_dns_prefix.id
    
      identity {
        type = "SystemAssigned"
      }
    
      default_node_pool {
        name       = "agentpool"
        vm_size    = "Standard_D2_v2"
        node_count = var.node_count
      }
      linux_profile {
        admin_username = var.username
    
        ssh_key {
          key_data = jsondecode(azapi_resource_action.ssh_public_key_gen.output).publicKey
        }
      }
      network_profile {
        network_plugin    = "kubenet"
        load_balancer_sku = "standard"
      }
    }
    
  5. variables.tf라는 파일을 만들고 다음 코드를 삽입합니다.

    variable "resource_group_location" {
      type        = string
      default     = "eastus"
      description = "Location of the resource group."
    }
    
    variable "resource_group_name_prefix" {
      type        = string
      default     = "rg"
      description = "Prefix of the resource group name that's combined with a random ID so name is unique in your Azure subscription."
    }
    
    variable "node_count" {
      type        = number
      description = "The initial quantity of nodes for the node pool."
      default     = 3
    }
    
    variable "msi_id" {
      type        = string
      description = "The Managed Service Identity ID. Set this value if you're running this example using Managed Identity as the authentication method."
      default     = null
    }
    
    variable "username" {
      type        = string
      description = "The admin username for the new cluster."
      default     = "azureadmin"
    }
    
  6. outputs.tf라는 파일을 만들고 다음 코드를 삽입합니다.

    output "resource_group_name" {
      value = azurerm_resource_group.rg.name
    }
    
    output "kubernetes_cluster_name" {
      value = azurerm_kubernetes_cluster.k8s.name
    }
    
    output "client_certificate" {
      value     = azurerm_kubernetes_cluster.k8s.kube_config[0].client_certificate
      sensitive = true
    }
    
    output "client_key" {
      value     = azurerm_kubernetes_cluster.k8s.kube_config[0].client_key
      sensitive = true
    }
    
    output "cluster_ca_certificate" {
      value     = azurerm_kubernetes_cluster.k8s.kube_config[0].cluster_ca_certificate
      sensitive = true
    }
    
    output "cluster_password" {
      value     = azurerm_kubernetes_cluster.k8s.kube_config[0].password
      sensitive = true
    }
    
    output "cluster_username" {
      value     = azurerm_kubernetes_cluster.k8s.kube_config[0].username
      sensitive = true
    }
    
    output "host" {
      value     = azurerm_kubernetes_cluster.k8s.kube_config[0].host
      sensitive = true
    }
    
    output "kube_config" {
      value     = azurerm_kubernetes_cluster.k8s.kube_config_raw
      sensitive = true
    }
    

Terraform 초기화

terraform init를 실행하여 Terraform 배포를 초기화합니다. 이 명령은 Azure 리소스를 관리하는 데 필요한 Azure 공급자를 다운로드합니다.

terraform init -upgrade

주요 정보:

  • -upgrade 매개 변수는 필요한 공급자 플러그 인을 구성의 버전 제약 조건을 준수하는 최신 버전으로 업그레이드합니다.

Terraform 실행 계획 만들기

terraform plan을 실행하여 실행 계획을 만듭니다.

terraform plan -out main.tfplan

주요 정보:

  • terraform plan 명령은 실행 계획을 만들지만 실행하지는 않습니다. 대신 구성 파일에 지정된 구성을 만드는 데 필요한 작업을 결정합니다. 이 패턴을 사용하면 실제 리소스를 변경하기 전에 실행 계획이 예상과 일치하는지 확인할 수 있습니다.
  • 선택 사항인 -out 매개 변수를 사용하여 계획의 출력 파일을 지정할 수 있습니다. -out 매개 변수를 사용하면 검토한 계획이 정확하게 적용됩니다.

Terraform 실행 계획 적용

terraform apply를 실행하여 실행 계획을 클라우드 인프라에 적용합니다.

terraform apply main.tfplan

주요 정보:

  • 예시 terraform apply 명령은 이전에 terraform plan -out main.tfplan를 실행했다고 가정합니다.
  • -out 매개 변수에 다른 파일 이름을 지정한 경우 terraform apply에 대한 호출에서 동일한 파일 이름을 사용합니다.
  • -out 매개 변수를 사용하지 않은 경우 매개 변수 없이 terraform apply를 호출합니다.

결과 확인

  1. 다음 명령을 사용하여 Azure 리소스 그룹 이름을 가져옵니다.

    resource_group_name=$(terraform output -raw resource_group_name)
    
  2. az aks list 명령을 사용하여 새 Kubernetes 클러스터의 이름을 표시합니다.

    az aks list \
      --resource-group $resource_group_name \
      --query "[].{\"K8s cluster name\":name}" \
      --output table
    
  3. 다음 명령을 사용하여 Terraform 상태에서 Kubernetes 구성을 가져오고 이를 kubectl이 읽을 수 있는 파일에 저장합니다.

    echo "$(terraform output kube_config)" > ./azurek8s
    
  4. 다음 명령을 사용하여 이전 명령이 ASCII EOT 문자를 추가하지 않았는지 확인합니다.

    cat ./azurek8s
    

    주요 정보:

    • 시작 부분에 << EOT가 있고 끝 부분에 EOT가 표시되면 파일에서 해당 문자를 제거합니다. 그렇지 않으면 다음 오류 메시지가 표시될 수 있습니다. error: error loading config file "./azurek8s": yaml: line 2: mapping values are not allowed in this context
  5. 다음 명령을 사용하여 kubectl이 올바른 구성을 선택할 수 있도록 환경 변수를 설정합니다.

    export KUBECONFIG=./azurek8s
    
  6. kubectl get nodes 명령을 사용하여 클러스터의 상태를 확인합니다.

    kubectl get nodes
    

주요 정보:

  • AKS 클러스터가 생성된 경우 클러스터 노드와 Pod의 상태 메트릭을 캡처하기 위한 모니터링이 설정되었습니다. 이 상태 메트릭은 Azure Portal에서 사용할 수 있습니다. 컨테이너 상태 모니터링에 대한 자세한 내용은 Azure Kubernetes Service 상태 모니터링을 참조하세요.
  • Terraform 실행 계획을 적용한 경우 여러 주요 값이 출력으로 분류되었습니다. 예를 들어, 호스트 주소, AKS 클러스터 사용자 이름 및 AKS 클러스터 암호가 출력됩니다.

애플리케이션 배포

응용 프로그램을 배포하려면 매니페스트 파일을 사용하여 AKS Store 응용 프로그램을 실행하는 데 필요한 모든 개체를 만듭니다. Kubernetes 매니페스트 파일은 실행할 컨테이너 이미지와 같은 클러스터에 대해 원하는 상태를 정의합니다. 매니페스트에는 다음 Kubernetes 배포 및 서비스가 포함됩니다.

Azure Store 샘플 아키텍처의 스크린샷.

  • 스토어 프런트: 고객이 제품을 보고 주문을 할 수 있는 웹 애플리케이션입니다.
  • 제품 서비스: 제품 정보를 표시합니다.
  • 주문 서비스: 주문을 합니다.
  • Rabbit MQ: 주문 큐에 대한 메시지 큐입니다.

참고 항목

프로덕션을 위한 영구 스토리지 없이 Rabbit MQ와 같은 상태 저장 컨테이너를 실행하지 않는 것이 좋습니다. 여기서는 단순화를 위해 사용되었지만 Azure CosmosDB 또는 Azure Service Bus와 같은 관리되는 서비스를 사용하는 것이 좋습니다.

  1. 파일 aks-store-quickstart.yaml을 만들고 다음 매니페스트에 복사합니다.

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: rabbitmq
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: rabbitmq
      template:
        metadata:
          labels:
            app: rabbitmq
        spec:
          nodeSelector:
            "kubernetes.io/os": linux
          containers:
          - name: rabbitmq
            image: mcr.microsoft.com/mirror/docker/library/rabbitmq:3.10-management-alpine
            ports:
            - containerPort: 5672
              name: rabbitmq-amqp
            - containerPort: 15672
              name: rabbitmq-http
            env:
            - name: RABBITMQ_DEFAULT_USER
              value: "username"
            - name: RABBITMQ_DEFAULT_PASS
              value: "password"
            resources:
              requests:
                cpu: 10m
                memory: 128Mi
              limits:
                cpu: 250m
                memory: 256Mi
            volumeMounts:
            - name: rabbitmq-enabled-plugins
              mountPath: /etc/rabbitmq/enabled_plugins
              subPath: enabled_plugins
          volumes:
          - name: rabbitmq-enabled-plugins
            configMap:
              name: rabbitmq-enabled-plugins
              items:
              - key: rabbitmq_enabled_plugins
                path: enabled_plugins
    ---
    apiVersion: v1
    data:
      rabbitmq_enabled_plugins: |
        [rabbitmq_management,rabbitmq_prometheus,rabbitmq_amqp1_0].
    kind: ConfigMap
    metadata:
      name: rabbitmq-enabled-plugins            
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: rabbitmq
    spec:
      selector:
        app: rabbitmq
      ports:
        - name: rabbitmq-amqp
          port: 5672
          targetPort: 5672
        - name: rabbitmq-http
          port: 15672
          targetPort: 15672
      type: ClusterIP
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: order-service
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: order-service
      template:
        metadata:
          labels:
            app: order-service
        spec:
          nodeSelector:
            "kubernetes.io/os": linux
          containers:
          - name: order-service
            image: ghcr.io/azure-samples/aks-store-demo/order-service:latest
            ports:
            - containerPort: 3000
            env:
            - name: ORDER_QUEUE_HOSTNAME
              value: "rabbitmq"
            - name: ORDER_QUEUE_PORT
              value: "5672"
            - name: ORDER_QUEUE_USERNAME
              value: "username"
            - name: ORDER_QUEUE_PASSWORD
              value: "password"
            - name: ORDER_QUEUE_NAME
              value: "orders"
            - name: FASTIFY_ADDRESS
              value: "0.0.0.0"
            resources:
              requests:
                cpu: 1m
                memory: 50Mi
              limits:
                cpu: 75m
                memory: 128Mi
          initContainers:
          - name: wait-for-rabbitmq
            image: busybox
            command: ['sh', '-c', 'until nc -zv rabbitmq 5672; do echo waiting for rabbitmq; sleep 2; done;']
            resources:
              requests:
                cpu: 1m
                memory: 50Mi
              limits:
                cpu: 75m
                memory: 128Mi    
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: order-service
    spec:
      type: ClusterIP
      ports:
      - name: http
        port: 3000
        targetPort: 3000
      selector:
        app: order-service
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: product-service
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: product-service
      template:
        metadata:
          labels:
            app: product-service
        spec:
          nodeSelector:
            "kubernetes.io/os": linux
          containers:
          - name: product-service
            image: ghcr.io/azure-samples/aks-store-demo/product-service:latest
            ports:
            - containerPort: 3002
            resources:
              requests:
                cpu: 1m
                memory: 1Mi
              limits:
                cpu: 1m
                memory: 7Mi
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: product-service
    spec:
      type: ClusterIP
      ports:
      - name: http
        port: 3002
        targetPort: 3002
      selector:
        app: product-service
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: store-front
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: store-front
      template:
        metadata:
          labels:
            app: store-front
        spec:
          nodeSelector:
            "kubernetes.io/os": linux
          containers:
          - name: store-front
            image: ghcr.io/azure-samples/aks-store-demo/store-front:latest
            ports:
            - containerPort: 8080
              name: store-front
            env: 
            - name: VUE_APP_ORDER_SERVICE_URL
              value: "http://order-service:3000/"
            - name: VUE_APP_PRODUCT_SERVICE_URL
              value: "http://product-service:3002/"
            resources:
              requests:
                cpu: 1m
                memory: 200Mi
              limits:
                cpu: 1000m
                memory: 512Mi
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: store-front
    spec:
      ports:
      - port: 80
        targetPort: 8080
      selector:
        app: store-front
      type: LoadBalancer
    

    YAML 매니페스트 파일의 분석은 배포 및 YAML 매니페스트를 참조하세요.

    YAML 파일을 로컬에서 만들고 저장하는 경우 파일 업로드/다운로드 단추를 선택하고 로컬 파일 시스템에서 파일을 선택하여 매니페스트 파일을 CloudShell의 기본 디렉터리에 업로드할 수 있습니다.

  2. kubectl apply 명령을 사용하여 애플리케이션을 배포하고 YAML 매니페스트의 이름을 지정합니다.

    kubectl apply -f aks-store-quickstart.yaml
    

    다음 예제 출력은 배포 및 서비스를 보여 줍니다.

    deployment.apps/rabbitmq created
    service/rabbitmq created
    deployment.apps/order-service created
    service/order-service created
    deployment.apps/product-service created
    service/product-service created
    deployment.apps/store-front created
    service/store-front created
    

애플리케이션 테스트

애플리케이션이 실행되면 애플리케이션 프런트 엔드를 인터넷에 공개하는 Kubernetes 서비스가 만들어집니다. 이 프로세스를 완료하는 데 몇 분이 걸릴 수 있습니다.

  1. 배포된 Pod의 상태는 kubectl get pods 명령을 사용하여 확인합니다. 계속하기 전에 모든 Pod를 Running으로 만듭니다.

    kubectl get pods
    
  2. store-front 애플리케이션의 공용 IP 주소를 확인합니다. --watch 인수와 함께 kubectl get service 명령을 사용하여 진행률을 모니터링합니다.

    kubectl get service store-front --watch
    

    store-front 서비스에 대한 EXTERNAL-IP 출력은 처음에 보류 중으로 표시됩니다.

    NAME          TYPE           CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE
    store-front   LoadBalancer   10.0.100.10   <pending>     80:30025/TCP   4h4m
    
  3. EXTERNAL-IP 주소가 보류 중에서 실제 공용 IP 주소로 변경되면 CTRL-C를 사용하여 kubectl 조사식 프로세스를 중지합니다.

    다음 예제 출력은 서비스에 할당된 유효한 공용 IP 주소를 보여줍니다.

    NAME          TYPE           CLUSTER-IP    EXTERNAL-IP    PORT(S)        AGE
    store-front   LoadBalancer   10.0.100.10   20.62.159.19   80:30025/TCP   4h5m
    
  4. Azure Store 앱이 작동하는 모습을 보려면 서비스의 외부 IP 주소로 웹 브라우저를 엽니다.

    AKS Store 샘플 애플리케이션의 스크린샷.

리소스 정리

AKS 리소스 삭제

Terraform을 통해 리소스를 만들 필요가 더 이상 없으면 다음 단계를 수행합니다.

  1. terraform 플랜을 실행하고 destroy 플래그를 지정합니다.

    terraform plan -destroy -out main.destroy.tfplan
    

    주요 정보:

    • terraform plan 명령은 실행 계획을 만들지만 실행하지는 않습니다. 대신 구성 파일에 지정된 구성을 만드는 데 필요한 작업을 결정합니다. 이 패턴을 사용하면 실제 리소스를 변경하기 전에 실행 계획이 예상과 일치하는지 확인할 수 있습니다.
    • 선택 사항인 -out 매개 변수를 사용하여 계획의 출력 파일을 지정할 수 있습니다. -out 매개 변수를 사용하면 검토한 계획이 정확하게 적용됩니다.
  2. terraform apply를 실행하여 실행 계획을 적용합니다.

    terraform apply main.destroy.tfplan
    

서비스 주체 삭제

  1. 다음 명령을 사용하여 서비스 주체 ID를 가져옵니다.

    sp=$(terraform output -raw sp)
    
  2. az ad sp delete 명령을 사용하여 서비스 주체를 삭제합니다.

    az ad sp delete --id $sp
    

Azure Developer CLI 템플릿 복제

Azure Developer CLI를 사용하면 Azure 샘플 리포지토리에서 샘플을 신속하게 다운로드할 수 있습니다. 빠른 시작에서는 aks-store-demo 애플리케이션을 다운로드합니다. 일반적인 사용 사례에 대한 자세한 내용은 azd 개요를 참조하세요.

  1. --template 매개 변수와 함께 azd init 명령을 사용하여 Azure-Samples 리포지토리에서 AKS 스토어 데모 템플릿을 복제합니다.

    azd init --template Azure-Samples/aks-store-demo
    
  2. aks-terraform-1과 같이 영숫자와 하이픈만 사용하는 프로젝트의 환경 이름을 입력합니다.

    Enter a new environment name: aks-terraform-1
    

Azure 클라우드 계정에 로그인

azd 템플릿에는 서비스를 만드는 데 필요한 모든 코드가 포함되어 있지만 AKS에서 애플리케이션을 호스트하려면 Azure 계정에 로그인해야 합니다.

  1. azd auth login 명령을 사용하여 계정에 로그인합니다.

    azd auth login
    
  2. 출력에 표시되는 디바이스 코드를 복사하고 Enter 키를 눌러 로그인합니다.

    Start by copying the next code: XXXXXXXXX
    Then press enter and continue to log in from your browser...
    

    Important

    네트워크 외부 가상 머신 또는 GitHub Codespace를 사용하는 경우 azd auth login으로 로그인하는 데 사용할 때 특정 Azure 보안 정책으로 인해 충돌이 발생합니다. 여기서 문제가 발생하면 제공된 azd 인증 해결 방법을 따를 수 있습니다. 여기에는 azd auth login을 실행한 후 리디렉션된 localhost URL에 대한 curl 요청을 사용하는 작업이 포함됩니다.

  3. 조직의 로그인 페이지에서 자격 증명으로 인증합니다.

  4. Azure CLI에서 연결을 시도하는지 확인합니다.

  5. "디바이스 코드 인증이 완료되었습니다. Azure에 로그인했습니다."라는 메시지가 원래 터미널에 나타나는지 확인합니다.

    Waiting for you to complete authentication in the browser...
    Device code authentication completed.
    Logged in to Azure.
    

azd 인증 해결 방법

이 해결 방법을 사용하려면 Azure CLI를 설치해야 합니다.

  1. 터미널 창을 열고 --scope 매개 변수가 https://graph.microsoft.com/.default로 설정된 az login 명령을 사용하여 Azure CLI로 로그인합니다.

    az login --scope https://graph.microsoft.com/.default
    

    다음 예제와 같이 브라우저 액세스 토큰을 만들려면 새 탭의 인증 페이지로 리디렉션되어야 합니다.

    https://login.microsoftonline.com/organizations/oauth2/v2.0/authorize?clientid=<your_client_id>.
    
  2. azd auth login으로 로그인을 시도한 후 받은 웹 페이지의 localhost URL을 복사합니다.

  3. 새 터미널 창에서 다음 curl 요청을 사용하여 로그인합니다. <localhost> 자리 표시자를 이전 단계에서 복사한 localhost URL로 바꿔야 합니다.

    curl <localhost>
    

    로그인에 성공하면 다음 예와 같이 HTML 웹페이지가 출력됩니다.

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8" />
        <meta http-equiv="refresh" content="60;url=https://docs.microsoft.com/cli/azure/">
        <title>Login successfully</title>
        <style>
            body {
                font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            }
    
            code {
                font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace;
                display: inline-block;
                background-color: rgb(242, 242, 242);
                padding: 12px 16px;
                margin: 8px 0px;
            }
        </style>
    </head>
    <body>
        <h3>You have logged into Microsoft Azure!</h3>
        <p>You can close this window, or we will redirect you to the <a href="https://docs.microsoft.com/cli/azure/">Azure CLI documentation</a> in 1 minute.</p>
        <h3>Announcements</h3>
        <p>[Windows only] Azure CLI is collecting feedback on using the <a href="https://learn.microsoft.com/windows/uwp/security/web-account-manager">Web Account Manager</a> (WAM) broker for the login experience.</p>
        <p>You may opt-in to use WAM by running the following commands:</p>
        <code>
            az config set core.allow_broker=true<br>
            az account clear<br>
            az login
        </code>
    </body>
    </html>
    
  4. 현재 터미널을 닫고 원래 터미널을 엽니다. 구독의 JSON 목록이 표시됩니다.

  5. 사용하려는 구독의 id 필드를 복사합니다.

  6. az account set 명령을 사용하여 구독을 설정합니다.

    az account set --subscription <subscription_id>
    

클러스터에 대한 리소스 만들기 및 배포

애플리케이션을 배포하려면 azd up 명령을 사용하여 AKS Store 애플리케이션을 실행하는 데 필요한 모든 개체를 만듭니다.

  • azure.yaml 파일은 가져올 컨테이너 이미지와 같은 클러스터의 원하는 상태를 정의하고 다음 Kubernetes 배포 및 서비스를 포함합니다.

Azure Store 샘플 아키텍처를 보여 주는 다이어그램.

  • 스토어 프런트: 고객이 제품을 보고 주문을 할 수 있는 웹 애플리케이션입니다.
  • 제품 서비스: 제품 정보를 표시합니다.
  • 주문 서비스: 주문을 합니다.
  • Rabbit MQ: 주문 큐에 대한 메시지 큐입니다.

참고 항목

프로덕션을 위한 영구 스토리지 없이 Rabbit MQ와 같은 상태 저장 컨테이너를 실행하지 않는 것이 좋습니다. 여기서는 단순화를 위해 사용되었지만 Azure Cosmos DB 또는 Azure Service Bus와 같은 관리되는 서비스를 사용하는 것이 좋습니다.

애플리케이션 리소스 배포

이 빠른 시작의 azd 템플릿은 AKS 클러스터 및 Azure Key Vault를 사용하여 새 리소스 그룹을 만듭니다. 키 자격 증명 모음은 클라이언트 암호를 저장하고 pets 네임스페이스에서 서비스를 실행합니다.

  1. azd up 명령을 사용하여 모든 애플리케이션 리소스를 만듭니다.

    azd up
    

    azd upazd-hooks 폴더 내의 모든 후크를 실행하여 애플리케이션 서비스를 사전 등록, 프로비전 및 배포합니다.

    후크를 사용자 지정하여 azd 워크플로 스테이지에 사용자 지정 코드를 추가합니다. 자세한 내용은 azd 후크 참조를 참조하세요.

  2. 청구 사용량에 대한 Azure 구독을 선택합니다.

    ? Select an Azure Subscription to use:  [Use arrows to move, type to filter]
    > 1. My Azure Subscription (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
    
  3. 애플리케이션을 배포할 지역을 선택합니다.

    Select an Azure location to use:  [Use arrows to move, type to filter]
      1.  (South America) Brazil Southeast (brazilsoutheast)
      2.  (US) Central US (centralus)
      3.  (US) East US (eastus)
    > 43. (US) East US 2 (eastus2)
      4.  (US) East US STG (eastusstg)
      5.  (US) North Central US (northcentralus)
      6.  (US) South Central US (southcentralus)
    

    azd는 사전 프로비전 및 사후 프로비전 후크를 자동으로 실행하여 애플리케이션에 대한 리소스를 만듭니다. 이 프로세스를 완료하는 데 몇 분이 걸릴 수 있습니다. 완료되면 다음 예제와 유사한 출력이 표시됩니다.

    SUCCESS: Your workflow to provision and deploy to Azure completed in 9 minutes 40 seconds.
    

Terraform 계획 생성

Azure 개발자 템플릿 내 /infra/terraform 폴더에는 Terraform 계획을 생성하는 데 사용되는 모든 코드가 포함되어 있습니다.

Terraform은 azd 프로비저닝 단계의 일부로 terraform apply를 사용하여 명령을 배포하고 실행합니다. 완료되면 다음 예제와 유사한 출력이 표시됩니다.

Plan: 5 to add, 0 to change, 0 to destroy.
...
Saved the plan to: /workspaces/aks-store-demo/.azure/aks-terraform-azd/infra/terraform/main.tfplan

애플리케이션 테스트

애플리케이션이 실행되면 애플리케이션 프런트 엔드를 인터넷에 공개하는 Kubernetes 서비스가 만들어집니다. 이 프로세스를 완료하는 데 몇 분이 걸릴 수 있습니다.

  1. kubectl set-context 명령을 사용하여 네임스페이스를 데모 네임스페이스 pets로 설정합니다.

    kubectl config set-context --current --namespace=pets
    
  2. 배포된 Pod의 상태는 kubectl get pods 명령을 사용하여 확인합니다. 계속하기 전에 모든 Pod가 Running인지 확인합니다.

    kubectl get pods
    
  3. 스토어 프런트 애플리케이션에 대한 공용 IP 주소를 확인하고 --watch 인수와 함께 kubectl get service 명령을 사용하여 진행 상황을 모니터링합니다.

    kubectl get service store-front --watch
    

    store-front 서비스에 대한 EXTERNAL-IP 출력은 처음에 보류 중으로 표시됩니다.

    NAME          TYPE           CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE
    store-front   LoadBalancer   10.0.100.10   <pending>     80:30025/TCP   4h4m
    
  4. EXTERNAL-IP 주소가 보류 중에서 실제 공용 IP 주소로 변경되면 CTRL-C를 사용하여 kubectl 조사식 프로세스를 중지합니다.

    다음 샘플 출력은 서비스에 할당된 유효한 공용 IP 주소를 보여 줍니다.

    NAME          TYPE           CLUSTER-IP    EXTERNAL-IP    PORT(S)        AGE
    store-front   LoadBalancer   10.0.100.10   20.62.159.19   80:30025/TCP   4h5m
    
  5. Azure Store 앱이 작동하는 모습을 보려면 서비스의 외부 IP 주소로 웹 브라우저를 엽니다.

    AKS Store 샘플 애플리케이션의 스크린샷.

클러스터 삭제

빠른 시작이 완료되면 Azure 요금이 청구되지 않도록 불필요한 리소스를 정리합니다.

  1. azd down 명령을 사용하여 빠른 시작에서 만든 모든 리소스를 삭제합니다.

    azd down
    
  2. y을 입력하고 Enter를 눌러 구독에서 사용된 모든 리소스를 제거하기로 한 결정을 확인합니다.

    ? Total resources to delete: 14, are you sure you want to continue? (y/N)
    
  3. y을 입력하고 Enter를 눌러 해당되는 경우 제거에서 빠른 시작 변수를 다시 사용하도록 허용합니다.

    [Warning]: These resources have soft delete enabled allowing them to be recovered for a period or time after deletion. During this period, their names can't be reused. In the future, you can use the argument --purge to skip this confirmation.
    

Azure의 Terraform 문제 해결

Azure에서 Terraform을 사용할 때 발생하는 일반적인 문제를 해결합니다.

다음 단계

이 빠른 시작에서는 Kubernetes 클러스터를 배포한 다음, 해당 클러스터에 간단한 다중 컨테이너 애플리케이션을 배포했습니다. 이 샘플 응용 프로그램은 데모 목적으로만 사용되며 Kubernetes 응용 프로그램에 대한 모든 모범 사례를 나타내지는 않습니다. 프로덕션용 AKS를 사용하여 전체 솔루션을 만드는 방법에 대한 지침은 AKS 솔루션 지침을 참조하세요.

AKS에 대해 자세히 알아보고 배포 예제에 대한 전체 코드를 연습해 보려면 Kubernetes 클러스터 자습서를 계속 진행합니다.