A configuração

A configuração

Eu tenho um aplicativo de página única construído usando pythonFrascoestrutura. estou a usargunicórniocomo o servidor web e eu o coloquei em contêiner usandojanela de encaixe. Ele é implantado emServiços Azure Kubernetes(perguntas) comControlador de entrada Nginx.

A configuração

Meu aplicativo Flask é assim:

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)

O base.htmlpossui uma barra de navegação onde utilizo a url_forfunção do Flask para obter o link para a página inicial e a página de importação, respectivamente href="{{ url_for('main.home') }}ehref="{{ url_for('main.import_page') }}

A entrada aks é definida no seguinte modelo 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

O problema

Quando implantado no aks, o aplicativo pode ser acessado em example.com/myapp. A página servida mostra o html da barra de navegação com hrefs as "/"e "/import". Ao clicar em qualquer um deles o navegador navega example.come example.com/importdescarta o myappprefixo, atingindo 404, é claro. A expectativa é que ao navegar pelas páginas a URL seja construída corretamente, com o prefixo, por exemplo example.com/myapp/import. As verificações de atividade e prontidão (disponíveis em example.com/myapp/health/livee example.com/myapp/health/ready) são encontradas pelo Kubernetes.

Minhas tentativas

Eu tentei várias soluções, mas nenhuma delas funcionou.

SCRIPT_NAME

Depois de algumas pesquisas encontreiesta postagem do blogque aludiu à solução certa. Defino a variável de ambiente em meu dockerfile e executo o contêiner em minha máquina local e sim, estava funcionando:

  • a página inicial estava emlocalhost/myapp
  • clicar na barra de navegação me enviou paralocalhost/myapp/import
  • clicando nos botões na página de importação postada para localhost/myapp/run_jobacionar o trabalho de back-end.

No entanto, após a implantação no aks, tudo simplesmente teve um prefixo extra:

  • a página inicial estava agora emexample.com/myapp/myapp
  • navegando para as outras páginas que me enviaram example.com/myapp/importquando a página estava agora emexample.com/myapp/myapp/import
  • assunto semelhante com orun_job
  • além disso, as verificações de atividade e prontidão falharam no kubernetes, pois também estavam no caminho de prefixo duplo.

ProxyFix

Tentei usar o ProxyFix conforme sugeridonesta resposta SOe adicionei a linha abaixo após inicializar o aplicativo:

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

Isso, no entanto, parecia não ter surtido efeito algum. Tentei passar também o x_prefix=1parâmetro, sem sucesso.

A questão

Eu li tantas coisas que fiquei bastante confuso agora. Comecei a procurar respostas usando "roteamento de flask com aks" como palavras-chave, depois mudei para "servidor wsgi", depois "proxy reverso nginx" "prefixo nginx" ou "entrada nginx" e agora não tenho certeza do que é realmente acontecendo. Não tenho certeza se a solução deve vir do ingress.yamlgunicorn ou se é o aplicativo flask que precisa se adaptar.

Qual é o comportamento que estou vendo e como resolvo isso?

Como esta estrutura de projeto (juntamente com a infraestrutura aks) é construída a partir de um modelo, gostaria de uma solução que pudesse ser adicionada a esse modelo ou que fosse uma única adição ao código.

Responder1

Sua configuração de proxy não possui a X-Forwarded-Prefixconfiguração de cabeçalho necessária.

Dea documentação:

Cabeçalho X-Forwarded-Prefix

Para adicionar o cabeçalho não padrão X-Forwarded-Prefixà solicitação upstream com um valor de string, a seguinte anotação pode ser usada:

nginx.ingress.kubernetes.io/x-forwarded-prefix: "/path"

Isso precisa ser usado junto com a configuração do frasco do Proxyfix, incluindo o x_prefix=1argumento, é claro.

informação relacionada