【发布时间】:2020-05-30 16:53:14
【问题描述】:
我正在运行一个通过 Helm 在我的 Kubernetes 集群上安装的 Nginx Ingress Controller。我想针对某些特定错误(例如 404)更改默认后端服务中的 HTML/CSS。
This 链接提供了一些关于默认后端的一般信息。但是,没有提及如何实际自定义提供的 HTML/CSS 文件。
【问题讨论】:
标签: nginx kubernetes
我正在运行一个通过 Helm 在我的 Kubernetes 集群上安装的 Nginx Ingress Controller。我想针对某些特定错误(例如 404)更改默认后端服务中的 HTML/CSS。
This 链接提供了一些关于默认后端的一般信息。但是,没有提及如何实际自定义提供的 HTML/CSS 文件。
【问题讨论】:
标签: nginx kubernetes
原始答案包含在 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 存储库,其中包含我在此答案中使用的文件。
【讨论】:
项目提供了Go custom error application,可以内置到容器镜像中来替代default-backend。 errorHandler function 具有魔力。
最终,它是一个 Web 服务器,它响应任何具有 404 内容的请求,/healthz 和 /metrics 除外。如果需要,您可以使用 nginx 实例和 html 错误页面来完成。
您可能不想使用完整的custom error handling,这与入口控制器会从常规应用后端查找某些 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: 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 控制器的实例,请根据部署指南进行部署,然后按照以下步骤操作:
--default-backend-service 标志为新的名称
创建了错误后端。注意分配给 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-ingress,static-files-nginx-ingressdefault-backend,customization-ingress-errors。
官方文档:nginx-ingress-controller.
【讨论】:
默认 httpbackend 的 docker 可以在以下位置找到: https://github.com/interlegis/nginx-ingress-controller-defaultbackend
在root/etc/nginx文件夹下,你可以根据自己的方便修改nginx.conf。 然后构建更新 docker 并部署。 (您可以查看上面的答案如何部署) 与其删除入口控制器然后安装,不如修改已部署的服务,使其指向您的 pod,您部署该 pod 以替换默认的 http 后端。
也许上面的答案可以让你的事情变得更容易。但是如果你已经在生产环境中运行,我不建议你移除 nginx 入口控制器并重新安装它。
【讨论】:
我之前遇到过这个问题,.. 但我想到了使用路由路径“/”到服务.. 所以入口控制器不会再次显示 404 页面.. 它可以工作!!!
创建一个简单服务的部署,在我的例子中我使用this 使用端口 80
然后,将部署公开为服务
kubectl expose deploy 部署名称 --port=80
最后一步,我们应该配置入口资源以将此服务路由到“/”路径
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
【讨论】:
使用官方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>
【讨论】: