摘要:近日發現一個問題應用程序在返回的時候丟失了原先訪問的端口。于是懷疑問題出在這幾個上。在中,在描述的時候提到,其返回的必須是。修改的端口為靠譜這個方法比較靠譜,只要將的端口改成就沒有問題了。使用靠譜使用提供的,將的值做文本替換。
github
近日發現一個問題:應用程序在返回Http Redirect的時候丟失了原先訪問的端口。比如,我們這樣訪問http://IP-A:Port-A/app/delete,這個url會響應302,但是它返回的Response header Location里丟失了端口,正確的結果應該是這樣:http://IP-A:Port-A/app/index,但返回的卻是:http://IP-A/app/index,把端口丟失了。
基本情況我們的部署情況是這樣的:
部署了Nginx Ingress,并使用NodePort的方式把Nginx Ingress Service暴露出來
配置了App的Ingress
服務器信息:
Server Name | NAT Server | K8S Node | Nginx Ingress Svc | Nginx Ingress Pod | App Svc | App Pod |
---|---|---|---|---|---|---|
IP | IP-A | IP-B | IP-C(Cluster IP/VIP) | IP-D(Cluster IP) | IP-E(Cluster IP/VIP) | IP-F(ClusterIP) |
Port | Port-A | Port-B(Nginx Ingress Svc"s NodePort) | Port-C | 80(Container Port) | Port-E | Port-F |
其實以上也不全是服務器,其中有兩個K8S Service不是服務器,它們是VIP,關于這個請看K8S - Using Source IP一文,當訪問http://IP-A:Port-A/app/delete的時候,這個請求從左到右貫穿了這些服務器。
順便一提上面的NAT Server是一臺普通的服務器,我們用它做了PAT使我們的Nginx Ingress能夠被外網訪問到。
觀察我們使用之前提到過的Echo Server來觀察透過Ingress訪問Echo Server時傳遞給Echo Server的Request header:http://IP-A:Port-A/echo-server,得到了這些有趣的Request header:
host=IP-A:Port-A x-original-uri=/echo-server x-forwarded-for=IP-B x-forwarded-host=IP-A:Port-A x-forwarded-port=80 x-forwarded-proto=http
然后直接訪問Echo Server Svc,發現是沒有上面提到的x-*Request header的。于是懷疑問題出在這幾個header上。
名詞解釋來講一下這些頭各自代表什么意思。
x-forwarded-for,client訪問proxy的時候,client的ip。
在這里之所以是K8S Node的IP,是因為在Nginx Ingress看來請求是來自K8S Node的(好好看看之前提到的K8S - Using Source IP一文),在這之前的NAT它是不知道的。
x-forwarded-host,client訪問proxy的時候,訪問的原始host。
x-forwarded-proto,client訪問proxy的時候,訪問的原始http scheme。
x-forwarded-port,client訪問proxy的時候,訪問的port。
x-original-uri,查不到權威資料。
注意,前三個是事實標準,MDN有收錄,x-forwarded-port和x-original-uri似乎是私有擴展。
實驗找一個趁手的Http Request工具(我用的是Postman),記得把Follow redirect關掉,然后模擬Nginx請求的方式(就是把上面提到的x-* header帶上/去掉/修改值)直接請求App Svc。
結果發現x-forwarded-port是Response header Location的關鍵,即如果x-forwarded-port=Port-A的話,Location就會帶上正確的端口。
分析 Redirect url是如何構造的可以推測,App利用了host和x-forwarded-*這些header來構造redirect url。
在Java Servlet API中,在描述HttpServletResponse#sendRedirect的時候提到,其返回的URL必須是Absolute URL。
Tomcat的org.apache.catalina.connector.Response的toAbsolute方法負責構造Absolute URL。
那么它又是如何知道選用什么Port的呢?這個和RemoteIPValve有關,有興趣的話你可以查閱相關文檔。
上面只是講了Tomcat是如何構造redirect url的,但這個方法不是標準的,不同的容器有各自的實現,畢竟Java Servlet API也沒有規定如何構造Absolute URL。
我之前也寫過一篇相關話題的文章《反向代理使用https協議,后臺tomcat使用http,redirect時使用錯誤協議的解決辦法》,你可以看一看。
為何x-forwarded-port是80那么問題來了,我明明訪問的是IP-A:Port-A,為何Nginx取到的值是80?
這是因為在整個請求鏈路的前段:NAT Server > K8S Node > Nginx Ingress Svc 都是在第4層工作的,可以認為它們干的事情都是NAT,Nginx Ingress Pod是不知道這些服務器/網絡節點的端口,因此它只能把自己的端口80(容器內Port)給x-forwarded-port。
關于這個邏輯你可以查看Nginx Ingress的配置文件就能夠知道了:
kubectl -n kube-system exec -it解決辦法 請求時帶上x-forwarded-port(不靠譜)-- cat /etc/nginx/nginx.conf
查看Nginx Ingress配置文件發現如果最初請求的時候帶上x-forwarded-port的話,就能夠改變它傳遞到后面的值,但是這有兩個問題:
通過瀏覽器訪問時,你沒有辦法加上這個header
這個header一般都是反向代理加的,也就是在我們的Nginx Ingress之前還得有一個反向代理
所以這個方法不好。
修改tomcat的代碼(不靠譜)雖然可以通過修改tomcat的代碼,讓它從x-forward-host/host header來取port,但是這個不現實。
修改NAT Server的端口為80(靠譜)這個方法比較靠譜,只要將NAT Server的端口改成80就沒有問題了。
事實上,如果你直接訪問K8S Node的話(NodePort方式),也是要將NodePort設置為80,記得前面說的嗎?Nginx Ingress無法知道上層NAT的端口。
總而言之,就是你最初請求的URL不能是80之外的端口,必須是http://some-ip/app才可以。
使用Nginx Ingress Annotations(靠譜)使用Nginx Ingress提供的Proxy redirect annotations,將Location的值做文本替換。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/32668.html
摘要:近日發現一個問題應用程序在返回的時候丟失了原先訪問的端口。于是懷疑問題出在這幾個上。在中,在描述的時候提到,其返回的必須是。修改的端口為靠譜這個方法比較靠譜,只要將的端口改成就沒有問題了。使用靠譜使用提供的,將的值做文本替換。 github 近日發現一個問題:應用程序在返回Http Redirect的時候丟失了原先訪問的端口。比如,我們這樣訪問http://IP-A:Port-A/ap...
摘要:參與者流量來自于內部系統和外部流量,其中大部分來自于外部流量。水平擴容服務的水平擴容重要性不言而喻。 背景 目前微店中臺團隊為了滿足公司大部分產品、運營以及部分后端開發人員的嘗鮮和試錯的需求,提供了一套基于圖形化搭建的服務端接口交付方案,利用該方案及提供的系統可生成一副包含運行時環境定義可立即運行的工程代碼,最后,通過 某種serverless平臺 實現生成后代碼的部署、CI、運行、反...
摘要:中暴露服務訪問自己實現了一個,它本質上是包裝了,在真正創建負載均衡器上它會調用來創建自身的。 Kubernetes概述 最近的一年,kubernetes的發展如此閃耀,正被越來越多的公司采納用于生產環境的實踐。同時,我們可以在最著名的開發者問答社區StackOverflow上看到k8s的問題數量的增長曲線(2015.5-2016.5),開發者是用腳投票的,從這一點看也無疑證明了k8s的...
摘要:中暴露服務訪問自己實現了一個,它本質上是包裝了,在真正創建負載均衡器上它會調用來創建自身的。 Kubernetes概述 最近的一年,kubernetes的發展如此閃耀,正被越來越多的公司采納用于生產環境的實踐。同時,我們可以在最著名的開發者問答社區StackOverflow上看到k8s的問題數量的增長曲線(2015.5-2016.5),開發者是用腳投票的,從這一點看也無疑證明了k8s的...
摘要:,托管于騰訊云容器平臺容器編排工具。適配我們目前的服務部署在騰訊云托管,節點使用核的網絡增強型機器,所有的后端服務都以部署,集群外部署高可用支持集群內服務發現,數據庫以為主,消息隊列采用。 距離2017年的見聞技術架構調整接近2年,隨著業務線的發展,見聞技術部的項目數量、項目架構類型、基礎設施規模、服務變更頻率都在不斷地增長,帶給SRE的挑戰是如何能更快地助力于開發人員更快更穩定地部署...
閱讀 1015·2021-10-19 11:42
閱讀 2973·2021-09-10 10:51
閱讀 677·2021-09-09 09:33
閱讀 1760·2021-09-01 10:43
閱讀 2768·2019-08-30 12:43
閱讀 3516·2019-08-30 11:24
閱讀 2114·2019-08-30 10:56
閱讀 2777·2019-08-29 11:00