如何自定义通过 nginx 入口控制器的默认后端提供的错误页面?

dvd*_*blk 7 nginx kubernetes

我正在我的 Kubernetes 集群上运行通过 Helm 安装的 Nginx 入口控制器。我想针对某些特定错误(例如 404)更改默认后端服务中的 HTML/CSS。

链接提供了有关默认后端的一些一般信息。但是,没有提到如何实际自定义所提供的 HTML/CSS 文件。

dvd*_*blk 17

2021 年 8 月更新:

原始答案包含在 kubernetes 上部署自定义默认后端所需的步骤。

但是,最新版本的ingress-nginx允许用户只指定要拉取的 docker 镜像——不需要其他 k8s 资源文件(即服务和部署)。

我当前values.yaml用于 nginx 入口控制器以允许自定义默认后端:

defaultBackend:
  enabled: true
  name: custom-default-backend
  image:
    repository: dvdblk/custom-default-backend
    tag: "latest"
    pullPolicy: Always
  port: 8080
  extraVolumeMounts:
    - name: tmp
      mountPath: /tmp
  extraVolumes:
    - name: tmp
      emptyDir: {}
Run Code Online (Sandbox Code Playgroud)

较旧的答案:

好的,这些答案的某些部分有助于寻找完整的解决方案,尤其是来自@Matt 的解决方案。但是,我花了相当长的时间来完成这项工作,所以我决定用其他人可能也会遇到的所有必要细节来写我自己的答案。

第一件事是创建一个 Docker 镜像服务器,能够响应任何带有 404 内容的请求,除了/healthz/metrics。正如@Matt提到的,这可能是一个 Nginx 实例(我已经使用过)。总结:

  • /healthz 应该回来 200
  • /metrics是可选的,但它应该返回 Prometheus 可读的数据,以防您将其用于 k8s 指标。Nginx 可以提供一些 Prometheus 可以读取的基本数据。如果您想获得与 Nginx 的完整 Prometheus 集成,请考虑此链接
  • / 返回带有自定义 HTML 内容的 404。

因此,Dockerfile看起来像这样:

FROM nginx:alpine

# Remove default NGINX Config
# Take care of Nginx logging
RUN rm /etc/nginx/conf.d/default.conf && \
    ln -sf /dev/stdout /var/log/nginx/access.log && \
    ln -sf /dev/stderr /var/log/nginx/error.log

# NGINX Config
COPY ./default.conf /etc/nginx/conf.d/default.conf

# Resources
COPY content/ /var/www/html/

CMD ["nginx", "-g", "daemon off;"]
Run Code Online (Sandbox Code Playgroud)

在 Dockerfile 所在的文件夹中,创建这个default.confNginx 配置文件:

server {
    root /var/www/html;
    index 404.html;

    location / {
        
    }

    location /healthz {
        access_log off;
        return 200 "healthy\n";
    }
    
    location /metrics {
        # This creates a readable and somewhat useful response for Prometheus
        stub_status on;
    }

    error_page 404 /404.html;
    location = /404.html {
        internal;
    }
}
Run Code Online (Sandbox Code Playgroud)

最后,根据content/404.html自己的喜好提供一个带有 HTML/CSS的文件。

现在使用以下命令构建 Docker 映像:

docker build --no-cache -t custom-default-backend .
Run Code Online (Sandbox Code Playgroud)

标记此映像,以便将其推送到 DockerHub(或您自己的私有 docker 注册表):

docker tag custom-default-backend:latest <your_dockerhub_username>/custom-default-backend
Run Code Online (Sandbox Code Playgroud)

将映像推送到 DockerHub 存储库:

docker push <your_dockerhub_username>/custom-default-backend
Run Code Online (Sandbox Code Playgroud)

现在是将这个自定义默认后端映像集成到 Helm 安装中的部分。为此,我们首先需要创建这个 k8s 资源文件 ( custom_default_backend.yaml):

---
apiVersion: v1
kind: Service
metadata:
  name: custom-default-backend
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: custom-default-backend
    app.kubernetes.io/part-of: ingress-nginx
spec:
  selector:
    app.kubernetes.io/name: custom-default-backend
    app.kubernetes.io/part-of: ingress-nginx
  ports:
  - port: 80
    targetPort: 80
    name: http
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: custom-default-backend
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: custom-default-backend
    app.kubernetes.io/part-of: ingress-nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: custom-default-backend
      app.kubernetes.io/part-of: ingress-nginx
  template:
    metadata:
      labels:
        app.kubernetes.io/name: custom-default-backend
        app.kubernetes.io/part-of: ingress-nginx
    spec:
      containers:
      - name: custom-default-backend
        # Don't forget to edit the line below
        image: <your_dockerhub_username>/custom-default-backend:latest
        imagePullPolicy: Always
        ports:
        - containerPort: 80
Run Code Online (Sandbox Code Playgroud)

假设我们ingress-nginx已经创建了一个 k8s 命名空间,我们可以创建这两个资源。

kubectl apply -f custom_default_backend.yaml
Run Code Online (Sandbox Code Playgroud)

现在为了将 Nginx 入口控制器与我们的新服务联系起来,我们可能只需编辑入口控制器的部署。但我决定通过 Helm 完全删除它:

helm delete nginx-ingress -n ingress-nginx
Run Code Online (Sandbox Code Playgroud)

并使用此命令再次安装它(确保您拥有--set包含正确参数的标志):

helm install nginx-ingress --namespace ingress-nginx stable/nginx-ingress --set defaultBackend.enabled=false,controller.defaultBackendService=ingress-nginx/custom-default-backend
Run Code Online (Sandbox Code Playgroud)

通过这些步骤,您应该最终得到一个有效的自定义默认后端实现。是一个 GitHub 存储库,其中包含我在此答案中使用的文件。


elm*_*edo 8

使用官方ingress-nginx/nginx-errors图像并从 ConfigMap 映射您的自定义页面。这样您就不必建立自己的形象。

参见 nginx-ingress 官方文档https://kubernetes.github.io/ingress-nginx/examples/customization/custom-errors/

如果使用 Helm 进行部署,这里是示例values.yaml文件。

# See https://github.com/kubernetes/ingress-nginx/blob/main/charts/ingress-nginx/values.yaml
controller:
    custom-http-errors: "404,500,503" # See https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/#custom-http-errors
defaultBackend:
  enabled: true
  image:
    registry: k8s.gcr.io
    image: ingress-nginx/nginx-errors # Source https://github.com/kubernetes/ingress-nginx/tree/main/images/custom-error-pages
    tag: "0.48.1" # Check latest version on https://github.com/kubernetes/ingress-nginx/blob/main/docs/examples/customization/custom-errors/custom-default-backend.yaml
  extraVolumes:
  - name: error_page
    configMap:
      name: error_page
      items:
      - key: "error_page"
        path: "404.html"
      - key: "error_page"
        path: "500.html"
      - key: "error_page"
        path: "503.html"
  extraVolumeMounts:
  - name: error_page
    mountPath: /www
Run Code Online (Sandbox Code Playgroud)

错误页面配置映射文件示例:

apiVersion: v1
kind: ConfigMap
metadata:
  name: error_page
  namespace: ingress-nginx
data:
  error_page: |
    <!DOCTYPE html>
    <html>
        <head>
            <title>ERROR PAGE</title>
        </head>
        <body>
          ERROR PAGE
        </body>
    </html>
Run Code Online (Sandbox Code Playgroud)