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

排查已启用 Azure Arc 的 Kubernetes 群集的扩展问题

本文档提供了与群集扩展(例如 GitOps (Flux v2) 和 Open Service Mesh)相关的常见问题的故障排除提示。

有关排查已启用 Azure Arc 的 Kubernetes 的常规问题的帮助,请参阅排查已启用 Azure Arc 的 Kubernetes 问题

GitOps (Flux v2)

注意

Flux v2 扩展可用于启用 Azure Arc 的 Kubernetes 群集或 Azure Kubernetes 服务 (AKS) 群集。 无论群集类型如何,这些故障排除技巧通常都适用。

有关对 fluxConfigurations 资源问题进行故障排除的常规帮助,请运行以下 Azure CLI 命令并指定 --debug 参数:

az provider show -n Microsoft.KubernetesConfiguration --debug
az k8s-configuration flux create <parameters> --debug

Webhook/试运行错误

如果看到 Flux 无法处理错误(如 dry-run failed, error: admission webhook "<webhook>" does not support dry run),你可以查找 ValidatingWebhookConfigurationMutatingWebhookConfiguration 并将 sideEffects 设置为 NoneNoneOnDryRun 来解决此问题:

有关详细信息,请参阅如何解决 webhook does not support dry run 错误?

安装 microsoft.flux 扩展时出错

microsoft.flux 扩展将 Flux 控制器和 Azure GitOps 代理安装到已启用 Azure Arc 的 Kubernetes 或 Azure Kubernetes 服务 (AKS) 群集。 如果尚未在群集中安装该扩展,并且你为该群集创建了 GitOps 配置资源,则会自动安装该扩展。

如果你在安装过程中遇到错误,或者扩展处于失败状态,请确保群集没有任何限制创建 flux-system 命名空间或该命名空间中的资源的策略。

对于 AKS 群集,确保订阅启用了 Microsoft.ContainerService/AKS-ExtensionManager 功能标志。

az feature register --namespace Microsoft.ContainerService --name AKS-ExtensionManager

之后,运行此命令以确定是否还有其他问题。 对于已启用 Arc 的群集,将群集类型 (-t) 参数设置为 connectedClusters;对于 AKS 群集,将群集类型参数设置为 managedClusters。 如果 microsoft.flux 扩展是在创建 GitOps 配置期间自动安装的,则该扩展的名称将是“flux”。 请查看 statuses 对象了解信息。

az k8s-extension show -g <RESOURCE_GROUP> -c <CLUSTER_NAME> -n flux -t <connectedClusters or managedClusters>

显示的结果可以帮助你确定出现的问题以及修复方式。 可能的修正操作包括:

  • 通过运行 az k8s-extension delete --force -g <RESOURCE_GROUP> -c <CLUSTER_NAME> -n flux -t <managedClusters OR connectedClusters> 强制删除扩展
  • 通过运行 helm uninstall flux -n flux-system 卸载 Helm 版本
  • 通过运行 kubectl delete namespaces flux-system 从群集中删除 flux-system 命名空间

之后,可以重新创建 Flux 配置(这会自动安装 microsoft.flux 扩展),也可以手动重新安装 Flux 扩展。

在已启用 Microsoft Entra Pod 标识的群集中安装 microsoft.flux 扩展时出错

如果尝试在已启用 Microsoft Entra Pod 标识的群集中安装 Flux 扩展,则扩展-代理 Pod 中可能会发生错误:

{"Message":"2021/12/02 10:24:56 Error: in getting auth header : error {adal: Refresh request failed. Status Code = '404'. Response body: no azure identity found for request clientID <REDACTED>\n}","LogType":"ConfigAgentTrace","LogLevel":"Information","Environment":"prod","Role":"ClusterConfigAgent","Location":"westeurope","ArmId":"/subscriptions/<REDACTED>/resourceGroups/<REDACTED>/providers/Microsoft.Kubernetes/managedclusters/<REDACTED>","CorrelationId":"","AgentName":"FluxConfigAgent","AgentVersion":"0.4.2","AgentTimestamp":"2021/12/02 10:24:56"}

扩展状态也返回为 Failed

"{\"status\":\"Failed\",\"error\":{\"code\":\"ResourceOperationFailure\",\"message\":\"The resource operation completed with terminal provisioning state 'Failed'.\",\"details\":[{\"code\":\"ExtensionCreationFailed\",\"message\":\" error: Unable to get the status from the local CRD with the error : {Error : Retry for given duration didn't get any results with err {status not populated}}\"}]}}",

在这种情况下,扩展代理 pod 会尝试从群集上的 IMDS 获取其令牌。 但令牌请求会被 pod 身份拦截。 可以通过将 升级到最新版本 () 的 microsoft.flux 扩展来解决此问题。

在 AKS 群集中安装 microsoft.flux 扩展时出现 kubelet 身份问题

使用 AKS 群集时,身份验证选项之一是使用用户分配的托管标识的 kubelet 标识。 在连接到 Azure 容器注册表等 Azure 资源时,使用 kubelet 标识可以减少操作开销并提高安全性。

若要让 Flux 使用 kubelet 标识,请在安装 Flux 扩展时添加参数 --config useKubeletIdentity=true

az k8s-extension create --resource-group <resource-group> --cluster-name <cluster-name> --cluster-type managedClusters --name flux --extension-type microsoft.flux --config useKubeletIdentity=true

确保满足 microsoft.flux 扩展安装的内存和 CPU 要求

使用 microsoft.flux 扩展在 Kubernetes 群集中安装的控制器需要 CPU 和内存资源才能在 Kubernetes 群集节点上正确进行计划。 确保群集能够满足可能请求的最低内存和 CPU 资源。 另请注意此处显示的潜在 CPU 和内存资源要求的最大限制。

容器名 最小 CPU 数量 最小内存量 最大 CPU 数量 最大内存
fluxconfig-agent 5 m 30 Mi 50 m 150 Mi
fluxconfig-controller 5 m 30 Mi 100 m 150 Mi
fluent-bit 5 m 30 Mi 20 m 150 Mi
helm-controller 100 m 64 Mi 1000 m 1 Gi
source-controller 50 m 64 Mi 1000 m 1 Gi
kustomize-controller 100 m 64 Mi 1000 m 1 Gi
notification-controller 100 m 64 Mi 1000 m 1 Gi
image-automation-controller 100 m 64 Mi 1000 m 1 Gi
image-reflector-controller 100 m 64 Mi 1000 m 1 Gi

如果启用了自定义或内置 Azure Gatekeeper 策略(例如 Kubernetes cluster containers CPU and memory resource limits should not exceed the specified limits)来限制 Kubernetes 群集上的容器的资源,请确保策略上的资源限制大于此处显示的限制,或者确保 flux-system 命名空间是策略分配中的 excludedNamespaces 参数的一部分。

Flux v1

注意

建议尽快迁移到 Flux v2。 自 2025 年 5 月 24 日起,将不再支持 2024 年 1 月 1 日之前创建的基于 Flux v1 的群集配置资源。 从 2024 年 1 月 1 日开始,你将无法创建新的基于 Flux v1 的群集配置资源。

为了帮助排查与 Flux v1 中的 sourceControlConfigurations 资源相关的问题,请运行以下 Azure CLI 命令并指定 --debug 参数:

az provider show -n Microsoft.KubernetesConfiguration --debug
az k8s-configuration create <parameters> --debug

Azure Monitor 容器见解

本部分提供对已启用 Azure Arc 的 Kubernetes 群集的 Azure Monitor 容器见解问题进行故障排除的帮助。

为 Canonical Charmed Kubernetes 群集启用特权模式

Azure Monitor 容器见解需要在特权模式下运行其 DaemonSet。 如果要成功设置用于监视的 Canonical Charmed Kubernetes 群集,请运行以下命令:

juju config kubernetes-worker allow-privileged=true

无法在 Oracle Linux 9.x 上安装 Azure Monitor 代理 (AMA)

尝试在 Oracle Linux (RHEL) 9.x Kubernetes 群集上安装 Azure Monitor Agent (AMA) 时,AMA Pod 和 AMA-RS Pod 可能会由于 Pod 中存在 addon-token-adapter 容器而无法正常工作。 如果出现此错误,则检查 ama-logs-rs pod addon-token-adapter container 的日志时会看到如下输出:

Command: kubectl -n kube-system logs ama-logs-rs-xxxxxxxxxx-xxxxx -c addon-token-adapter
 
Error displayed: error modifying iptable rules: error adding rules to custom chain: running [/sbin/iptables -t nat -N aad-metadata --wait]: exit status 3: modprobe: can't change directory to '/lib/modules': No such file or directory

iptables v1.8.9 (legacy): can't initialize iptables table `nat': Table does not exist (do you need to insmod?)

Perhaps iptables or your kernel needs to be upgraded.

出现此错误的原因是安装扩展需要 iptable_nat 模块,但该模块不会自动加载到 Oracle Linux (RHEL) 9.x 发行版中。

若要解决此问题,必须使用 modprobe 命令 sudo modprobe iptables_nat 在群集中的每个节点上显式加载 iptables_nat 模块。 登录到每个节点并手动添加 iptable_nat 模块后,重试 AMA 安装。

注意

执行此步骤不会使 iptables_nat 模块持久化。

启用了 Azure Arc 的开放式服务网格

本部分提供的命令可用于验证群集上的Open Service Mesh (OSM) 扩展组件的部署并对其进行故障排除。

检查 OSM 控制器部署

kubectl get deployment -n arc-osm-system --selector app=osm-controller

如果 OSM 控制器运行正常,则会看到如下输出:

NAME             READY   UP-TO-DATE   AVAILABLE   AGE
osm-controller   1/1     1            1           59m

检查 OSM 控制器 Pod

kubectl get pods -n arc-osm-system --selector app=osm-controller

如果 OSM 控制器运行正常,则会看到如下输出:

NAME                            READY   STATUS    RESTARTS   AGE
osm-controller-b5bd66db-wglzl   0/1     Evicted   0          61m
osm-controller-b5bd66db-wvl9w   1/1     Running   0          31m

即使一个控制器在某个时间点被逐出,也会有另一个控制器(即 READY 1/1Running0 的控制器)重启。 如果 READY 列并非显示 1/1,则表示服务网格处于中断状态。 如果 READY 列显示 0/1,则表示控制平面容器崩溃。

使用以下命令检查控制器日志:

kubectl logs -n arc-osm-system -l app=osm-controller

如果 READY 列下的 / 后面显示大于 1 的数字,则表示安装了挎斗。 OSM 控制器通常不适用于附加的挎斗。

检查 OSM 控制器服务

kubectl get service -n arc-osm-system osm-controller

如果 OSM 控制器运行正常,将看到以下输出:

NAME             TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)              AGE
osm-controller   ClusterIP   10.0.31.254   <none>        15128/TCP,9092/TCP   67m

注意

CLUSTER-IP 将有所不同。 服务 NAMEPORT(S) 应与此处显示的内容匹配。

检查 OSM 控制器终结点

kubectl get endpoints -n arc-osm-system osm-controller

如果 OSM 控制器运行正常,则会看到如下输出:

NAME             ENDPOINTS                              AGE
osm-controller   10.240.1.115:9092,10.240.1.115:15128   69m

如果群集针对 osm-controller 不包含 ENDPOINTS,则表明控制平面运行不正常。 这种运行不正常的状态意味着控制器 Pod 崩溃或者从未正确部署。

检查 OSM 注入程序部署

kubectl get deployments -n arc-osm-system osm-injector

如果 OSM 注入程序运行正常,则会看到如下输出:

NAME           READY   UP-TO-DATE   AVAILABLE   AGE
osm-injector   1/1     1            1           73m

检查 OSM 注入程序 pod

kubectl get pod -n arc-osm-system --selector app=osm-injector

如果 OSM 注入程序运行正常,则会看到如下输出:

NAME                            READY   STATUS    RESTARTS   AGE
osm-injector-5986c57765-vlsdk   1/1     Running   0          73m

READY 列必须是 1/1。 任何其他值都表示 OSM 注入程序 pod 运行不正常。

检查 OSM 注入程序服务

kubectl get service -n arc-osm-system osm-injector

如果 OSM 注入程序运行正常,则会看到如下输出:

NAME           TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)    AGE
osm-injector   ClusterIP   10.0.39.54   <none>        9090/TCP   75m

确保对于 osm-injector 服务列出的 IP 地址为 9090。 不应该有 EXTERNAL-IP

检查 OSM 注入程序终结点

kubectl get endpoints -n arc-osm-system osm-injector

如果 OSM 注入程序运行正常,则会看到如下输出:

NAME           ENDPOINTS           AGE
osm-injector   10.240.1.172:9090   75m

要使 OSM 正常工作,osm-injector 必须至少有一个终结点。 OSM 注入程序终结点的 IP 地址会有所不同,但端口 9090 必须相同。

检查“验证”Webhook 和“变异”Webhook

kubectl get ValidatingWebhookConfiguration --selector app=osm-controller

如果验证 Webhook 运行正常,则会看到如下输出:

NAME                     WEBHOOKS   AGE
osm-validator-mesh-osm   1          81m
kubectl get MutatingWebhookConfiguration --selector app=osm-injector

如果变异 Webhook 运行正常,则会看到如下输出:

NAME                  WEBHOOKS   AGE
arc-osm-webhook-osm   1          102m

通过运行以下命令,检查验证 Webhook 的服务和 CA 捆绑包:

kubectl get ValidatingWebhookConfiguration osm-validator-mesh-osm -o json | jq '.webhooks[0].clientConfig.service'

配置良好的验证 Webhook 配置将具有如下输出:

{
  "name": "osm-config-validator",
  "namespace": "arc-osm-system",
  "path": "/validate",
  "port": 9093
}

通过运行以下命令,检查“变异”Webhook 的服务和 CA 捆绑包:

kubectl get MutatingWebhookConfiguration arc-osm-webhook-osm -o json | jq '.webhooks[0].clientConfig.service'

配置良好的变异 Webhook 配置将具有如下输出:

{
  "name": "osm-injector",
  "namespace": "arc-osm-system",
  "path": "/mutate-pod-creation",
  "port": 9090
}

使用以下命令来检查 OSM 控制器是否为“验证”(或“变异”)Webhook 提供了 CA 捆绑包:

kubectl get ValidatingWebhookConfiguration osm-validator-mesh-osm -o json | jq -r '.webhooks[0].clientConfig.caBundle' | wc -c
kubectl get MutatingWebhookConfiguration arc-osm-webhook-osm -o json | jq -r '.webhooks[0].clientConfig.caBundle' | wc -c

示例输出:

1845

输出中的这个数字表示字节数或 CA 捆绑包的大小。 如果输出为空、0 或小于 1000 的数字,则表示 CA 捆绑包未正确预配。 如果没有正确的 CA 捆绑包,那么 ValidatingWebhook 将引发错误。

检查 osm-mesh-config 资源

检查资源是否存在:

kubectl get meshconfig osm-mesh-config -n arc-osm-system

检查 OSM MeshConfig 的内容:

kubectl get meshconfig osm-mesh-config -n arc-osm-system -o yaml

此时会看到与下面类似的输出:

apiVersion: config.openservicemesh.io/v1alpha1
kind: MeshConfig
metadata:
  creationTimestamp: "0000-00-00A00:00:00A"
  generation: 1
  name: osm-mesh-config
  namespace: arc-osm-system
  resourceVersion: "2494"
  uid: 6c4d67f3-c241-4aeb-bf4f-b029b08faa31
spec:
  certificate:
    certKeyBitSize: 2048
    serviceCertValidityDuration: 24h
  featureFlags:
    enableAsyncProxyServiceMapping: false
    enableEgressPolicy: true
    enableEnvoyActiveHealthChecks: false
    enableIngressBackendPolicy: true
    enableMulticlusterMode: false
    enableRetryPolicy: false
    enableSnapshotCacheMode: false
    enableWASMStats: true
  observability:
    enableDebugServer: false
    osmLogLevel: info
    tracing:
      enable: false
  sidecar:
    configResyncInterval: 0s
    enablePrivilegedInitContainer: false
    logLevel: error
    resources: {}
  traffic:
    enableEgress: false
    enablePermissiveTrafficPolicyMode: true
    inboundExternalAuthorization:
      enable: false
      failureModeAllow: false
      statPrefix: inboundExtAuthz
      timeout: 1s
    inboundPortExclusionList: []
    outboundIPRangeExclusionList: []
    outboundPortExclusionList: []
kind: List
metadata:
  resourceVersion: ""
  selfLink: ""

osm-mesh-config 资源值:

密钥 类型 默认值 Kubectl Patch 命令示例
spec.traffic.enableEgress bool false kubectl patch meshconfig osm-mesh-config -n arc-osm-system -p '{"spec":{"traffic":{"enableEgress":false}}}' --type=merge
spec.traffic.enablePermissiveTrafficPolicyMode bool true kubectl patch meshconfig osm-mesh-config -n arc-osm-system -p '{"spec":{"traffic":{"enablePermissiveTrafficPolicyMode":true}}}' --type=merge
spec.traffic.outboundPortExclusionList array [] kubectl patch meshconfig osm-mesh-config -n arc-osm-system -p '{"spec":{"traffic":{"outboundPortExclusionList":[6379,8080]}}}' --type=merge
spec.traffic.outboundIPRangeExclusionList array [] kubectl patch meshconfig osm-mesh-config -n arc-osm-system -p '{"spec":{"traffic":{"outboundIPRangeExclusionList":["10.0.0.0/32","1.1.1.1/24"]}}}' --type=merge
spec.traffic.inboundPortExclusionList array [] kubectl patch meshconfig osm-mesh-config -n arc-osm-system -p '{"spec":{"traffic":{"inboundPortExclusionList":[6379,8080]}}}' --type=merge
spec.certificate.serviceCertValidityDuration string "24h" kubectl patch meshconfig osm-mesh-config -n arc-osm-system -p '{"spec":{"certificate":{"serviceCertValidityDuration":"24h"}}}' --type=merge
spec.observability.enableDebugServer bool false kubectl patch meshconfig osm-mesh-config -n arc-osm-system -p '{"spec":{"observability":{"enableDebugServer":false}}}' --type=merge
spec.observability.osmLogLevel 字符串 "info" kubectl patch meshconfig osm-mesh-config -n arc-osm-system -p '{"spec":{"observability":{"tracing":{"osmLogLevel": "info"}}}}' --type=merge
spec.observability.tracing.enable bool false kubectl patch meshconfig osm-mesh-config -n arc-osm-system -p '{"spec":{"observability":{"tracing":{"enable":true}}}}' --type=merge
spec.sidecar.enablePrivilegedInitContainer bool false kubectl patch meshconfig osm-mesh-config -n arc-osm-system -p '{"spec":{"sidecar":{"enablePrivilegedInitContainer":true}}}' --type=merge
spec.sidecar.logLevel string "error" kubectl patch meshconfig osm-mesh-config -n arc-osm-system -p '{"spec":{"sidecar":{"logLevel":"error"}}}' --type=merge
spec.featureFlags.enableWASMStats bool "true" kubectl patch meshconfig osm-mesh-config -n arc-osm-system -p '{"spec":{"featureFlags":{"enableWASMStats":"true"}}}' --type=merge
spec.featureFlags.enableEgressPolicy bool "true" kubectl patch meshconfig osm-mesh-config -n arc-osm-system -p '{"spec":{"featureFlags":{"enableEgressPolicy":"true"}}}' --type=merge
spec.featureFlags.enableMulticlusterMode bool "false" kubectl patch meshconfig osm-mesh-config -n arc-osm-system -p '{"spec":{"featureFlags":{"enableMulticlusterMode":"false"}}}' --type=merge
spec.featureFlags.enableSnapshotCacheMode bool "false" kubectl patch meshconfig osm-mesh-config -n arc-osm-system -p '{"spec":{"featureFlags":{"enableSnapshotCacheMode":"false"}}}' --type=merge
spec.featureFlags.enableAsyncProxyServiceMapping bool "false" kubectl patch meshconfig osm-mesh-config -n arc-osm-system -p '{"spec":{"featureFlags":{"enableAsyncProxyServiceMapping":"false"}}}' --type=merge
spec.featureFlags.enableIngressBackendPolicy bool "true" kubectl patch meshconfig osm-mesh-config -n arc-osm-system -p '{"spec":{"featureFlags":{"enableIngressBackendPolicy":"true"}}}' --type=merge
spec.featureFlags.enableEnvoyActiveHealthChecks bool "false" kubectl patch meshconfig osm-mesh-config -n arc-osm-system -p '{"spec":{"featureFlags":{"enableEnvoyActiveHealthChecks":"false"}}}' --type=merge

检查命名空间

注意

arc-osm-system 命名空间永远不会加入服务网格,并且永远不会使用如下所示的键/值进行标记或批注。

可以使用 osm namespace add 命令将命名空间加入到给定的服务网格。 当 Kubernetes 命名空间是网格的一部分时,请按照以下步骤确认满足要求。

查看命名空间 bookbuyer 的注释:

kubectl get namespace bookbuyer -o json | jq '.metadata.annotations'

必须存在以下注释:

{
  "openservicemesh.io/sidecar-injection": "enabled"
}

查看命名空间 bookbuyer 的标签:

kubectl get namespace bookbuyer -o json | jq '.metadata.labels'

必须存在以下标签:

{
  "openservicemesh.io/monitored-by": "osm"
}

如果未使用 osm CLI,也可以手动将这些注释添加到命名空间。 如果命名空间不带有 "openservicemesh.io/sidecar-injection": "enabled" 批注或 "openservicemesh.io/monitored-by": "osm" 标签,则 OSM 注入程序不会添加 Envoy 挎斗。

注意

只有在调用 osm namespace add 之后,新的 Pod 才会与 Envoy 挎斗一起注入。 必须使用 kubectl rollout restart deployment 命令重启现有 Pod。

验证 SMI CRD

使用以下命令检查群集是否具有所需的自定义资源定义 (CRD) :

kubectl get crds

确保 CRD 与版本分支中可用的版本相对应。 若要确认正在使用的 CRD 版本,请访问 SMI 支持的版本页面,然后从版本下拉列表中选择你的版本。

使用以下命令获取已安装的 CRD 版本:

for x in $(kubectl get crds --no-headers | awk '{print $1}' | grep 'smi-spec.io'); do
    kubectl get crd $x -o json | jq -r '(.metadata.name, "----" , .spec.versions[].name, "\n")'
done

如果缺少 CRD,请使用以下命令在群集上安装它们。 根据需要替换这些命令中的版本(例如,v1.1.0 将是 release-v1.1)。

kubectl apply -f https://raw.githubusercontent.com/openservicemesh/osm/release-v1.0/cmd/osm-bootstrap/crds/smi_http_route_group.yaml

kubectl apply -f https://raw.githubusercontent.com/openservicemesh/osm/release-v1.0/cmd/osm-bootstrap/crds/smi_tcp_route.yaml

kubectl apply -f https://raw.githubusercontent.com/openservicemesh/osm/release-v1.0/cmd/osm-bootstrap/crds/smi_traffic_access.yaml

kubectl apply -f https://raw.githubusercontent.com/openservicemesh/osm/release-v1.0/cmd/osm-bootstrap/crds/smi_traffic_split.yaml

若要查看版本之间的 CRD 更改,请参阅 OSM 发行说明

排查证书管理问题

有关 OSM 如何向应用程序 Pod 上运行的 Envoy 代理颁发证书和管理这些证书的信息,请参阅 OSM 文档站点

升级 Envoy

在加载项监视的命名空间中创建新的 Pod 时,OSM 会在该 Pod 中注入一个 Envoy 代理挎斗。 如果需要更新 Envoy 版本,可以按照 OSM 文档站点上升级指南中的步骤操作。

后续步骤