Ingress企業實戰:URL重寫與高級玩法
Ingress企業實戰:URL重寫與高級玩法
什麼是URL重寫
URL重寫(URL rewriting)是一種在Web服務器上修改或轉換請求URL的過程。它通常涉及使用服務器配置或規則來更改傳入的URL,以便在不改變實際請求資源的情況下,實現不同的行為,如重定向、路徑映射、參數處理等。URL重寫在服務器層面進行,因此客戶端(如瀏覽器)對於URL的請求不會感知到這些更改,但服務器會根據配置進行適當的處理。URL重寫可以用於多種目的,例如:
- 重定向: 將一個URL重寫為另一個URL,實現301永久重定向或302臨時重定向。這可以用於更改站點結構、修復錯誤的URL、實現SEO優化等。
- 路徑映射: 將一個URL的路徑映射到另一個位置,這對於隱藏實際文件路徑或路徑重組很有用。
- 查詢參數處理: 在URL中添加、刪除或修改查詢參數,以適應不同的應用需求。
- 動態URL到靜態URL: 將動態生成的URL(帶有參數)轉化為靜態URL,更友好且易於索引。
- 隱藏技術細節: 可以通過URL重寫隱藏後端服務器或應用程序的實際技術細節,提高安全性。
在Nginx、Apache等常見的Web服務器中,URL重寫可以通過正則表達式、規則匹配等方式來實現。具體的語法和方法會因服務器軟件的不同而有所不同。通常,服務器配置文件中會有專門的部分用於配置URL重寫規則,例如在Nginx中是使用rewrite指令。URL重寫是一種強大的技術,但在使用時需要小心,確保配置正確以避免潛在的問題,例如無限循環重定向或錯誤的重寫規則可能導致網站不可用。
Ingress 內置變量
內置預定義變量即無需聲明就可以使用的變量,通常包括一個http請求或響應中一部分內容的值,以下為一些常用的內置預定義變量:
变量名 定义
$arg_PARAMETER GET请求中变量名PARAMETER参数的值。
$args 这个变量等于GET请求中的参数。例如,foo=123&bar=blahblah;这个变量只可以被修改
$binary_remote_addr 二进制码形式的客户端地址。
$body_bytes_sent 传送页面的字节数
$content_length 请求头中的Content-length字段。
$content_type 请求头中的Content-Type字段。
$cookie_COOKIE cookie COOKIE的值。
$document_root 当前请求在root指令中指定的值。
$document_uri 与$uri相同。
$host 请求中的主机头(Host)字段,如果请求中的主机头不可用或者空,则为处理请求的server名称(处理请求的server的server_name指令的值)。值为小写,不包含端口。
$hostname 机器名使用 gethostname系统调用的值
$http_HEADER HTTP请求头中的内容,HEADER为HTTP请求中的内容转为小写,-变为_(破折号变为下划线),例如:$http_user_agent(Uaer-Agent的值);
$http_user_agent : 客户端agent信息;
$http_cookie : 客户端cookie信息;
$sent_http_HEADER HTTP响应头中的内容,HEADER为HTTP响应中的内容转为小写,-变为_(破折号变为下划线),例如: $sent_http_cache_control, $sent_http_content_type…;
$is_args 如果$args设置,值为"?",否则为""。
$limit_rate 这个变量可以限制连接速率。
$nginx_version 当前运行的nginx版本号。
$query_string 与$args相同。
$remote_addr 客户端的IP地址。
$remote_port 客户端的端口。
$remote_user 已经经过Auth Basic Module验证的用户名。
$request_filename 当前连接请求的文件路径,由root或alias指令与URI请求生成。
$request_body 这个变量(0.7.58+)包含请求的主要信息。在使用proxy_pass或fastcgi_pass指令的location中比较有意义。
$request_body_file 客户端请求主体信息的临时文件名。
$request_completion 如果请求成功,设为"OK";如果请求未完成或者不是一系列请求中最后一部分则设为空。
$request_method 这个变量是客户端请求的动作,通常为GET或POST。包括0.8.20及之前的版本中,这个变量总为main request中的动作,如果当前请求是一个子请求,并不使用这个当前请求的动作。
$request_uri 这个变量等于包含一些客户端请求参数的原始URI,它无法修改,请查看$uri更改或重写URI,
包含请求参数的原始URI,不包含主机名,如:”/foo/bar.php?arg=baz”。
$scheme 所用的协议,比如http或者是https,比如rewrite ^(.+)$ $scheme://example.com$1 redirect;
$server_addr 服务器地址,在完成一次系统调用后可以确定这个值,如果要绕开系统调用,则必须在listen中指定地址并且使用bind参数。
$server_name 服务器名称。
$server_port 请求到达服务器的端口号。
$server_protocol 请求使用的协议,通常是HTTP/1.0或HTTP/1.1。
$uri 请求中的当前URI(不带请求参数,参数位于args),不同于浏览器传递的args),不同于浏览器传递的args),不同于浏览器传递的request_uri的值,它可以通过内部重定向,或者使用index指令进行修改。uri不包含主机名,如”/foo/bar.html”。
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
Ingress 正則表達式
正则表达式匹配,其中:
~ 为区分大小写匹配
~* 为不区分大小写匹配
!~和!~* 分别为区分大小写不匹配及不区分大小写不匹配
. 匹配除换行符以外的任意字符
\w 匹配字母或数字或下划线或汉字
\s 匹配任意的空白符
\d 匹配数字
\b 匹配单词的开始或结束
^ 匹配字符串的开始
$ 匹配字符串的结束
* 重复零次或更多次
+ 重复一次或更多次
? 重复零次或一次
{n} 重复n次
{n,} 重复n次或更多次
{n,m} 重复n到m次
*? 复任意次,但尽可能少重复
+? 重复1次或更多次,但尽可能少重复
?? 重复0次或1次,但尽可能少重复
{n,m}? 重复n到m次,但尽可能少重复
{n,}? 重复n次以上,但尽可能少重复
\W 匹配任意不是字母,数字,下划线,汉字的字符
\S 匹配任意不是空白符的字符
\D 匹配任意非数字的字符
\B 匹配不是单词开头或结束的位置
[^x] 匹配除了x以外的任意字符
[^aeiou] 匹配除了aeiou这几个字母以外的任意字符
(exp) 匹配exp,并捕获文本到自动命名的组里
(?<name>exp) 匹配exp,并捕获文本到名称为name的组里,也可以写成(?'name'exp)
(?:exp) 匹配exp,不捕获匹配的文本,也不给此分组分配组号
(?=exp) 匹配exp前面的位置
(?<=exp) 匹配exp后面的位置
(?!exp) 匹配后面跟的不是exp的位置
(?<!exp) 匹配前面不是exp的位置
(?#comment) 注释分组不对正则表达式的处理产生任何影响
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
配置URL重寫規則
在某些應用場景中,後端服務提供的URL與Ingress規則中執行的路徑不同,而Ingress訪將訪問路徑直接轉發到後端相同路徑,如果不配置URL重寫規則,所有訪問都將返回404 。比如如下案例,Ingress規則中配置的是/user/info,而後端服務提供的訪問路徑是/info,在不配置重寫的情況下,會直接轉發給後端/user/info與實際提供的訪問路徑/info不匹配,會直接返回404。接下來咱們用案例的方式進行驗證。
不配置URL重寫直接轉發:
$ cat ingress.yml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: demo
spec:
rules:
- host: demo.kubesre.com
http:
paths:
- path: /
pathType: ImplementationSpecific
backend:
service:
name: demo-svc
port:
number: 8080
ingressClassName: nginx
$ kubectl apply -f ingress.yml
ingress.networking.k8s.io/demo configured
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
訪問驗證(/user/info):
# 访问/user/info,可以看出直接返回404
$ curl http://demo.kubesre.com/user/info
404 page not found
- 1.
- 2.
- 3.
配置URL重寫:
$ cat ingress.yml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: demo
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
rules:
- host: demo.kubesre.com
http:
paths:
- path: /user(/|$)(.*)
pathType: ImplementationSpecific
backend:
service:
name: demo-svc
port:
number: 8080
ingressClassName: nginx
$ kubectl apply -f ingress.yml
ingress.networking.k8s.io/demo configured
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
訪問驗證(/user/info):
# 访问/user/info,可以看出直接正常返回了
$ curl http://demo.kubesre.com/user/info
{"message":"云原生运维圈!"}
- 1.
- 2.
- 3.
註解說明:
以上案例Ingress重寫是通過nginx.ingress.kubernetes.io/rewrite-target註解實現不同路徑的重寫規則。佔位符$2表示將第二個括號即(.*)中匹配到的所有字符填寫到nginx.ingress.kubernetes.io/rewrite-target註解中。想必大家都知道Ingress是基於Nginx開發的,此時是通過Ingress CRD進行創建的重寫配置,其本質也是修改Nginx配置文件的,此時從Ingress裡的Nginx拷貝出來的配置如下:
server {
server_name demo.kubesre.com ;
listen 80 ;
listen [::]:80 ;
listen 443 ssl http2 ;
listen [::]:443 ssl http2 ;
set $proxy_upstream_name "-";
ssl_certificate_by_lua_block {
certificate.call()
}
location ~* "^/user(/|$)(.*)" {
set $namespace "default";
rewrite "(?i)/user(/|$)(.*)" /$2 break;
proxy_pass http://upstream_balancer;
proxy_redirect off;
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
高級URL重寫規則
對於一些複雜的重寫規則需求,可以通過如下註解來實現,其本質也是修改Nginx配置文件。
- nginx.ingress.kubernetes.io/server-snippet:在nginx.conf的“server”字段中添加自定義配置。
- nginx.ingress.kubernetes.io/configuration-snippet:在nginx.conf的“location”字段中添加自定義配置。
URL重寫Flag參數:
- last:表示本條規則匹配完成後繼續向下匹配。
- break:表示本條規則匹配完成後停止匹配。
- redirect:表示臨時重定向,返回狀態碼302。
- permanent:表示永久重定向,返回狀態碼301。
重定向就是將網頁自動轉向重定向:
- 301永久性重定向:新網址完全繼承舊網址,舊網址的SEO網絡搜索引擎的排名等完全清零
- 301重定向是網頁更改地址後對搜索引擎友好的最好方法,只要不是暫時搬移的情況,都建議使用301來做轉址。
- 302臨時性重定向:對舊網址沒有影響,但新網址不會有排名
- 搜索引擎爬蟲會抓取新的內容而保留舊的網址
配置Location:
通過Ingress註解nginx.ingress.kubernetes.io/server-snippet配置location,訪問/sre,返回401錯誤代碼,案例如下:
$ cat sre.yml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/server-snippet: |
location /sre {
return 401;
}
name: demo-redirect
spec:
rules:
- host: demo.kubesre.com
http:
paths:
- path: /
pathType: ImplementationSpecific
backend:
service:
name: demo-svc
port:
number: 8080
ingressClassName: nginx
$ kubectl apply -f 1.yml
ingress.networking.k8s.io/demo-redirect configured
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
訪問驗證:
# 表示验证成功
$ curl http://demo.kubesre.com/sre/
<html>
<head><title>401 Authorization Required</title></head>
<body>
<center><h1>401 Authorization Required</h1></center>
<hr><center>nginx</center>
</body>
</html>
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
URL重定向(permanent):
cat demo-permanent.yml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/configuration-snippet: |
rewrite ^/$ https://www.baidu.com redirect;
name: demo-redirect
spec:
rules:
- host: demo.kubesre.com
http:
paths:
- path: /
pathType: ImplementationSpecific
backend:
service:
name: demo-svc
port:
number: 8080
ingressClassName: nginx
$ kubectl apply -f demo-permanent.yml
ingress.networking.k8s.io/demo-permanent created
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
訪問驗證:
# 301永久重定向,浏览器器地址栏会显示跳转后的URL地址,真实效果可以通过浏览器访问测试验证
$ curl http://demo.kubesre.com
<html>
<head><title>301 Moved Permanently</title></head>
<body>
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx</center>
</body>
</html>
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
URL重定向(redirect):
通過URL重定向,訪問/test/info,直接重定向302跳轉到/user/info。
$ cat demo-redirect.yml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/configuration-snippet: |
rewrite ^/test/(.*)$ /user/$1 redirect;
name: demo-redirect
spec:
rules:
- host: demo.kubesre.com
http:
paths:
- path: /test
pathType: ImplementationSpecific
backend:
service:
name: demo-svc
port:
number: 8080
ingressClassName: nginx
$ kubectl apply -f demo-redirect.yml
ingress.networking.k8s.io/demo-redirect created
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
訪問驗證:
# 302 说明已经重定向了,实际效果可以通过浏览器访问查看
$ curl http://demo.kubesre.com/test/info
<html>
<head><title>302 Found</title></head>
<body>
<center><h1>302 Found</h1></center>
<hr><center>nginx</center>
</body>
</html>
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
URL重寫(last):
通過URL重寫實現,訪問/sre,返回的是/kube的結果,可以利用重寫Flag last參數,當URL重寫後,會發送一個新的請求,再次進入server塊,重試location匹配,匹配成功直接把結果直接返回。
$ cat sre.yml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/configuration-snippet: |
rewrite ^/sre /kube last;
nginx.ingress.kubernetes.io/server-snippet: |
location /sre {
return 401;
}
location /kube {
return 403;
}
name: demo-redirect
spec:
rules:
- host: demo.kubesre.com
http:
paths:
- path: /sre
pathType: ImplementationSpecific
backend:
service:
name: demo-svc
port:
number: 8080
ingressClassName: nginx
$ kubectl apply -f sre.yml
ingress.networking.k8s.io/demo-redirect configured
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
訪問驗證:
# 访问/sre,则返回/kube结果403
$ curl http://demo.kubesre.com/sre/
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx</center>
</body>
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
總結
本文介紹了URL重寫的概念,並通過實際案例的方式講解了URL重寫的方方面面,下一章將講解Ingress更多企業級實戰,請敬請期待!