Работа с путями маршрутизации Flask при развертывании за префиксом URL-адреса
У меня есть сборка одностраничного приложения с использованием платформы Python Flask . Я использую Gunicorn в качестве веб-сервера и поместил его в контейнер с помощью Docker . Он развертывается в Azure Kubernetes Services (aks) с помощью Nginx Ingress Controller.
Установка
Мое приложение Flask выглядит так:
источник/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)
The base.html
есть панель навигации, где я использую Flaskurl_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
это как"/"
и"/import"
. При нажатии на любой из них браузер переходит кexample.com
иexample.com/import
бросаяmyapp
префикс, конечно, достигающий 404. Ожидается, что при навигации по страницам URL-адрес будет построен правильно, с префиксом, например . Проверки работоспособности и готовности (доступны по адресуexample.com/myapp/health/live
иexample.com/myapp/health/ready
) находятся Kubernetes.
Мои попытки
Я попробовал несколько решений, но ни одно из них не сработало.
СКРИПТ_ИМЯ
После нескольких поисков я нашел сообщение в блоге , в котором указывалось на правильное решение. Я установил переменную среды в своем файле docker и запустил контейнер на своем локальном компьютере, и да, он работал:
- домашняя страница была по адресу
localhost/myapp
- нажатие на панель навигации отправило меня в
localhost/myapp/import
- нажимая на кнопки на странице импорта, опубликованной на
localhost/myapp/run_job
запуск серверной задачи.
Однако после развертывания в акс все просто имело лишний префикс:
- домашняя страница теперь находилась по адресу
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
параметр, но безуспешно.
Вопрос
Я прочитал так много всего, что теперь совсем запутался. Я начал искать ответы, используя в качестве ключевых слов «маршрутизацию колб с помощью aks», затем перешел к «серверу wsgi», затем «обратному прокси-серверу nginx», «префиксу nginx» или «входу nginx», и теперь я не уверен, что такое на самом деле. происходит. Я не уверен, что решение должно исходить отingress.yaml
, Gunicorn или приложение Flask, которое необходимо адаптировать.
Какое поведение я наблюдаю и как мне его решить?
Поскольку эта структура проекта (вместе с инфраструктурой aks) построена на основе шаблона, мне хотелось бы найти решение, которое можно было бы добавить в такой шаблон или которое было бы отдельным дополнением к коду.
1 ответ
В вашей конфигурации прокси отсутствует необходимая конфигурация заголовка.
Из документации :
Заголовок X-Forwarded-Prefix
Чтобы добавить нестандартный
X-Forwarded-Prefix
заголовок восходящего запроса со строковым значением, можно использовать следующую аннотацию:nginx.ingress.kubernetes.io/x-forwarded-prefix: "/path"
Это необходимо использовать вместе с конфигурацией колбы Proxyfix, включаяx_prefix=1
аргумент конечно.