我使用 python 建立單頁應用程式燒瓶框架。我在用著古尼康作為網頁伺服器,我使用它進行了容器化泊塢窗。它部署在Azure Kubernetes 服務(阿克斯) 和Nginx 入口控制器。
設定
我的 Flask 應用程式如下所示:
src/main.py
from flask import Flask
from src.routes import main_bp
app = Flask(__name__)
app.register_blueprint(main_bp)
@app.route('/health/live')
def healthLiveMsg():
return 'Healthy'
@app.route('/health/ready')
def healthReadyMsg():
return 'Healthy'
if __name__ == '__main__':
app.run(host='0.0.0.0', port=80)
src/main_bp.py
from flask import Blueprint, render_template
main_bp = Blueprint('main', __name__)
# home page
@main_bp.route('/')
def home():
return render_template('index.html')
# some other page
@main_bp.route('/import')
def import_page():
# some code...
return renter_template('import.html')
# some backend job trigger
@main_bp.route('/run_job', methods=['POST'])
def run_job():
# some code...
def register_blueprints(app):
app.register_blueprint(main_bp)
有base.html
一個導航欄,我使用 Flask 的url_for
功能分別獲取主頁和導入頁面的鏈接href="{{ url_for('main.home') }}
,href="{{ url_for('main.import_page') }}
aks 入口在以下 yaml 模板中定義:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: __AksIngress__-ingress
namespace: __AksNamespace__
annotations:
nginx.ingress.kubernetes.io/proxy-buffer-size: 16k
nginx.ingress.kubernetes.io/proxy-body-size: "0"
nginx.ingress.kubernetes.io/server-alias: __AksNamespace__.__AksDnsZone__.__AksDomainName__
nginx.ingress.kubernetes.io/rewrite-target: /$1
nginx.ingress.kubernetes.io/proxy-connect-timeout: "3600"
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
nginx.ingress.kubernetes.io/server-snippet: keepalive_timeout 3600s;client_body_timeout 3600s;client_header_timeout 3600s;
spec:
tls:
- hosts:
- __AksNamespace__.__AksDnsZone__.__AksDomainName__
secretName: __AksIngress__-tls
ingressClassName: nginx
rules:
- host: __AksNamespace__.__AksDnsZone__.__AksDomainName__
http:
paths:
- path: /myapp/?(.*)
pathType: Prefix
backend:
service:
name: myapp-service
port:
number: 80
問題
當部署在 aks 上時,可以透過以下位址存取該應用程式example.com/myapp
。所提供的頁面顯示導覽列的 html,其中包含href
s as"/"
和"/import"
。當點擊其中任何一個時,瀏覽器會導航到example.com
並example.com/import
刪除myapp
前綴,當然會出現 404 錯誤。我們期望在頁面導航時正確建立 URL,並帶有前綴,例如example.com/myapp/import
。活性和就緒性檢查(可在example.com/myapp/health/live
和獲取example.com/myapp/health/ready
)由 Kubernetes 找到。
我的嘗試
我嘗試了多種解決方案,但沒有一個有效。
SCRIPT_NAME
經過幾次搜索我發現這篇博文這暗示了正確的解決方案。我在 dockerfile 中設定了環境變數並在本地電腦上運行容器,是的,它正在工作:
- 首頁位於
localhost/myapp
- 點擊導航列將我帶到
localhost/myapp/import
- 按一下匯入頁面中發布的按鈕以
localhost/myapp/run_job
觸發後端作業。
然而,部署到 aks 後,一切都只是多了一個額外的前綴:
- 主頁現在位於
example.com/myapp/myapp
- 當導航到其他頁面
example.com/myapp/import
時,我會看到該頁面現在位於example.com/myapp/myapp/import
- 類似的事情與
run_job
- 此外,kubernetes 的活性和就緒性檢查失敗,因為它們也在雙前綴路徑下。
代理修復
我嘗試按照建議使用 ProxyFix在這個SO答案中並在初始化應用程式後新增以下行:
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_host=1)
然而,這似乎並沒有產生任何效果。我也嘗試過傳遞x_prefix=1
參數,但沒有成功。
問題
我讀了很多東西,現在我已經很困惑了。我開始使用“flaskrouting with aks”作為關鍵字來搜尋答案,然後轉移到“wsgi伺服器”,然後“nginx反向代理”“nginx前綴”或“nginx入口”,現在我不確定實際上是什麼正在發生。我不確定解決方案是否應該來自ingress.yaml
gunicorn,或者是否是需要適應的flask應用程式。
我看到的行為是什麼以及如何解決它?
由於此專案結構(與 aks 基礎設施一起)是根據模板構建的,因此我想要一個可以添加到此類模板中或可以單獨添加到程式碼中的解決方案。
答案1
您的代理配置缺少必要的X-Forwarded-Prefix
標頭配置。
從文件:
X-Forwarded-Prefix 標頭
若要將非標準
X-Forwarded-Prefix
標頭新增至帶有字串值的上游請求中,可以使用下列註解:nginx.ingress.kubernetes.io/x-forwarded-prefix: "/path"
這需要與 Proxyfix Flask 配置一起使用,x_prefix=1
當然包括參數。