Cargas con estado en Kubernetes, y la pregunta que deberías hacerte primero
Un StatefulSet garantiza menos de lo que se supone, un volumen ancla un pod a una zona, y la pregunta honesta es si esa base de datos debería estar en el clúster siquiera.
El clúster ejecuta todo lo demás, así que la base de datos se muda también. Seis meses después se drena un nodo durante una actualización, el volumen no se desasocia porque el pod no ha terminado limpiamente, el drenaje se queda colgado, y alguien descubre a las dos de la madrugada que la réplica que creía tener estaba planificada en la misma zona de disponibilidad que el primario.
Nada de eso es un argumento contra ejecutar cargas con estado en Kubernetes. Es un argumento a favor de saber qué garantiza la plataforma de verdad, porque la distancia entre lo que promete un StatefulSet y lo que la gente cree que promete es donde viven estos incidentes.
Qué te da de verdad un StatefulSet
Tres cosas, y son más estrechas de lo que sugiere el nombre.
Identidad de red estable. Cada pod recibe un nombre predecible y una entrada DNS estable que sobrevive a la replanificación. Es lo que permite a los miembros de un clúster encontrarse entre ellos, y es la razón principal de que existan los StatefulSets.
Almacenamiento estable. Cada pod recibe su propia reclamación de volumen persistente, y cuando se replanifica se vuelve a asociar al mismo volumen. La reclamación no se borra cuando se borra el pod, lo cual es deliberado y es también la razón de que se acumulen volúmenes huérfanos.
Operaciones ordenadas. Los pods se crean y se reducen en orden, y las actualizaciones progresivas avanzan de uno en uno, esperando a que cada uno esté listo.
Lo que no te da: ningún entendimiento de tus datos. No promoverá una réplica, no comprobará el retraso de replicación, no te impedirá reducir el pod que tiene la única copia vigente, y no coordinará una copia de seguridad. El orden no es consenso. Si tu base de datos necesita elegir un líder, alguien tiene que hacerlo, y ese alguien o es la propia base de datos o es un operador.
Clases de almacenamiento y las restricciones que heredas
El modo de acceso es la primera restricción. Casi todo el almacenamiento de bloque en la nube admite asociarse a un nodo cada vez, lo cual es correcto para una base de datos y significa que un pod no puede arrancar en un nodo nuevo hasta que el volumen se desasocie del antiguo. Los sistemas de ficheros compartidos admiten acceso multinodo a mayor coste y menor rendimiento. Elegir un sistema de ficheros compartido para que dos pods puedan escribir en el mismo directorio suele ser señal de que hay que revisar la arquitectura, no una decisión de almacenamiento.
Fija la política de recuperación a conciencia. Borrar elimina el volumen subyacente cuando desaparece la reclamación, lo que está bien para una caché y es catastrófico para una base de datos. Retener lo conserva, que es lo correcto para una base de datos y es por lo que los entornos acumulan discos huérfanos que facturan para siempre, como se señala en almacenamiento y transferencia en Azure.
La expansión de volumen funciona en casi todas las clases modernas y es de un solo sentido: puedes agrandar un volumen, no encogerlo. Comprueba que la clase tiene la expansión activada antes de necesitarla a medianoche.
El rendimiento se aprovisiona, y la clase por defecto suele ser la equivocada para una base de datos. El caudal y las operaciones por segundo de un volumen son un ajuste con precio, y una base de datos sobre un volumen de propósito general que agota su crédito de ráfaga produce un incidente de latencia que parece un problema de aplicación.
El anclaje a la zona es la restricción que se olvida
Un volumen de bloque existe en una zona de disponibilidad. Un pod que lo use solo puede planificarse en esa zona. Ese único hecho tiene consecuencias que la gente descubre durante los fallos y no durante el diseño.
Tus réplicas no están distribuidas salvo que tú lo hayas hecho. Si los tres pods de base de datos acabaron en la misma zona porque ahí era donde había capacidad, tienes tres copias con un solo dominio de fallo. Usa restricciones de dispersión topológica, y verifica el resultado en vez de suponerlo, porque el planificador satisface las restricciones donde puede y continúa donde no puede salvo que las hagas duras.
Perder una zona significa que los pods que hay en ella no pueden replanificarse en otro sitio, porque sus volúmenes se quedan varados. La recuperación es una restauración desde copia o la promoción de una réplica en otra zona, no una replanificación. Es exactamente el escenario que el experimento de pérdida de zona de los cinco primeros experimentos de caos está diseñado para sacar a la luz.
Las instantáneas no son copias de seguridad
La interfaz de instantáneas de almacenamiento te da instantáneas de volumen a un punto en el tiempo, y son genuinamente útiles para revertir rápido una migración mala.
No son una copia de seguridad, por tres razones. Una instantánea de volumen de una base de datos en marcha puede ser consistente a nivel de caída y no a nivel de aplicación, así que restaurarla equivale a recuperarse de un corte de luz, cosa que la mayoría de las bases de datos manejan y algunas no. Las instantáneas viven normalmente en la misma cuenta y el mismo dominio de fallo que aquello que protegen. Y no capturan el estado del clúster necesario para reconstruir la carga.
Usa el mecanismo de copia propio de la base de datos, escríbelo fuera del radio de impacto del clúster y prueba la restauración. El razonamiento está en una copia que el atacante puede borrar y la disciplina en objetivos de recuperación y la prueba de restauración.
Operadores, y qué estás comprando
Un operador de base de datos codifica conocimiento operativo como un controlador: aprovisionamiento, topología de replicación, conmutación, programación de copias, actualizaciones de versión menor y encaminamiento de conexiones al primario actual.
Los buenos valen genuinamente la pena, y son la única forma de que ejecutar una base de datos en el clúster tenga sentido a cierta escala, porque la alternativa es un StatefulSet más un puñado de scripts y una persona que recuerda cómo funciona la conmutación.
Lo que compras es la opinión del operador sobre tu base de datos, y lo que asumes es una dependencia con su propio ciclo de actualizaciones, sus propios errores y sus propios modos de fallo. Evalúalo por lo que importa a las tres de la madrugada: ¿maneja la conmutación automáticamente?, ¿verifica las copias?, ¿cómo se comporta durante el drenaje de un nodo?, ¿qué pasa cuando el propio operador está caído?, ¿quién lo mantiene?
La pregunta honesta
¿Debería esta base de datos estar en el clúster siquiera?
El argumento a favor de un servicio de base de datos gestionado es fuerte y los equipos lo infravaloran. Obtienes copias automáticas con restauración probada, parcheo, conmutación, recuperación a un punto en el tiempo y un contrato de soporte, y no eres dueño de nada de eso a las dos de la madrugada. La prima sobre cómputo en crudo es real y suele ser menor que el coste del tiempo de ingeniería que sustituye, en particular para un equipo sin una persona especialista en bases de datos.
Las razones genuinas para operarla tú: una base de datos sin equivalente gestionado, un perfil de coste a gran escala donde la prima del gestionado supere al coste operativo, un requisito de residencia o soberanía que el servicio gestionado no cumpla, o la necesidad de extensiones y configuración que el gestionado prohíbe. La comparación para el caso más común está en ajustar PostgreSQL gestionado.
Nuestra recomendación por defecto: gestionado para la base de datos transaccional principal, en el clúster para cachés, colas, índices de búsqueda y todo aquello donde perder el dato sea una molestia y no un incidente.
Lo que se olvida
- El drenaje se bloquea con los pods con estado. Un presupuesto de interrupción que no permite ninguna cuelga el drenaje de un nodo para siempre, que es la causa más común de una actualización de clúster atascada, como se describe en actualizaciones de clúster.
- Reducir escala borra pods, no reclamaciones. Los volúmenes se quedan y siguen facturando.
- Estar disponible no es lo mismo que poder servir. Una réplica que todavía se está poniendo al día pasa una sonda ingenua y recibe tráfico que no puede responder correctamente.
- Los límites de recursos matan bases de datos. Un límite de memoria ligeramente por debajo de un conjunto de trabajo legítimo produce una muerte por falta de memoria que parece aleatoria.
- Las reservas de conexiones no saben de conmutaciones. Después de una promoción, los clientes que mantienen conexiones con el primario antiguo tienen que ser forzados a reconectar.
Qué hacer esta semana
Para tu carga con estado más importante, ejecuta un comando: lista los pods con la zona en la que está cada uno. Si dos réplicas comparten zona, has encontrado un punto único de fallo que tu diagrama de arquitectura dice que no existe, y una restricción de dispersión topológica lo arregla. Lo comprobamos en la fase de plataforma de un proyecto cloud.