빠른 시작: Bicep을 사용하여 Azure Nexus Kubernetes 클러스터 배포
- Bicep을 사용하여 Azure Nexus Kubernetes 클러스터를 배포합니다.
Bicep은 선언적 구문을 사용하여 Azure 리소스를 배포하는 DSL(도메인 특정 언어)입니다. 간결한 구문, 신뢰할 수 있는 형식 안전성 및 코드 다시 사용에 대한 지원을 제공합니다. Bicep은 Azure에서 코드형 인프라 솔루션에 대한 최고의 제작 환경을 제공합니다.
필수 조건
Azure를 구독하고 있지 않다면 시작하기 전에 Azure 체험 계정을 만듭니다.
Azure Cloud Shell에서 Bash 환경을 사용합니다. 자세한 내용은 Azure Cloud Shell의 Bash에 대한 빠른 시작을 참조하세요.
CLI 참조 명령을 로컬에서 실행하려면 Azure CLI를 설치합니다. Windows 또는 macOS에서 실행 중인 경우 Docker 컨테이너에서 Azure CLI를 실행하는 것이 좋습니다. 자세한 내용은 Docker 컨테이너에서 Azure CLI를 실행하는 방법을 참조하세요.
로컬 설치를 사용하는 경우 az login 명령을 사용하여 Azure CLI에 로그인합니다. 인증 프로세스를 완료하려면 터미널에 표시되는 단계를 수행합니다. 다른 로그인 옵션은 Azure CLI를 사용하여 로그인을 참조하세요.
메시지가 표시되면 처음 사용할 때 Azure CLI 확장을 설치합니다. 확장에 대한 자세한 내용은 Azure CLI에서 확장 사용을 참조하세요.
az version을 실행하여 설치된 버전과 종속 라이브러리를 찾습니다. 최신 버전으로 업그레이드하려면 az upgrade를 실행합니다.
필요한 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 파일 배포
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...."
}
}
}
- 템플릿을 배포합니다.
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
를 가져올 수 있습니다.
CLUSTER_NAME
,RESOURCE_GROUP
및SUBSCRIPTION_ID
변수를 설정합니다.CLUSTER_NAME="myNexusK8sCluster" RESOURCE_GROUP="myResourceGroup" SUBSCRIPTION_ID=<set the correct subscription_id>
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)
다음 명령은 지정된 Nexus Kubernetes 클러스터에 대한 Kubernetes API 서버에 연결할 수 있게 해주는 connectedk8s 프록시를 시작합니다.
az connectedk8s proxy -n $CLUSTER_NAME -g $MANAGED_RESOURCE_GROUP &
kubectl
을 사용하여 클러스터로 요청을 보냅니다.kubectl get pods -A
이제 모든 노드 목록이 포함된 클러스터의 응답이 표시됩니다.
참고 항목
"클라이언트 프록시에 액세스 토큰을 게시하지 못했습니다. MSI에 연결하지 못했습니다." 오류 메시지가 표시되면 az login
을 수행하여 Azure에 다시 인증해야 할 수 있습니다.
에이전트 풀 추가
이전 단계에서 만든 클러스터에는 노드 풀이 하나 있습니다. Bicep 템플릿을 사용하여 두 번째 에이전트 풀을 추가해 보겠습니다. 다음 예에서는 myNexusK8sCluster-nodepool-2
라는 에이전트 풀을 만듭니다.
- 템플릿을 검토합니다.
에이전트 풀 템플릿을 추가하기 전에 콘텐츠를 검토하여 구조를 이해해 보겠습니다.
// 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
이라는 템플릿 파일을 검토하고 저장한 후 다음 섹션으로 진행하여 템플릿을 배포합니다.
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>"
}
}
}
- 템플릿을 배포합니다.
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를 배포할 수 있습니다.