私は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 ingress は次の 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
どちらかをクリックすると、ブラウザは に移動してプレフィックスを削除し、当然ながら 404 を返します。ページ内を移動するときに、プレフィックス (例 ) を使用して URL が正しく構築されることが期待されます。ライブネス チェックと準備チェック ( および で利用可能)は、Kubernetes によって検出されます。"/"
"/import"
example.com
example.com/import
myapp
example.com/myapp/import
example.com/myapp/health/live
example.com/myapp/health/ready
私の試み
いくつかの解決策を試しましたが、どれも機能しませんでした。
スクリプト名
いくつか検索してみたところこのブログ投稿それは正しい解決策を示唆していました。私は 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 の liveness チェックと readiness チェックも、二重プレフィックス パスの下にあるため失敗しました。
プロキシフィックス
提案された通りProxyFixを使ってみましたこのSOの回答でアプリを初期化した後、以下の行を追加しました:
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_host=1)
しかし、これはまったく効果がなかったようです。パラメータも渡してみましたがx_prefix=1
、成功しませんでした。
質問
あまりにも多くのことを読んだので、かなり混乱してしまいました。キーワードとして「flask routing with aks」を使用して回答を検索し始めましたが、次に「wsgi server」に移動し、「nginx river proxy」「nginx prefix」「nginx ingress」に移動しましたが、実際に何が起こっているのかわかりません。解決策が、、ingress.yaml
gunicorn から得られるのか、それとも適応する必要があるのは flask アプリなのかはわかりません。
どのような動作が見られますか? また、どうすれば解決できますか?
このプロジェクト構造 (aks インフラストラクチャと共に) はテンプレートから構築されるため、そのようなテンプレートに追加できるソリューション、またはコードに 1 つ追加するだけで済むソリューションが必要です。
答え1
プロキシ設定に必要なX-Forwarded-Prefix
ヘッダー設定がありません。
からドキュメント:
X-Forwarded-Prefix ヘッダー
文字列値を含む非標準
X-Forwarded-Prefix
ヘッダーをアップストリーム リクエストに追加するには、次のアノテーションを使用できます。nginx.ingress.kubernetes.io/x-forwarded-prefix: "/path"
x_prefix=1
もちろん引数も含めて、Proxyfix フラスコ設定と一緒に使用する必要があります。