La puesta en marcha

La puesta en marcha

Tengo una aplicación de una sola página compilada usando Python.Matrazestructura. Estoy usandogunicorniocomo servidor web y lo he contenedorizado usandoestibador. Está desplegado enServicios de Azure Kubernetes(pregunta) conControlador de ingreso Nginx.

La puesta en marcha

Mi aplicación Flask se ve así:

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)

Tiene base.htmluna barra de navegación donde uso la url_forfunción de Flask para obtener el enlace a la página de inicio y la página de importación, respectivamente href="{{ url_for('main.home') }}yhref="{{ url_for('main.import_page') }}

La entrada de aks se define en la siguiente plantilla 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

El problema

Cuando se implementa en aks, se puede acceder a la aplicación en example.com/myapp. La página servida muestra el html de la barra de navegación con hrefs como "/"y "/import". Al hacer clic en cualquiera de ellos, el navegador navega example.comy example.com/importsuelta el myappprefijo, alcanzando un 404, por supuesto. La expectativa es que al navegar por las páginas, la URL se cree correctamente, con el prefijo, por ejemplo example.com/myapp/import, . Kubernetes encuentra las comprobaciones de actividad y preparación (disponibles en example.com/myapp/health/livey ).example.com/myapp/health/ready

Mis intentos

Probé varias soluciones, pero ninguna funcionó.

SCRIPT_NOMBRE

Después de algunas búsquedas encontréesta publicación de blogeso aludía a la solución correcta. Configuré la variable de entorno en mi dockerfile y ejecuté el contenedor en mi máquina local y sí, estaba funcionando:

  • la página de inicio estaba enlocalhost/myapp
  • Al hacer clic en la barra de navegación me envió alocalhost/myapp/import
  • Al hacer clic en los botones en la página de importación publicada para localhost/myapp/run_jobactivar el trabajo de backend.

Sin embargo, después de implementar en aks, todo simplemente tenía un prefijo adicional:

  • la página de inicio ahora estaba enexample.com/myapp/myapp
  • navegar a las otras páginas a las que me envió example.com/myapp/importcuando la página estaba ahora enexample.com/myapp/myapp/import
  • asunto similar con elrun_job
  • Además, las comprobaciones de actividad y preparación fallaron para Kubernetes, ya que también estaban bajo la ruta de doble prefijo.

ProxyFix

Intenté usar ProxyFix como se sugiereen esta respuesta SOy agregó la siguiente línea después de inicializar la aplicación:

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

Sin embargo, esto no pareció haber tenido efecto alguno. Intenté pasar también el x_prefix=1parámetro, sin éxito.

La pregunta

He leído tantas cosas que ahora me he confundido bastante. Comencé a buscar respuestas usando "enrutamiento de matraces con aks" como palabras clave, luego pasé a "servidor wsgi", luego a "proxy inverso nginx", "prefijo nginx" o "ingreso nginx", y ahora no estoy seguro de qué es realmente sucediendo. No estoy seguro de si la solución debería venir de ingress.yamlgunicorn o si es la aplicación flask la que necesita adaptarse.

¿Cuál es el comportamiento que estoy viendo y cómo lo soluciono?

Debido a que la estructura de este proyecto (junto con la infraestructura de aks) se construye a partir de una plantilla, me gustaría una solución que pueda agregarse a dicha plantilla o que sea una única adición al código.

Respuesta1

A su configuración de proxy le falta la X-Forwarded-Prefixconfiguración de encabezado necesaria.

Dela documentación:

Encabezado de prefijo reenviado X

Para agregar el encabezado no estándar X-Forwarded-Prefixa la solicitud ascendente con un valor de cadena, se puede utilizar la siguiente anotación:

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

Esto debe usarse junto con la configuración del matraz Proxyfix, incluido el x_prefix=1argumento, por supuesto.

información relacionada