网站运行过程中难免出现问题,为用户抛出一个错误页面,常见的错误页面包含403、404、500、502、503、504状态码,这些常见的错误页面状态码的含义如下
403 Forbidden
404 Not Found
500 Internal Server Eroor
502 Bad Gateway
503 Service Unavailable
504 Gateway Timeout
默认的错误页面是我们经常看到的那样,很素。如下所示:
出于安全考虑和友好提示,我们一般建议创建默认后端页面。
我们虽然隐藏了Ingress nginx的版本号,但直接返回状态码还是不够友好。一些网站都会有自定义的较友好、美观的错误页面或跳转到公益页面等。
部署默认后端
Ingress nginx提供了默认的自定义后端供用户使用,yaml如下
---
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: quay.io/kubernetes-ingress-controller/custom-error-pages-amd64:0.3
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"
配置启动参数
修改Ingress controller控制器的启动参数,加入以下配置,通过--default-backend
标志的值设置为新创建的错误后端的名称
- --default-backend-service=ingress-nginx/nginx-errors
修改ingress-nginx对应的configmap指定要关联到默认后端服务的服务状态码,意味着如果状态码是配置项中的值,那么返回给客户端浏览器的就是默认后端服务
custom-http-errors: 403,404,500,502,503,504
剖析请求与关键
如下图所示,Ingress Controller控制器的工作原理,简单来说,将控制器理解为一个监听器,通过不断地监听 kube-apiserver,实时的感知后端 Service和Pod的变化,当得到这些信息变化后,Ingress Controller再结合Ingress的配置,更新反向代理负载均衡器,从而达到服务发现的作用。Ingress-nginx的最终目标是构造nginx.conf这样的配置文件,主要用途是在配置文件有任何变更后都需要重新加载 nginx。
通过上面创建ingress资源,以及配置控制器启动参数和configmap,进入到nginx-ingress-controller的pod中查看配置(文件内容很多,可以导出或过滤查看)。
会看到将状态码关联了自定义的默认后端
# kubectl -n ingress-nginx exec -it nginx-ingress-controller-2rrsw bash
www-data@k8s-node3:/etc/nginx$ grep "error_page" nginx.conf -C 10
ssl_ecdh_curve auto;
proxy_intercept_errors on;
error_page 404 = @custom_upstream-default-backend_404;
error_page 500 = @custom_upstream-default-backend_500;
error_page 502 = @custom_upstream-default-backend_502;
error_page 503 = @custom_upstream-default-backend_503;
error_page 504 = @custom_upstream-default-backend_504;
proxy_ssl_session_reuse on;
upstream upstream_balancer {
server 0.0.0.1; # placeholder
过滤出上面创建的域名example.bar.com相关配置
## start server example.bar.com
server {
server_name example.bar.com ;
listen 80;
listen [::]:80;
set $proxy_upstream_name "-";
set $pass_access_scheme $scheme;
set $pass_server_port $server_port;
set $best_http_host $http_host;
set $pass_port $pass_server_port;
...
location @custom_upstream-default-backend_404 {
internal;
proxy_intercept_errors off;
proxy_set_header X-Code 404;
proxy_set_header X-Format $http_accept;
proxy_set_header X-Original-URI $request_uri;
proxy_set_header X-Namespace $namespace;
proxy_set_header X-Ingress-Name $ingress_name;
proxy_set_header X-Service-Name $service_name;
proxy_set_header X-Service-Port $service_port;
proxy_set_header X-Request-ID $req_id;
proxy_set_header Host $best_http_host;
set $proxy_upstream_name upstream-default-backend;
rewrite (.*) / break;
proxy_pass http://upstream_balancer;
log_by_lua_block {
monitor.call()
}
}
location @custom_upstream-default-backend_500 {
internal;
proxy_intercept_errors off;
proxy_set_header X-Code 500;
proxy_set_header X-Format $http_accept;
proxy_set_header X-Original-URI $request_uri;
proxy_set_header X-Namespace $namespace;
proxy_set_header X-Ingress-Name $ingress_name;
proxy_set_header X-Service-Name $service_name;
proxy_set_header X-Service-Port $service_port;
proxy_set_header X-Request-ID $req_id;
proxy_set_header Host $best_http_host;
set $proxy_upstream_name upstream-default-backend;
rewrite (.*) / break;
proxy_pass http://upstream_balancer;
log_by_lua_block {
monitor.call()
}
}
...
这个server中关于默认后端的配置内容是关键信息(踩坑发现,后面只有用到这里的相关配置才能达到最终目标,否则无法判断)。
可以看到,在传递默认后端时,设置了多个请求头字段,其中X-Code即状态码正是所需要的,这里意味着将控制器返回的对应状态码,例如500定义在了X-Code中。如果自定义一个默认后端来取代官方的默认后端,就可以通过X-Code这个特定的头部来判断实现不同的状态码从而返回不同的自定义错误页面。
关于X-code早期的版本可能会不生效,参考:https://github.com/kubernetes/ingress-nginx/issues/2281
部署自定义后端
镜像已构建,直接使用。
apiVersion: v1
kind: Service
metadata:
name: gl-ingress-nginx-errors
labels:
app.kubernetes.io/name: gl-ingress-nginx-errors
app.kubernetes.io/part-of: ingress-nginx
namespace: ingress-nginx
spec:
selector:
app.kubernetes.io/name: gl-ingress-nginx-errors
app.kubernetes.io/part-of: ingress-nginx
ports:
- port: 80
targetPort: 80
name: http
您暂时无权查看此隐藏内容!
ports:
- containerPort: 80
# 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"
修改Ingress controller控制器的启动参数,修改关联的service名称
- --default-backend-service=ingress-nginx/gl-ingress-nginx-errors