Nginx Ingress Controller - 调用Webhook失败

78
我在Ubuntu虚拟机上使用kubeadm(v1.18)搭建了一个k8s集群。现在我需要添加一个Ingress Controller,我决定使用nginx(但我也可以接受其他解决方案)。我按照文档中的“裸机”部分进行安装:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-0.31.1/deploy/static/provider/baremetal/deploy.yaml
我认为安装看起来很好:
kubectl get all -n ingress-nginx
NAME                                            READY   STATUS      RESTARTS   AGE
pod/ingress-nginx-admission-create-b8smg        0/1     Completed   0          8m21s
pod/ingress-nginx-admission-patch-6nbjb         0/1     Completed   1          8m21s
pod/ingress-nginx-controller-78f6c57f64-m89n8   1/1     Running     0          8m31s

NAME                                         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)                      AGE
service/ingress-nginx-controller             NodePort    10.107.152.204   <none>        80:32367/TCP,443:31480/TCP   8m31s
service/ingress-nginx-controller-admission   ClusterIP   10.110.191.169   <none>        443/TCP                      8m31s

NAME                                       READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/ingress-nginx-controller   1/1     1            1           8m31s

NAME                                                  DESIRED   CURRENT   READY   AGE
replicaset.apps/ingress-nginx-controller-78f6c57f64   1         1         1       8m31s

NAME                                       COMPLETIONS   DURATION   AGE
job.batch/ingress-nginx-admission-create   1/1           2s         8m31s
job.batch/ingress-nginx-admission-patch    1/1           3s         8m31s

然而,当尝试应用自定义Ingress时,我收到以下错误消息:
服务器错误(InternalError):在创建“yaml/xxx/xxx-ingress.yaml”时出错:发生内部错误:调用webhook“validate.nginx.ingress.kubernetes.io”失败:Post https://ingress-nginx-controller-admission.ingress-nginx.svc:443/extensions/v1beta1/ingresses?timeout=30s: Temporary Redirect
有什么想法是怎么回事吗?
我怀疑是DNS的问题,但其他NodePort服务按预期工作,并且DNS在集群内部工作。
我唯一能看到的是,我没有这里的默认的http后端。然而,根据此线程,在我的情况下似乎很正常。
最后,我还尝试了使用清单进行安装(在从先前安装中删除ingress-nginx命名空间之后)和通过Helm图表进行安装。结果相同。
我在k8s上是一个新手,这是我的游乐场集群。因此,我也可以接受替代方案,只要我不需要从头开始设置整个集群。
更新: 通过“应用自定义Ingress”,我的意思是: kubectl apply -f <myIngress.yaml> myIngress.yaml的内容
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: my-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - http:
      paths:
      - path: /someroute/fittingmyneeds
        pathType: Prefix
        backend:
          serviceName: some-service
          servicePort: 5000

“当尝试应用自定义Ingress时”是什么意思?你的自定义Ingress具体是什么? - Wytrzymały Wiktor
@OhHiMark:我的意思是 kubectl apply -f <myIngress.yaml>。我已经在原帖中添加了这些信息。 - PhotonTamer
看起来你的 Ingress.yaml 配置有误。我发现你正在尝试使用重写注释,但没有定义捕获组。这里 你可以找到一个解释示例,说明如何使用该注释。请查看一下,看看是否有所帮助。 - Wytrzymały Wiktor
有没有不删除ValidatingWebhookConfiguration的解决方案? - jarvo69
18个回答

92

您还有另一种选择,就是完全删除验证 Webhook:

kubectl delete -A ValidatingWebhookConfiguration ingress-nginx-admission

我在另一个问题上发现了这个方法,但是这个解决办法在这里也适用。

这不是最好的答案;最好的答案是找出为什么它不起作用。但是在某些时候,你只能使用解决办法。

我正在安装 Docker for Mac,所以我使用了cloud版本而不是baremetal版本:

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v0.34.1/deploy/static/provider/cloud/deploy.yaml


2
在我的minikube 1.12和k8s 1.18上,kubectl delete -A ValidatingWebhookConfiguration ingress-nginx-admission解决了我的问题。 - Fernando Correia
1
@Patrick Gardella,这似乎是许多人的实际解决方案,正如您相关帖子https://dev59.com/DVIH5IYBdhLWcg3wFIrR#62044090上的许多赞所证明的那样。我甚至不确定它只是一个解决方法。 - Chris Halcrow
3
不要删除Admission Webhook,更实际的解决方案是允许防火墙中的所有节点与端口8443通信。https://kubernetes.github.io/ingress-nginx/deploy/ - "如果有网络策略或其他防火墙,请允许访问端口8443。" - Joao M
2
我真的很不想点赞这个。但它起作用了。 - meh

60

在我的情况下,我把安装程序搞混了。 我通过执行以下步骤解决了问题:

$ kubectl get validatingwebhookconfigurations 

我遍历了上面步骤收到的配置列表,并使用删除了该配置。

$ `kubectl delete validatingwebhookconfigurations [configuration-name]`

11
不删除 ValidatingWebhookConfiguration 的任何解决方案? - jarvo69
1
谢谢!在我的情况下,ingress-nginx-admission有另一个名称=> nginx-ingress-nginx-admission。通过kubectl get validatingwebhookconfigurations找到了它。 - Pleymor
我在安装第二个入口时搞砸了一切。当我移除第二个入口时,validatingwebhookconfigurations仍然保留在集群中,所以这个解决方案解决了我的问题。 - Ziul

27
在我的情况下,我不需要删除ValidatingWebhookConfiguration。问题是我使用的是GCP版本为1.17.14-gke.1600的私有集群。对于gke私有集群,validatingwebhook尝试访问主节点API的8443端口。在我的情况下,它失败了,因为我没有在防火墙上允许该端口。所以目前的解决方法是,按照Google自己推荐的(但文档非常不完善),在GCP上添加一个防火墙规则,允许入站(Ingress)TCP请求到达您的主节点的8443端口,这样集群中的其他节点就可以通过该端口访问运行在主节点上的validatingwebhook API。
至于如何创建规则,以下是我的做法:
  1. 防火墙规则并添加一个新的规则。
  2. 网络字段中,选择我的集群所在的VPC。
  3. 流量方向设置为Ingress
  4. 匹配时的操作设置为允许
  5. 目标设置为指定的目标标签
  6. 可以在主节点详细信息的属性网络标签中找到目标标签。要找到它,我打开了一个新窗口,进入了我的集群节点池,找到了主节点池。然后进入其中一个节点查找虚拟机详细信息。在那里我找到了网络标签。复制了它的值然后回到了防火墙规则表单。
  7. 将复制的网络标签粘贴到标签字段中
  8. 协议和端口中,勾选了指定的协议和端口
  9. 然后勾选了TCP并填写了8443
  10. 保存规则并再次应用清单。
请注意:大多数文章会说使用端口9443,这可能有效。但我首先尝试了8443,因为有报道称其可以在此主题上运行。对我来说它有效,所以我甚至没有尝试过9443。

2
非常感谢您的详细解释!我在我们的私有prod GKE集群中遇到了这个问题。我应该注意到,我只添加了端口8443才使它正常工作。 - Abdenour Keddar
跟我一样。在我的情况下,我必须在我的AWS自定义安装中打开一个安全组。 - Joao M
3
非常有帮助,谢谢!我只添加了端口8443,就成功了。您可能需要添加一些关于在创建防火墙规则时选择哪个源的信息(我使用了在创建集群时指定的整个块 --master-ipv4-cidr=)。 - otherguy
2
这是正确的答案。更好地过滤主CIDR源。 - motobói
1
谢谢你,Mauricio,你的指导对我帮助很大。非常感激。 - Stanislav Hordiyenko

21

可能是因为之前的nginx-ingress-controller配置引起的。
您可以尝试运行以下命令 -

kubectl delete -A ValidatingWebhookConfiguration ingress-nginx-admission

谢谢。你的评论可能解释了我的情况。我成功安装了一些较旧版本的入口控制器,感谢一些没有更新的文档(或者是我没有注意)。 - ilvez
这对我有用。我之前安装了ingress-nginx,然后更新了docker并重新安装了ingress-nginx,之后我遇到了错误,但是使用这个命令,我能够摆脱以前的nginx-ingress控制器配置。 - Eric Guzman

12

我已经解决了这个问题。问题在于您使用的是Kubernetes版本1.18,但当前ingress-Nginx中的ValidatingWebhookConfiguration使用的是最旧的API;请参阅文档: https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#prerequisites

确保Kubernetes集群至少与v1.16一样新(以使用admissionregistration.k8s.io/v1),或者v1.9(以使用admissionregistration.k8s.io/v1beta1)。

并且在当前的yaml文件中:

 # Source: ingress-nginx/templates/admission-webhooks/validating-webhook.yaml
    # before changing this value, check the required kubernetes version
    # https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#prerequisites
apiVersion: admissionregistration.k8s.io/v1beta1

并且在规则中:

apiVersions:
          - v1beta1

所以你需要在v1上进行更改:

apiVersion: admissionregistration.k8s.io/v1

并添加规则-v1:

apiVersions:
          - v1beta1
          - v1

在您更改并重新部署后,您的自定义Ingress服务将成功部署。


1
为了知道哪个版本的 admissionregistration.k8s.io 与您的设置兼容,请使用 kubectl api-versions | grep admissionregistration - Lucas Cimon
这太棒了,它让我在长时间的故障排除后得以解脱。谢谢 Oleg。 - Brett
那似乎解决了我的问题,伙计。谢谢! - davidfm
Oleg,在“or v1.9(使用admissionregistration.k8s.io/v1beta1)”中,你是不是想写v1.19?截至我撰写此文,v1.24似乎是最新的K8s版本。 - David Wesby

9

最终,我通过更改安装方式成功地运行了Ingress Nginx。我仍然不明白为什么之前的安装没有起作用,但是我将分享解决方案以及对原始问题的更多见解。

解决方案

卸载Ingress Nginx:删除ingress-nginx命名空间。这不会删除验证Webhook配置-请手动删除此配置。然后安装MetalLB并重新安装Ingress Nginx。我现在使用了来自Helm稳定库的版本。现在一切都按预期工作了。感谢kubernetes Slack频道上的Long!

对原始问题的更多见解

安装指南提供的YAML包含一个ValidatingWebHookConfiguration:

apiVersion: admissionregistration.k8s.io/v1beta1
kind: ValidatingWebhookConfiguration
metadata:
  labels:
    helm.sh/chart: ingress-nginx-2.0.3
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/version: 0.32.0
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/component: admission-webhook
  name: ingress-nginx-admission
  namespace: ingress-nginx
webhooks:
  - name: validate.nginx.ingress.kubernetes.io
    rules:
      - apiGroups:
          - extensions
          - networking.k8s.io
        apiVersions:
          - v1beta1
        operations:
          - CREATE
          - UPDATE
        resources:
          - ingresses
    failurePolicy: Fail
    clientConfig:
      service:
        namespace: ingress-nginx
        name: ingress-nginx-controller-admission
        path: /extensions/v1beta1/ingresses

每当我创建或更新一个入口时(我的ingress.yaml的内容不重要),都会执行验证。验证失败,因为调用服务时,响应是临时重定向。我不知道原因。

相应的服务是:

apiVersion: v1
kind: Service
metadata:
  labels:
    helm.sh/chart: ingress-nginx-2.0.3
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/version: 0.32.0
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/component: controller
  name: ingress-nginx-controller-admission
  namespace: ingress-nginx
spec:
  type: ClusterIP
  ports:
    - name: https-webhook
      port: 443
      targetPort: webhook
  selector:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/component: controller

选择器匹配的 Pod 来自此部署:
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    helm.sh/chart: ingress-nginx-2.0.3
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/version: 0.32.0
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/component: controller
  name: ingress-nginx-controller
  namespace: ingress-nginx
spec:
  selector:
    matchLabels:
      app.kubernetes.io/name: ingress-nginx
      app.kubernetes.io/instance: ingress-nginx
      app.kubernetes.io/component: controller
  revisionHistoryLimit: 10
  minReadySeconds: 0
  template:
    metadata:
      labels:
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/instance: ingress-nginx
        app.kubernetes.io/component: controller
    spec:
      dnsPolicy: ClusterFirst
      containers:
        - name: controller
          image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.32.0
          imagePullPolicy: IfNotPresent
          lifecycle:
            preStop:
              exec:
                command:
                  - /wait-shutdown
          args:
            - /nginx-ingress-controller
            - --election-id=ingress-controller-leader
            - --ingress-class=nginx
            - --configmap=ingress-nginx/ingress-nginx-controller
            - --validating-webhook=:8443
            - --validating-webhook-certificate=/usr/local/certificates/cert
            - --validating-webhook-key=/usr/local/certificates/key
          securityContext:
            capabilities:
              drop:
                - ALL
              add:
                - NET_BIND_SERVICE
            runAsUser: 101
            allowPrivilegeEscalation: true
          env:
            - name: POD_NAME
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
            - name: POD_NAMESPACE
              valueFrom:
                fieldRef:
                  fieldPath: metadata.namespace
          livenessProbe:
            httpGet:
              path: /healthz
              port: 10254
              scheme: HTTP
            initialDelaySeconds: 10
            periodSeconds: 10
            timeoutSeconds: 1
            successThreshold: 1
            failureThreshold: 3
          readinessProbe:
            httpGet:
              path: /healthz
              port: 10254
              scheme: HTTP
            initialDelaySeconds: 10
            periodSeconds: 10
            timeoutSeconds: 1
            successThreshold: 1
            failureThreshold: 3
          ports:
            - name: http
              containerPort: 80
              protocol: TCP
            - name: https
              containerPort: 443
              protocol: TCP
            - name: webhook
              containerPort: 8443
              protocol: TCP
          volumeMounts:
            - name: webhook-cert
              mountPath: /usr/local/certificates/
              readOnly: true
          resources:
            requests:
              cpu: 100m
              memory: 90Mi
      serviceAccountName: ingress-nginx
      terminationGracePeriodSeconds: 300
      volumes:
        - name: webhook-cert
          secret:
            secretName: ingress-nginx-admission

这个验证链中出现了问题。知道是什么和为什么很有趣,但我可以继续使用我的MetalLB解决方案。请注意,此解决方案根本不包含验证webhook。


6

我不确定这是否能在此时对您有所帮助,但您的集群是否在代理后面?如果是这种情况,您需要正确配置no_proxy。具体来说,它必须包括.svc,.cluster.local,否则验证Webhook请求(例如https://ingress-nginx-controller-admission.ingress-nginx.svc:443/extensions/v1beta1/ingresses?timeout=30s中的.svc)将通过代理服务器路由。

我曾经遇到过这个问题,将.svc添加到no_proxy变量中可以解决。您可以通过修改/etc/kubernetes/manifests/kube-apiserver.yaml文件来快速尝试,这将自动重新创建您的Kubernetes API服务器pod。

这不仅适用于入口验证,还适用于其他可能引用以.svc.namespace.svc.cluster.local结尾的集群URL的事物(请参见此错误)。


1
顺便说一句 - 我不会禁用Ingress资源的验证Webhook。它们存在是有原因的,可以防止某人应用损坏的Ingress(不是语法问题,而是运行时问题)导致您的控制器完全崩溃。然后,该Ingress控制器后面的所有应用程序都将变为不可用状态。 - petermicuch
确实,我在代理后面。你的解决方案看起来很干净,而且有效。谢谢! - PhotonTamer
@petermicuch,请详细说明如何操作。我尝试添加-->--no_proxy=".svc",重启主节点后,我的 kubectl 仍无法访问它。 - Bino Oetomo

6

在裸机集群上,我在Helm3安装期间禁用了admissionWebhooks

kubectl create ns ingress-nginx

helm install [RELEASE_NAME] ingress-nginx/ingress-nginx -n ingress-nginx --set controller.admissionWebhooks.enabled=false


4
在我的情况下,是AWS EKS模块,现在该模块配备有强化的安全组。但是Nginx-ingress需要集群与Ingress控制器进行通信,因此我必须在节点安全组中将以下端口列入白名单。
  node_security_group_additional_rules = {
    cluster_to_node = {
      description      = "Cluster to ingress-nginx webhook"
      protocol         = "-1"
      from_port        = 8443
      to_port          = 8443
      type             = "ingress"
      source_cluster_security_group = true
    }
  }

input_node_security_group_additional_rules


请问您能否分享如何在AWS UI中实现此功能?我没有看到类型为ingress,而自定义协议不允许端口。 - Ishika Jain
1
在AWS UI中,您可以单击任何工作节点,选择安全性 -> 安全组并打开所需的端口。 - Adiii
如果有人正在遵循Nginx Ingress的官方指南(https://kubernetes.github.io/ingress-nginx/deploy/#aws)并使用Terraform,这就是解决方案。 - johnny68

2
如果使用terraform和helm,请禁用验证Webhook。
resource "helm_release" "nginx_ingress" {

...

  set {
    name  = "controller.admissionWebhooks.enabled"
    value = "false"
  }

...

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接