다음을 통해 공유


빠른 시작: Bicep을 사용하여 Azure Nexus Kubernetes 클러스터 배포

  • Bicep을 사용하여 Azure Nexus Kubernetes 클러스터를 배포합니다.

Bicep은 선언적 구문을 사용하여 Azure 리소스를 배포하는 DSL(도메인 특정 언어)입니다. 간결한 구문, 신뢰할 수 있는 형식 안전성 및 코드 다시 사용에 대한 지원을 제공합니다. Bicep은 Azure에서 코드형 인프라 솔루션에 대한 최고의 제작 환경을 제공합니다.

필수 조건

Azure를 구독하고 있지 않다면 시작하기 전에 Azure 체험 계정을 만듭니다.

  • 필요한 Azure CLI 확장의 최신 버전을 설치합니다.

  • 이 문서대로 하려면 Azure CLI 버전 2.49.0 이상이 필요합니다. Azure Cloud Shell을 사용하는 경우 최신 버전이 이미 설치되어 있습니다.

  • Azure 구독이 여러 개인 경우 az account 명령을 사용하여 리소스가 청구되어야 하는 적절한 구독 ID를 선택합니다.

  • 지원되는 VM SKU 목록은 참조 섹션의 VM SKU 표를 참조하세요.

  • 지원되는 Kubernetes 버전 목록은 지원되는 Kubernetes 버전을 참조하세요.

  • az group create 명령을 사용하여 리소스 그룹을 만듭니다. Azure 리소스 그룹은 Azure 리소스가 배포되고 관리되는 논리 그룹입니다. 리소스 그룹을 만들 때 위치를 지정하라는 메시지가 표시됩니다. 이 위치는 리소스 그룹 메타데이터의 스토리지 위치이며 리소스를 만드는 중에 다른 지역을 지정하지 않은 경우 Azure에서 리소스가 실행되는 위치입니다. 다음 예제에서는 eastus 위치에 myResourceGroup이라는 리소스 그룹을 만듭니다.

    az group create --name myResourceGroup --location eastus
    

    다음 출력 예는 리소스 그룹의 성공적인 만드는 것과 유사합니다.

    {
      "id": "/subscriptions/<guid>/resourceGroups/myResourceGroup",
      "location": "eastus",
      "managedBy": null,
      "name": "myResourceGroup",
      "properties": {
        "provisioningState": "Succeeded"
      },
      "tags": null
    }
    
  • Bicep 파일 또는 ARM 템플릿을 배포하려면 배포하는 리소스에 대한 쓰기 액세스 및 Microsoft.Resources/deployments 리소스 형식의 모든 작업에 대한 액세스가 필요합니다. 예를 들어, 클러스터를 배포하려면 Microsoft.NetworkCloud/kubernetesclusters/write 및 Microsoft.Resources/deployments/* 권한이 필요합니다. 역할 및 사용 권한 목록은 Azure 기본 제공 역할을 참조하세요.

  • Azure Operator Nexus 클러스터의 custom location 리소스 ID가 필요합니다.

  • 특정 워크로드 요구 사항에 따라 다양한 네트워크를 만들어야 하며 워크로드에 사용할 수 있는 적절한 IP 주소를 확보해야 합니다. 원활한 구현을 위해서는 관련 지원 팀에 문의하여 도움을 받는 것이 좋습니다.

  • 이 빠른 시작에서는 Kubernetes 기본 개념을 이해하고 있다고 가정합니다. 자세한 내용은 AKS(Azure Kubernetes Service)의 Kubernetes 핵심 개념을 참조하세요.

Bicep 파일 검토

Kubernetes 템플릿을 배포하기 전에 콘텐츠를 검토하여 구조를 이해해 보겠습니다.

// Azure parameters

@description('The name of Nexus Kubernetes cluster')
param kubernetesClusterName string

@description('The Azure region where the cluster is to be deployed')
param location string = resourceGroup().location

@description('The custom location of the Nexus instance')
param extendedLocation string

@description('The metadata tags to be associated with the cluster resource')
param tags object = {}

@description('The username for the administrative account on the cluster')
param adminUsername string = 'azureuser'

@description('The object IDs of Azure Active Directory (AAD) groups that will have administrative access to the cluster')
param adminGroupObjectIds array = []

// Networking Parameters

@description('The Azure Resource Manager (ARM) id of the network to be used as the Container Networking Interface (CNI) network')
param cniNetworkId string

@description('The ARM id of the network to be used for cloud services network')
param cloudServicesNetworkId string

@description('The CIDR blocks used for Nexus Kubernetes PODs in the cluster')
param podCidrs array = ['10.244.0.0/16']

@description('The CIDR blocks used for k8s service in the cluster')
param serviceCidrs array = ['10.96.0.0/16']

@description('The IP address of the DNS service in the cluster')
param dnsServiceIp string = '10.96.0.10'

@description('The Layer 2 networks associated with the initial agent pool')
param agentPoolL2Networks array = []
// {
//   networkId: 'string'
//   pluginType: 'SRIOV|DPDK|OSDevice|MACVLAN|IPVLAN'
// }

@description('The Layer 3 networks associated with the initial agent pool')
param agentPoolL3Networks array = []
// {
//   ipamEnabled: 'True/False'
//   networkId: 'string'
//   pluginType: 'SRIOV|DPDK|OSDevice|MACVLAN|IPVLAN'
// }

@description('The trunked networks associated with the initial agent pool')
param agentPoolTrunkedNetworks array = []
// {
//   networkId: 'string'
//   pluginType: 'SRIOV|DPDK|OSDevice|MACVLAN|IPVLAN'
// }

@description('The Layer 2 networks associated with the cluster')
param l2Networks array = []
// {
//   networkId: 'string'
//   pluginType: 'SRIOV|DPDK|OSDevice|MACVLAN|IPVLAN'
// }

@description('The Layer 3 networks associated with the cluster')
param l3Networks array = []
// {
//   ipamEnabled: 'True/False'
//   networkId: 'string'
//   pluginType: 'SRIOV|DPDK|OSDevice|MACVLAN|IPVLAN'
// }

@description('The trunked networks associated with the cluster')
param trunkedNetworks array = []
// {
//   networkId: 'string'
//   pluginType: 'SRIOV|DPDK|OSDevice|MACVLAN|IPVLAN'
// }

@description('The LoadBalancer IP address pools associated with the cluster')
param ipAddressPools array = []
// {
//   addresses: [
//     'string'
//   ]
//   autoAssign: 'True/False'
//   name: 'string'
//   onlyUseHostIps: 'True/False'
// }

// Cluster Configuration Parameters

@description('The version of Kubernetes to be used in the Nexus Kubernetes cluster')
param kubernetesVersion string = 'v1.24.9'

@description('The number of control plane nodes to be deployed in the cluster')
param controlPlaneCount int = 1

@description('The zones/racks used for placement of the control plane nodes')
param controlPlaneZones array = []
// "string" Example: ["1", "2", "3"]

@description('The zones/racks used for placement of the agent pool nodes')
param agentPoolZones array = []
// "string" Example: ["1", "2", "3"]

@description('The size of the control plane nodes')
param controlPlaneVmSkuName string = 'NC_G6_28_v1'

@description('The number of worker nodes to be deployed in the initial agent pool')
param systemPoolNodeCount int = 1

@description('The size of the worker nodes')
param workerVmSkuName string = 'NC_P10_56_v1'

@description('The configurations for the initial agent pool')
param initialPoolAgentOptions object = {}
// {
//   "hugepagesCount": integer,
//   "hugepagesSize": "2M/1G"
// }

@description('The SSH public key that will be associated with the "azureuser" user for secure remote login')
param sshPublicKey string = ''

@description('The labels to assign to the nodes in the cluster for identification and organization')
param labels array = []
// {
//   key: 'string'
//   value: 'string'
// }
@description('The taints to apply to the nodes in the cluster to restrict which pods can be scheduled on them')
param taints array = []
// {
//   key: 'string'
//   value: 'string:NoSchedule|PreferNoSchedule|NoExecute'
// }

resource kubernetescluster 'Microsoft.NetworkCloud/kubernetesClusters@2023-07-01' = {
  name: kubernetesClusterName
  location: location
  tags: tags
  extendedLocation: {
    name: extendedLocation
    type: 'CustomLocation'
  }
  properties: {
    kubernetesVersion: kubernetesVersion
    managedResourceGroupConfiguration: {
      name: '${uniqueString(resourceGroup().name)}-${kubernetesClusterName}'
      location: location
    }
    aadConfiguration: {
      adminGroupObjectIds: adminGroupObjectIds
    }
    administratorConfiguration: {
      adminUsername: adminUsername
      sshPublicKeys: [
        {
          keyData: sshPublicKey
        }
      ]
    }
    initialAgentPoolConfigurations: [
      {
        name: '${kubernetesClusterName}-nodepool-1'
        administratorConfiguration: {}
        count: systemPoolNodeCount
        vmSkuName: workerVmSkuName
        mode: 'System'
        labels: empty(labels) ? null : labels
        taints: empty(taints) ? null : taints
        agentOptions: empty(initialPoolAgentOptions) ? null : initialPoolAgentOptions
        attachedNetworkConfiguration: {
          l2Networks: empty(agentPoolL2Networks) ? null : agentPoolL2Networks
          l3Networks: empty(agentPoolL3Networks) ? null : agentPoolL3Networks
          trunkedNetworks: empty(agentPoolTrunkedNetworks) ? null : agentPoolTrunkedNetworks
        }
        availabilityZones: empty(agentPoolZones) ? null : agentPoolZones
        upgradeSettings: {
          maxSurge: '1'
        }
      }
    ]
    controlPlaneNodeConfiguration: {
      administratorConfiguration: {}
      count: controlPlaneCount
      vmSkuName: controlPlaneVmSkuName
      availabilityZones: empty(controlPlaneZones) ? null : controlPlaneZones
    }
    networkConfiguration: {
      cniNetworkId: cniNetworkId
      cloudServicesNetworkId: cloudServicesNetworkId
      dnsServiceIp: dnsServiceIp
      podCidrs: podCidrs
      serviceCidrs: serviceCidrs
      attachedNetworkConfiguration: {
        l2Networks: empty(l2Networks) ? null : l2Networks
        l3Networks: empty(l3Networks) ? null : l3Networks
        trunkedNetworks: empty(trunkedNetworks) ? null : trunkedNetworks
      }
      bgpServiceLoadBalancerConfiguration: {
        ipAddressPools: empty(ipAddressPools) ? null : ipAddressPools
      }
    }
  }
}

kubernetes-deploy.bicep이라는 템플릿 파일을 검토하고 저장한 후 다음 섹션으로 진행하여 템플릿을 배포합니다.

Bicep 파일 배포

  1. kubernetes-deploy-parameters.json이라는 파일을 만들고 JSON 형식으로 필수 매개 변수를 추가합니다. 다음 예를 시작점으로 사용할 수 있습니다. 사용자 고유의 값으로 대체합니다.
{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "kubernetesClusterName":{
      "value": "myNexusK8sCluster"
    },
    "adminGroupObjectIds": {
      "value": [
        "00000000-0000-0000-0000-000000000000"
      ]
    },
    "cniNetworkId": {
      "value": "/subscriptions/<subscription_id>/resourceGroups/<resource_group>/providers/Microsoft.NetworkCloud/l3Networks/<l3Network-name>"
    },
    "cloudServicesNetworkId": {
      "value": "/subscriptions/<subscription_id>/resourceGroups/<resource_group>/providers/Microsoft.NetworkCloud/cloudServicesNetworks/<csn-name>"
    },
    "extendedLocation": {
      "value": "/subscriptions/<subscription_id>/resourceGroups/<managed_resource_group>/providers/microsoft.extendedlocation/customlocations/<custom-location-name>"
    },
    "location": {
      "value": "eastus"
    },
    "sshPublicKey": {
      "value": "ssh-rsa AAAAB...."
    }
  }
}
  1. 템플릿을 배포합니다.
    az deployment group create \
      --resource-group myResourceGroup \
      --template-file kubernetes-deploy.bicep \
      --parameters @kubernetes-deploy-parameters.json

배포된 리소스 검토

배포가 완료되면 CLI 또는 Azure Portal을 사용하여 리소스를 볼 수 있습니다.

myResourceGroup 리소스 그룹에 있는 myNexusK8sCluster 클러스터의 세부 정보를 보려면 다음 Azure CLI 명령을 실행합니다.

az networkcloud kubernetescluster show \
  --name myNexusK8sCluster \
  --resource-group myResourceGroup

또한 myResourceGroup 리소스 그룹의 myNexusK8sCluster 클러스터와 연결된 에이전트 풀 이름 목록을 가져오려면 다음 Azure CLI 명령을 사용할 수 있습니다.

az networkcloud kubernetescluster agentpool list \
  --kubernetes-cluster-name myNexusK8sCluster \
  --resource-group myResourceGroup \
  --output table

클러스터에 연결

이제 Nexus Kubernetes 클러스터가 성공적으로 만들어져 Azure Arc에 연결되었으므로 클러스터 연결 기능을 사용하여 쉽게 연결할 수 있습니다. 클러스터 연결을 사용하면 어디에서나 클러스터에 안전하게 액세스하고 관리할 수 있으므로 대화형 개발, 디버깅 및 클러스터 관리 작업이 편리해집니다.

사용 가능한 옵션에 대한 자세한 내용은 Azure Operator Nexus Kubernetes 클러스터에 연결을 참조하세요.

참고 항목

Nexus Kubernetes 클러스터를 만들면 Nexus는 클러스터 리소스 저장 전용 관리되는 리소스 그룹을 자동으로 만들며, 이 그룹 내에서 Arc 연결 클러스터 리소스가 설정됩니다.

클러스터에 액세스하려면 클러스터 연결 kubeconfig를 설정해야 합니다. 관련 Microsoft Entra 엔터티를 사용하여 Azure CLI에 로그인하면 클러스터를 둘러싸고 있는 방화벽 외부에서도 어디에서나 클러스터와 통신하는 데 필요한 kubeconfig를 가져올 수 있습니다.

  1. CLUSTER_NAME, RESOURCE_GROUPSUBSCRIPTION_ID 변수를 설정합니다.

    CLUSTER_NAME="myNexusK8sCluster"
    RESOURCE_GROUP="myResourceGroup"
    SUBSCRIPTION_ID=<set the correct subscription_id>
    
  2. az를 사용하여 관리되는 리소스 그룹을 쿼리하고 MANAGED_RESOURCE_GROUP에 저장합니다.

     az account set -s $SUBSCRIPTION_ID
     MANAGED_RESOURCE_GROUP=$(az networkcloud kubernetescluster show -n $CLUSTER_NAME -g $RESOURCE_GROUP --output tsv --query managedResourceGroupConfiguration.name)
    
  3. 다음 명령은 지정된 Nexus Kubernetes 클러스터에 대한 Kubernetes API 서버에 연결할 수 있게 해주는 connectedk8s 프록시를 시작합니다.

    az connectedk8s proxy -n $CLUSTER_NAME  -g $MANAGED_RESOURCE_GROUP &
    
  4. kubectl을 사용하여 클러스터로 요청을 보냅니다.

    kubectl get pods -A
    

    이제 모든 노드 목록이 포함된 클러스터의 응답이 표시됩니다.

참고 항목

"클라이언트 프록시에 액세스 토큰을 게시하지 못했습니다. MSI에 연결하지 못했습니다." 오류 메시지가 표시되면 az login을 수행하여 Azure에 다시 인증해야 할 수 있습니다.

에이전트 풀 추가

이전 단계에서 만든 클러스터에는 노드 풀이 하나 있습니다. Bicep 템플릿을 사용하여 두 번째 에이전트 풀을 추가해 보겠습니다. 다음 예에서는 myNexusK8sCluster-nodepool-2라는 에이전트 풀을 만듭니다.

  1. 템플릿을 검토합니다.

에이전트 풀 템플릿을 추가하기 전에 콘텐츠를 검토하여 구조를 이해해 보겠습니다.

// Azure Parameters
@description('The name of Nexus Kubernetes cluster')
param kubernetesClusterName string

@description('The Azure region where the cluster is to be deployed')
param location string = resourceGroup().location

@description('The custom location of the Nexus instance')
param extendedLocation string

@description('Tags to be associated with the resource')
param tags object = {}

@description('The username for the administrative account on the cluster')
param adminUsername string = 'azureuser'

@description('The SSH public key that will be associated with the "azureuser" user for secure remote login')
param sshPublicKey string = ''

// Cluster Configuration Parameters
@description('Number of nodes in the agent pool')
param agentPoolNodeCount int = 1

@description('Agent pool name')
param agentPoolName string = 'nodepool-2'

@description('VM size of the agent nodes')
param agentVmSku string = 'NC_P10_56_v1'

@description('The zones/racks used for placement of the agent pool nodes')
param agentPoolZones array = []
// "string" Example: ["1", "2", "3"]

@description('Agent pool mode')
param agentPoolMode string = 'User'

@description('The configurations for the initial agent pool')
param agentOptions object = {}
// {
//   "hugepagesCount": integer,
//   "hugepagesSize": "2M/1G"
// }

@description('The labels to assign to the nodes in the cluster for identification and organization')
param labels array = []
// {
//   key: 'string'
//   value: 'string'
// }
@description('The taints to apply to the nodes in the cluster to restrict which pods can be scheduled on them')
param taints array = []
// {
//   key: 'string'
//   value: 'string:NoSchedule|PreferNoSchedule|NoExecute'
// }

// Networking Parameters
@description('The Layer 2 networks to connect to the agent pool')
param l2Networks array = []
// {
//   networkId: 'string'
//   pluginType: 'SRIOV|DPDK|OSDevice|MACVLAN|IPVLAN'
// }

@description('The Layer 3 networks to connect to the agent pool')
param l3Networks array = []
// {
//   ipamEnabled: 'True/False'
//   networkId: 'string'
//   pluginType: 'SRIOV|DPDK|OSDevice|MACVLAN|IPVLAN'
// }

@description('The trunked networks to connect to the agent pool')
param trunkedNetworks array = []
// {
//   networkId: 'string'
//   pluginType: 'SRIOV|DPDK|OSDevice|MACVLAN|IPVLAN'
// }

resource agentPools 'Microsoft.NetworkCloud/kubernetesClusters/agentPools@2023-07-01' = {
  name: '${kubernetesClusterName}/${kubernetesClusterName}-${agentPoolName}'
  location: location
  tags: tags
  extendedLocation: {
    name: extendedLocation
    type: 'CustomLocation'
  }
  properties: {
    administratorConfiguration: sshPublicKey != '' ? {
      adminUsername: adminUsername
      sshPublicKeys: [
        {
          keyData: sshPublicKey
        }
      ]
    }: {}
    attachedNetworkConfiguration: {
      l2Networks: empty(l2Networks) ? null : l2Networks
      l3Networks: empty(l3Networks) ? null : l3Networks
      trunkedNetworks: empty(trunkedNetworks) ? null : trunkedNetworks
    }
    count: agentPoolNodeCount
    mode: agentPoolMode
    vmSkuName: agentVmSku
    labels: empty(labels) ? null : labels
    taints: empty(taints) ? null : taints
    agentOptions: empty(agentOptions) ? null : agentOptions
    availabilityZones: empty(agentPoolZones) ? null : agentPoolZones
    upgradeSettings: {
      maxSurge: '1'
    }
  }
}

kubernetes-add-agentpool.bicep이라는 템플릿 파일을 검토하고 저장한 후 다음 섹션으로 진행하여 템플릿을 배포합니다.

  1. kubernetes-nodepool-parameters.json이라는 파일을 만들고 JSON 형식으로 필수 매개 변수를 추가합니다. 다음 예를 시작점으로 사용할 수 있습니다. 사용자 고유의 값으로 대체합니다.
{
    "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
      "kubernetesClusterName":{
        "value": "myNexusK8sCluster"
      },
      "extendedLocation": {
        "value": "/subscriptions/<subscription_id>/resourceGroups/<resource_group>/providers/microsoft.extendedlocation/customlocations/<custom-location-name>"
      }
    }
  }
  1. 템플릿을 배포합니다.
    az deployment group create \
      --resource-group myResourceGroup \
      --template-file kubernetes-add-agentpool.bicep \
      --parameters @kubernetes-nodepool-parameters.json

참고 항목

초기 에이전트 풀 구성을 사용하여 클러스터 자체를 처음 만드는 동안 여러 에이전트 풀을 추가할 수 있습니다. 그러나 초기 생성 후 에이전트 풀을 추가하려는 경우 위 명령을 활용하여 Nexus Kubernetes 클러스터에 대한 추가 에이전트 풀을 만들 수 있습니다.

다음 출력 예는 에이전트 풀의 성공적인 만들기와 유사합니다.

$ az networkcloud kubernetescluster agentpool list --kubernetes-cluster-name myNexusK8sCluster --resource-group myResourceGroup --output table
This command is experimental and under development. Reference and support levels: https://aka.ms/CLI_refstatus
Count    Location    Mode    Name                          ProvisioningState    ResourceGroup    VmSkuName
-------  ----------  ------  ----------------------------  -------------------  ---------------  -----------
1        eastus      System  myNexusK8sCluster-nodepool-1  Succeeded            myResourceGroup  NC_P10_56_v1
1        eastus      User    myNexusK8sCluster-nodepool-2  Succeeded            myResourceGroup  NC_P10_56_v1

리소스 정리

더 이상 필요하지 않은 경우 리소스 그룹을 삭제합니다. 리소스 그룹 및 리소스 그룹의 모든 리소스가 삭제됩니다.

리소스 그룹, Kubernetes 클러스터 및 Operator Nexus 네트워크 리소스를 제외한 모든 관련 리소스를 제거하려면 az group delete 명령을 사용합니다.

az group delete --name myResourceGroup --yes --no-wait

다음 단계

이제 클러스터 연결을 통해 직접 또는 Azure Operator Service Manager를 통해 CNF를 배포할 수 있습니다.