A medida que más empresas migran sus aplicaciones a la nube, se enfrentan a la decisión entre hacer un "lift and shift" o rediseñar sus soluciones para que sean "nativas de la nube", un concepto cuya definición varía. Este post se centra en lo segundo y, en concreto, en una técnica útil que puede ayudarte a llevar aplicaciones a contenedores (es decir, Docker) y orquestarlas con Kubernetes.

Fuente: iStockPhoto
El reto del bootstrapping
Una de las promesas de DevOps y de las migraciones a la nube es reducir el trabajo repetitivo de las operaciones tradicionales automatizando procesos manuales. La naturaleza declarativa de Kubernetes, que garantiza de forma automática el estado deseado de tus aplicaciones, es muy potente. Aun así, a veces las aplicaciones requieren pasos de "bootstrapping" antes de ejecutarse correctamente, o deben arrancarse en un orden específico para resolver dependencias con otros sistemas, como colas o bases de datos.
Para que la aplicación arranque sin problemas, podrías reescribirla con lógica de reintentos a medida hasta que se den las condiciones óptimas, pero eso retrasaría tu migración. Una alternativa que evita reescribir código es crear pequeñas apps, scripts o comandos y añadirlos como InitContainers.
Posibles casos de uso de los Init Containers
- Una aplicación de blockchain que necesita registrarse entre sus pares
- Una app que debe obtener un token de acceso de un proveedor de identidad
- Datos dinámicos obtenidos desde una base de datos y cacheados para que la app se ejecute tras el arranque
- Obtener secretos cifrados desde un vault y escribirlos en el sistema de archivos
- Bloquear el arranque de la app hasta que otro sistema esté disponible (por ejemplo, una cola o un servidor de base de datos)
Ejemplo sencillo con dos imágenes de Busybox
En este ejemplo, supongamos que una app necesita poblarse dinámicamente con algunos datos antes de iniciarse (como en los escenarios anteriores). Esto también se podría conseguir con un ConfigMap, pero para mostrar el potencial de esta técnica, mantén la mente abierta sobre lo que más podrías hacer.
- Crear un PersistentVolumeClaim
Primero, necesitamos un volumen de almacenamiento al que podamos acceder.
Persistent Volume Claim
$ kubectl apply -f test-pvc.yamlpersistentvolumeclaim/test-pvc created
2. Genera un archivo YAML de configuración del Deployment
$ kubectl create deployment test-app --image=busybox:1.28.0 -o yaml --dry-run > test-app.yaml
3. Edita el Deployment y añade el volumen y el Init Container de esta forma
Deployment con Init Container
Fíjate en que en este archivo añadimos el volumen y, después, otra imagen de Busybox dentro del initContainer. Podría ser literalmente cualquier imagen, pero para este ejemplo solo quería escribir algo de contenido en un archivo del sistema de archivos montado para que, cuando la app arranque con la otra imagen de Busybox, acceda al archivo y lea su contenido.
4. Ejecuta el Deployment y monitorea los logs
# deploy app
$ kubectl apply -f test-app.yamldeployment.apps/test-app configured# monitor logs
$ kubectl logs -f deployment/test-appFile content: Hello, World!
Si ves "File content: Hello, World!", funcionó. A partir de este ejemplo básico, puedes adaptar tu app para sustituir la imagen del contenedor principal y agregar tantos init containers como necesites para asegurarte de que tu app arranque con todo lo que requiere. La ventaja de esta técnica es que automatizas el despliegue de tus apps sin escribir lógica compleja de reintentos ni manejo de errores para resolver dependencias que antes eran manuales.
Para más información sobre los Init Containers, consulta la documentación oficial de Kubernetes: