業務架構:前端
部署細節:
兩容器均部署在同一機器上,經過 docker-compose
編排,而且經過link
方式連接。node
在有次更新代碼時,發現前端可以打開,可是全部接口請求全是502(Bad GateWay)
python
查看前端容器compose_ui_1
的日誌,刷了一大波502(Bad GateWay)
nginx
UI沒問題的話,第一反映就是 compose_api_1
跪了,因此直接去容器看看日誌
docker
容器日誌看起來很正常,沒有崩潰,並且這個日誌就好像歷來沒收到請求那樣,可是很明顯我前端確定有訪問的,感受很奇怪。將接口取出來單獨訪問試試看:
flask
接口單獨訪問結果仍是很殘暴的502(Bad GateWay)
,感受仍是不太可信,是否是端口或者主機什麼訪問錯誤了?
本機開啓 wireshark 抓包確認下請求的主機和端口:
segmentfault
這樣就很確保前端compose_ui_1
訪問的主機和端口是正確的,並且確切結果是502(Bad GateWay)
,這樣只能從compose_api_1
下手排查了。後端
以前也是遇到類似的問題,由於compose_api_1
是經過uwsgi
部署的python flask
,那會老是用法以爲有點問題,改過uwsgi
配置以後消停了一會。如今又捲土重來了。api
先判斷下compose_api_1
是否是真的跪了。。。雖然對這個沒抱什麼但願。。。緩存
直接訪問 後端api 接口
額。。。尷尬。。。彷彿冤枉錯好人了。這不對吧,抓包看看再次確認下先:
彷彿真的是。。。再 see see 容器日誌:
額。。。好吧。。。我錯了,compose_api_1
沒跪。
因而問題來了。。。後端接口沒問題,前端訪問出錯了,見鬼了?
有種預感是容器的特性致使的問題。希望不要。。
先進去compose_ui_1
容器抓包分析下,看看整個請求鏈有沒有問題:
彷佛發現了點貓膩,Flags[R.]
是表明 tcp連接 被 reset
重置 了,可是爲何無緣無故重置呢?
看到 172.17.0.5.8080
返回的, 先 telnet
問問先:
What???這就很迷了,首先這個 172.17.0.5.8080
哪來的呢?其次就是爲毛端口不通?
忽然想到一個很重要的問題:
容器之間是怎麼知道它要把請求發給誰呢 ?
在前面已經交代過,這兩個容器是經過 link
的方式連接的,像下面這樣:
谷歌搜了下 link
工做原理:
link機制經過環境變量的方式提供了這些信息,除此以外像db的密碼這些信息也會經過環境變量提供,docker將source container中定義的環境變量所有導入到received container中,在received container中能夠經過環境變量來獲取鏈接信息。 使用了link機制後,能夠經過指定的名字來和目標容器通訊,這實際上是經過給/etc/hosts中加入名稱和IP的解析關係來實現的
因此就是說在 compose_ui_1
的 根據指定的名字並在 /etc/hosts
翻譯出具體的ip而後進行通訊咯?
看看容器的名字是啥?
compose_ui_1
的 /etc/hosts
root@e23430ed1ed7:/# cat /etc/hosts 127.0.0.1 localhost ::1 localhost ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters 172.17.0.4 detectapi fc1537d83fdf compose_api_1 172.17.0.3 authapi ff83f8e3adf2 compose_authapi_1 172.17.0.3 authapi_1 ff83f8e3adf2 compose_authapi_1 172.17.0.3 compose_authapi_1 ff83f8e3adf2 172.17.0.4 api_1 fc1537d83fdf compose_api_1 172.17.0.4 compose_api_1 fc1537d83fdf 172.17.0.6 e23430ed1ed7
若是真是按照資料所說,那 172.17.0.4:8080
纔是 compose_api_1
的地址隱射纔對吧?,試下先
雖然返回了 auth product is None
,但其實這是有效的請求。
再看看 compose_api_1
容器的日誌:
因此基本沒跑了, 爲何前端訪問直接就是 502, 緣由就是 ui容器向錯誤的地址發送請求了
那麼爲何會這樣呢?無緣無故抽風了?
剛纔根據 host 的記錄實驗了,按照它的映地址發起接口請求,是沒有問題的:
查看下 compose_ui_1
的 nginx
日誌
尷尬。。。 nginx
日誌竟然直接鏈接到標準輸出和標準錯誤。。。
那爲了簡單點,仍是直接用 docker logs 查看吧
看來 nginx
的轉發已是錯誤的,爲何會轉發到 172.17.0.5, 看看 nginx
關於轉發的配置:
這個 detectapi
和 上面貼出的 hosts
表能找到正確的地址 172.17.0.4
呀?搞不明白爲何會轉發到 172.17.0.5
難道是系統的域名解析錯誤了?
尼瑪這真是太神奇了。
男人的直覺告訴我 nginx
有貓膩!
重啓下容器的 nginx
,然而容器也被重啓了。。。
再訪問頁面,竟然能夠了。。。
再看看容器的nginx日誌,已經轉發成功了
這樣子的話,其實應該能定位到,問題是出在了 nginx 上面?
只是爲何 nginx
會有這樣的錯誤呢?不太應該呀。。 感受應該是 nginx
內部域名解析緩存問題。
而後查了下資料,呵呵,還真有。https://www.zhihu.com/questio...
這就很是尷尬了。對這個問題抱有點懷疑,諮詢了資深大佬,而後大佬的回覆就是:
若是 proxy_pass 後面跟的域名的話,在 nginx 啓動的時候就會初始化好,之後就只會複用這個值;參考:ngx_http_upstream_init_round_robin 函數 若是 proxy_pass 後面跟的是upstream,配置纔會走解析和緩存的邏輯;
proxy_pass
真實域名,而是轉發到 upstream
配置;compose_ui_1
指定的 compose_api_1
會出錯?proxy_pass
若是後面跟真實域名,是真的直接複用仍是有時間緩存?原本想用 gdb
調試下這個問題,然而花了一天時間,毛都沒有。不過也有點小收穫,那就是如何配置nginx
來支持gdb
:
1.修改編譯配置文件:auto/cc/conf
ngx_compile_opt="-c" 改爲 ngx_compile_opt="-c -g"
2../configure
時,增長編譯參數:--with-cc-opt='-O0'
, 避免編譯器優化;
例如:./configure --prefix=/usr/local/nginx --with-cc-opt='-O0' ....
若是不這樣的話,編譯器會優化代碼,致使調試過程當中,循環中的一些變量值沒法打印,會報下面的錯誤:
value optimized out
下面能夠看下調試的效果:
nginx worker process 處理入口:ngx_http_static_handler
歡迎各位大神指點交流, QQ討論羣: 258498217
轉載請註明來源: https://segmentfault.com/a/11...