Config Sync 问题排查

本页面介绍如何解决 Config Controller 的问题。

尽管我们一直努力为您提供 Config Sync 始终可用的体验,但在某些情况下,您可能遇到需要排查安装问题的情况。本指南将引导您完成一些可以帮助您解决所遇到的问题的常见机制。

一般最佳实践

查看 Config Sync 状态

nomos status 命令为您提供汇总数据和错误,帮助您了解 Config Sync 安装发生的情况。以下信息可通过 nomos status 获得:

  • 每个集群的安装状态
  • 同步错误(从 Git 读取和协调更改)

如需使用 nomos status,请安装 nomos 命令

您还可以使用 gcloud alpha anthos config sync repo 命令或 Config Sync 信息中心按代码库查看 Config Sync 状态。

使用服务等级指标 (SLI)

如需在 Config Sync 未按预期工作时收到通知,请根据 Config Sync SLI 设置 Prometheus 提醒规则。如需了解详情,请参阅使用 Config Sync SLI

使用 kubectl 检查资源

Config Sync 由多个自定义资源组成,您可以使用 kubectl 命令查询这些资源。这些命令可帮助您了解 Config Sync 的每个对象的状态。

您应该了解 Config Sync 管理的 Kubernetes 资源的以下信息:

  • config-management-system 是用于运行 Config Sync 所有核心系统组件的命名空间。
  • configmanagement.gke.io/v1configsync.gke.io 是我们用于所有自定义资源的版本前缀。

通过运行以下命令,您可以获取自定义资源的完整列表:

kubectl api-resources | grep -E "configmanagement.gke.io|configsync.gke.io"

通过运行 kubectl get RESOURCE -o yaml,可以使用各个自定义资源。

例如,以下命令的输出使您可以检查 RootSync 对象的状态:

kubectl get rootsync -n config-management-system -o yaml

您还可以使用 gcloud alpha anthos config sync resources 命令或 Config Sync 信息中心查看 Config Sync 管理的资源。

探索 RootSync 和 RepoSync 对象

使用 kubectl 安装 Config Sync 时,您可以创建一个 RootSync 对象,其中包含有关根代码库配置的详细信息。当您使用 Google Cloud 控制台或 Google Cloud CLI 安装 Config Sync 时,Config Sync 会自动为您创建 RootSync 对象。配置从多个代码库同步时,您将创建 RepoSync 对象,其中包含有关命名空间代码库的配置信息。

探索这些对象可以揭示有关 Config Sync 状态的重要信息。如需了解详情,请参阅监控 RootSync 和 RepoSync 对象

使用审核日志

审核日志是一种有用的调试工具。

如果您使用 Google Cloud 控制台或 Google Cloud CLI 安装了 Config Sync,请完成以下步骤,以使用审核日志调查 Config Sync。

控制台

  1. 启用 GKE Connect/Hub API 审核日志。

    1. 在 Google Cloud 控制台中,转到 IAM 审核日志页面。

      转到“审核日志”页面

    2. 在表格中,选中 GKE Connect/Hub API 复选框。

    3. 选中以下复选框:

      • 管理员读取
      • 数据读取
      • 数据写入
    4. 点击保存

  2. 转到日志浏览器页面。

    转到“日志浏览器”页面

  3. 查询构建器文本框中,添加以下过滤条件:

    resource.type="audited_resource" resource.labels.service="gkehub.googleapis.com"
    
  4. 点击运行查询

  5. 查询结果部分中,选择相关条目以详细了解事件。

排查一般问题

FailedScheduling 事件

kubectl get events 的输出可能包含类型为 FailedScheduling 的事件。此事件类似于以下示例:

LAST SEEN   TYPE      REASON              OBJECT                                       MESSAGE
9s          Warning   FailedScheduling    pod/config-management-operator-74594dc8f6    0/1 nodes are available: 1 Insufficient cpu.

发生此事件是因为无法在节点上安排 pod,这通常意味着节点上的 CPU 或内存不足。要修复此错误,请选择以下选项之一:

  • 将节点添加到现有 GKE 节点池
  • 创建具有更大节点的节点池。

有效但不正确的 ConfigManagement 对象

如果您使用 kubectl 命令安装 Config Sync,并且安装失败是由于 ConfigManagement 对象有问题(不是因为 YAML 或 JSON 语法错误所致),则该对象可能会在集群中实例化,但无法正常运行。在这种情况下,您可以使用 nomos status 命令检查该对象中的错误。

对于没有问题的有效安装,其状态为 PENDINGSYNCED

对于无效的安装,其状态为 NOT CONFIGURED,并且系统会列出以下错误之一:

  • missing git-creds Secret
  • missing required syncRepo field
  • git-creds Secret is missing the key specified by secretType

为解决此问题,请更正配置错误。根据错误类型,您可能需要将 ConfigManagement 清单重新应用到集群。

如果问题的原因是您忘记创建 git-creds Secret,则 Config Sync 会在您创建该 Secret 后立即检测到它,这样您就无需重新应用配置。

ResourceGroup 字段不断变化

对于同步到集群的各 Git 代码库,所有资源的协调状态会汇总到一个名为 ResourceGroup 的资源中。对于每个 RootSync 或 RepoSync 对象,系统会生成一个 ResourceGroup 来捕获应用于集群的资源集,并汇总其状态。

有时,您的 ResourceGroup 可以循环更新 ResourceGroup 的 spec。如果发生这种情况,您可能会注意到以下问题:

  • ResourceGroup 的 metadata.generation 在短时间内不断增长。
  • ResourceGroup spec 不断在变化。
  • ResourceGroup spec 不包含同步到集群的资源的 status.resourceStatuses

如果您观察到这些问题,则表示 Git 代码库中的某些资源未应用于集群。造成这些问题的原因是您缺少应用这些资源所需的权限。

您可以通过获取 RepoSync 资源状态来验证是否缺少这些权限:

kubectl get reposync repo-sync -n NAMESPACE -o yaml

NAMESPACE 替换为在其中创建了命名空间代码库的命名空间。

此外,您也可以使用 nomos status

如果您在状态中看到以下消息,则表示 NAMESPACE 中的协调器缺少应用资源所需的权限:

errors:
  - code: "2009"
    errorMessage: |-
      KNV2009: deployments.apps "nginx-deployment" is forbidden: User "system:serviceaccount:config-management-system:ns-reconciler-     default" cannot get resource "deployments" in API group "apps" in the namespace "default"

      For more information, see https://g.co/cloud/acm-errors#knv2009

如需解决此问题,您需要声明一个 RoleBinding 配置,向 ns-reconciler-NAMESPACE 服务帐号授予管理该命名空间中失败资源的权限。如需详细了解如何添加 RoleBinding,请参阅配置从多个代码库同步

Git 代码库中有大量资源

当 RepoSync 或 RootSync 对象同步到集群的 Git 代码库包含数千个资源的配置时,可能会导致 ResourceGroup 超过 etcd 对象的大小限制。发生这种情况时,您无法查看 Git 代码库中资源的汇总状态。虽然您将无法查看汇总状态,但您的代码库可能仍然处于同步状态。

如果您在 RootSync 对象、RepoSync 对象或协调器日志中看到以下错误,则表示 ResourceGroup 资源超出了 etcd 对象的大小限制。

KNV2009: etcdserver: request is too large

为解决此问题,我们建议您将 Git 代码库拆分为多个代码库。如需了解详情,请参阅将代码库拆分为多个代码库

如果您无法拆分 Git 代码库,在 Config Sync v1.11.0 及更高版本中,您可以通过停止显示状态数据来缓解此问题。为此,您可以将 RootSync 或 RepoSync 对象的 .spec.override.statusMode 字段设置为 disabled。这样,Config Sync 便会停止更新 ResourceGroup 对象中的代管资源状态;从而减小 ResourceGroup 对象的大小。但是,无法再从 nomos statusgcloud alpha anthos config sync 查看代管资源的状态。

如果您使用 Google Cloud 控制台或 Google Cloud CLI 安装了 Config Sync,请创建可修改的 RootSync 对象,以便设置 spec.override.statusMode。如需了解详情,请参阅使用 kubectl 命令配置 Config Sync

如果您在 RootSync 或 RepoSync 对象中没有看到任何错误,则表示您的 Git 代码库已同步到集群。如需检查 ResourceGroup 资源是否超出 etcd 对象的大小限制,请检查 ResourceGroup 资源状态以及 ResourceGroup 控制器的日志:

  1. 检查 ResourceGroup 状态:

    • 要检查 RootSync 对象,请运行以下命令:
     kubectl get resourcegroup.kpt.dev root-sync -n config-management-system
    
    • 要检查 RepoSync 对象,请运行以下命令:
    kubectl get resourcegroup.kpt.dev repo-sync -n NAMESPACE
    

    输出类似于以下示例:

    NAME        RECONCILING   STALLED   AGE
    root-sync   True          False     35m
    

    如果 RECONCILING 列中的值为 True,则意味着 ResourceGroup 资源仍在协调。

  2. 检查 ResourceGroup 控制器的日志:

    kubectl logs deployment/resource-group-controller-manager -c manager -n resource-group-system
    

    如果您在输出中看到以下错误,则表示 ResourceGroup 资源过大,超出了 etcd 对象的大小限制:

    "error":"etcdserver: request is too large"
    

如需防止 ResourceGroup 过大,请减少 Git 代码库中的资源数量。您可以按照说明将一个根代码库拆分为多个根代码库。

与 Git 代码库不同步

如果新提交内容被推送到您的 Git 代码库,但集群的 Config Sync 状态仍是 Synced 到旧提交内容(时间长于 spec.git.period),则您需要检查 git-sync 容器的日志:

# check git-sync logs for a root reconciler
kubectl logs -n config-management-system deployment/root-reconciler -c git-sync

# check git-sync logs for a namespace reconciler
kubectl logs -n config-management-system deployment/ns-reconciler-NAMESPACE -c git-sync

有可能 git-sync 无法从 Git 代码库同步,但 Reconciler 会继续从先前同步的提交同步。以下示例输出表明您遇到了 git-sync 问题:

"msg"="unexpected error syncing repo, will retry" "error"="Run(git fetch -f
--tags --depth 1 origin develop): exit status 128: { stdout: "", stderr: "fatal:
couldn't find remote ref develop\n" }"

Webhook 拒绝更新/删除由已删除的 RootSync/RepoSync 管理的资源的请求

删除 RootSync 或 RepoSync 对象不会清理 Config Sync 注解和标签,并且如果集群中仍启用 Config Sync,Config Sync 准入网络钩子会拒绝尝试修改或删除这些资源的请求。

如果您想要保留这些代管式资源,您可以先针对在 Git 代码库中声明的每个代管式资源将 configmanagement.gke.io/managed 注释设置disabled 以取消管理这些资源。这将从代管式资源中移除 Config Sync 注释和标签,但不会删除这些资源。同步完成后,您可以移除 RootSync 或 RepoSync 对象。

如果意图删除这些代管式资源,您可以首先通过修改 RootSync 或 RepoSync 对象从空的 Git 目录进行同步来删除代管式资源。同步完成后,您可以移除 RootSync 或 RepoSync 对象。

如果在取消管理或删除代管式资源之前删除了 RootSync 或 RepoSync 对象,您可以重新添加回 RootSync 或 RepoSync 对象,取消管理或删除代管式资源,然后再次删除 RootSync 或 RepoSync 对象。

水平 Pod 自动扩缩功能不起作用

Config Sync 管理您在 Git 代码库中的清单中指定的所有字段。当两个控制器尝试控制同一字段时,可能会发生资源争用。当您尝试将水平 Pod 自动扩缩功能与 Config Sync 搭配使用时,会发生此类资源争用。

如果要使用水平 Pod 自动扩缩功能,则应让水平 Pod 自动扩缩器从 Git 代码库中的所有清单中移除 spec.replicas 字段。否则,Config Sync 会尝试还原对代码库中指定的内容所做的任何更改。

PersistentVolumeClaim 处于“丢失”状态

将 Kubernetes 集群升级到 1.22 及更高版本时,代管的 PersistentVolumeClaim 可能会处于 Lost 状态。如果使用 PersistentVolume 资源中的 claimRef 字段定义 PersistentVolume 和 PersistentVolumeClaim 的绑定,便会发生这种情况。上游 Kubernetes 更改使得 claimRef 字段具有原子性,继而导致此错误,因为在服务器端应用更改时,系统不允许不同的 claimRef 子字段拥有不同的字段所有者。

在此问题在上游 Kubernetes 中得到解决(GitHub 问题跟踪器问题修复 PR)之前,我们建议您更新 PersistentVolume 和 PersistentVolumeClaim 资源以使用替代绑定方法。您可以改为在 PersistentVolumeClaim 资源的 spec.volumeName 中设置绑定。此操作可以在 Kubernetes 1.21 版及更低版本中完成,以防止在升级到 1.22 版后出现任何服务中断。

以下是将 staging-pvc 绑定到 staging-pv 的最简示例:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: staging-pvc
  namespace: staging
spec:
  volumeName: staging-pv
  ...

---

apiVersion: v1
kind: PersistentVolume
metadata:
  name: staging-pv
spec:
  ...

如果使用 volumeName 而不是 claimRef 进行绑定,则无法保证对 PersistentVolume 的任何绑定特权

根据错误消息排查问题

KNV1045:不允许使用指定了“status”的配置

如果您在源代码库中指定任何 status 字段,您可能会遇到 KNV1045:不允许使用指定了“status”的配置。不允许使用 Config Sync 同步 status 字段。另一个控制器应动态地管理和更新集群中的 status 字段。如果 Config Sync 尝试控制 status 字段的所需状态,则会与负责管理 status 字段的控制器发生争用。

要修复此错误,请从源代码库中移除 status 字段。对于不归您所有的第三方配置,请使用 kustomize 补丁批量移除清单中指定的 status 字段。

KNV2004:git-sync 容器中的无法同步代码库错误

Config Sync 会创建 Git 代码库的浅层克隆。在极少数情况下,Config Sync 可能无法从浅层克隆中找到提交。发生此情况时,Config Sync 会增加要提取的 Git 提交次数。

您可以通过在 RootSync 或 RepoSync 对象中设置 spec.override.gitSyncDepth 字段来设置要提取的 Git 提交次数:

以下示例将要提取的 Git 提交数量设置为 88

apiVersion: configsync.gke.io/v1beta1
kind: RootSync
metadata:
  name: root-sync
  namespace: config-management-system
spec:
  override:
    gitSyncDepth: 88
  git:
    ...

运行以下命令以验证更改生效(在 root-reconciler-git-sync ConfigMap 的 data 字段中,GIT_SYNC_DEPTH 应被设置为 88):

kubectl get cm root-reconciler-git-sync -n config-management-system -o yaml

您可以通过类似的方法替换命名空间协调器中要提取的 Git 提交次数。

错误:权限遭拒

如果您在尝试配置 Config Sync 时收到类似于以下示例的错误,则您可能没有 GKE Hub Admin 角色:

Permission 'gkehub.features.create' denied on 'projects/PROJECT_ID/locations/global/features/configmanagement'

为确保您拥有所需的权限,请确保您已授予所需的 IAM 角色

错误:准许 Webhook 拒绝了请求

如果您在尝试对 Config Sync 管理的字段应用更改时收到以下错误,则表明您可能进行了有冲突的更改:

error: OBJECT could not be patched: admission webhook "v1.admission-webhook.configsync.gke.io"
denied the request: fields managed by Config Sync can not be modified

如果您在配置中声明字段并且代码库已同步到集群,Config Sync 将管理该字段。您尝试对该字段进行的任何更改都是有冲突的更改。

例如,如果带有 environment:prod 标签的代码库中有 Deployment 配置,并且尝试将该标签更改为集群中的 environment:dev,则会出现有冲突的更改,并且您将会收到之前的错误消息。但是,如果您向 Deployment 添加新标签(例如 tier:frontend),则不会发生冲突。

如果您希望 Config Sync 忽略对对象所做的任何更改,则可以添加忽略对象变更中所述的注释。

错误:准许网络钩子请求 i/o 超时

如果您在协调器尝试将配置应用于集群时收到以下错误,则控制平面网络的防火墙可能阻止了准入网络钩子端口 8676

KNV2009: Internal error occurred: failed calling webhook "v1.admission-webhook.configsync.gke.io": Post https://admission-webhook.config-management-system.svc:8676/admission-webhook?timeout=3s: dial tcp 10.1.1.186:8676: i/o timeout

要解决此问题,请添加防火墙规则以允许端口 8676,Config Sync 准入网络钩子使用此端口来防止出现偏差。

错误:准入网络钩子连接遭拒

如果在协调器尝试将配置应用于集群时收到以下错误,则表示准入网络钩子尚未准备就绪:

KNV2009: Internal error occurred: failed calling webhook "v1.admission-webhook.configsync.gke.io": Post "https://admission-webhook.config-management-system.svc:8676/admission-webhook?timeout=3s": dial tcp 10.92.2.14:8676: connect: connection refused

您在引导 Config Sync 时可能会遇到暂时性错误。如果问题仍然存在,请查看准许网络钩子部署,以查看其 pod 是否可安排并且健康。

kubectl describe deploy admission-webhook -n config-management-system

kubectl get pods -n config-management-system -l app=admission-webhook

错误:无法装载 Git Secret

如果您在 git-sync 容器尝试将 Secret 与代码库同步时收到以下错误,则表示 Git Secret 未成功装载到 git-sync 容器中:

KNV2004: unable to sync repo Error in the git-sync container: ERROR: can't configure SSH: can't access SSH key: stat /etc/git-secret/ssh: no such file or directory: lstat /repo/root/rev: no such file or directory

此错误可能是由于您的 Git 代码库身份验证类型从 nonegcenodegcpserviceaccount 切换到需要 Secret 的其他类型引起的。

如要解决此问题,请运行以下命令来重启 Reconciler Manager 和 Reconciler:

# Stop the reconciler-manager Pod. The reconciler-manager Deployment will spin
# up a new Pod which can pick up the latest `spec.git.auth`.
kubectl delete po -l app=reconciler-manager -n config-management-system

# Delete the reconciler Deployments. The reconciler-manager will recreate the
# reconciler Deployments with correct volume mount.
kubectl delete deployment -l app=reconciler -n config-management-system

错误:无法从公共代码库中拉取远程库

如果您在渲染过程中尝试从公共代码库拉取远程库时收到以下错误,渲染过程将无法成功完成:

KNV1068: failed to run kustomize build in /repo/source/0a7fd88d6c66362584131f9dfd024024352916af/remote-base, stdout:...
no 'git' program on path: exec: "git": executable file not found in $PATH

For more information, see https://g.co/cloud/acm-errors#knv1068

如需解决此问题,请将 spec.override.enableShellInRendering 设置为 true

协调器 Pod 中的容器因内存不足而终止

您可以替换根代码库或命名空间代码库的 CPU 和/或内存请求和限制。如需替换这些值,请使用 RootSync 或 RepoSync 对象的 spec.override.resources 字段。如果您使用 Google Cloud 控制台或 Google Cloud CLI 安装了 Config Sync,请创建可修改的 RootSync 对象,以便设置 spec.override.resources。如需了解详情,请参阅使用 kubectl 命令配置 Config Sync

以下示例展示了如何替换 reconciler 容器的 CPU 和内存限制以及根协调器的 git-sync 容器的 CPU 请求和内存限制。允许替换 git-syncoci-synchelm-synchydration-controllerreconciler 容器。允许部分替换:如果未提供资源请求或限制的替换值,则使用默认资源请求或限制值。

apiVersion: configsync.gke.io/v1beta1
kind: RootSync
metadata:
  name: root-sync
  namespace: config-management-system
spec:
  sourceFormat: "unstructured"
  override:
    resources:
    - containerName: "reconciler"
      cpuLimit: "800m"
      memoryLimit: "500Mi"
    - containerName: "git-sync"
      cpuRequest: "100m"
      memoryLimit: "400Mi"
  git:
     ...

运行以下命令以验证新资源限制生效:

kubectl get deployment.apps/root-reconciler -n config-management-system -o yaml

您可以通过类似的方法替换命名空间协调器的资源限制。

错误:命名空间卡在 Terminating 阶段

卡在 Terminating 阶段的命名空间应具有以下条件:

    message: 'Failed to delete all resource types, 1 remaining: admission webhook
      "v1.admission-webhook.configsync.gke.io" denied the request: system:serviceaccount:kube-system:namespace-controller
      is not authorized to delete managed resource "_configmap_bookstore_cm1"'
    reason: ContentDeletionFailed
    status: "True"
    type: NamespaceDeletionContentFailure

如果您尝试从根代码库中删除命名空间,但命名空间下的某些对象仍由命名空间协调器主动管理,就会发生此错误。删除命名空间时,服务帐号为 system:serviceaccount:kube-system:namespace-controller命名空间控制器将尝试删除该命名空间中的所有对象。但是,Config Sync 准入网络钩子只允许根协调器或命名空间协调器删除这些对象,并拒绝命名空间控制器删除这些对象。

解决方法是删除 Config Sync 准入网络钩子:

kubectl delete deployment.apps/admission-webhook -n config-management-system

Config Management Operator 会重新创建 Config Sync 准入网络钩子。

如果此解决方法无效,您可能需要重新安装 Config Sync。

为避免再次发生该错误,请在移除命名空间之前移除命名空间代码库

错误:在 ValidatingWebhookConfiguration 中找不到 webhooks 字段

如果您在运行 kubectl logs -n config-management-system -l app=admission-webhook 时发现 Config Sync 准入网络钩子日志中存在以下错误:

cert-rotation "msg"="Unable to inject cert to webhook." "error"="`webhooks` field not found in ValidatingWebhookConfiguration" "gvk"={"Group":"admissionregistration.k8s.io","Version":"v1","Kind":"ValidatingWebhookConfiguration"} "name"="admission-webhook.configsync.gke.io"
controller-runtime/manager/controller/cert-rotator "msg"="Reconciler error" "error"="`webhooks` field not found in ValidatingWebhookConfiguration" "name"="admission-webhook-cert" "namespace"="config-management-system"

这意味着 root-reconciler 尚未将任何资源同步到集群。这可能是因为 root-reconciler 尚未就绪,或者没有要从 Git 代码库同步的任何内容(例如,同步目录为空)。如果问题仍然存在,您应检查 root-reconciler 的运行状况:

kubectl get pods -n config-management-system -l configsync.gke.io/reconciler=root-reconciler

如果 root-reconciler 是崩溃循环或 OOMKilled,请提高其资源限制

错误:无法创建 Stackdriver/GoogleCloud 导出器

当 Open Telemetry Collector 中的组件无法访问同一命名空间下的默认服务帐号时,您可能会注意到 config-management-monitoring 下的 otel-collector Pod 处于 CrashLoopBackoff 状态,或者您可能会看到类似于以下示例的错误消息:

Error: cannot build exporters: error creating stackdriver exporter: cannot configure Google Cloud metric exporter: stackdriver: google: could not find default credentials. See https://developers.google.com/accounts/docs/application-default-credentials for more information.

此问题通常在集群中启用了 Workload Identity 时出现。

要解决此问题,请按照监控 Config Sync 中的说明向默认服务帐号授予指标写入权限。

如果设置 IAM 后错误仍然存在,请重启 otel-collector Pod 以使更改生效。

错误:服务器证书验证失败

如果 git-sync 容器无法克隆 Git 代码库并显示以下错误消息 server certificate verification failed. CAfile: /etc/ca-cert/cert CRLfile: none,则表示 Git 服务器配置了来自自定义证书授权机构 (CA) 的证书。但是,自定义 CA 未正确配置,从而导致 git-sync 容器克隆 Git 代码库失败。

首先,您可以验证是否已在 RootSync 或 RepoSync 对象中指定 spec.git.caCertSecretRef.name 字段,并检查 Secret 对象是否存在。

如果该字段已经过配置并且 Secret 对象已存在,请确保 Secret 对象包含完整的证书。

检查完整证书的方法可能会有所不同,具体取决于自定义 CA 的预配方式。

以下示例说明了如何列出服务器证书:

echo -n | openssl s_client -showcerts -connect HOST:PORT -servername SERVER_NAME 2>/dev/null | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p'

您可以请求网络管理团队为您获取 CA 证书。