Al menos para mí, así fue.
En 2017 trabajaba como Data Engineer para el gobierno federal de México.
Venía de ser developer lead, había pasado por data analyst, y estaba descubriendo mi gusto por construir sistemas de datos.
El requisito era sencillo: crear una solución para publicar datos abiertos geográficos.
No había más contexto, ni restricciones claras, ni discusiones de arquitectura. Así que hice lo que sabía hacer: diseñé un sistema que cubriera el requerimiento y, de paso, le agregué valor. La idea era que pudiera publicar cualquier dataset, sin importar el formato de origen, y además ofrecer servicios WMS/WFS para que los datos pudieran consumirse directamente en mapas web.
Desplegué un servicio de GeoServer.
Escribí scripts para instalarlo y configurarlo.
Después de algunas semanas, el sistema estaba corriendo on-premise.
Hice un demo mostrando cómo los usuarios podían consumir los servicios WMS para generar análisis sobre ellos. Todo funcionó, el requisito estaba cumplido y con valor agregado.
Todo funciona hasta que no
Un buen día, todo el servicio se cayó, producción estaba en llamas.
No había ambiente de pruebas.
No había snapshots.
No había un plan claro de recuperación.
Y, lo más importante: no tenía respuestas listas para cuando alguien preguntara qué había pasado.
Tenía scripts, sí. Pero al ejecutarlos solo devolvían errores. Ahí entendí que hay una enorme diferencia entre ejecutar un script en un sistema limpio y hacerlo sobre un sistema medio configurado, medio roto.
Tomé una decisión poco elegante, pero efectiva: di de baja todo el servicio, eliminé todos mis archivos y levanté el sistema desde cero. Después de algunas horas, volvió a estar arriba.
Funcionó.
Pero más que una victoria fue un parche.
No era el culpable, pero sí el responsable
Ese día entendí que todo falla eventualmente: hardware, software, proveedores de internet, Cloudflare o AWS us-east-1.
Y entendí algo más incómodo: tal vez yo no había sido el culpable de la caída, pero sí era el responsable de un funcionamiento adecuado.
La presión, la confusión, estar bajo el reflector sin tener respuestas claras… era una experiencia que no quería repetir.
Eso me llevó a enfrentar dos problemas grandes que hasta ese momento había ignorado:
-
No tenía replicabilidad real del sistema. Mis scripts existían, pero dependían de demasiadas cosas: versiones, repositorios, estados intermedios. Bastaba con que MySQL cambiara de repositorio o que una versión dejara de estar disponible para que todo se rompiera.
-
No tenía mecanismos de tolerancia a fallos. El sistema funcionaba… mientras todo funcionara.
Las herramientas fueron una respuesta
Buscando resolver el primer problema llegué a Docker. No porque fuera tendencia, sino porque era exactamente lo que necesitaba en ese momento: una forma de empaquetar el sistema y poder replicarlo.
Con los pocos tutoriales en español que existían entonces, escribí mi primer Dockerfile. Usé Docker Compose para desplegar los servicios, reiniciarlos si era necesario o destruirlos por completo. Por primera vez, sentí que podía repetir el mismo resultado más de una vez sin cruzar los dedos.
Pero apareció otra pregunta inevitable: ¿qué pasa cuando falle el servidor?
Si estaba asumiendo que todo podía fallar, entonces el servidor también iba a fallar en algún momento. Necesitaba correr el servicio en más de una máquina.
Ahí llegó Kubernetes. No como una meta, sino como una consecuencia. Llegó a resolver un problema real, pero también a traer mucha más complejidad. Docker Compose se instalaba con un comando. Kubernetes implicaba desplegar etcd, hacer SSH a servidores, configurar hostnames, redes, certificados… y no quería volver a confiar todo eso a scripts que ya me habían fallado una vez.
Eso me llevó a Ansible, escribí mis playbooks y desplegué Kubernetes en bare-metal.
Quitarme a mí del camino
Todo funcionaba. Pero todavía había fricción.
Agregar o quitar nodos seguía siendo un proceso manual. Quería que el sistema se ajustara solo, aunque el entorno on-premise no tuviera demasiado movimiento. Ahí llegué al service discovery con Consul y, de paso, al stack de HashiCorp.
La idea era simple: dejarle a la máquina la mayor responsabilidad posible. Yo solo ejecutaba un pequeño script de Consul. No importaba si lo corría una o cien veces, el resultado era el mismo: el nodo quedaba agregado una sola vez a la red. Más tarde entendí que eso se llamaba idempotencia, pero en ese momento solo sabía que me daba tranquilidad.
Lo que realmente estaba aprendiendo
Con el tiempo entendí: hay muchas formas de cumplir un requisito, pero no todas sobreviven al primer fallo en producción.
Yo no sabía que eso era DevOps.
No estaba intentando “hacer DevOps”.
Solo estaba intentando que el sistema fallara sin romperme a mí en el proceso.