flex 노드 호스트 및 ID 준비(미리 보기)

Important

AKS 미리 보기 기능은 셀프 서비스에서 사용할 수 있습니다(옵트인 방식). 미리 보기는 "있는 그대로" 및 "사용 가능한 상태로" 제공되며 서비스 수준 계약 및 제한적 보증에서 제외됩니다. AKS 미리 보기의 일부는 고객 지원팀에서 최선을 다해 지원합니다. 따라서 이러한 기능은 프로덕션 용도로 사용할 수 없습니다. 자세한 내용은 다음 지원 문서를 참조하세요.

Linux 호스트를 flex 노드로 연결하기 전에 호스트를 준비하고, 계획 중에 선택한 ID를 구성하고, 해당 ID에 AKS(Azure Kubernetes Service) 클러스터에 대한 액세스 권한을 부여합니다.

이 글에서 당신은 다음을 하게 됩니다.

  • 호스트 요구 사항을 검토한 다음 Linux 호스트 및 해당 Azure ID를 프로비전하거나 선택합니다.
  • 호스트를 준비 및 검사하고 첨부 파일 워크플로에서 사용하는 값을 기록합니다.
  • AKS 클러스터 범위에서 ID 액세스를 할당하고 해당 ID를 확인합니다.

필요한 도구와 네트워크 액세스 권한이 있는 Linux 호환 Bash 환경에서 이 문서의 관리 명령을 실행합니다. 이 문서에서는 그 환경을 Bash 환경이라고 부릅니다. 클러스터를 조인하는 별도의 컴퓨터는 flex 노드 호스트입니다. 단계가 명시적으로 지시하는 경우에만 명령을 실행합니다.

시작하기 전 주의 사항:

배포 환경 로드

새 Bash 세션을 시작하고, 계획 문서에서 환경 파일을 식별하고, 로드합니다. <deployment-name>를 배포 레이블로 대체하세요.

export FLEXNODE_DEPLOYMENT="<deployment-name>"
export FLEXNODE_ENV_FILE="${HOME}/.config/aks-flexnode/${FLEXNODE_DEPLOYMENT}.env"
test -s "${FLEXNODE_ENV_FILE}"
source "${FLEXNODE_ENV_FILE}"

환경 파일은 이 문서에서 사용하는 공유된 배포 값(이 문서에서 다운로드한 파일과 생성된 파일을 저장하는 Bash 환경의 디렉터리인 WORK_DIR 포함)을 제공합니다. 기본적으로 WORK_DIR는 ~/.local/share/aksflexnode/<deployment-name>입니다. 이 문서에서는 필요한 다른 변수를 파생합니다. 환경 파일을 아직 만들지 않은 경우 먼저 flex 노드 배포 계획을 완료합니다 .

파일을 찾을 수 없거나 로드할 수 없는 경우 계속하기 전에 중지하고 계획 문서로 돌아갑니다.

활성 구독을 설정하고 선택한 클러스터를 확인합니다.

az account set --subscription "${SUBSCRIPTION_ID}"

az aks show \
    --resource-group "${RESOURCE_GROUP}" \
    --name "${CLUSTER_NAME}" \
    --query "{Name:name,ResourceId:id,ProvisioningState:provisioningState}" \
    --output table

리소스 ID가 일치 AKS_RESOURCE_ID 하고 프로비저닝 상태가 Succeeded될 때 계속합니다.

1. 호스트 요구 사항 검토

다음 요구 사항을 충족하는 전용 호스트를 사용합니다.

  • Ubuntu 24.04 LTS, Azure Linux 3.x 또는 RHEL(Red Hat Enterprise Linux) 9 또는 10을 실행하는 AMD64 또는 ARM64 호스트입니다.
  • 유효한 DNS 하위 도메인 이름인 고유한 호스트 이름입니다. 에이전트는 노드를 등록할 때 소문자로 변환합니다.
  • /var/lib 아래에서 사용 가능한 vCPU가 최소 4개, 여유 공간이 최소 8 GiB 있어야 합니다.
  • 호스트에서 루트 또는 암호 없는 sudo 액세스 권한이 있는 SSH 계정입니다.
  • AKS API 서버, Azure Resource Manager, Microsoft Entra ID, 선택한 flex 노드 릴리스와 아티팩트 미러, 그리고 필요한 컨테이너 레지스트리에 대한 네트워크 액세스
  • flex 노드 호스트 네트워크와 AKS에서 관리되는 노드 네트워크 간의 기존 3계층 연결 호스트 및 AKS 클러스터는 동일한 Azure 지역에 있을 필요가 없습니다.

또한 Bash 환경은 SSH를 통해 flex 노드 호스트에 연결할 수 있어야 합니다. 다른 승인된 관리 경로가 있는 경우 공용 IP 주소가 필요하지 않습니다.

2. 호스트와 ID를 프로비저닝하거나 선택합니다

flex 노드의 ID 및 액세스 개념에서 선택한 ID 옵션에 해당하는 섹션만 완료하세요. 동일한 호스트에 대해 둘 이상의 지속성 Azure ID 모드를 구성하지 마세요.

팁 (조언)

Azure 외부에서 컴퓨터를 연결하시겠습니까? 컴퓨터가 이미 Arc를 사용하도록 설정된 경우 Azure Arc 관리 ID를 사용하거나 서비스 주체를 사용합니다. flex 노드 호스트가 Azure VM인 경우에만 Azure VM 관리 ID를 사용합니다.

모든 ID 옵션에 사용되는 SSH 키 경로를 설정합니다.

export SSH_PRIVATE_KEY_PATH="<path-to-private-key>"
export SSH_PUBLIC_KEY_PATH="<path-to-public-key>"

각 ID 옵션은 두 개의 호스트 주소도 설정합니다. FLEX_HOST_SSH_TARGET 는 Bash 환경에서 사용하는 주소입니다. FLEX_HOST_PRIVATE_IP 는 AKS 관리 노드 네트워크에서 연결할 수 있는 호스트 주소입니다. 네트워크 관리자에게 FLEX_HOST_SUBNET_CIDR이(가) FLEX_HOST_PRIVATE_IP에 속해 있으며 AKS 관리형 노드 네트워크에서 도달 가능한 주소인지 확인하세요. 별도의 공용 또는 관리 전용 주소를 flex 노드 주소로 사용하지 마세요.

Azure Arc 관리 ID 사용

Azure Arc 이미 연결된 호스트에 대해 이 옵션을 사용합니다. 필요한 경우 Azure Arc 지원 서버를 사용하여 하이브리드 머신을 연결합니다.

Arc 리소스 값 및 호스트 주소를 설정합니다.

export ARC_RESOURCE_GROUP="<arc-machine-resource-group>"
export ARC_MACHINE_NAME="<arc-machine-name>"
export FLEX_HOST_SSH_TARGET="<admin-user>@<reachable-host-address>"
export FLEX_HOST_PRIVATE_IP="<private-ip-reachable-from-aks>"

리소스 ID, 연결 상태 및 보안 주체 개체 ID를 가져옵니다.

ARC_RESOURCE_ID="/subscriptions/${SUBSCRIPTION_ID}/resourceGroups/${ARC_RESOURCE_GROUP}/providers/Microsoft.HybridCompute/machines/${ARC_MACHINE_NAME}"
export ARC_RESOURCE_ID

HOST_PRINCIPAL_OBJECT_ID="$(az resource show \
    --ids "${ARC_RESOURCE_ID}" \
    --query identity.principalId \
    --output tsv)"
export HOST_PRINCIPAL_OBJECT_ID

az resource show \
    --ids "${ARC_RESOURCE_ID}" \
    --query "{Name:name,Status:properties.status,IdentityType:identity.type,PrincipalId:identity.principalId}" \
    --output yaml

상태가 이고 Connected에 값이 있으면 계속합니다.

호스트에서 연결된 컴퓨터 에이전트 및 하이브리드 인스턴스 메타데이터 서비스를 확인합니다.

ssh -i "${SSH_PRIVATE_KEY_PATH}" "${FLEX_HOST_SSH_TARGET}" \
    'sudo azcmagent show && systemctl is-active himdsd'

ARC_RESOURCE_ID가 azcmagent show, ARC_RESOURCE_GROUP 및 ARC_MACHINE_NAME와 동일한 구독 ID, 리소스 그룹 및 컴퓨터 이름을 보고하는지 확인합니다. 활성 상태인지 himdsd 도 확인합니다. 리소스가 일치하지 않는 경우 액세스를 할당하기 전에 Arc 리소스 값을 중지하고 수정합니다.

Arc 및 ID 값을 기록합니다.

set_flexnode_env ARC_RESOURCE_GROUP "${ARC_RESOURCE_GROUP}"
set_flexnode_env ARC_MACHINE_NAME "${ARC_MACHINE_NAME}"
set_flexnode_env ARC_RESOURCE_ID "${ARC_RESOURCE_ID}"
set_flexnode_env FLEX_HOST_SSH_TARGET "${FLEX_HOST_SSH_TARGET}"
set_flexnode_env FLEX_HOST_PRIVATE_IP "${FLEX_HOST_PRIVATE_IP}"
set_flexnode_env HOST_PRINCIPAL_OBJECT_ID "${HOST_PRINCIPAL_OBJECT_ID}"
set_flexnode_env HOST_IDENTITY_CLIENT_ID ""

서비스 주체 사용

지원되는 다른 가상 머신 또는 베어메탈 호스트에는 이 옵션을 사용하세요. 수명이 긴 클라이언트 암호보다 인증서 자격 증명을 선호합니다. 다음 단계에서는 평가를 위해 자체 서명된 인증서를 사용하여 전용 애플리케이션 및 서비스 주체를 만듭니다. 클라이언트 비밀을 만들거나 Azure 역할을 할당하지 않습니다. 4단계에서 대상 AKS 클러스터에 대한 액세스 권한을 부여합니다.

계속하기 전에 다음을 수행합니다.

  • Bash 환경에 OpenSSL을 설치하고 az login --certificate를 지원하는 최신 Azure CLI를 사용하세요.
  • 애플리케이션을 등록하고 대상 구독과 연결된 Microsoft Entra 테넌트에 서비스 주체를 만들 수 있는 계정으로 로그인합니다. Azure 구독 소유권만으로는 이러한 디렉터리 권한을 부여하지 않습니다. 테넌트가 애플리케이션 등록을 제한하는 경우 테넌트 관리자에게 도움을 요청합니다. Azure CLI 사용하여 Azure 서비스 주체 만들기를 참조하세요.
  • 조직에서 평가에 자체 서명된 인증서를 허용하는지 확인합니다. 기존 승인 ID의 경우 테넌트 ID, 애플리케이션 클라이언트 ID, 서비스 주체 개체 ID 및 보호된 PEM 파일을 사용하고 서비스 주체 및 호스트 값 기록으로 건너뜁니다.

공유 환경 파일에 자격 증명, 프라이빗 키 또는 자격 증명 경로를 저장하지 마세요. PEM 파일을 인쇄하거나 소스 제어에 포함하지 마세요. PEM 파일에는 에이전트가 대화형 암호 프롬프트 없이 인증할 수 있도록 암호화되지 않은 프라이빗 키가 포함되어 있습니다. 파일 권한 및 승인된 호스트 액세스 제어를 사용하여 보호합니다.

인증서 기반 서비스 주체 만들기

운영자 계정으로 로그인하는 동안 Bash 환경에서 이러한 명령을 실행합니다.

  1. 구독, 테넌트 및 로그인한 계정을 확인합니다.

    az account set --subscription "${SUBSCRIPTION_ID}"
    az account show \
        --query "{SubscriptionId:id,TenantId:tenantId,Account:user.name}" \
        --output table
    
    SP_TENANT_ID="$(az account show --query tenantId --output tsv)"
    export SP_TENANT_ID
    

    구독 및 테넌트가 의도한 대상인지 확인한 경우에만 계속 진행하세요.

  2. 고유한 애플리케이션 표시 이름을 선택하고 보호된 자격 증명 디렉터리를 만듭니다.

    export SP_DISPLAY_NAME="aks-flexnode-${FLEXNODE_DEPLOYMENT}-$(date -u +%Y%m%dT%H%M%SZ)"
    install -d -m 0700 "${WORK_DIR:?Load the deployment environment first.}"
    SP_CREDENTIAL_DIR="$(mktemp -d "${WORK_DIR}/sp-credential.XXXXXXXX")"
    export SP_CREDENTIAL_DIR
    export SP_CLIENT_CERTIFICATE_FILE="${SP_CREDENTIAL_DIR:?Credential directory wasn't created.}/sp-client.pem"
    
  3. 인증서 및 프라이빗 키가 포함된 30일 인증서 및 결합된 PEM 파일을 만듭니다.

    (
        set -e
        umask 077
    
        openssl req -x509 -newkey rsa:2048 -sha256 -days 30 -nodes \
            -keyout "${SP_CREDENTIAL_DIR}/sp-client.key" \
            -out "${SP_CREDENTIAL_DIR}/sp-client.crt" \
            -subj "/CN=${SP_DISPLAY_NAME}"
    
        cat "${SP_CREDENTIAL_DIR}/sp-client.crt" \
            "${SP_CREDENTIAL_DIR}/sp-client.key" \
            > "${SP_CLIENT_CERTIFICATE_FILE}"
        chmod 0600 "${SP_CLIENT_CERTIFICATE_FILE}"
        rm -f "${SP_CREDENTIAL_DIR}/sp-client.key"
    )
    
    openssl x509 \
        -in "${SP_CREDENTIAL_DIR}/sp-client.crt" \
        -noout -subject -dates
    stat -c '%a %n' "${SP_CLIENT_CERTIFICATE_FILE}"
    

    인증서 만들기가 실패하면 중지합니다. PEM 권한이 있는지 확인합니다.600 30일의 유효성은 회전 정책이 아니라 평가를 위한 것입니다. 호스트가 연결된 상태로 유지되는 경우 만료되기 전에 승인된 프로세스를 통해 자격 증명을 바꿉니다.

  4. 공용 인증서만 업로드하여 애플리케이션 및 서비스 주체를 만듭니다.

    SP_CLIENT_ID="$(az ad sp create-for-rbac \
        --name "${SP_DISPLAY_NAME}" \
        --cert "@${SP_CREDENTIAL_DIR}/sp-client.crt" \
        --query appId \
        --output tsv)"
    export SP_CLIENT_ID
    

    명령이 성공하고 애플리케이션 클라이언트 ID를 반환하는 경우에만 계속합니다. 이 명령은 인증서의 만료 날짜와 일치하도록 자격 증명 종료 날짜를 조정했다고 보고할 수 있습니다. 추가 --role 하지 마세요. --scopes이후 역할 할당은 AKS 클러스터로 제한됩니다. 기존 애플리케이션의 자격 증명을 갱신하려고 애플리케이션 만들기 작업을 다시 실행하지 마세요.

  5. 서비스 주체 개체 ID를 검색하고 등록된 자격 증명을 검사합니다.

    SP_OBJECT_ID="$(az ad sp show \
        --id "${SP_CLIENT_ID}" \
        --query id \
        --output tsv)"
    export SP_OBJECT_ID
    
    az ad sp show \
        --id "${SP_CLIENT_ID}" \
        --query "{ClientId:appId,ServicePrincipalObjectId:id}" \
        --output table
    
    az ad app show \
        --id "${SP_CLIENT_ID}" \
        --query "{ClientId:appId,PasswordCredentials:length(passwordCredentials),Certificates:keyCredentials[].{KeyId:keyId,Expires:endDateTime}}" \
        --output json
    

    서비스 주체 개체 ID가 채워지고, 두 클라이언트 ID가 모두 일치 SP_CLIENT_ID하고, PasswordCredentials 가 0있으며, 정확히 하나의 인증서가 예상 만료로 등록되어 있는지 확인합니다. 디렉터리 복제로 인해 조회가 지연되는 경우 잠시 기다렸다가 다른 애플리케이션을 만드는 대신 조회를 다시 시도합니다.

자격 증명 전용 테스트의 경우 서비스 주체 확인에서 인증서 인증 확인만 실행합니다. Azure 역할을 할당하거나 해당 검사를 위해 호스트를 준비할 필요가 없습니다. 테스트가 완료되면 전용 테스트 애플리케이션 및 로컬 자격 증명을 삭제합니다.

서비스 주체 및 호스트 값 기록

호스트 주소를 설정합니다. 기존 ID를 선택한 경우 먼저 해당 식별자를 설정합니다SP_TENANT_IDSP_CLIENT_IDSP_OBJECT_ID.

export FLEX_HOST_SSH_TARGET="<admin-user>@<reachable-host-address>"
export FLEX_HOST_PRIVATE_IP="<private-ip-reachable-from-aks>"

: "${SP_TENANT_ID:?Set the Microsoft Entra tenant ID.}"
: "${SP_CLIENT_ID:?Set the application client ID.}"
: "${SP_OBJECT_ID:?Set the service principal object ID.}"
export HOST_IDENTITY_CLIENT_ID=""
export HOST_PRINCIPAL_OBJECT_ID="${SP_OBJECT_ID}"

set_flexnode_env FLEX_HOST_SSH_TARGET "${FLEX_HOST_SSH_TARGET}"
set_flexnode_env FLEX_HOST_PRIVATE_IP "${FLEX_HOST_PRIVATE_IP}"
set_flexnode_env SP_TENANT_ID "${SP_TENANT_ID}"
set_flexnode_env SP_CLIENT_ID "${SP_CLIENT_ID}"
set_flexnode_env SP_OBJECT_ID "${SP_OBJECT_ID}"
set_flexnode_env HOST_IDENTITY_CLIENT_ID "${HOST_IDENTITY_CLIENT_ID}"
set_flexnode_env HOST_PRINCIPAL_OBJECT_ID "${HOST_PRINCIPAL_OBJECT_ID}"

SP_OBJECT_ID 는 엔터프라이즈 애플리케이션의 개체 ID이며 서비스 주체 개체 ID라고도 합니다. 앱 등록의 개체 ID가 아닙니다. SP_OBJECT_ID, SP_CLIENT_ID 및 인증서가 동일한 서비스 주체에 속하는지 확인합니다.

부트스트랩은 생성된 에이전트 구성에서 SP_TENANT_ID 및 SP_CLIENT_ID을 azure.servicePrincipal.tenantId 및 azure.servicePrincipal.clientId에 매핑합니다. SP_OBJECT_ID는 에이전트의 클라이언트 ID가 아닌 Azure 역할 할당에 사용됩니다. 인증서 파일 필드, 전체 수정된 구성 셰이프 및 안전한 확인 명령은 렌더링된 서비스 주체 구성 검사를 참조하세요.

ID 확인 및 호스트 부트스트랩을 위해 보호된 PEM 파일을 유지합니다. 첨부하기 전에 승인된 자격 증명 관리 프로세스를 통해 호스트에서 사용할 수 있도록 합니다. 공유 환경 파일이 아닌 승인된 자격 증명 관리 프로세스를 통해 해당 위치를 기록합니다. 호스트를 준비하고 검사하기를 계속 진행한 다음, AKS 역할을 할당합니다.

Azure 가상 머신 관리 ID 사용

Azure VM에 이 옵션을 사용합니다. 빠른 시작: Azure CLI 사용하여 Linux 가상 머신을 만들거나 기존 VM을 선택하여 VM을 만듭니다. 이 배포를 위해 계획된 flex 노드 호스트 네트워크에 VM을 배치합니다. Bash 환경에 승인된 다른 SSH 경로가 있는 경우 공용 IP 주소가 필요하지 않습니다.

VM 값을 설정합니다.

export VM_RESOURCE_GROUP="<vm-resource-group>"
export VM_NAME="<vm-name>"
export VM_ADMIN_USER="<vm-admin-user>"

VM 리소스 ID 및 호스트 주소를 검색합니다. SSH 대상은 VM에 공용 IP 주소가 있는 경우 공용 IP 주소를 사용하고, 그렇지 않으면 개인 주소를 사용합니다.

VM_RESOURCE_ID="$(az vm show \
    --resource-group "${VM_RESOURCE_GROUP}" \
    --name "${VM_NAME}" \
    --query id \
    --output tsv)"
export VM_RESOURCE_ID

FLEX_HOST_PRIVATE_IP="$(az vm show \
    --resource-group "${VM_RESOURCE_GROUP}" \
    --name "${VM_NAME}" \
    --show-details \
    --query privateIps \
    --output tsv)"
export FLEX_HOST_PRIVATE_IP

VM_PUBLIC_IP="$(az vm show \
    --resource-group "${VM_RESOURCE_GROUP}" \
    --name "${VM_NAME}" \
    --show-details \
    --query publicIps \
    --output tsv)"
export VM_PUBLIC_IP

export FLEX_HOST_SSH_TARGET="${VM_ADMIN_USER}@${VM_PUBLIC_IP:-${FLEX_HOST_PRIVATE_IP}}"

VM에 대해 반환된 개인 주소를 확인합니다.

az vm list-ip-addresses \
    --resource-group "${VM_RESOURCE_GROUP}" \
    --name "${VM_NAME}" \
    --query "[0].virtualMachine.{Name:name,PrivateAddresses:network.privateIpAddresses}" \
    --output table

FLEX_HOST_SUBNET_CIDR에 FLEX_HOST_PRIVATE_IP에 속하며 AKS 관리 노드 네트워크에서 연결할 수 있는 단일 프라이빗 주소가 포함된 경우에만 계속합니다. Azure가 둘 이상의 주소를 반환하는 경우, 계속하기 전에 FLEX_HOST_PRIVATE_IP를 계획된 플렉스 노드 주소로 설정합니다.

VM에 공용 IP 주소가 없거나 Bash 환경이 승인된 다른 관리 경로를 통해 호스트에 도달하는 경우 Bash 환경에 연결할 수 있는 주소 또는 호스트 이름으로 설정합니다 FLEX_HOST_SSH_TARGET .

다음 관리 ID 옵션 중 하나를 완료합니다.

시스템 할당 관리 ID

시스템 할당 관리 ID를 사용하도록 설정합니다.

az vm identity assign \
    --resource-group "${VM_RESOURCE_GROUP}" \
    --name "${VM_NAME}" \
    --output none

해당 주체 개체 ID를 검색합니다.

HOST_PRINCIPAL_OBJECT_ID="$(az vm show \
    --resource-group "${VM_RESOURCE_GROUP}" \
    --name "${VM_NAME}" \
    --query identity.principalId \
    --output tsv)"
export HOST_PRINCIPAL_OBJECT_ID

export HOST_IDENTITY_CLIENT_ID=""

사용자가 할당한 관리 ID

Azure CLI 사용하여 사용자 할당 관리 ID 관리에 따라 ID를 만들거나 선택합니다.

ID 값을 설정합니다.

export USER_ASSIGNED_IDENTITY_RESOURCE_GROUP="<identity-resource-group>"
export USER_ASSIGNED_IDENTITY_NAME="<identity-name>"

ID 식별자를 검색합니다.

USER_ASSIGNED_IDENTITY_RESOURCE_ID="$(az identity show \
    --resource-group "${USER_ASSIGNED_IDENTITY_RESOURCE_GROUP}" \
    --name "${USER_ASSIGNED_IDENTITY_NAME}" \
    --query id \
    --output tsv)"
export USER_ASSIGNED_IDENTITY_RESOURCE_ID

HOST_PRINCIPAL_OBJECT_ID="$(az identity show \
    --resource-group "${USER_ASSIGNED_IDENTITY_RESOURCE_GROUP}" \
    --name "${USER_ASSIGNED_IDENTITY_NAME}" \
    --query principalId \
    --output tsv)"
export HOST_PRINCIPAL_OBJECT_ID

HOST_IDENTITY_CLIENT_ID="$(az identity show \
    --resource-group "${USER_ASSIGNED_IDENTITY_RESOURCE_GROUP}" \
    --name "${USER_ASSIGNED_IDENTITY_NAME}" \
    --query clientId \
    --output tsv)"
export HOST_IDENTITY_CLIENT_ID

VM에 ID를 할당합니다.

az vm identity assign \
    --resource-group "${VM_RESOURCE_GROUP}" \
    --name "${VM_NAME}" \
    --identities "${USER_ASSIGNED_IDENTITY_RESOURCE_ID}" \
    --output none

VM에 선택한 ID가 나열되는지 확인합니다.

az vm identity show \
    --resource-group "${VM_RESOURCE_GROUP}" \
    --name "${VM_NAME}" \
    --query "{Type:type,UserAssignedIdentities:userAssignedIdentities}" \
    --output yaml

출력에 USER_ASSIGNED_IDENTITY_RESOURCE_ID가 포함되면 계속합니다.

VM ID 기록

VM 및 ID 값을 기록합니다.

set_flexnode_env VM_RESOURCE_GROUP "${VM_RESOURCE_GROUP}"
set_flexnode_env VM_NAME "${VM_NAME}"
set_flexnode_env VM_ADMIN_USER "${VM_ADMIN_USER}"
set_flexnode_env VM_RESOURCE_ID "${VM_RESOURCE_ID}"
set_flexnode_env VM_PUBLIC_IP "${VM_PUBLIC_IP}"
set_flexnode_env FLEX_HOST_SSH_TARGET "${FLEX_HOST_SSH_TARGET}"
set_flexnode_env FLEX_HOST_PRIVATE_IP "${FLEX_HOST_PRIVATE_IP}"
set_flexnode_env HOST_PRINCIPAL_OBJECT_ID "${HOST_PRINCIPAL_OBJECT_ID}"
set_flexnode_env HOST_IDENTITY_CLIENT_ID "${HOST_IDENTITY_CLIENT_ID}"

3. 호스트를 준비하고 검사합니다

호스트에 연결:

ssh -i "${SSH_PRIVATE_KEY_PATH}" "${FLEX_HOST_SSH_TARGET}"

호스트에서 운영 체제, 아키텍처, 호스트 이름, CPU 및 사용 가능한 스토리지를 검사합니다.

source /etc/os-release
printf 'Operating system: %s %s\n' "${NAME}" "${VERSION_ID}"
printf 'Architecture: %s\n' "$(uname -m)"
printf 'Host name: %s\n' "$(hostname)"
printf 'vCPUs: %s\n' "$(nproc)"
free -h
df -h /var/lib

결과를 1단계의 호스트 요구 사항과 비교합니다. 계속하기 전에 차이점을 해결합니다.

부트스트랩 스크립트는 호스트에 curl, jq, tar가 필요하며, 이들 중 하나라도 없으면 중지됩니다. flex 노드 에이전트는 부트스트랩 중에 나머지 런타임 패키지를 설치합니다.

이미지에 아직 포함되지 않은 세 가지 중 한 가지를 설치합니다.

# Ubuntu
sudo apt-get update && sudo apt-get install -y curl jq tar

# Azure Linux 3
sudo tdnf install -y curl jq tar

호스트 세션을 종료합니다.

exit

Bash 환경에서 실제 Linux 호스트 이름을 읽습니다.

FLEX_HOST_NAME="$(ssh \
    -i "${SSH_PRIVATE_KEY_PATH}" \
    "${FLEX_HOST_SSH_TARGET}" \
    hostname)"
export FLEX_HOST_NAME

printf 'Flex host name: %s\n' "${FLEX_HOST_NAME}"

명령이 예상된 호스트 이름을 반환하는 경우 계속합니다.

AKS API 서버 FQDN을 확인하고 호스트에서 이름 확인 및 HTTPS 연결 여부를 확인하세요.

AKS_API_FQDN="$(az aks show \
    --resource-group "${RESOURCE_GROUP}" \
    --name "${CLUSTER_NAME}" \
    --query '(privateFqdn || fqdn)' \
    --output tsv)"
export AKS_API_FQDN
ssh -i "${SSH_PRIVATE_KEY_PATH}" "${FLEX_HOST_SSH_TARGET}" \
    "getent hosts '${AKS_API_FQDN}' && \
    timeout 5 bash -c '</dev/tcp/${AKS_API_FQDN}/443'"

이름 확인 또는 TCP 연결이 실패하는 경우 계속하기 전에 DNS, 라우팅 또는 네트워크 컨트롤을 수정합니다. 공용 AKS 클러스터는 공용 API FQDN을 사용합니다. 프라이빗 AKS 클러스터의 경우 Bash 환경 및 flex 노드 호스트 네트워크가 프라이빗 API FQDN을 확인하고 라우팅해야 합니다.

호스트 값을 기록합니다. 공유 환경 파일은 키 또는 자격 증명 콘텐츠가 아닌 경로 및 비보안 식별자를 저장합니다.

set_flexnode_env SSH_PRIVATE_KEY_PATH "${SSH_PRIVATE_KEY_PATH}"
set_flexnode_env SSH_PUBLIC_KEY_PATH "${SSH_PUBLIC_KEY_PATH}"
set_flexnode_env FLEX_HOST_NAME "${FLEX_HOST_NAME}"

4. AKS 역할 할당

현재 미리 보기 워크플로는 정확한 AKS 클러스터 범위에서 Azure Kubernetes Service 기여자 역할을 사용합니다. 세 가지 ID 옵션은 모두 Azure 역할 기반 액세스 제어에 서비스 주체 개체 ID를 사용합니다. 전용 호스트 ID를 사용하고 AKS에서 Flex 노드 관리 및 제거에 설명된 대로 호스트를 제거할 때 이 할당을 제거합니다.

선택한 주체 개체 ID를 표시합니다.

printf 'Principal object ID: %s\n' "${HOST_PRINCIPAL_OBJECT_ID}"

값이 채워지고 선택한 VM ID, Arc 컴퓨터 또는 서비스 주체에 속하는 경우에만 계속합니다.

할당이 이미 있는지 확인합니다.

az role assignment list \
    --assignee-object-id "${HOST_PRINCIPAL_OBJECT_ID}" \
    --scope "${AKS_RESOURCE_ID}" \
    --fill-principal-name false \
    --query "[?roleDefinitionName=='Azure Kubernetes Service Contributor Role'].{PrincipalId:principalId,Role:roleDefinitionName,Scope:scope}" \
    --output table

명령어가 행을 반환하지 않으면, 할당을 생성합니다.

az role assignment create \
    --assignee-object-id "${HOST_PRINCIPAL_OBJECT_ID}" \
    --assignee-principal-type ServicePrincipal \
    --role "Azure Kubernetes Service Contributor Role" \
    --scope "${AKS_RESOURCE_ID}" \
    --output none

목록 명령을 다시 실행합니다. 주체 ID와 범위가 선택한 ID 및 AKS_RESOURCE_ID와 일치하면 계속 진행합니다. 역할 할당 전파에는 몇 분 정도 걸릴 수 있습니다.

5. 선택한 ID 확인

호스트를 부트스트랩하기 전에 선택한 ID가 정확한 대상 AKS 클러스터를 인증하고 읽을 수 있는지 확인합니다. ID 옵션에 대한 섹션만 완료합니다.

Azure Arc 관리 ID 확인

Bash 환경에서 비보안 AKS 리소스 ID를 Azure Arc 사용 가능한 서버에 전달합니다.

[[ "${AKS_RESOURCE_ID}" == /subscriptions/*/providers/Microsoft.ContainerService/managedClusters/* ]]
printf -v AKS_RESOURCE_ID_QUOTED '%q' "${AKS_RESOURCE_ID}"

ssh -t \
    -i "${SSH_PRIVATE_KEY_PATH}" \
    "${FLEX_HOST_SSH_TARGET}" \
    "export AKS_RESOURCE_ID=${AKS_RESOURCE_ID_QUOTED}; \
    exec bash -l"

Azure Arc 사용 가능한 서버에서 HIMDS(Hybrid Instance Metadata Service)에서 Azure Resource Manager 토큰을 요청하고 이를 사용하여 AKS 리소스를 읽습니다. 챌린지 토큰을 읽으려면 himds 그룹의 루트 권한 또는 멤버십이 필요합니다.

TOKEN_URL="${IDENTITY_ENDPOINT:-http://127.0.0.1:40342/metadata/identity/oauth2/token}?api-version=2019-11-01&resource=https%3A%2F%2Fmanagement.azure.com"

CHALLENGE_TOKEN_PATH="$(curl --silent --show-error \
    --dump-header - \
    --output /dev/null \
    --header Metadata:true \
    "${TOKEN_URL}" |
    sed -n 's/^[Ww][Ww][Ww]-[Aa]uthenticate: Basic realm=//p' |
    tr -d '\r')"

test -n "${CHALLENGE_TOKEN_PATH}"
CHALLENGE_TOKEN="$(sudo cat "${CHALLENGE_TOKEN_PATH}")"

TOKEN="$(curl --fail --silent --show-error \
    --header Metadata:true \
    --header "Authorization: Basic ${CHALLENGE_TOKEN}" \
    "${TOKEN_URL}" |
    jq -r '.access_token // empty')"

test -n "${TOKEN}"

AKS_ARM_HTTP="$(curl --silent --show-error \
    --output /dev/null \
    --write-out '%{http_code}' \
    --header "Authorization: Bearer ${TOKEN}" \
    "https://management.azure.com${AKS_RESOURCE_ID}?api-version=2025-07-01")"

unset CHALLENGE_TOKEN TOKEN
printf 'AKS_ARM_HTTP=%s\n' "${AKS_ARM_HTTP}"

예상 출력: AKS_ARM_HTTP=200. 실행 exit 하여 Azure Arc 사용 가능한 서버 세션을 종료합니다.

서비스 주체 확인

Bash 환경에서 서비스 주체 준비 단계에서 결합된 PEM 파일을 사용합니다. 새 세션을 시작하거나 기존 ID를 선택한 경우 보호된 경로를 다시 설정합니다.

export SP_CLIENT_CERTIFICATE_FILE="<protected-path-to-sp-client.pem>"
test -s "${SP_CLIENT_CERTIFICATE_FILE}"

파일이 없거나 비어 있으면 중지합니다. 공유 환경 파일에 이 경로를 추가하지 마세요.

먼저 격리된 Azure CLI 프로필을 사용하여 인증서 인증을 확인합니다. 하위 셀은 명령이 실패하고 일반 Azure CLI 로그인을 변경하지 않는 경우에도 임시 토큰 캐시를 제거합니다.

(
    set -e
    SP_AZURE_CONFIG_DIR="$(mktemp -d)"
    chmod 0700 "${SP_AZURE_CONFIG_DIR}"
    trap 'rm -rf -- "${SP_AZURE_CONFIG_DIR}"' EXIT
    export AZURE_CONFIG_DIR="${SP_AZURE_CONFIG_DIR}"

    az login \
        --service-principal \
        --username "${SP_CLIENT_ID}" \
        --certificate "${SP_CLIENT_CERTIFICATE_FILE}" \
        --tenant "${SP_TENANT_ID}" \
        --allow-no-subscriptions \
        --output none

    az account get-access-token \
        --resource https://management.azure.com/ \
        --query "{Tenant:tenant,ExpiresOn:expiresOn}" \
        --output table
)

테넌트가 SP_TENANT_ID와 일치하는지, 그리고 토큰이 만료되지 않았는지 확인합니다. 이 명령은 액세스 토큰이 아닌 테넌트 및 만료만 출력합니다. --allow-no-subscriptions에서는 Azure 액세스 권한을 부여하기 전에 인증을 테스트할 수 있습니다. 인증에 성공해도 AKS 클러스터를 읽거나 등록할 수 있는 권한이 증명되지는 않습니다.

4단계의 AKS 역할 할당이 전파된 후 정확한 대상 클러스터에 대한 액세스를 확인합니다.

(
    set -e
    SP_AZURE_CONFIG_DIR="$(mktemp -d)"
    chmod 0700 "${SP_AZURE_CONFIG_DIR}"
    trap 'rm -rf -- "${SP_AZURE_CONFIG_DIR}"' EXIT
    export AZURE_CONFIG_DIR="${SP_AZURE_CONFIG_DIR}"

    az login \
        --service-principal \
        --username "${SP_CLIENT_ID}" \
        --certificate "${SP_CLIENT_CERTIFICATE_FILE}" \
        --tenant "${SP_TENANT_ID}" \
        --output none

    az account set --subscription "${SUBSCRIPTION_ID}"

    az aks show \
        --resource-group "${RESOURCE_GROUP}" \
        --name "${CLUSTER_NAME}" \
        --query "{Name:name,ResourceId:id,ProvisioningState:provisioningState}" \
        --output table
)

반환된 리소스 ID가 AKS_RESOURCE_ID와 일치하고 프로비저닝 상태가 Succeeded인 경우에만 계속하세요. 인증에 성공했지만 클러스터 요청이 거부된 경우 다시 시도하기 전에 서비스 주체 개체 ID, 정확한 역할 할당 범위 및 전파를 확인합니다. 이 검사는 서비스 주체와 해당 인증서가 대상 클러스터를 읽을 수 있음을 증명합니다. 호스트는 AKS 클러스터에 flex 노드 연결에서 준비된 자격 증명을 사용합니다.

Azure VM 관리 ID 확인

Bash 환경에서 비보안 AKS 리소스 ID 및 ID 클라이언트 ID를 Azure VM에 전달합니다.

[[ "${AKS_RESOURCE_ID}" == /subscriptions/*/providers/Microsoft.ContainerService/managedClusters/* ]]
printf -v AKS_RESOURCE_ID_QUOTED '%q' "${AKS_RESOURCE_ID}"
printf -v HOST_IDENTITY_CLIENT_ID_QUOTED '%q' "${HOST_IDENTITY_CLIENT_ID}"

ssh -t \
    -i "${SSH_PRIVATE_KEY_PATH}" \
    "${FLEX_HOST_SSH_TARGET}" \
    "export AKS_RESOURCE_ID=${AKS_RESOURCE_ID_QUOTED}; \
    export HOST_IDENTITY_CLIENT_ID=${HOST_IDENTITY_CLIENT_ID_QUOTED}; \
    exec bash -l"

Azure VM에서 선택한 관리 ID에서 Azure Resource Manager 토큰을 요청하고 이를 사용하여 AKS 리소스를 읽습니다.

TOKEN_URL="http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https%3A%2F%2Fmanagement.azure.com%2F"

if [ -n "${HOST_IDENTITY_CLIENT_ID}" ]; then
    ENCODED_CLIENT_ID="$(jq -rn \
        --arg value "${HOST_IDENTITY_CLIENT_ID}" \
        '$value|@uri')"
    TOKEN_URL="${TOKEN_URL}&client_id=${ENCODED_CLIENT_ID}"
fi

TOKEN="$(curl --fail --silent --show-error \
    --header Metadata:true \
    "${TOKEN_URL}" |
    jq -r '.access_token // empty')"

test -n "${TOKEN}"

AKS_ARM_HTTP="$(curl --silent --show-error \
    --output /dev/null \
    --write-out '%{http_code}' \
    --header "Authorization: Bearer ${TOKEN}" \
    "https://management.azure.com${AKS_RESOURCE_ID}?api-version=2025-07-01")"

unset TOKEN
printf 'AKS_ARM_HTTP=%s\n' "${AKS_ARM_HTTP}"

예상 출력: AKS_ARM_HTTP=200. 사용자 할당 ID의 경우, 요청은 첨부 워크플로가 HOST_IDENTITY_CLIENT_ID에 전달하는 것과 동일한 --msi-client-id를 사용합니다. 실행 exit 하여 Azure VM 세션을 종료합니다.

호스트가 선택한 ID를 사용하여 Azure Machine 리소스를 등록할 때 첨부 파일 워크플로는 최종 엔드 투 엔드 검사를 수행합니다.

다음 단계

다음으로, 준비된 호스트를 flex 노드로 연결하고 확인합니다.