【问题标题】:How to customize error pages served via the default backend of an nginx ingress controller?如何自定义通过 nginx 入口控制器的默认后端提供的错误页面?
【发布时间】:2020-05-30 16:53:14
【问题描述】:

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

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

【问题讨论】:

    标签: nginx kubernetes


    【解决方案1】:

    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: {}
    

    这是自定义后端的GitHub repo


    旧答案:

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

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

    • /healthz 应该返回 200
    • /metrics 是可选的,但它应该返回 Prometheus 可读的数据,以防您将其用于 k8s 指标。 Nginx 可以提供一些 Prometheus 可以读取的基础数据。如果您想获得 Prometheus 与 Nginx 的完整集成,请考虑使用 link
    • / 使用您的自定义 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;"]
    

    在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;
        }
    }
    

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

    现在构建 Docker 镜像:

    docker build --no-cache -t custom-default-backend .
    

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

    docker tag custom-default-backend:latest <your_dockerhub_username>/custom-default-backend
    

    将镜像推送到 DockerHub 存储库:

    docker push <your_dockerhub_username>/custom-default-backend
    

    现在是将此自定义默认后端映像集成到 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
    

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

    kubectl apply -f custom_default_backend.yaml
    

    现在为了将 Nginx Ingress Controller 与我们的新服务绑定,我们可能只需编辑 Ingress Controller 的部署即可。但我决定通过 Helm 完全删除它:

    helm delete nginx-ingress -n ingress-nginx
    

    然后用这个命令重新安装它(确保你有 --set 标志和正确的参数):

    helm install nginx-ingress --namespace ingress-nginx stable/nginx-ingress --set defaultBackend.enabled=false,controller.defaultBackendService=ingress-nginx/custom-default-backend
    

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

    【讨论】:

    • 我收到错误:验证“ingress-co.yaml”时出错:验证数据时出错:[ValidationError(Ingress.spec.defaultBackend): io.k8s.api.networking 中的未知字段“已启用” .v1.IngressBackend.... 用于新的(2021 年 8 月)解决方案
    • @Nedudi 也许您使用的是旧版本的舵图? It should work
    【解决方案2】:

    项目提供了Go custom error application,可以内置到容器镜像中来替代default-backenderrorHandler function 具有魔力。

    最终,它是一个 Web 服务器,它响应任何具有 404 内容的请求,/healthz/metrics 除外。如果需要,您可以使用 nginx 实例和 html 错误页面来完成。

    您可能不想使用完整的custom error handling,这与入口控制器会从常规应用后端查找某些 HTTP 状态代码并将它们传递给默认后端进行处理的情况略有不同。这会导致大多数应用程序出现问题,除非它们从一开始就设计为使用它。

    【讨论】:

      【解决方案3】:

      您必须使用后端配置创建示例部署:

      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: quay.io/kubernetes-ingress-controller/custom-error-pages-amd64:0.3
              ports:
              - containerPort: 8080
      

      那么你必须为它指定服务:

      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
      

      如果您还没有运行 NGINX Ingress 控制器的实例,请根据部署指南进行部署,然后按照以下步骤操作:

      1. 编辑 nginx-ingress-controller 部署并设置 --default-backend-service 标志为新的名称 创建了错误后端。
      2. 编辑 nginx-configuration ConfigMap 并创建密钥 值为 404 的 custom-http-errors。

      注意分配给 NGINX Ingress 控制器服务的 IP 地址。

      $ 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-nginx 服务的类型为 ClusterIP。这可能因您的环境而异。在继续本示例的其余部分之前,请确保您可以使用该服务访问 NGINX。

      用于后端 pod 的 NGINX 配置由 ConfigMaps 定义。二进制 ConfigMap 创建在 RPS 测试中返回给客户端的文件。因此,如果您想在以下文件中进行修改,请在 configmap 中指定它们并应用更改。

      Ingress Controller 有一项职责 - 实施集群中定义的 Ingress 规则。要提供静态内容,您应该有一个可以做到这一点的 pod,这确实意味着 ie。在你的堆栈中运行第二个 nginx。问题是,您应该将入口控制器视为提供通用集群功能的基础设施的一部分,并且从某个地方(或容器,如果它们被版本化/构建为 docker 映像)提供静态文件实际上是您的应用程序的一部分。

      看看这里:configmap-kubernetes-ingressstatic-files-nginx-ingressdefault-backendcustomization-ingress-errors

      官方文档:nginx-ingress-controller.

      【讨论】:

        【解决方案4】:

        您需要创建和部署自定义默认后端,这将返回自定义错误页面。按照doc 部署自定义默认后端并通过修改部署 yaml 来配置 nginx 入口控制器以使用此自定义默认后端。

        自定义默认后端的部署yaml为here,源代码为here

        【讨论】:

          【解决方案5】:

          默认 httpbackend 的 docker 可以在以下位置找到: https://github.com/interlegis/nginx-ingress-controller-defaultbackend

          在root/etc/nginx文件夹下,你可以根据自己的方便修改nginx.conf。 然后构建更新 docker 并部署。 (您可以查看上面的答案如何部署) 与其删除入口控制器然后安装,不如修改已部署的服务,使其指向您的 pod,您部署该 pod 以替换默认的 http 后端。

          也许上面的答案可以让你的事情变得更容易。但是如果你已经在生产环境中运行,我不建议你移除 nginx 入口控制器并重新安装它。

          【讨论】:

            【解决方案6】:

            我之前遇到过这个问题,.. 但我想到了使用路由路径“/”到服务.. 所以入口控制器不会再次显示 404 页面.. 它可以工作!!!

            1. 创建一个简单服务的部署,在我的例子中我使用this 使用端口 80

            2. 然后,将部署公开为服务

              kubectl expose deploy 部署名称 --port=80

            3. 最后一步,我们应该配置入口资源以将此服务路由到“/”路径

            
            apiVersion: networking.k8s.io/v1beta1
            kind: Ingress
            metadata:
              name: default-ingress
              annotations:
                ingress.kubernetes.io/rewrite-target: /
            spec:
              rules:
              - http:
                  paths:
                    - path: /
                      backend:
                        serviceName: service-name
                        servicePort: 80
            

            【讨论】:

              【解决方案7】:

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

              如果使用 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
              

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

              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>
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2020-08-13
                • 2021-10-16
                • 1970-01-01
                • 1970-01-01
                • 2019-04-03
                • 2021-10-26
                • 1970-01-01
                • 2013-02-27
                相关资源
                最近更新 更多