Ingress NGINX Controller 自定义错误页面完整指南:基于自定义 default-backend 的 Custom Errors 实战
【免费下载链接】ingress-nginxIngress NGINX Controller for Kubernetes项目地址: https://gitcode.com/GitHub_Trending/in/ingress-nginx
导读
本文基于 Ingress NGINX Controller 仓库中的官方示例 custom-errors README,系统讲解如何用自定义 default-backend 服务渲染自定义错误页面:包括 Helm Chart 与手动部署两种方式、custom-http-errors配置的底层原理、curl 验证方法,以及用 503 维护页面对整集群做计划内停机。读完本文,你将掌握从部署、配置到源码级验证的完整闭环,并可直接复用仓库提供的三份 YAML 清单完成落地。
一、方案原理:错误码如何被"劫持"到自定义后端
默认情况下,当 Ingress 后端返回 4xx/5xx 错误时,NGINX 会返回一个简单的错误页。Ingress NGINX Controller 提供custom-http-errors配置,可让指定错误码不再由 NGINX 直接渲染,而是转发给自定义的 default-backend 服务,由该服务根据请求的Accept头返回 HTML、JSON 等自定义响应。
从 NGINX 配置模板 rootfs/etc/nginx/template/nginx.tmpl 可以看到其底层实现:
- 全局 http 层(第 493-502 行):当设置了
CustomHTTPErrors且未禁用DisableProxyInterceptErrors时,开启proxy_intercept_errors on;,并为每个错误码生成error_page {{ $errCode }} = @custom_upstream-default-backend_{{ $errCode }};,将错误响应内部重定向到 default-backend 上游; - location 层(第 1399-1405 行):如果某个 Ingress 通过注解单独指定了错误码,则在该 location 内同样开启
proxy_intercept_errors on;并生成error_page {{ $errCode }} = @custom_{{ $location.DefaultBackendUpstreamName }}_{{ $errCode }};,实现按 Ingress 粒度的错误页覆盖。
也就是说,这套机制同时支持"全局错误页"和"单条 Ingress 的错误页覆盖"两种粒度。
二、前置条件:准备一个可用的 Ingress Controller
开始之前,请确保集群中已部署 Ingress NGINX Controller。若尚未部署,请参考官方部署指南完成安装。
仓库的示例资源位于 docs/examples/customization/custom-errors/,共包含三份关键文件,下文将逐一讲解:
| 文件 | 用途 |
|---|---|
| custom-default-backend.yaml | 手动部署方式:自定义错误后端(Service + Deployment) |
| custom-default-backend-error_pages.configMap.yaml | 自定义 404/503 错误页内容的 ConfigMap |
| custom-default-backend.helm.values.yaml | Helm Chart 部署方式使用的 values 片段 |
三、方式一:使用 Helm Chart 部署自定义错误页(推荐)
如果控制器是通过 Helm Chart(charts/ingress-nginx)安装的,最省事的方式是复用仓库提供的 values 文件 custom-default-backend.helm.values.yaml,内容如下:
controller: config: custom-http-errors: "404,503" defaultBackend: enabled: true image: registry: registry.k8s.io image: ingress-nginx/custom-error-pages tag: v1.2.9@sha256:203d3020005dbdd735c1ad51f238d8663b9851399b52cc0c9c9e3f7273b6b299 extraVolumes: - name: custom-error-pages configMap: name: custom-error-pages items: - key: "404" path: "404.html" - key: "503" path: "503.html" extraVolumeMounts: - name: custom-error-pages mountPath: /www要点说明:
controller.config.custom-http-errors: "404,503":等价于 ConfigMap 中的custom-http-errors键,告诉控制器哪些错误码要走自定义错误页;defaultBackend.enabled: true:启用 Chart 内置的 default-backend,并替换为registry.k8s.io/ingress-nginx/custom-error-pages:v1.2.9镜像;extraVolumes/extraVolumeMounts:将上面提到的custom-error-pagesConfigMap 挂载到容器/www目录,即自定义错误页的渲染根目录;- 别忘了同时创建ConfigMap custom-default-backend-error_pages.configMap.yaml,否则 Volume 挂载会因找不到 ConfigMap 而失败。其内容为:
apiVersion: v1 kind: ConfigMap metadata: name: custom-error-pages data: 404: | <!DOCTYPE html> <html> <head><title>PAGE NOT FOUND</title></head> <body>PAGE NOT FOUND</body> </html> 503: | <!DOCTYPE html> <html> <head><title>CUSTOM SERVICE UNAVAILABLE</title></head> <body>CUSTOM SERVICE UNAVAILABLE</body> </html>注意:ConfigMap 中
data的键名(404、503)对应 HTTP 状态码,通过items映射为404.html、503.html写入挂载目录,custom-error-pages 镜像会根据请求状态码在/www下查找同名文件渲染页面。你也可以把键改为其他 400-599 的错误码,只需保持与custom-http-errors列表一致。
四、方式二:手动部署自定义 default-backend
如果不使用 Helm,可按原文档的手动流程操作。
4.1 创建自定义错误后端
使用仓库提供的 custom-default-backend.yaml 创建资源:
$ kubectl create -f custom-default-backend.yaml service "nginx-errors" created deployment.apps "nginx-errors" created该文件包含一个 Service 和一个 Deployment,二者均名为nginx-errors。核心定义如下:
apiVersion: v1 kind: Service metadata: name: nginx-errors labels: app.kubernetes.io/name: nginx-errors app.kubernetes.io/part-of: ingress-nginx spec: selector: app.kubernetes.io/name: nginx-errors app.kubernetes.io/part-of: ingress-nginx ports: - port: 80 targetPort: 8080 name: http --- apiVersion: apps/v1 kind: Deployment metadata: name: nginx-errors labels: app.kubernetes.io/name: nginx-errors app.kubernetes.io/part-of: ingress-nginx spec: replicas: 1 selector: matchLabels: app.kubernetes.io/name: nginx-errors app.kubernetes.io/part-of: ingress-nginx template: metadata: labels: app.kubernetes.io/name: nginx-errors app.kubernetes.io/part-of: ingress-nginx spec: containers: - name: nginx-error-server image: registry.k8s.io/ingress-nginx/custom-error-pages:v1.2.9@sha256:203d3020005dbdd735c1ad51f238d8663b9851399b52cc0c9c9e3f7273b6b299 ports: - containerPort: 8080 # Setting the environment variable DEBUG we can see the headers sent # by the ingress controller to the backend in the client response. # env: # - name: DEBUG # value: "true" # Mounting custom error page from configMap # volumeMounts: # - name: custom_error_pages # mountPath: /www # Mounting custom error page from configMap # volumes: # - name: custom_error_pages # configMap: # name: custom_error_pages # items: # - key: "404" # path: "404.html" # - key: "503" # path: "503.html"几点值得注意:
- 镜像使用
registry.k8s.io/ingress-nginx/custom-error-pages:v1.2.9(含 SHA256 摘要以保证可复现性),该镜像即仓库images/custom-error-pages/目录下构建的官方错误页服务; - 调试技巧:取消注释
DEBUG=true环境变量,即可在客户端响应中看到 Ingress Controller 转发给后端时携带的请求头,便于排查问题; - 自定义页面:取消注释
volumeMounts与volumes两段,即可把前面创建的custom-error-pagesConfigMap 挂载到/www,用你自己的 HTML 替换默认错误页。
验证创建结果:
$ kubectl get deploy,svc NAME DESIRED CURRENT READY AGE deployment.apps/nginx-errors 1 1 1 10s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/nginx-errors ClusterIP 10.0.0.12 <none> 80/TCP 10s此时集群中已有一个名为nginx-errors的 Deployment 和 Service。
4.2 配置 Ingress Controller
按原文档的指引,需要完成以下三步:
- 指定默认后端:编辑
ingress-nginx-controller的 Deployment,将启动参数--default-backend-service的值设置为新创建的错误后端,格式为namespace/service-name(例如default/nginx-errors); - 声明错误码:编辑
ingress-nginx-controller的 ConfigMap,添加键custom-http-errors,值为404,503(多个错误码用逗号分隔,也支持404, 500这类带空格写法,源码解析时会自动去除空白); - 记录 Service 地址:查看 Ingress Controller 的 Service IP,后续 curl 测试会用到:
$ kubectl get svc ingress-nginx NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE ingress-nginx ClusterIP 10.0.0.13 <none> 80/TCP,443/TCP 10m说明:示例中
ingress-nginxService 类型为ClusterIP,实际环境可能是LoadBalancer或NodePort。无论哪种类型,请确保能通过该 Service 访问到 NGINX 后再继续后续步骤。
五、源码级原理:custom-http-errors 的解析与校验
custom-http-errors既可作为ConfigMap 全局配置(本文场景),也可以作为Ingress 注解按规则覆盖。其解析实现在 internal/ingress/annotations/customhttperrors/main.go,关键逻辑如下:
- 注解名常量
custom-http-errors,属于backend组、作用域为location、风险等级Low; - 校验正则
^(?:[4,5]\d{2},?)*$,只接受 400-599 之间的错误码,且必须为逗号分隔(如403,503),非法值会直接报错; Parse方法将逗号分隔的字符串按逗号切分、TrimSpace去除空白后逐个strconv.Atoi转为整数,最终返回[]int错误码列表。因此"404, 503"、"404,503"均合法,而包含非数字(如abc)则解析失败。
对应测试 customhttperrors/main_test.go 验证了:
- 合法输入
400,404,500,502可正常解析; - 非法输入
400,404,abc,502会返回错误。
此外,internal/ingress/annotations/annotations_test.go 的TestCustomHTTPErrors也覆盖了"404,415"→[404, 415]、空字符串 →[]等边界场景。
关于错误转发到哪个后端,可结合两个注解的文档说明理解:
- defaultbackend/main.go 中的
default-backend注解(组backend、作用域location、风险Low):该 Service 用于处理 Ingress 规则中配置的 Service没有可用端点时的响应;如果同时设置了default-backend与custom-http-errors注解,错误响应会转发给该注解指定的 Service; - customhttperrors/main.go 的文档说明:如果 Ingress 上指定了
default-backend注解,则custom-http-errors列出的错误码转发到该注解指定的后端;否则转发到全局 default-backend(即--default-backend-service指向的服务)。
补充:仓库还提供了 disableproxyintercepterrors/main.go 中的
disable-proxy-intercept-errors注解,用于在设置了custom-http-errors时显式关闭 NGINX 的proxy_intercept_errors,可按需查阅。
六、验证错误页:curl 实战测试
配置完成后,用 cURL 对 Ingress Controller Service 发起请求验证。
场景 1:请求到默认后端,返回自定义 404 页面
$ curl -D- http://10.0.0.13/ HTTP/1.1 404 Not Found Server: nginx/1.13.12 Date: Tue, 12 Jun 2018 19:11:24 GMT Content-Type: */* Transfer-Encoding: chunked Connection: keep-alive <span>The page you're looking for could not be found.</span>场景 2:携带Accept: application/json,返回 JSON 格式错误体
$ curl -D- -H 'Accept: application/json' http://10.0.0.13/ HTTP/1.1 404 Not Found Server: nginx/1.13.12 Date: Tue, 12 Jun 2018 19:12:36 GMT Content-Type: application/json Transfer-Encoding: chunked Connection: keep-alive Vary: Accept-Encoding { "message": "The page you're looking for could not be found" }可以看到,custom-error-pages 后端会根据客户端的Accept头协商响应格式(HTML、JSON 等),这正是"自定义错误页"在前后端分离架构下特别有价值的原因——前端可以直接消费结构化错误体。
进一步验证:部署你自己的应用与 Ingress 对象,然后将某个 Deployment 的副本数缩到 0,请求该服务应返回 503,且响应体同样为自定义错误格式。这可以验证"后端无可用端点 → 返回 503 → 自定义错误页接管"的完整链路(default-backend注解的文档正是这么描述的:用于处理配置的 Service 无可用端点时的响应)。
七、进阶玩法:集群级"服务维护中"页面
custom-http-errors还有一个实用场景:为整个集群设置"服务维护中"页面,在计划性维护期间阻止用户访问业务。
实现步骤(按原文档):
- 为 503 启用自定义错误页:按前文步骤,在
custom-http-errors中加入503,并确保自定义后端能渲染 503 页面; - 停止读取 Ingress 资源:将
ingress-nginx-controller的启动参数--watch-namespace-selector设置为一个不存在的命名空间(例如nonexistent-namespace)。这样控制器不会从任何命名空间读取 Ingress 资源,业务流量自然无法被路由; - 强制返回 503:给控制器 ConfigMap 配置
location-snippet: return 503;(或在对应 location 中注入该片段),让 NGINX 对所有请求都返回 503 错误码。
由于custom-http-errors已包含 503,所有请求都会命中自定义错误页,客户端将看到统一风格的维护页面,同时 HTTP 状态码保持标准的 503 Service Unavailable,便于监控与客户端识别。
原文档提示:
--watch-namespace-selector指向不存在命名空间,本质上是"清空"控制器监听的 Ingress 集合;维护结束后恢复原值即可正常服务。执行维护前建议先在测试环境演练一遍,确认错误页与状态码符合预期。
八、相关资源与进一步阅读
- 示例资源目录:docs/examples/customization/custom-errors/
- 手动部署清单:custom-default-backend.yaml
- Helm values:custom-default-backend.helm.values.yaml
- 错误页 ConfigMap:custom-default-backend-error_pages.configMap.yaml
- 默认后端概念:default-backend.md
- 注解参考(含
custom-http-errors、default-backend、disable-proxy-intercept-errors):annotations.md - ConfigMap 配置项说明:configmap.md
- 控制器部署文档:deploy/index.md
如需继续深入源码,可阅读 customhttperrors/main.go(解析逻辑)、customhttperrors/main_test.go(解析测试)、defaultbackend/main.go(默认后端注解)、nginx.tmpl(proxy_intercept_errors与error_page的生成逻辑),以及 config.go 中CustomHTTPErrors的默认空切片定义(第 874 行附近)。
【免费下载链接】ingress-nginxIngress NGINX Controller for Kubernetes项目地址: https://gitcode.com/GitHub_Trending/in/ingress-nginx
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考