Установка

Установка

У меня есть одностраничное приложение, созданное с использованием 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 панели навигации с hrefs как "/"и "/import". При нажатии на любой из них браузер переходит на example.comи example.com/importотбрасывает myappпрефикс, попадая на 404, конечно. Ожидается, что при навигации по страницам URL-адрес будет построен правильно, с префиксом, например example.com/myapp/import. Проверки жизнеспособности и готовности (доступные по адресу example.com/myapp/health/liveи example.com/myapp/health/ready) обнаруживаются Kubernetes.

Мои попытки

Я перепробовал несколько решений, но ни одно из них не сработало.

ИМЯ_СКРИПТА

После нескольких поисков я нашелэтот пост в блогеэто намекало на правильное решение. Я установил переменную окружения в моем 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

Я попробовал использовать ProxyFix, как было предложено.в этом SO ответи добавил следующую строку после инициализации приложения:

app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_host=1)

Однако это, похоже, не дало никакого эффекта. Я пробовал также передать x_prefix=1параметр, но безуспешно.

Вопрос

Я прочитал так много всего, что теперь совсем запутался. Я начал искать ответы, используя «маршрутизация Flask с AKS» в качестве ключевых слов, затем перешел к «серверу WSGI», затем «обратному прокси-серверу nginx», «префиксу nginx» или «входу nginx», и теперь я не уверен, что на самом деле происходит. Я не уверен, должно ли решение исходить от ingress.yamlgunicorn или это приложение 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аргумент, конечно.

Связанный контент