You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kubernetes中Cert-manager HTTP-01挑战超时问题求助

问题描述

我有一个单节点裸金属Kubernetes集群,已部署MetalLB和Nginx Ingress Controller用于集群流量路由。

  • Kubernetes v1.28.3
  • MetalLB v0.13.12
  • Nginx Ingress Controller v1.8.0
  • Cert-manager v1.13.2

我创建了Ingress资源将请求路由到集群内部署的ArgoCD实例,并安装了cert-manager Helm Chart用于TLS证书管理。

ClusterIssuer状态正常:

$ kubectl get clusterissuer -o wide

NAME                     READY   STATUS                                                 AGE
letsencrypt-production   True    The ACME account was registered with the ACME server   4d1h
letsencrypt-staging      True    The ACME account was registered with the ACME server   4d1h
selfsigned               True                                                           4d1h

ArgoCD的Ingress资源配置如下:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-production
    kubernetes.io/tls-acme: "true"
    nginx.ingress.kubernetes.io/backend-protocol: HTTPS
    nginx.ingress.kubernetes.io/ssl-passthrough: "true"
  labels:
    app.kubernetes.io/component: server
    app.kubernetes.io/environment: develop
    app.kubernetes.io/instance: argocd
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: argocd-server
    app.kubernetes.io/part-of: argocd
    app.kubernetes.io/version: v2.8.6
    helm.sh/chart: argo-cd-5.50.1
  name: argocd-server
  namespace: develop
spec:
  ingressClassName: nginx
  rules:
  - host: argocd.mydomain.com
    http:
      paths:
      - backend:
          service:
            name: argocd-server
            port:
              number: 443
        path: /
        pathType: Prefix
  tls:
  - hosts:
    - argocd.mydomain.com
    secretName: argocd-secret

但ACME挑战无法完成,Challenge、Order和Certificate资源一直处于Pending状态:

Waiting for HTTP-01 challenge propagation: failed to perform self check GET request 'http://argocd.mydomain.com/.well-known/acme-challenge/Scy7Eh4E8LvN6yM1rT3y4qcCYKfEVZ6MHJdQNqKJN7M'.
Get "http://argocd.mydomain.com/.well-known/acme-challenge/Scy7Eh4E8LvN6yM1rT3y4qcCYKfEVZ6MHJdQNqKJN7M": context deadline exceeded (Client.Timeout exceeded while awaiting headers)

奇怪的是,集群外机器curl该URL能正常响应,但集群节点或集群内Pod中请求超时。DNS解析正常:

$ nslookup argocd.mydomain.com

Server:         127.0.0.53
Address:        127.0.0.53#53

Non-authoritative answer:
argocd.mydomain.com  canonical name = mydoamin.com.
Name:   mydomain.com
Address: xx.xx.xx.xx

用节点内网IP加Host头curl正常:

curl http://192.168.1.1/.well-known/acme-challenge/Scy7Eh4E8LvN6yM1rT3y4qcCYKfEVZ6MHJdQNqKJN7M -H "Host: argocd.mydomain.com"

但用FQDN请求就超时。Ingress Nginx Controller Service配置:

spec:
  allocateLoadBalancerNodePorts: true
  clusterIP: 10.96.108.180
  clusterIPs:
  - 10.96.108.180
  externalTrafficPolicy: Local
  healthCheckNodePort: 30708
  internalTrafficPolicy: Cluster
  ipFamilies:
  - IPv4
  ipFamilyPolicy: SingleStack
  ports:
  - appProtocol: http
    name: http
    nodePort: 31629
    port: 80
    protocol: TCP
    targetPort: http
  - appProtocol: https
    name: https
    nodePort: 30634
    port: 443
    protocol: TCP
    targetPort: https

cm-acme-http-solver已创建,日志显示收到挑战请求:

I1113 18:50:06.845744       1 solver.go:87] 
cert-manager/acmesolver: got successful challenge request, writing key" host="mydomain.com" path="/.well-known/acme-challenge/1yJeWYLrQ_EP5MjWH_0Ztq8NodV81kaFkPHQ6Kz41CM" base_path="/.well-known/acme-challenge" token="1yJeWYLrQ_EP5MjWH_0Ztq8NodV81kaFkPHQ6Kz41CM

更换CNI(weave-net→Calico)后问题依旧,公网IP请求挑战URL超时,但用LoadBalancer内网IP请求正常。

解决方案

1. 修复集群内部回环流量问题

核心原因是单节点集群的hairpin NAT缺失:当集群内部Pod请求FQDN解析到公网IP后,因Ingress Controller的externalTrafficPolicy: Local配置,流量无法正确回传到Ingress服务。

修改Ingress Controller Service的流量策略:

kubectl patch service ingress-nginx-controller -n ingress-nginx -p '{"spec":{"externalTrafficPolicy":"Cluster"}}'

等待Service刷新后,重新触发证书挑战:

kubectl delete certificate argocd-secret -n develop

2. 临时调整SSL Passthrough配置

Ingress中的nginx.ingress.kubernetes.io/ssl-passthrough: "true"会让Nginx直接转发HTTPS流量到ArgoCD,可能干扰HTTP-01挑战的路由逻辑。

临时移除该注解,等证书颁发后再恢复:

# 从Ingress的metadata.annotations中删除以下行
nginx.ingress.kubernetes.io/ssl-passthrough: "true"

更新Ingress后重新触发挑战。

3. 检查节点防火墙/iptables规则

确认节点防火墙未拦截集群内部到节点公网IP的80端口流量:

iptables -L -n | grep 80

确保存在允许Pod网段访问节点80端口的规则,若缺失需手动添加。

4. 验证MetalLB ARP配置

检查MetalLB的ConfigMap,确认IP池属于节点内网网段,且ARP模式配置正确:

kubectl get configmap metallb-config -n metallb-system -o yaml

单节点环境下,确保MetalLB分配的LoadBalancer IP与节点内网IP在同一网段。

5. 切换到DNS01挑战(备选)

若HTTP-01挑战始终无法解决,可改用DNS01挑战,无需集群内部回环流量。修改Ingress注解指定挑战类型:

# 在Ingress metadata.annotations中添加
cert-manager.io/acme-challenge-type: dns01

需确保域名服务商支持DNS API自动更新解析记录,同时对应ClusterIssuer已配置DNS服务商的API密钥。

内容的提问来源于stack exchange,提问作者Jose Rodriguez

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 14:34:56