定制ingress-nginx后端
  FfLdSbUwpgnu 2023年11月02日 111 0

 

深入ingress-nginx

1.  使用deployment 是否合适
2. 四层代理
3. 定制配置(超时, buffersize 设置)
4. https服务
5. 访问控制(session保持,支不支持AB测试)

 

错误页面是发生错误时显示的网页。错误页面会警告用户发生的错误类型,并可能为用户提供解决问题的步骤的建议。除了在未样式化的网页上提供错误信息的基本页面之外,

还可以使用可以设计为具有额外功能和样式外观的自定义错误页面。这些设置可以在服务器上更改。许多服务器提供了可用于生成自定义错误页面的实用程序。

 

1、错误页面状态码

网站运行过程中难免出现问题,为用户抛出一个错误页面,常见的错误页面包含​​403​​​、​​404​​​、​​500​​​、​​502​​​、​​503​​​、​​504​​状态码,这些常见的错误页面状态码的含义如下

403 Forbidden

404 Not Found

500 Internal Server Eroor

502 Bad Gateway

503 Service Unavailable

504 Gateway Timeout

 

2、在 k8s 中模拟错误页面

本文中涉及到的的​​k8s集群​​​版本、​​Ingress nginx​​版本如下

 

bash-5.1$ ./nginx-ingress-controller  --version
-------------------------------------------------------------------------------
NGINX Ingress controller
Release: v1.2.0
Build: a2514768cd282c41f39ab06bda17efefc4bd233a
Repository: https://github.com/kubernetes/ingress-nginx
nginx version: nginx/1.19.10

 

对于错误页面状态码,为了方便,这里模拟出​​404​​​和​​503​​两个错误状态码页面

  • 404页面
  • 503页面

     

在​​k8s​​​中创建一个如下的​​Ingress​​资源

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-nginx
annotations:
spec:
ingressClassName: nginx
rules:
- host: "example.abc.com"
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: nginx-service
port:
number: 80

 

同样将对应的域名解析到​​Ingress controller​​​所在的节点进行访问,由于该​​Ingress​​​的后端并没有对应的​​nginx-service​​​,因此会返回默认的​​503​​(服务暂时不可用)

 

定制ingress-nginx后端_状态码

 

 

 这里对​​Ingress nginx​​​做了版本号的隐藏,返回了默认的​​404 Not Found​​(页面未找到)

 

3、默认后端错误页面

很多时候我们虽然隐藏了​​Ingress nginx​​的版本号,但直接返回状态码还是不够友好。一些网站都会有自定义的较友好、美观的错误页面或跳转到公益页面等。

 

3.1 部署默认后端

​Ingress nginx​​​提供了默认的自定义后端供用户使用,​​yaml​​如下

 

apiVersion: v1
kind: Service
metadata:
name: nginx-errors
namespace: ingress-nginx
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
namespace: ingress-nginx
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"

 

直接创建对应资源即可

# kubectl create -f custom-default-backend.yaml
service "nginx-errors" created
deployment.apps "nginx-errors" created

 

检查创建的资源

# kubectl get deploy,svc -n ingress-nginx
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

 

3.2 配置启动参数

修改​​Ingress controller​​​控制器的启动参数,加入以下配置,通过​​--default-backend​​标志的值设置为新创建的错误后端的名称

# kubectl -n ingress-nginx edit ds nginx-ingress-controller
...
spec:
containers:
- args:
- /nginx-ingress-controller
- --configmap=$(POD_NAMESPACE)/nginx-configuration
- --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services
- --udp-services-configmap=$(POD_NAMESPACE)/udp-services
- --publish-service=$(POD_NAMESPACE)/ingress-nginx
- --annotations-prefix=nginx.ingress.kubernetes.io
- --default-backend-service=ingress-nginx/nginx-errors # 添加此行

 

3.3 修改configmap

修改对应的​​configmap​​指定要关联到默认后端服务的服务状态码,意味着如果状态码是配置项中的值,那么返回给客户端浏览器的就是默认后端服务

 

# kubectl -n ingress-nginx edit configmap nginx-configuration
apiVersion: v1
data:
custom-http-errors: 403,404,500,502,503,504 # 添加此行

 

 

3.4 测试

通过终端命令访问上面​​404​​​和​​503​​页面的两个域名

ingress-nginx curl example.bar.com                              
5xx html # ingress-nginx curl example.foo.com
<span>The page you're looking for could not be found.</span>
# 自定义Accept标头
# ingress-nginx curl -H 'Accept: application/json' example.foo.com
{ "message": "The page you're looking for could not be found" }

 

页面测试

 定制ingress-nginx后端_状态码_02

 

 

4、自定义错误页面

4.1 剖析请求与关键

如下图所示,​​Ingress Controller​​​控制器的工作原理,简单来说,将控制器理解为一个监听器,通过不断地监听 ​​kube-apiserver​​​,实时的感知后端 ​​Service​​​和​​Pod​​​的变化,当得到这些信息变化后,​​Ingress Controller​​​再结合​​Ingress​​​的配置,更新反向代理负载均衡器,从而达到服务发现的作用。​​Ingress-nginx​​​的最终目标是构造​​nginx.conf​​​这样的配置文件,主要用途是在配置文件有任何变更后都需要重新加载 ​​nginx​​。

定制ingress-nginx后端_nginx_03

 

 

通过上面创建​​ingress​​​资源,以及配置控制器启动参数和​​configmap​​​,进入到​​nginx-ingress-controller​​​的​​pod​​中查看配置(文件内容很多,可以导出或过滤查看)。

会看到将状态码关联了自定义的默认后端

# kubectl -n ingress-nginx exec -it nginx-ingress-controller-2rrsw bash
www-data@k8s-qa-node-03:/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​​早期的版本可能会不生效,issue 参考

 

4.2 构建自定义后端

自定义后端页面可以理解成就是简单的静态页面,这里可以通过熟悉的​​nginx​​​来构建这样的自定义后端。即通过手动编译安装​​nginx​​​,并打包好自定义错误页面、配置文件成一个​​docker​​镜像。

镜像中​​nginx.conf​​的关键配置

  • 利用上面提到的​​X-code​​特定头部进行原始状态码的判断。
  • ​nginx​​​不支持嵌套的​​if​​判断以及逻辑运算,因此通过设置​​flag​​变量标记的形式实现不同状态码的判断返回,如果列出的状态码都不匹配,将状态码设置为返回​​404​​。
root@a93f3a423b80 conf]# cat nginx.conf
user www;
worker_processes 4;
worker_rlimit_nofile 65535;
pid /var/run/nginx.pid;
events {
use epoll;
worker_connections 4096;
multi_accept on;
}
http {
server_tokens off;
include mime.types;
default_type application/octet-stream;
add_header X-Frame-Options SAMEORIGIN;
add_header Set-Cookie "HttpOnly";
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
log_format proxy_log '$http_x_real_ip - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
server_names_hash_bucket_size 128;
client_header_buffer_size 32k;
large_client_header_buffers 4 32k;
client_max_body_size 500m;
keepalive_timeout 3600;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
# FastCGI Configure
fastcgi_connect_timeout 3600;
fastcgi_send_timeout 3600;
fastcgi_read_timeout 3600;
fastcgi_buffer_size 64k;
fastcgi_buffers 4 64k;
fastcgi_busy_buffers_size 128k;
fastcgi_temp_file_write_size 128k;
# gzip compression configure
gzip on;
gzip_http_version 1.0;
gzip_comp_level 2;
gzip_proxied any;
gzip_min_length 1k;
gzip_buffers 4 16k;
gzip_types text/plain application/x-javascript text/css application/xml;
gzip_vary on;
include fastcgi.conf;
server {
listen 80;
server_name localhost;
index index.html index.htm;
access_log /var/log/nginx_access.log main;
error_log /var/log/nginx_error.log;
root /data/www/error;
error_page 403 /403.html;
error_page 404 /404.html;
error_page 500 /500.html;
error_page 502 /502.html;
error_page 503 /503.html;
error_page 504 /504.html;
location = / {
set $flag 404;
if ($http_x_code = "403"){set $flag 403;}
if ($http_x_code = "404"){set $flag 404;}
if ($http_x_code = "500"){set $flag 500;}
if ($http_x_code = "502"){set $flag 502;}
if ($http_x_code = "503"){set $flag 503;}
if ($http_x_code = "504"){set $flag 504;}
if ($flag = "403"){return 403;}
if ($flag = "404"){return 404;}
if ($flag = "500"){return 500;}
if ($flag = "502"){return 502;}
if ($flag = "503"){return 503;}
if ($flag = "504"){return 504;}
}
location = /403.html {
internal;
}
location = /404.html {
internal;
}
location = /500.html {
internal;
}
location = /502.html {
internal;
}
location = /503.html {
internal;
}
location = /504.html {
internal;
}
}
}

代码根目录结构

[root@docker nginx_error]# tree error/
error/
├── 403.html
├── 404.html
├── 500.html
├── 502.html
├── 503.html
└── 504.html

 

docker pull 10.20.1.186/test/nginx:nginx_error_1.14.2_v1.0

 

4.3 部署自定义后端

参照已有模板,重新部署一个新的默认后端

---
apiVersion: v1
kind: Service
metadata:
name: ssgeek-errors
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ssgeek-errors
app.kubernetes.io/part-of: ingress-nginx
namespace: ingress-nginx
spec:
selector:
app.kubernetes.io/name: ssgeek-errors
app.kubernetes.io/part-of: ingress-nginx
ports:
- port: 80
targetPort: 80
name: http
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: ssgeek-errors
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ssgeek-errors
app.kubernetes.io/part-of: ingress-nginx
namespace: ingress-nginx
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: ssgeek-errors
app.kubernetes.io/part-of: ingress-nginx
template:
metadata:
labels:
app.kubernetes.io/name: ssgeek-errors
app.kubernetes.io/part-of: ingress-nginx
spec:
containers:
- name: ssgeek-errors
image: 10.20.1.186/test/nginx:nginx_error_1.14.2_v1.0
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

 

同样的,修改​​Ingress controller​​​控制器的启动参数,修改关联的​​service​​名称

 

# kubectl -n ingress-nginx edit ds nginx-ingress-controller
...
spec:
containers:
- args:
- /nginx-ingress-controller
- --configmap=$(POD_NAMESPACE)/nginx-configuration
- --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services
- --udp-services-configmap=$(POD_NAMESPACE)/udp-services
- --publish-service=$(POD_NAMESPACE)/ingress-nginx
- --annotations-prefix=nginx.ingress.kubernetes.io
- --default-backend-service=ingress-nginx/ssgeek-errors # 修改成自定义的默认后端服务

 


【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

FfLdSbUwpgnu