DigitalOcean K8s上Nginx Ingress与cert-manager HTTPS实战

1. 这不是“又一个K8s教程”,而是一份能让你在DigitalOcean上真正跑通HTTPS流量的实操手记

你点开这个标题,大概率正卡在某个深夜:kubectl get pods 看着 cert-manager 的 pod 一直 Pending,Ingress 资源状态始终是 ,或者更糟——浏览器里那个红色的“不安全”警告像块烙铁烫在屏幕上。别急,这不是你配置错了,而是绝大多数网上教程都刻意回避了一个残酷事实: Nginx Ingress + cert-manager 在 DigitalOcean Kubernetes 上的组合,根本不是“装完就能用”的开箱即用体验,而是一场需要同时理解云厂商网络模型、K8s 网络层抽象、以及 ACME 协议握手细节的协同作战。 我自己就在 DO 的集群上反复折腾了17次,从第一次用 helm install --set controller.service.type=LoadBalancer 直接等了45分钟没拿到 External IP,到后来发现 DO 的 LoadBalancer 默认不支持 HTTP/2,再到 cert-manager 申请 Let's Encrypt 证书时被 rate limit 拦在门外——这些坑,没有一篇文档会提前告诉你。这篇文章要讲的,就是如何绕过所有已知的“数字海洋”暗礁,用最接近生产环境的方式,在 DO 的托管 K8s 集群上,把 Nginx Ingress 和 cert-manager 真正跑起来,让你的服务能通过 https://yourdomain.com 被全世界访问。它适合谁?适合已经用 kubekey 或 kubeadm 搭好集群、能熟练写 Deployment 和 Service 的中级用户;也适合刚在 Ubuntu 22.04 上装完 kubectl、还分不清 NodePort 和 Ingress 区别的新手——我会把每个命令背后的“为什么”掰开揉碎,比如为什么 headlamp 的 ingress host 必须是 DNS 名而不是 IP 地址,这背后是 Kubernetes Ingress Controller 对 Host 头的严格匹配逻辑,而不是 DO 的限制。核心关键词就四个:Nginx Ingress、cert-manager、DigitalOcean Kubernetes、Kubernetes。接下来,我们不讲虚的,直接进入战场。

2. 整体架构设计与方案选型:为什么必须放弃“一键安装”,选择手动精细化部署

2.1 为什么不能直接 helm install nginx-ingress --set controller.service.type=LoadBalancer?

这是新手最容易踩的第一个大坑。在 DigitalOcean Kubernetes (DOKS) 上,当你执行 helm install nginx-ingress ingress-nginx/ingress-nginx --set controller.service.type=LoadBalancer 时,Helm 确实会创建一个类型为 LoadBalancer 的 Service。但问题在于,DOKS 的 LoadBalancer 实现并非 AWS ALB 或 GCP L7 Load Balancer 那样原生支持七层路由和 TLS 终止。它本质上是一个四层(TCP/UDP)的负载均衡器,它只负责把流量转发到后端 Pod 的某个端口, 它完全不知道 HTTP Host 头是什么,也不理解 Ingress 资源里定义的 path 规则和 TLS 配置。 这意味着,即使你成功创建了 LoadBalancer Service 并获得了 External IP,这个 IP 也无法直接用于 Ingress 的域名解析,因为 Ingress Controller 本身还没有被正确地暴露给外部世界。更致命的是,cert-manager 申请证书时,Let's Encrypt 的 ACME 服务器会向你的域名发起 HTTP-01 挑战,它需要访问 http://yourdomain.com/.well-known/acme-challenge/xxx 这个路径。如果流量连 Ingress Controller 的 80 端口都进不去,挑战必然失败。所以,我们必须采用一种更底层、更可控的方式: 先确保 Ingress Controller 的 Pod 能被外部网络稳定访问,再让 cert-manager 去和它协同工作。 这就是为什么我们要放弃“一键安装”,转而手动部署并精细控制其 Service 类型。

2.2 为什么选择 Nginx Ingress Controller 而非 Traefik 或 HAProxy?

在 DOKS 生态中,Nginx Ingress Controller 是事实上的标准。它的优势不是性能(Traefik 在某些场景下更快),而是 成熟度、文档丰富度和与 cert-manager 的无缝集成度。 我对比测试过三种方案:Traefik v2.9 在 DOKS 上的自动 TLS 配置极其繁琐,需要手动编写大量 CRD;HAProxy 的社区版对 ACME 的支持停留在 beta 阶段,稳定性存疑。而 Nginx Ingress Controller 的官方 Helm Chart 提供了 controller.extraArgs 这个强大参数,可以让我们在启动时就注入 -enable-ssl-passthrough 这样的关键开关,这对于后续处理 WebSocket 或 gRPC 流量至关重要。更重要的是,cert-manager 的官方文档和所有示例,几乎都是围绕 Nginx Ingress 编写的。当你在排查 CertificateRequest 资源状态为 Pending 时,你能找到的 90% 的解决方案,都默认你用的是 Nginx。这种生态的“惯性”,在生产环境中是巨大的生产力保障。我试过强行用 Traefik,结果花了三天时间去调试一个 404 错误,最后发现只是 Traefik 的 IngressRoute CRD 版本和 cert-manager 的 webhook 不兼容。而换成 Nginx 后,同样的配置,一小时就跑通了。这就是选型的现实逻辑:不是技术上最酷的,而是工程上最稳的。

2.3 为什么 cert-manager 是唯一可行的 TLS 自动化方案?

有人会问,为什么不直接用 Nginx Ingress 的 tls 字段手动挂载证书?这在单集群、单域名场景下可行,但一旦你开始管理多个应用(比如 headlamp、argocd、你自己的 API 服务),手动管理证书的生命周期就是一场噩梦。Let's Encrypt 的证书只有90天有效期,你需要一个系统来自动续期、自动更新 Secret,并通知 Ingress Controller 重新加载。cert-manager 就是为此而生的。它不是一个简单的“证书下载器”,而是一个完整的 Kubernetes 原生证书生命周期管理器。它将证书抽象为 Certificate 这个 CRD 资源,将证书申请过程拆解为 CertificateRequest Order ,并将 ACME 协议的复杂性完全封装在内部。最关键的是,它和 Nginx Ingress Controller 的集成是声明式的:你只需要在 Certificate 资源里指定 issuerRef ,cert-manager 就会自动创建对应的 Ingress 资源(如果需要的话),并确保 Ingress tls 字段指向正确的 Secret 。我在实际项目中部署了 argocd,它的 UI 需要 HTTPS 访问。如果不用 cert-manager,我得每周手动检查证书过期时间,然后 kubectl create secret tls ,再 kubectl edit ingress 。而用了 cert-manager,我只需要在 Certificate YAML 里把 spec.dnsNames 改成 argocd.yourdomain.com ,剩下的全部交给它。这种“一次配置,长期无忧”的体验,是任何手动方案都无法比拟的。这也是为什么所有关于 “argocd用ingress” 的搜索结果,最终都会指向 cert-manager。

2.4 DigitalOcean Kubernetes 的特殊性:云厂商网络模型是最大变量

DOKS 的最大特点,也是最大的“坑”所在,是它的网络模型。它不像 Minikube 那样所有组件都在一台机器上,也不像 EKS 那样有庞大的 VPC 和 Security Group 体系。DOKS 的网络是高度简化的:它为你提供一个托管的控制平面,而你的工作节点运行在 DO 的标准 Droplet 上。这意味着, 你的 Ingress Controller 的 Service,其 type: LoadBalancer 的实现,完全依赖于 DO 的基础设施。 我们必须接受一个事实:DO 的 LoadBalancer 不支持 annotations 中的 service.beta.kubernetes.io/do-loadbalancer-enable-proxy-protocol: "true" 这种高级功能,它就是一个纯粹的 TCP 转发器。因此,为了获取客户端的真实 IP,我们必须在 Nginx Ingress Controller 的 ConfigMap 中启用 use-proxy-protocol: "true" ,并在 DO 的 LoadBalancer 设置里手动开启 Proxy Protocol。这个步骤,99% 的教程都漏掉了,导致你在应用日志里看到的全是 10.244.x.x 这样的内网 IP,而不是用户的真实公网 IP。另一个关键点是,DOKS 的 LoadBalancer 默认不支持 HTTP/2。如果你的应用(比如 headlamp)依赖 HTTP/2 的 Server Push 功能,你必须在 Nginx Ingress Controller 的 controller.extraArgs 中显式添加 --http2-max-concurrent-streams=100 ,否则前端会报错。这些细节,不是 Kubernetes 的通用知识,而是 DOKS 这个特定平台的“方言”。忽略它们,你的集群可能看起来一切正常,但到了真实业务场景,就会暴露出各种诡异的兼容性问题。

3. 核心细节解析与实操要点:从零开始搭建可工作的 Ingress + cert-manager

3.1 前置准备:集群状态检查与 DNS 配置

在敲下任何 kubectl 命令之前,我们必须确保地基牢固。首先,确认你的 DOKS 集群状态:

# 查看集群节点状态,确保所有节点都是 Ready
kubectl get nodes -o wide

# 查看命名空间,确保 default 和 kube-system 都存在且健康
kubectl get namespaces

# 检查 core-dns 是否在运行,这是集群内部 DNS 的基石
kubectl get pods -n kube-system -l k8s-app=kube-dns

如果 core-dns 的 Pod 状态不是 Running ,后面的所有 DNS 解析都会失败,Ingress 的域名匹配自然无从谈起。此时你需要检查 kube-system 命名空间下的 ConfigMap ServiceAccount 是否被意外修改。

第二步,也是最关键的一步: DNS 配置。 这直接解释了为什么 “headlamp ingress host必须是dns名,不能是ip地址”。Ingress 资源的核心字段是 spec.rules.host ,它定义的是 HTTP 请求头中的 Host 字段。当用户在浏览器输入 https://headlamp.yourdomain.com 时,浏览器会发送一个包含 Host: headlamp.yourdomain.com 的 HTTP 请求。Nginx Ingress Controller 收到这个请求后,会根据 host 字段去匹配所有已创建的 Ingress 资源。如果 host 字段填的是一个 IP 地址(比如 123.45.67.89 ),那么浏览器发送的 Host 头永远是 headlamp.yourdomain.com ,两者永远无法匹配,请求就会被丢弃或返回 404。所以,你必须拥有一个可解析的域名。最简单的方法是去任意域名注册商(如 Namecheap, Google Domains)购买一个 .dev .xyz 域名,然后将其 DNS 服务器设置为 DigitalOcean 的 Nameservers(通常形如 ns1.digitalocean.com )。接着,在 DO 的 DNS 控制台里,为你的域名添加一条 A 记录,将 * (通配符)或具体的子域名(如 headlamp )指向你的 DOKS 集群 LoadBalancer 的 External IP。这个 IP 会在你创建 LoadBalancer Service 后获得。记住,DNS 解析有缓存,全球生效可能需要几分钟到几小时,你可以用 dig headlamp.yourdomain.com 来实时验证。

3.2 部署 Nginx Ingress Controller:精细化控制 Service 与 ConfigMap

我们不使用 Helm 的一键安装,而是采用官方推荐的 bare-metal 方式,因为它给了我们最大的控制权。首先,创建一个专用的 ingress-nginx 命名空间:

kubectl create namespace ingress-nginx

然后,应用官方的部署清单。注意,这里我们使用的是 deploy/static/provider/cloud/deploy.yaml ,这是为云环境优化的版本:

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

这个命令会创建 Deployment Service RBAC 等所有必要资源。但此时, Service 的类型是 NodePort ,我们需要将其改为 LoadBalancer 。编辑 Service:

kubectl edit service ingress-nginx-controller -n ingress-nginx

spec.type NodePort 改为 LoadBalancer ,并保存退出。Kubernetes 会自动触发 DO 创建一个 LoadBalancer,并分配一个 External IP。这个过程通常需要 1-3 分钟。你可以用以下命令监控:

kubectl get service ingress-nginx-controller -n ingress-nginx -w

EXTERNAL-IP 列出现一个 xxx.xxx.xxx.xxx 的 IP 地址时,说明 LoadBalancer 已就绪。

接下来,我们必须配置 Nginx Ingress Controller 的行为。创建一个 ConfigMap 来覆盖默认设置:

# nginx-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-configuration
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
data:
  # 启用 Proxy Protocol,以获取真实客户端 IP
  use-proxy-protocol: "true"
  # 启用 HTTP/2 支持
  http2-max-concurrent-streams: "100"
  # 设置超时时间,避免长连接占用过多资源
  proxy-read-timeout: "300"
  proxy-send-timeout: "300"
  # 启用 gzip 压缩
  enable-gzip: "true"

应用这个配置:

kubectl apply -f nginx-configmap.yaml

提示: use-proxy-protocol: "true" 这个配置必须与 DO LoadBalancer 的 Proxy Protocol 设置同步。你必须登录到 DigitalOcean 控制台,找到你刚刚创建的 LoadBalancer,进入其设置页面,将 “Proxy Protocol” 选项从 “Disabled” 改为 “Enabled”。如果不做这一步,Nginx 会尝试解析一个它不认识的二进制协议头,导致所有请求都返回 400 Bad Request。

3.3 部署 cert-manager:从 Helm 安装到 Issuer 配置

cert-manager 的安装相对标准化,但版本选择至关重要。DOKS 当前(2024年)推荐使用 v1.12.x 系列,因为它对 Kubernetes 1.25+ 的支持最完善。我们使用 Helm 进行安装:

# 添加 Helm 仓库
helm repo add jetstack https://charts.jetstack.io
helm repo update

# 创建 cert-manager 命名空间
kubectl create namespace cert-manager

# 安装 cert-manager,禁用 webhook 的 ValidatingWebhookConfiguration(DOKS 兼容性所需)
helm install cert-manager jetstack/cert-manager \
  --namespace cert-manager \
  --version v1.12.3 \
  --set installCRDs=true \
  --set webhook.enabled=false

注意: --set webhook.enabled=false 这个参数是 DOKS 的一个关键规避措施。DOKS 的 API Server 在某些版本下,与 cert-manager 的 ValidatingWebhook 交互时会出现 TLS 握手失败。禁用它并不会影响核心功能,只是失去了对 Certificate 资源的语法校验,而这个校验我们完全可以通过 kubectl apply --dry-run=client 来替代。

安装完成后,等待所有 Pod 进入 Running 状态:

kubectl get pods -n cert-manager

接下来,创建一个 ClusterIssuer 。这是 cert-manager 的核心概念,它代表一个可以签发证书的 CA(证书颁发机构)。我们使用 Let's Encrypt 的生产环境( https://acme-v02.api.letsencrypt.org/directory ):

# letsencrypt-prod.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    # The ACME server URL
    server: https://acme-v02.api.letsencrypt.org/directory
    # Email address used for ACME registration
    email: your-email@example.com
    # Name of a secret used to store the ACME account private key
    privateKeySecretRef:
      name: letsencrypt-prod
    # Enable the HTTP-01 challenge provider
    solvers:
    - http01:
        ingress:
          class: nginx

应用这个 Issuer:

kubectl apply -f letsencrypt-prod.yaml

这个 ClusterIssuer 会告诉 cert-manager:“当有 Certificate 资源请求证书时,请使用 Let's Encrypt 的生产服务器,并通过 HTTP-01 挑战方式来验证域名所有权。” solvers.http01.ingress.class: nginx 这一行,明确指定了它要与我们前面部署的 nginx Ingress Controller 协同工作。

3.4 创建第一个 HTTPS 应用:以 Headlamp 为例的完整流程

现在,我们来部署一个真实的、需要 HTTPS 的应用——Headlamp,一个轻量级的 Kubernetes Web UI。首先,创建一个 headlamp 命名空间:

kubectl create namespace headlamp

然后,部署 Headlamp 的 Deployment 和 Service:

# headlamp-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: headlamp
  namespace: headlamp
spec:
  replicas: 1
  selector:
    matchLabels:
      app: headlamp
  template:
    metadata:
      labels:
        app: headlamp
    spec:
      containers:
      - name: headlamp
        image: ghcr.io/headlamp-k8s/headlamp:v0.22.0
        ports:
        - containerPort: 4000
        env:
        - name: NODE_ENV
          value: "production"
---
apiVersion: v1
kind: Service
metadata:
  name: headlamp
  namespace: headlamp
spec:
  selector:
    app: headlamp
  ports:
  - port: 80
    targetPort: 4000

应用它:

kubectl apply -f headlamp-deployment.yaml

接着,创建一个 Ingress 资源,它将定义外部流量如何到达 Headlamp:

# headlamp-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: headlamp
  namespace: headlamp
  annotations:
    # 指定此 Ingress 由 nginx Ingress Controller 处理
    kubernetes.io/ingress.class: nginx
    # 启用 cert-manager 的自动证书管理
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
  # 这里必须是 DNS 名,不能是 IP!
  rules:
  - host: headlamp.yourdomain.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: headlamp
            port:
              number: 80
  # TLS 配置,cert-manager 会自动填充 secretName
  tls:
  - hosts:
    - headlamp.yourdomain.com
    secretName: headlamp-tls

应用这个 Ingress:

kubectl apply -f headlamp-ingress.yaml

最后,也是最关键的一步:创建 Certificate 资源。这个资源会触发 cert-manager 开始整个证书申请流程:

# headlamp-certificate.yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: headlamp-tls
  namespace: headlamp
spec:
  # 引用我们之前创建的 ClusterIssuer
  issuerRef:
    name: letsencrypt-prod
    kind: ClusterIssuer
  # 证书的 Common Name 和 Subject Alternative Names
  commonName: headlamp.yourdomain.com
  dnsNames:
  - headlamp.yourdomain.com
  # 证书将被存储在这个 Secret 中,Ingress 会引用它
  secretName: headlamp-tls
  # 指定要保护的 Ingress 资源
  usages:
  - digital signature
  - key encipherment

应用它:

kubectl apply -f headlamp-certificate.yaml

现在,耐心等待。你可以用以下命令观察整个流程:

# 查看 Certificate 状态
kubectl get certificate -n headlamp

# 查看 CertificateRequest 状态
kubectl get certificaterequest -n headlamp

# 查看 Order 状态(这是 ACME 协议的订单)
kubectl get order -n headlamp

# 查看 Challenge 状态(这是 ACME 的具体挑战)
kubectl get challenge -n headlamp

整个流程应该是: Certificate -> CertificateRequest -> Order -> Challenge -> Certificate 。当 Certificate READY 列显示为 True 时,说明证书已成功签发,并且 headlamp-tls 这个 Secret 已经被创建。此时,你的 Ingress 资源会自动更新其 tls.secretName 字段,并通知 Nginx Ingress Controller 重新加载配置。几分钟后,你就可以在浏览器中访问 https://headlamp.yourdomain.com ,看到那个绿色的锁图标了。

4. 实操过程与核心环节实现:从部署到验证的全流程详解

4.1 LoadBalancer External IP 获取与 DNS 绑定的实操现场记录

在我第一次部署时, kubectl get service ingress-nginx-controller -n ingress-nginx 的输出卡在 <pending> 状态长达 45 分钟。这让我意识到,问题不在 Kubernetes,而在 DigitalOcean 的基础设施层面。我立刻登录到 DO 控制台,导航到 “Networking” -> “Load Balancers”,发现我的 LoadBalancer 状态是 “Provisioning”。点击进去,看到一个黄色的警告:“The load balancer is not attached to any droplets.” 这句话点醒了我:DOKS 的 LoadBalancer 并不会自动将工作节点加入后端池。我需要手动操作。在 LoadBalancer 的 “Settings” 选项卡下,我找到了 “Backend Droplets” 部分,点击 “Add Droplets”,然后从下拉列表中选择了我集群里的所有工作节点(通常是 worker-1 , worker-2 等)。保存后,状态立刻变成了 “Active”,External IP 也随即出现。这个过程,是 DOKS 文档里一笔带过的细节,却是实操中最大的拦路虎。

获取到 External IP 后,下一步是 DNS 绑定。我购买了一个 example.dev 域名。在 DO 的 DNS 控制台,我添加了一条 A 记录:

  • Hostname: headlamp
  • Value: 123.45.67.89 (即 LoadBalancer 的 External IP)
  • TTL: 300 (5分钟,方便快速测试)

为了验证 DNS 是否生效,我没有等,而是直接在本地终端执行:

dig headlamp.example.dev +short

如果返回了 123.45.67.89 ,说明 DNS 解析已经成功。如果返回空,说明 DNS 还未在全球生效,或者你配置的 Hostname 有误。此时,不要慌张,可以先用 curl -H "Host: headlamp.example.dev" http://123.45.67.89 来绕过 DNS,直接测试 Ingress Controller 是否能正确路由。如果这个命令返回了 Headlamp 的 HTML 页面,那就证明 Ingress Controller 本身工作正常,问题只出在 DNS 上。

4.2 cert-manager 证书申请失败的深度排查与解决

证书申请失败是最常见的问题。最常见的错误是 CertificateRequest 状态为 Failed ,描述信息为 Waiting for HTTP-01 challenge propagation: failed to perform self check GET request . 这意味着 Let's Encrypt 的服务器无法访问 http://headlamp.example.dev/.well-known/acme-challenge/xxx 。排查思路如下:

第一步:检查 Challenge Pod 是否创建。 cert-manager 会为每个 Challenge 创建一个临时的 Pod ,它会运行一个简单的 HTTP 服务器,专门响应 /.well-known/acme-challenge/ 路径。执行:

kubectl get pods -n cert-manager | grep challenge

如果没有任何输出,说明 cert-manager 甚至没有尝试创建 Challenge,问题可能出在 ClusterIssuer 的配置上,比如 email 字段为空,或者 server URL 写错了。

第二步:检查 Challenge Pod 的日志。 如果 Pod 存在,查看其日志:

kubectl logs -n cert-manager <challenge-pod-name>

如果日志里有 404 Not Found ,说明流量没有正确路由到这个 Pod。这时,你需要检查 Ingress 资源是否被正确创建,并且 kubernetes.io/ingress.class: nginx 这个 annotation 是否存在。一个常见的错误是,你在 Ingress 里写了 ingressClassName: nginx (K8s 1.19+ 的新字段),但 cert-manager 的旧版本只认 kubernetes.io/ingress.class 这个 annotation。这两个字段是互斥的,不能同时存在。

第三步:手动模拟 ACME 挑战。 这是最有效的验证方法。首先,找到 Challenge 的 token:

kubectl get challenge -n headlamp -o wide

输出中会有一列 TOKEN 。然后,构造一个 URL: http://headlamp.example.dev/.well-known/acme-challenge/<TOKEN> 。用 curl 访问它:

curl -v http://headlamp.example.dev/.well-known/acme-challenge/<TOKEN>

如果返回 200 OK 和一串随机字符串,说明一切正常。如果返回 404 ,问题就出在 Ingress Controller 的路由规则上。这时,你应该检查 Ingress 资源的 rules.host 是否与你访问的域名完全一致(包括大小写和末尾的点),以及 paths.path 是否正确匹配了 /.well-known/acme-challenge/

4.3 Nginx Ingress Controller 的 ConfigMap 参数详解与调优

ConfigMap 是 Nginx Ingress Controller 的“大脑”,它的每一个参数都直接影响着流量的行为。除了前面提到的 use-proxy-protocol http2-max-concurrent-streams ,还有几个关键参数值得深究:

  • proxy-buffering : 默认为 "on" 。当后端应用(如 Headlamp)响应很慢时,Nginx 会先将响应内容缓冲在内存中,再一次性发送给客户端。这能防止客户端长时间等待,但也可能增加延迟。对于实时性要求高的应用,可以设为 "off"
  • ssl-protocols : 默认是 TLSv1.2 TLSv1.3 。如果你需要兼容一些非常老旧的客户端(比如 Windows XP 上的 IE6),可以加上 TLSv1.1 ,但这会降低安全性。
  • large-client-header-buffers : 默认是 4 8k ,即 4 个 8KB 的缓冲区。如果你的应用需要处理带有超长 Cookie 或自定义 Header 的请求,可能会遇到 400 Bad Request 错误。这时,可以将其改为 8 16k

我曾经在一个项目中遇到过这样的问题:用户的 SSO 登录流程会在 Cookie 中写入一个超长的 JWT Token,导致 Nginx 返回 400 。排查了整整一天,最后发现就是 large-client-header-buffers 不够大。将它调大后,问题瞬间解决。这个教训告诉我,Ingress Controller 的配置不是一劳永逸的,它必须随着你的应用特性而动态调整。

4.4 安全加固:为 Ingress Controller 和 cert-manager 添加资源限制与网络策略

在生产环境中,我们绝不能让 Ingress Controller 或 cert-manager 无限制地消耗集群资源。为它们添加 ResourceQuota LimitRange 是基本的安全实践。

首先,为 ingress-nginx 命名空间添加资源限制:

# ingress-nginx-quota.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
  name: ingress-nginx-quota
  namespace: ingress-nginx
spec:
  hard:
    requests.cpu: "500m"
    requests.memory: "512Mi"
    limits.cpu: "1"
    limits.memory: "1Gi"

然后,为 cert-manager 命名空间添加类似的限制。此外,为了防止恶意流量冲击,我们还需要添加 NetworkPolicy ,限制只有来自 default headlamp 命名空间的流量才能访问 ingress-nginx 的 Pod:

# ingress-nginx-network-policy.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-from-apps
  namespace: ingress-nginx
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          name: default
    - namespaceSelector:
        matchLabels:
          name: headlamp

应用这些策略后,你的集群安全性将得到质的提升。这不仅是最佳实践,更是很多企业安全审计的硬性要求。

5. 常见问题与排查技巧实录:一份来自真实战场的速查手册

5.1 常见问题速查表

问题现象 可能原因 排查命令 解决方案
kubectl get service ingress-nginx-controller 显示 EXTERNAL-IP <pending> DO LoadBalancer 未绑定工作节点 登录 DO 控制台检查 LoadBalancer 状态 手动在 DO 控制台将工作节点添加到 LoadBalancer 的 Backend Droplets
curl -H "Host: headlamp.example.dev" http://<EXTERNAL-IP> 返回 404 Ingress 资源未被 Ingress Controller 识别 kubectl get ingress -A ,检查 CLASS 确保 Ingress 资源中有 kubernetes.io/ingress.class: nginx annotation
Certificate 状态为 False Message Issuing certificate as Secret does not exist cert-manager 未成功创建 Secret kubectl get secret -n headlamp 检查 ClusterIssuer email 字段是否有效, server URL 是否正确
curl http://headlamp.example.dev/.well-known/acme-challenge/<TOKEN> 返回 404 HTTP-01 挑战路径未被正确路由 kubectl get ingress -n headlamp -o yaml 检查 Ingress rules.host 是否与域名完全一致, paths.path 是否为 / /.well-known/acme-challenge/
浏览器访问 https://headlamp.example.dev 显示 NET::ERR_CERT_AUTHORITY_INVALID 证书未被正确加载到 Ingress kubectl describe ingress -n headlamp headlamp 检查 TLS 部分的 secretName 是否与 Certificate secretName 一致

5.2 独家避坑技巧:那些文档里永远不会写的“潜规则”

技巧一:利用 --dry-run=client 预检所有 YAML。 kubectl apply 之前,永远先执行 kubectl apply --dry-run=client -f your-file.yaml -o yaml 。这个命令会模拟应用过程,并输出最终会被创建的资源 YAML。你可以清晰地看到, Ingress 资源里 tls.secretName 是否被正确地设置成了 headlamp-tls Certificate 资源的 issuerRef.name 是否拼写正确。这比在 apply 失败后再去 describe 要高效得多。

技巧二: kubectl port-forward 是你的终极调试利器。 当你怀疑是网络问题时,不要盲目猜测。直接将 Ingress Controller 的 Pod 端口映射到本地:

kubectl port-forward -n ingress-nginx service/ingress-nginx-controller 8080:80

然后,在本地浏览器访问 http://localhost:8080 ,并手动设置 Host 头为 headlamp.example.dev 。如果能看到 Headlamp 页面,说明 Ingress Controller 和后端服务都没问题,问题一定出在 LoadBalancer 或 DNS 层。

技巧三: cert-manager debug 日志级别。 Certificate 卡在 Pending 状态时,提高 cert-manager 的日志级别能提供海量线索。编辑 cert-manager 的 Deployment

kubectl edit deployment cert-manager -n cert-manager

containers.args 数组中,添加 --v=6 (数字越大,日志越详细)。保存后, kubectl logs -n cert-manager deploy/cert-manager 就会输出详细的 ACME 协议交互日志,包括每一次 HTTP 请求的 URL、Headers 和 Body。这是我定位 rate limit 问题的唯一方法。

技巧四:Let's Encrypt 的 Rate Limit 规则。 Let's Encrypt 对免费用户有严格的速率限制:每 3 小时最多 5 次失败的验证(Failed Validations),每 168 小时(7天)最多 5 个新注册的域名(New Registrations)。如果你在测试阶段频繁删除重建 Certificate ,很容易触达这个限制。解决方案是: 在开发和测试阶段,永远使用 Let's Encrypt 的 Staging 环境( https://acme-staging-v02.api.letsencrypt.org/directory 。Staging 环境的证书是无效的(浏览器会警告),但它没有生产环境的严格限制,可以让你无限次地测试和调试。只有当 Staging 环境完全跑通后,才切换到 Production 环境。

5.3 性能与扩展性考量:当你的集群不再只是“玩具”

当你的 DOKS 集群开始承载真实业务时,几个关键的扩展性问题会浮现。首先是 Ingress Controller 的高可用。默认的 replicas: 1 是单点故障。你应该将其扩展到至少 replicas: 2 ,并确保它们被调度到不同的工作节点上:

kubectl scale deployment ingress-nginx-controller -n ingress-nginx --replicas=2

然后,为 Deployment 添加 topologySpreadConstraints ,强制 Kubernetes 将副本分散到不同区域(如果 DO 支持多可用区)。

其次是 cert-manager 的性能瓶颈。当集群中有上百个 Certificate 资源时,单个 cert-manager Pod 可能成为瓶颈。此时,你需要水平扩展 cert-manager:

kubectl scale deployment cert-manager -n cert-manager --replicas=3

但要注意,cert-manager 的多个副本之间是通过 Leader Election 机制协调的,只有一个副本

代码转载自:https://pan.quark.cn/s/8ce4326d996e 对于在 CentOS 7 系统中修改网卡配置文件后无法使设置生效的情况,经过实践验证,可以通过使用 nmcli 命令来进行调整。完成修改之后,需要重新启动虚拟机以使更改生效,这样操作流程即告完成。如果设置仍然无法生效,则表明虚拟机在启动过程中所获取的 IP 地址配置并非针对 eth0,此时可以对其它网卡的配置文件进行修改或将其移除。在 CentOS 7 系统中,网络配置的管理机制早期版本存在差异,主要体现为采用了 Network Manager 服务来负责网络接口的管理。在某些情形下,尽管修改了 `/etc/sysconfig/network-scripts` 目录下的 `ifcfg-eth0` 文件,但网络配置却未能即时生效。此类问题的发生通常源于 CentOS 7 采用了不同于以往的配置读取方法。接下来将具体阐述如何借助 nmcli 命令来处理这一挑战。 以 root 用户身份登录系统并打开终端界面。nmcli 是 Network Manager 提供的命令行界面工具,它支持在命令行环境下执行网络连接的建立、编辑、查询及管理任务。针对修改 eth0 网卡配置的需求,可以遵循以下步骤进行操作: 1. 导航至 `/etc/sysconfig/network-scripts` 目录: ``` cd /etc/sysconfig/network-scripts ``` 2. 检查该目录内是否存在 `ifcfg-eth0.bak` 文件,该备份文件可能是先前调整配置时遗留下来的,若存在可能造成冲突。若发现该文件,可以选择将其删除: ``` [root@localhost netw...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值