你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn。

将弹性节点附加到 AKS 群集(预览版)

Important

AKS 预览功能可在自助服务和自愿选择的基础上启用。 预览版按“现状”和“视供应情况”提供,它们不包括在服务级别协议和有限保证范围内。 AKS 预览功能是由客户支持尽最大努力部分覆盖。 因此,这些功能并不适合用于生产。 有关详细信息,请参阅以下支持文章:

准备Azure Kubernetes 服务 (AKS)群集、网络、弹性节点池、主机和标识后,启动主机并将其附加到目标池。

在本文中,你将了解:

  • 下载并验证 Flex node 发行版。
  • 通过使用所选Azure标识来检索新的池数据,启动主机。
  • 验证 Kubernetes 节点、Azure计算机、网络状态和代理服务。
  • 验证工作负荷放置、Kubernetes 回调和跨节点连接。

在 Linux 兼容的 Bash 环境中运行具有所需工具和网络访问权限的本文中的管理命令。 本文将该环境称为你的 Bash 环境。 加入集群的独立机器是 flex 节点主机;仅当某个步骤明确指示您这样做时,才在该主机上运行命令。

对于专用 AKS 群集,请从可以解析并访问专用 API 服务器的 Bash 环境运行每个 kubectl 命令。 当 Bash 环境具有所需的Azure和主机访问权限时,可以从 Bash 环境中运行Azure CLI、项目下载、SSH 和 SCP 命令。 弹性节点主机网络还必须解析并访问专用 API 终结点。

在您开始之前

  • 完成 配置网络并在 AKS 中创建弹性节点池。
  • 完成 准备弹性节点主机和标识。
  • 在你的 Bash 环境中安装 Azure CLI、aks-preview 扩展、与 scp 相差不超过一个次版本的 kubectl 版本、sha256sum、AKS_VERSION、jq、OpenSSH 客户端和 curl。
  • 对于托管标识或服务主体,请使用Azure帐户,该帐户可以检索所选弹性节点池的启动数据。
  • 确保 Bash 环境可以通过批准的 SSH 管理路径访问弹性节点主机。
  • 确保弹性节点主机能够通过 HTTPS 访问池引导数据中返回的发布工件终结点和引导工件终结点、Azure 资源管理器、Microsoft Entra ID 以及所选的 AKS API 终结点。

注释

不要在共享环境文件中存储凭据、证书、私钥、访问令牌、启动数据或 kubeconfig 内容。

加载部署环境

启动新的 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}"
export KUBECONFIG="${FLEXNODE_KUBECONFIG}"
install -d -m 0700 "${WORK_DIR:?Load the deployment environment first.}"

环境文件提供了本文要读取的共享部署值,包括 WORK_DIR(即你在 Bash 环境中用于存储本文下载内容和生成文件的目录)。 默认情况下,WORK_DIR 为 ~/.local/share/aksflexnode/<deployment-name>。 本文会推导出所需的其他变量。 如果尚未创建环境文件,请先 完成计划弹性节点部署 。 如果 shell 报告错误,请不要继续执行此步骤。

设置活动订阅并显示Azure、Kubernetes 和主机目标:

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

az aks show \
    --resource-group "${RESOURCE_GROUP}" \
    --name "${CLUSTER_NAME}" \
    --query "{Cluster:name,ResourceId:id,ApiServer:(privateFqdn || fqdn)}" \
    --output table
kubectl cluster-info

printf 'Recorded flex host: %s\n' "${FLEX_HOST_NAME}"
ssh -i "${SSH_PRIVATE_KEY_PATH}" "${FLEX_HOST_SSH_TARGET}" hostname

确认 ResourceId 匹配 AKS_RESOURCE_ID,Kubernetes 控制平面主机名与 ApiServer 匹配,SSH 命令返回 FLEX_HOST_NAME。 如果任何目标不匹配,请在传输或运行文件之前停止并更正环境文件、kubeconfig 或 SSH 目标。

下载并验证 Flex 节点发行版

  1. 标识主机体系结构并选择匹配的发布存档。

    HOST_ARCH="$(ssh \
        -i "${SSH_PRIVATE_KEY_PATH}" \
        "${FLEX_HOST_SSH_TARGET}" \
        uname -m)"
    export HOST_ARCH
    
    case "${HOST_ARCH}" in
        x86_64) export AGENT_ARCH="amd64" ;;
        aarch64|arm64) export AGENT_ARCH="arm64" ;;
        *)
            printf 'Unsupported host architecture: %s\n' "${HOST_ARCH}" >&2
            false
            ;;
    esac
    
    export AGENT_ARCHIVE="aks-flex-node-linux-${AGENT_ARCH}.tar.gz"
    printf 'Selected release archive: %s\n' "${AGENT_ARCHIVE}"
    
  2. 从所选发布版本中下载归档文件和校验和清单。

    curl --fail --location --silent --show-error \
        --proto '=https' \
        --tlsv1.2 \
        "https://github.com/Azure/AKSFlexNode/releases/download/${AKS_FLEX_NODE_VERSION}/${AGENT_ARCHIVE}" \
        --output "${WORK_DIR}/${AGENT_ARCHIVE}"
    
    curl --fail --location --silent --show-error \
        --proto '=https' \
        --tlsv1.2 \
        "https://github.com/Azure/AKSFlexNode/releases/download/${AKS_FLEX_NODE_VERSION}/checksums.txt" \
        --output "${WORK_DIR}/checksums.txt"
    
  3. 为归档文件恰好选择一个校验和条目,并验证该文件。

    AGENT_CHECKSUM_ENTRY="$(awk \
        -v file="${AGENT_ARCHIVE}" \
        '$2 == file {print}' \
        "${WORK_DIR}/checksums.txt")"
    export AGENT_CHECKSUM_ENTRY
    
    test "$(printf '%s\n' "${AGENT_CHECKSUM_ENTRY}" |
        sed '/^$/d' |
        wc -l)" -eq 1
    
    (
        cd "${WORK_DIR:?Load the deployment environment first.}"
        printf '%s\n' "${AGENT_CHECKSUM_ENTRY}" |
            sha256sum --check --strict -
    )
    
    export AGENT_SHA256="${AGENT_CHECKSUM_ENTRY%% *}"
    test -n "${AGENT_SHA256}"
    

    除非校验和命令显示该归档文件为 OK,否则请勿继续。

  4. 从同一发布标记下载启动脚本并验证其 Bash 语法。

    curl --fail --location --silent --show-error \
        --proto '=https' \
        --tlsv1.2 \
        "https://raw.githubusercontent.com/Azure/AKSFlexNode/${AKS_FLEX_NODE_VERSION}/scripts/bootstrap.sh" \
        --output "${WORK_DIR}/bootstrap.sh"
    
    chmod 0700 "${WORK_DIR}/bootstrap.sh"
    bash -n "${WORK_DIR}/bootstrap.sh"
    

    此版本当前不会为此脚本发布单独的校验和。 下载时不要通过管道传给 shell,使其与已验证的代理归档包版本保持一致,并在语法检查失败时停止。

获取当前池引导数据

托管标识和服务主体路径使用在 Bash 环境中检索的启动数据。 如果您选择了 Azure Arc 托管标识,请跳过本节。 Arc bootstrap 命令通过 Arc 机器标识获取最新数据。

对于托管标识或服务主体,在将文件传输到主机之前立即提取数据。 响应包含一个启动令牌,该令牌在一小时后过期。 不要打印响应或将其存储在笔记中。

az aks nodepool get-bootstrap-data \
    --resource-group "${RESOURCE_GROUP}" \
    --cluster-name "${CLUSTER_NAME}" \
    --name "${FLEX_POOL_NAME}" \
    --output json \
    > "${WORK_DIR}/base-config.json"

chmod 0600 "${WORK_DIR}/base-config.json"
test -s "${WORK_DIR}/base-config.json"

当 ${WORK_DIR}/base-config.json 存在且不为空时,继续。 在一小时内完成传输和主机启动。 如果令牌过期,请再次运行该命令并替换旧文件。

传输文件并准备主机

  1. 创建一个非机密主机交接文件。

    {
        printf 'export AGENT_ARCHIVE=%q\n' "${AGENT_ARCHIVE}"
        printf 'export AGENT_SHA256=%q\n' "${AGENT_SHA256}"
        printf 'export AKS_FLEX_NODE_VERSION=%q\n' "${AKS_FLEX_NODE_VERSION}"
        printf 'export AKS_RESOURCE_ID=%q\n' "${AKS_RESOURCE_ID}"
        printf 'export FLEX_POOL_NAME=%q\n' "${FLEX_POOL_NAME}"
        printf 'export FLEX_HOST_PRIVATE_IP=%q\n' "${FLEX_HOST_PRIVATE_IP}"
        printf 'export HOST_IDENTITY_CLIENT_ID=%q\n' "${HOST_IDENTITY_CLIENT_ID:-}"
        printf 'export SP_TENANT_ID=%q\n' "${SP_TENANT_ID:-}"
        printf 'export SP_CLIENT_ID=%q\n' "${SP_CLIENT_ID:-}"
    } > "${WORK_DIR}/host-bootstrap.env"
    
    chmod 0600 "${WORK_DIR}/host-bootstrap.env"
    
  2. 将已验证的发布文件和移交文件复制到主机。

    scp -i "${SSH_PRIVATE_KEY_PATH}" \
        "${WORK_DIR}/${AGENT_ARCHIVE}" \
        "${WORK_DIR}/bootstrap.sh" \
        "${WORK_DIR}/host-bootstrap.env" \
        "${FLEX_HOST_SSH_TARGET}:/tmp/"
    
  3. 对于托管标识或服务主体,还请复制受保护的引导数据:

    scp -i "${SSH_PRIVATE_KEY_PATH}" \
        "${WORK_DIR}/base-config.json" \
        "${FLEX_HOST_SSH_TARGET}:/tmp/"
    
  4. 连接到主机并启动 root Shell:

    ssh -i "${SSH_PRIVATE_KEY_PATH}" "${FLEX_HOST_SSH_TARGET}"
    sudo -i
    
  5. 加载非机密交接值并验证已传输的文件:

    source /tmp/host-bootstrap.env
    chmod 0600 "/tmp/${AGENT_ARCHIVE}" /tmp/host-bootstrap.env
    chmod 0700 /tmp/bootstrap.sh
    bash -n /tmp/bootstrap.sh
    printf '%s  %s\n' \
        "${AGENT_SHA256}" \
        "/tmp/${AGENT_ARCHIVE}" |
        sha256sum --check --strict -
    

    当校验和命令报告该归档文件为 OK 时,继续。 如果校验和或脚本语法检查失败,则停止。

  6. 对于托管标识或服务主体,请安装引导数据:

    install -d -o root -g root -m 0700 /etc/aks-flex-node
    install -o root -g root -m 0600 \
        /tmp/base-config.json \
        /etc/aks-flex-node/base-config.json
    test -s /etc/aks-flex-node/base-config.json
    

启动主机

仅完成与前一篇文章中配置的身份相匹配的章节。

仅当前文已验证以下条件均已满足后,才使用本节:Arc 计算机资源与 SSH 主机匹配,himdsd 处于活动状态,针对对应的确切 AKS 资源执行的 HIMDS 验证返回 HTTP 200,并且已存在作用域为 AKS 的角色分配。 该路径通过 Arc 计算机身份获取最新的引导数据,并且不会使用 Bash 环境中的 base-config.json 文件。

CONFIG_OVERRIDES="$(jq -cn \
    --arg nodeIP "${FLEX_HOST_PRIVATE_IP}" \
    '{node:{kubelet:{nodeIP:$nodeIP}}}')"
export CONFIG_OVERRIDES

bash /tmp/bootstrap.sh \
    --auth arc \
    --fetch-bootstrap-data \
    --cluster-resource-id "${AKS_RESOURCE_ID}" \
    --agent-pool-name "${FLEX_POOL_NAME}" \
    --agent-url "file:///tmp/${AGENT_ARCHIVE}" \
    --agent-sha256 "${AGENT_SHA256}" \
    --config-overrides "${CONFIG_OVERRIDES}"

当输出显示 Arc preflight: OK、机器注册完成,并且引导脚本报告弹性节点代理服务已启动时,继续。 如果 bootstrap 无法检索数据,请验证 Arc 连接、himdsd、AKS 范围的角色分配以及主机对 Azure 资源管理器的访问权限。

删除临时发布文件

引导成功后,从主机上删除临时脚本、归档文件和移交文件:

rm -f \
    "/tmp/${AGENT_ARCHIVE}" \
    /tmp/bootstrap.sh \
    /tmp/base-config.json \
    /tmp/host-bootstrap.env
exit
exit

第一个 exit 离开根 shell。 第二个关闭 SSH 会话并返回到 Bash 环境。

删除 Bash 环境中的副本:

rm -f \
    "${WORK_DIR:?Load the deployment environment first.}/${AGENT_ARCHIVE}" \
    "${WORK_DIR}/bootstrap.sh" \
    "${WORK_DIR}/base-config.json" \
    "${WORK_DIR}/host-bootstrap.env" \
    "${WORK_DIR}/checksums.txt"

在主机保持附加状态时,保留 /etc/aks-flex-node 和服务主体凭据。 运行中的智能体使用此配置进行节点和 Azure 计算机协调。

验证 Kubernetes 节点

将节点名称设置为共享环境中记录的 Linux 主机名。 首先,等待创建 Node 对象,然后等待它准备就绪:

export FLEX_NODE_NAME="$(printf '%s' "${FLEX_HOST_NAME}" | tr -d '[:space:]' | tr '[:upper:]' '[:lower:]')"

kubectl wait \
    --for=create \
    "node/${FLEX_NODE_NAME}" \
    --timeout=5m

kubectl wait \
    --for=condition=Ready \
    "node/${FLEX_NODE_NAME}" \
    --timeout=10m

kubectl get node "${FLEX_NODE_NAME}" -o wide

当节点为 Ready 时继续。 如果节点未创建或未准备就绪,请在重试启动之前验证启动输出、API 连接和代理服务。

验证 Azure Machine 资源

  1. 列出目标弹性节点池中的计算机。

    az aks machine list \
        --resource-group "${RESOURCE_GROUP}" \
        --cluster-name "${CLUSTER_NAME}" \
        --nodepool-name "${FLEX_POOL_NAME}" \
        --query "[].{name:name,state:properties.provisioningState,nodeName:properties.kubernetes.nodeName,version:properties.kubernetes.currentOrchestratorVersion}" \
        --output table
    
  2. 查找注册了已准备好的 Kubernetes 节点的计算机:

    FLEX_MACHINE_NAME="$(az aks machine list \
        --resource-group "${RESOURCE_GROUP}" \
        --cluster-name "${CLUSTER_NAME}" \
        --nodepool-name "${FLEX_POOL_NAME}" \
        --query "[?properties.kubernetes.nodeName=='${FLEX_NODE_NAME}'].name | [0]" \
        --output tsv)"
    export FLEX_MACHINE_NAME
    
    printf 'Machine: %s\n' "${FLEX_MACHINE_NAME}"
    

    仅当该命令恰好返回一个机器名称时,才继续。

  3. 显示该机器:

    az aks machine show \
        --resource-group "${RESOURCE_GROUP}" \
        --cluster-name "${CLUSTER_NAME}" \
        --nodepool-name "${FLEX_POOL_NAME}" \
        --machine-name "${FLEX_MACHINE_NAME}" \
        --output yaml
    

    当机器存在、引用 FLEX_NODE_NAME 且其预配状态为成功时,继续。 记录用于生命周期操作的机器名称:

    set_flexnode_env FLEX_MACHINE_NAME "${FLEX_MACHINE_NAME}"
    

验证弹性节点网络

  1. 显示 Flex 站点、Pod CIDR 和 WireGuard 公钥。

    kubectl get node "${FLEX_NODE_NAME}" \
        -L net.unbounded-cloud.io/site \
        -o wide
    
    kubectl get node "${FLEX_NODE_NAME}" \
        -o jsonpath='{.metadata.name}{" site="}{.metadata.labels.net\.unbounded-cloud\.io/site}{" podCIDR="}{.spec.podCIDR}{" wg="}{.metadata.annotations.net\.unbounded-cloud\.io/wg-pubkey}{"\n"}'
    
  2. 验证站点及相关的 Unbounded-Net 网络资源。

    kubectl get \
        sites,sitenodeslices,gatewaypools,sitegatewaypoolassignments,gatewaypoolpeerings \
        -o wide
    
  3. 显示已调度到 flex 节点的 Unbounded-Net Pod。

    kubectl get pods --all-namespaces \
        --field-selector "spec.nodeName=${FLEX_NODE_NAME}" \
        -o wide
    

除非符合以下条件,否则不要继续进行工作负载验证:

  • 节点为 Ready.
  • 该站点是网络文章中配置的“无界”灵活站点。
  • Pod CIDR 属于计划中的 FLEX_POD_CIDR 范围。
  • WireGuard 公钥已填入。
  • cluster-flex-private-l3 SitePeering 引用了 cluster 和 flex-site 站点。
  • 节点上返回的每个 Unbounded-Net Pod 均为 Running。
  • 对于公共 WireGuard 拓扑,已存在预期的网关池对等连接。

验证弹性节点代理

等待最多一分钟,直到服务变为活动状态。 如果未显示,则显示服务状态和最近日志:

ssh -i "${SSH_PRIVATE_KEY_PATH}" "${FLEX_HOST_SSH_TARGET}" \
    'set -euo pipefail
     for attempt in {1..12}; do
         if sudo systemctl is-active --quiet aks-flex-node-agent; then
             sudo systemctl show aks-flex-node-agent \
                 -p ActiveState \
                 -p SubState \
                 -p Result \
                 -p NRestarts
             exit 0
         fi
         sleep 5
     done

     sudo systemctl show aks-flex-node-agent \
         -p ActiveState \
         -p SubState \
         -p Result \
         -p NRestarts
     sudo journalctl -u aks-flex-node-agent --no-pager -n 80
     exit 1'

当输出包含ActiveState=active和SubState=runningResult=success时继续。

如果代理因无法列出 MachineOperation 资源而重复重启,请返回到配置网络中的临时弹性守护程序 RBAC 步骤,并在 AKS 中创建弹性节点池,验证角色和绑定是否存在,然后重启代理:

ssh -i "${SSH_PRIVATE_KEY_PATH}" "${FLEX_HOST_SSH_TARGET}" \
    'sudo systemctl restart aks-flex-node-agent'

验证工作负载部署位置和连接性

创建验证工作负荷

创建专用命名空间。 如果此命名空间已存在,请在重试之前清理以前的验证运行。

export VALIDATION_NAMESPACE="flex-node-validation"

if kubectl get namespace "${VALIDATION_NAMESPACE}" >/dev/null 2>&1; then
    printf 'Validation namespace already exists: %s\n' \
        "${VALIDATION_NAMESPACE}" >&2
    false
fi

kubectl create namespace "${VALIDATION_NAMESPACE}"
kubectl label namespace "${VALIDATION_NAMESPACE}" \
    app.kubernetes.io/managed-by=flex-node-article

创建 Kubernetes 计划程序放置在弹性节点上的 HTTP 服务器,并通过 ClusterIP 服务公开它:

kubectl --namespace "${VALIDATION_NAMESPACE}" run flex-http-server \
    --image=busybox:1.36 \
    --restart=Never \
    --labels app=flex-http \
    --overrides="{\"spec\":{\"nodeSelector\":{\"kubernetes.io/hostname\":\"${FLEX_NODE_NAME}\"},\"tolerations\":[{\"operator\":\"Exists\"}]}}" \
    --command -- sh -c \
    'mkdir -p /www; echo flex-network-ok >/www/index.html; exec httpd -f -p 8080 -h /www'

kubectl --namespace "${VALIDATION_NAMESPACE}" wait \
    --for=condition=Ready \
    pod/flex-http-server \
    --timeout=3m

kubectl --namespace "${VALIDATION_NAMESPACE}" expose pod flex-http-server \
    --name=flex-http-service \
    --port=8080 \
    --target-port=8080

验证回调和本地服务连通性

使用 Kubernetes API 服务器回调路径检查日志和命令执行:

kubectl --namespace "${VALIDATION_NAMESPACE}" logs flex-http-server --tail=5
kubectl --namespace "${VALIDATION_NAMESPACE}" exec flex-http-server -- \
    sh -c 'printf "exec-callback-ok\n"'

获取 ClusterIP,并从弹性节点工作负载访问该服务:

SERVICE_IP="$(kubectl --namespace "${VALIDATION_NAMESPACE}" \
    get service flex-http-service \
    --output jsonpath='{.spec.clusterIP}')"
export SERVICE_IP

kubectl --namespace "${VALIDATION_NAMESPACE}" exec flex-http-server -- \
    wget -qO- "http://${SERVICE_IP}:8080"

预期响应为:

flex-network-ok

验证端口转发

在当前终端中,通过 Kubernetes API 服务器转发本地端口。 此命令使用前面加载的部署环境和 kubeconfig:

kubectl --namespace "${VALIDATION_NAMESPACE}" \
    port-forward pod/flex-http-server 18080:8080

在第二个终端中,请求转发的终结点:

curl -fsS http://127.0.0.1:18080

预期的响应为 flex-network-ok。 在检查后,在第一个终端中按 Ctrl+C。

验证来自 AKS 托管节点的连接

查找已就绪的 AKS 托管系统节点:

SYSTEM_NODE="$(kubectl get nodes \
    --selector agentpool=systempool \
    --output json |
    jq -r '
        .items[]
        | select(any(.status.conditions[];
            .type == "Ready" and .status == "True"))
        | .metadata.name
    ' |
    head -n 1)"
export SYSTEM_NODE

test -n "${SYSTEM_NODE}"
printf 'Managed-node test target: %s\n' "${SYSTEM_NODE}"

在该节点上运行客户端 Pod 并检查预期的响应:

kubectl --namespace "${VALIDATION_NAMESPACE}" run system-http-client \
    --image=busybox:1.36 \
    --restart=Never \
    --overrides="{\"spec\":{\"nodeSelector\":{\"kubernetes.io/hostname\":\"${SYSTEM_NODE}\"}}}" \
    --command -- sh -c \
    "test \"\$(wget -qO- http://${SERVICE_IP}:8080)\" = flex-network-ok"

kubectl --namespace "${VALIDATION_NAMESPACE}" wait \
    --for=jsonpath='{.status.phase}'=Succeeded \
    pod/system-http-client \
    --timeout=3m

kubectl --namespace "${VALIDATION_NAMESPACE}" \
    get pod flex-http-server system-http-client -o wide

处于 Ready 状态的 Kubernetes 节点表示节点已注册。 它本身并不能证明工作负荷网络、回调操作或Azure生命周期操作。

清理验证工作负荷

仅删除本文中创建的临时资源。

kubectl delete namespace "${VALIDATION_NAMESPACE}"

后续步骤

接下来, 管理、更新、升级或删除附加的弹性节点。