Cuando docker-compose no es suficiente
Docker Compose es una herramienta excelente para gestionar aplicaciones multi-contenedor en desarrollo, pero se queda corta cuando tu entorno empieza a imitar configuraciones de producción, especialmente las que involucran Kubernetes. Si tu aplicación consta de numerosos microservicios que necesitan interactuar dentro de un clúster de Kubernetes, o si necesitas feedback en tiempo real y depuración optimizada, TILT se convierte en la mejor opción.
A diferencia de Docker Compose, TILT está diseñado específicamente para manejar las complejidades de los microservicios basados en Kubernetes, ofreciendo funcionalidades como reconstrucciones automáticas, redespliegues y una interfaz integrada para monitorización y depuración. Esto lo hace ideal para desarrolladores que necesitan un entorno más robusto y parecido a producción durante el desarrollo, donde las capacidades de Docker Compose son limitadas. ¡Y si buscas una interfaz visual para tus microservicios, TILT también te tiene cubierto!
TILT para Aplicaciones GO
Imagina que tienes una API REST implementada en Go y quieres desarrollarla usando TILT. Primero necesitas un Dockerfile para construir la imagen (además de los manifiestos de Kubernetes para desplegar la aplicación y otros recursos):
FROM golang:1.21
WORKDIR /usr/src/app
COPY . .
RUN go build -gcflags="all=-N -l" -o example-go cmd/main.go
EXPOSE 8080
ENTRYPOINT ["/usr/src/app/example-go"]
Ahora puedes ejecutar la aplicación usando TILT con el siguiente Tiltfile:
docker_build('example-go', '.', dockerfile='./Dockerfile')
k8s_yaml('deployments/kubernetes.yaml')
k8s_resource('example-go', port_forwards=8080)
Esta es una configuración básica suficiente para esta sección, pero puedes aprovechar más funcionalidades como optimizaciones de compilación y actualizaciones en vivo ante cambios. Más información aquí.
Con esta configuración puedes ejecutar tu aplicación en un clúster k8s local usando TILT pero… ¿quién no necesita depurar algo durante el desarrollo?
Cómo depurar una aplicación Go ejecutándose con TILT
Como la aplicación no se ejecuta en tu máquina local, necesitas añadir delve a tu Dockerfile y exponer un puerto para permitir conexiones de depuración remota.
FROM golang:1.21
WORKDIR /usr/src/app
COPY . .
# añadir delve
RUN go install github.com/go-delve/delve/cmd/dlv@v1.21.2
RUN go build -gcflags="all=-N -l" -o example-go cmd/main.go
EXPOSE 8080
# permitir depuración remota
EXPOSE 40000
ENTRYPOINT ["/usr/src/app/example-go"]
Después, debes indicarle a Tilt que ejecute el binario con delve y exportar el puerto para que también se reenvíe al clúster. Modifica tu Tiltfile así:
# Tiltfile
# ...
docker_build_with_restart(
'example-go',
'.',
entrypoint='GOPATH/bin/dlv listen=40000 api-version=2 headless=true exec /usr/src/app/example-go continue accept-multiclient',
dockerfile='./Dockerfile'
)
k8s_yaml('deployments/kubernetes.yaml')
k8s_resource('example-go', port_forwards=[8080, 40000])
Finalmente, solo necesitas configurar tu IDE —o la herramienta que uses— para conectarte al depurador remoto. Por ejemplo, la siguiente configuración para VSCode:
{
"version": "0.2.0",
"configurations": [
{
"name": "Attach to Delve",
"type": "go",
"request": "attach",
"mode": "remote",
"showLog": true,
"trace": "log",
"port": 40000,
"host": "127.0.0.1",
"debugAdapter": "dlv-dap",
"substitutePath": [{ "from": "${workspaceFolder}", "to": "/usr/src/app" }]
}
]
}
¡Voilà! Ahora puedes depurar la aplicación remota igual que depurarías una local… ¿verdad? Bueno, no exactamente. El depurador no está listo para conectarse hasta que el contenedor y la aplicación hayan arrancado completamente. Entonces, ¿cómo sabes cuándo empezar a depurar? ¿Simplemente pruebas suerte cada vez y esperas que funcione?
Por ejemplo, si estás desarrollando una API REST, puedes depurar los endpoints a medida que se llaman por la naturaleza de la aplicación. Sin embargo, si necesitas depurar la aplicación desde el momento en que arranca, necesitas pausar el proceso hasta que se reciba una señal específica.
Cómo depurar una aplicación Go en TILT desde el inicio
Esta es una forma sencilla de detener la aplicación hasta que el depurador se conecte, usando el paquete await del repositorio tilt-enhancements:
package main
import (
// ...
_ "github.com/deveeztech/tilt-enhancements/pkg/await"
)
func main() {
initConfigurations()
initClients()
addHandlers()
startServer()
}
Por defecto el paquete await está desactivado; para activarlo debes establecer la variable de entorno TILT_AWAIT_DEBUGGER_ENABLED=true.
TILT_AWAIT_DEBUGGER_ENABLED=true
¡Ahora tienes el control desde la primera línea de la función main! 🐛
Conclusión
TILT proporciona un entorno potente para ejecutar y gestionar aplicaciones dentro de un clúster de Kubernetes local, pero puede hacer que la depuración sea compleja y difícil. El paquete await del repositorio tilt-enhancements ofrece una solución eficaz al permitir a los desarrolladores pausar el arranque de la aplicación hasta que el depurador se conecte. Esta funcionalidad proporciona un control preciso sobre el proceso de depuración desde la primera línea de código, facilitando la resolución de problemas en entornos complejos de microservicios.
Recuerda mantener el entorno local de desarrollo lo más sencillo posible siempre que funcione para todos en el equipo y cumpla con los estándares de la organización con el mínimo bucle de feedback.