Работа с путями маршрутизации 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аргумент конечно.

Другие вопросы по тегам