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

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

本文介绍与 Azure 中的 GitOps (Flux v2) 或开放服务网格 (OSM) 等群集扩展相关的常见问题的故障排除提示。

如需相关帮助来排查已启用 Azure Arc 的 Kubernetes 问题,请参阅排查已启用 Azure Arc 的 Kubernetes 问题

GitOps (Flux v2)

注意

可以在已启用 Azure Arc 的 Kubernetes 群集或 Azure Kubernetes 服务 (AKS) 群集中使用 Flux v2 扩展。 这些故障排除提示基本适用于所有群集类型。

如需常规性帮助来排查使用 fluxConfigurations 资源时遇到的问题,可使用 --debug 参数运行以下 Azure CLI 命令:

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 不支持试运行”错误?

安装 microsoft.flux 扩展时出错

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

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

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

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

接下来,运行以下命令以确定是否存在其他问题。 对于已启用 Azure Arc 的群集,将群集类型参数 (-t) 设置为 connectedClusters;对于 AKS 群集,设置为 managedClusters。 如果扩展是在创建 GitOps 配置期间自动安装的,则 microsoft.flux 扩展的名称将是 flux

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 扩展,则 extension-agent 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}}\"}]}}",

在这种情况下,extension-agent Pod 会尝试从群集上的 Azure 实例元数据服务获取其令牌,但令牌请求会被 Pod 标识截获。 可以通过将 升级到最新版本 () 的 microsoft.flux 扩展来解决此问题。

安装 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 1,000 m 1 Gi
source-controller 50 m 64 Mi 1,000 m 1 Gi
kustomize-controller 100 m 64 Mi 1,000 m 1 Gi
notification-controller 100 m 64 Mi 1,000 m 1 Gi
image-automation-controller 100 m 64 Mi 1,000 m 1 Gi
image-reflector-controller 100 m 64 Mi 1,000 m 1 Gi

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

Flux v1

注意

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

如需相关帮助来排查 Flux v1 中 sourceControlConfigurations 资源的问题,请运行以下 Azure CLI 命令,并在其中包含 --debug 参数:

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

Azure Monitor 容器见解

本部分提供有关排查 Azure Monitor 中已启用 Azure Arc 的 Kubernetes 群集的容器见解的相关问题的帮助。

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

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

juju config kubernetes-worker allow-privileged=true

无法在 Oracle Linux 9.x 上安装 AMA Pod

如果尝试在 Oracle Linux (Red Hat Enterprise 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 发行版中。

要解决此问题,需要在群集中的每个节点上显式加载 iptables_nat 模块。 使用 modprobe 命令 sudo modprobe 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

即使一个控制器在一个时点的状态为 Evicted,另一个控制器的状态为 READY1/1,且具有 0Running 重启。 如果 READY 状态不是 1/1,则服务网格处于中断状态。 如果 READY0/1,表示控制平面容器崩溃。

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

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

如果 READY 状态是一个大于正斜杠 (/) 后 1 的数字,则安装了跨斗。 附加了 sidecars 时,OSM 控制器通常无法正常工作。

检查 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-controllerENDPOINTS,则表示控制平面运行不正常。 这种运行不正常的状态意味着控制器 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

通过运行以下命令来检查“变异”Webhook:

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 布尔 false kubectl patch meshconfig osm-mesh-config -n arc-osm-system -p '{"spec":{"traffic":{"enableEgress":false}}}' --type=merge
spec.traffic.enablePermissiveTrafficPolicyMode 布尔 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 布尔 false kubectl patch meshconfig osm-mesh-config -n arc-osm-system -p '{"spec":{"observability":{"enableDebugServer":false}}}' --type=merge
spec.observability.osmLogLevel string "info" kubectl patch meshconfig osm-mesh-config -n arc-osm-system -p '{"spec":{"observability":{"tracing":{"osmLogLevel": "info"}}}}' --type=merge
spec.observability.tracing.enable 布尔 false kubectl patch meshconfig osm-mesh-config -n arc-osm-system -p '{"spec":{"observability":{"tracing":{"enable":true}}}}' --type=merge
spec.sidecar.enablePrivilegedInitContainer 布尔 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 布尔 "true" kubectl patch meshconfig osm-mesh-config -n arc-osm-system -p '{"spec":{"featureFlags":{"enableWASMStats":"true"}}}' --type=merge
spec.featureFlags.enableEgressPolicy 布尔 "true" kubectl patch meshconfig osm-mesh-config -n arc-osm-system -p '{"spec":{"featureFlags":{"enableEgressPolicy":"true"}}}' --type=merge
spec.featureFlags.enableMulticlusterMode 布尔 "false" kubectl patch meshconfig osm-mesh-config -n arc-osm-system -p '{"spec":{"featureFlags":{"enableMulticlusterMode":"false"}}}' --type=merge
spec.featureFlags.enableSnapshotCacheMode 布尔 "false" kubectl patch meshconfig osm-mesh-config -n arc-osm-system -p '{"spec":{"featureFlags":{"enableSnapshotCacheMode":"false"}}}' --type=merge
spec.featureFlags.enableAsyncProxyServiceMapping 布尔 "false" kubectl patch meshconfig osm-mesh-config -n arc-osm-system -p '{"spec":{"featureFlags":{"enableAsyncProxyServiceMapping":"false"}}}' --type=merge
spec.featureFlags.enableIngressBackendPolicy 布尔 "true" kubectl patch meshconfig osm-mesh-config -n arc-osm-system -p '{"spec":{"featureFlags":{"enableIngressBackendPolicy":"true"}}}' --type=merge
spec.featureFlags.enableEnvoyActiveHealthChecks 布尔 "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

对于 OSM 服务网格接口 (SMI),请检查群集是否具有所需的自定义资源定义(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,请使用以下命令在群集上安装它们。 根据需要替换这些命令中的版本(例如,可以使用 release-v1.1,而不是 v1.1.0)。

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 文档中升级指南中的步骤操作。