Tenemos una aplicación Spring Boot (2.0.4) que expone varios puntos finales, uno de los cuales permite a los clientes recuperar archivos a veces muy grandes (~200 GB). La aplicación se expone en un pod a través de una implementación de Kubernetes configurada con la estrategia de actualización continua.
Cuando actualizamos nuestra implementación configurando la imagen a la última versión, los pods se destruyen y se activan otros nuevos. Nuestra prestación de servicios es perfecta para nuevas solicitudes. Sin embargo, las solicitudes actuales pueden interrumpirse y esto puede resultar molesto para los clientes que descargan archivos muy grandes.
Podemos configurar ganchos previos a la parada del ciclo de vida del contenedor en nuestra especificación de implementación para inyectar una pausa antes de enviar señales de apagado a la aplicación a través de su PID. Esto ayuda a evitar que el tráfico nuevo se dirija a los pods que se configuraron para Terminar. ¿Hay alguna forma de pausar el proceso de cierre de la aplicación hasta que se hayan completado todas las solicitudes actuales (esto puede llevar decenas de minutos)?
Esto es lo que hemos probado desde la aplicación Spring Boot:
Implementando un detector de apagado que intercepta ContextCloseEvents ; Lamentablemente, no podemos recuperar de forma fiable una lista de solicitudes activas. Las métricas de Actuator que pueden haber sido útiles no están disponibles en esta etapa del proceso de apagado.
Cuente las sesiones activas implementando un HttpSessionListener y anulando los métodos sessionCreated/Destroy para actualizar un contador. Esto falla porque los métodos no se invocan en un subproceso separado, por lo que siempre informe el mismo valor en el oyente de apagado.
¿Alguna otra estrategia que debamos probar? ¿Desde la propia aplicación, el contenedor o directamente a través de los descriptores de recursos de Kubernetes? Consejos/Ayuda/Indicadores serían muy apreciados.
Editar: administramos el clúster, por lo que solo intentamos mitigar las interrupciones del servicio a los clientes conectados actualmente durante una actualización administrada de nuestra implementación a través de una especificación de pod modificada
Puede aumentar la terminationGracePeriodSeconds , el valor predeterminado es 30 segundos. Pero desafortunadamente, no hay nada que impida que un administrador de clúster fuerce la eliminación de su pod, y hay todo tipo de razones por las que todo el nodo podría desaparecer.
Hicimos una combinación de lo anterior para resolver nuestro problema.
Tenga en cuenta que debido a que enviamos TERM a pid 1 desde el script de monitoreo, el pod terminará en este punto y la terminación GracePeriodSeconds nunca se ve afectada (está ahí como precaución)
Aquí está el guión:
#!/bin/sh while [ "$(/bin/netstat -ap 2>/dev/null | /bin/grep http-alt.*ESTABLISHED.*1/java | grep -c traefik-ingress-service)" -gt 0 ] do sleep 1 done kill -TERM 1Aquí está la nueva especificación de pod:
containers: - env: - name: spring_profiles_active value: dev image: container.registry.host/project/app:@@version@@ imagePullPolicy: Always lifecycle: preStop: exec: command: - /bin/sh - -c - sleep 5 && /monitoring.sh livenessProbe: httpGet: path: /actuator/health port: 8080 initialDelaySeconds: 60 periodSeconds: 20 timeoutSeconds: 3 name: app ports: - containerPort: 8080 readinessProbe: httpGet: path: /actuator/health port: 8080 initialDelaySeconds: 60 resources: limits: cpu: 2 memory: 2Gi requests: cpu: 2 memory: 2Gi imagePullSecrets: - name: app-secret serviceAccountName: vault-auth terminationGracePeriodSeconds: 86400Intente cerrar correctamente su aplicación Spring Boot.
Esto podría ayudar:
https://dzone.com/articles/graceful-shutdown-spring-boot-applications
Esta implementación se asegurará de que ninguna de sus conexiones activas se elimine y la aplicación esperará con gracia a que finalicen antes del cierre.