Docker, Docker, Docker…

En CAPSiDE tenemos un equipo de operaciones increíble y también desarollamos herramientas internas y orientadas al cliente. Como parte del equipo de desarrollo, tengo una firme opinión que me gustaría compartir: no se habla lo suficiente de los beneficios de herramientas como Docker en desarrollo. En este post, explicaré los beneficios de adoptar Docker y Docker Compose en fases de desarrollo, basándome en nuestra experiencia.

  1. Una nueva aproximación
  2. Desplegar o no desplegar (contenedores en producción)
  3. ¿Qué pasa si no despliegas contenedores?
  4. Cómo entrenar a tu dragón
  5. Prepara tu aplicación para su hábitat
  6. Llévalo todo a desarrollo
  7. Nuestra vida ha mejorado usando Docker para desarrollo

1. Una nueva aproximación

Tradicionalmente, un desarrollador ejecutaría la aplicación entera en un portátil. Hacerlo así trae múltiples problemas, como largos tiempos de configuración inicial e incompatibilidades cuando se trabaja en múltiples proyectos.

Estos proyectos se mitigaban de algún modo usando devboxes. Normalmente, una devbox es una máquina virtual con todas las herramientas necesarias para trabajar en un proyecto en particular. Añade una capa de oblicuidad, pero reduce el tiempo de despliegue y aísla los proyectos. Igualmente, hemos encontrado ciertos problemas con esta aproximación:

Decidimos ir un paso más allá y usar Docker para desarrollo. Construir imágenes de Docker no para cada aplicación, sino para cada uno de sus componentes. Si una aplicación tiene, por ejemplo, una API, un worker y una database, crearíamos tres imágenes diferentes. Entonces, usaríamos Docker Compose para orquestrarlas y hacer que cada contenedor montara el código desde el disco local.

Es importante tener en cuenta que las únicas dependencias que necesitamos instaladas en nuestros portátiles son Docker y Docker Compose. Tenemos nuestro Dockerfile y docker-compose.yml bajo control de versiones. Eso significa que podemos recrear un entorno de desarrollo en cuestión de minutos sin interacción humana. Una gran ventaja a la hora de incorporar nuevos colaboradores, cuando tu portátil se estropea o cuando tienes que configurar entornos de prueba.

Docker for Developers - CAPSiDE

2. Desplegar o no desplegar (contenedores en producción)

Si despliegas contenedores en producción, tiene mucho sentido trabajar con las mismas imágenes en desarrollo. Esas imágenes son tus artefactos, tus unidades de despliegue, y ahora estás utilizando Docker como medio de distribución de código. También podrías usar las mismas imágenes en tu pipeline de integración continua. Escribes código, pruebas y despliegas la misma imagen utilizando el mismo conjunto de herramientas.

La mayoría de vosotros no tendréis esa configuración establecida. Mucha gente piensa que solo se pueden ejecutar contenedores en plataformas de orquestación como Kubernetes. Estas plataformas, por asombrosas que sean, no son un requisito para ejecutar tus imágenes en producción: puedes implementar las imágenes en máquinas virtuales tradicionales con Docker instalado y ejecutarlas en ellas.

Luego, utilizarás exactamente la misma imagen en producción que ya habrás probado extensivamente durante la fase de desarrollo.

Utilizamos esta aproximación en escenarios donde la máquina host está adaptada a la aplicación a nivel de recursos (eso en CloudLand es fácil debido a la gran cantidad de tamaños de instancia que puedes elegir). Hasta ahora nos ha dado excelentes resultados, por lo que os animo a que lo tengáis en cuenta. CloudLand permite concentrarte en contener tu aplicación sin tener que lidiar con la carga adicional de la plataforma de orquestación. Al menos, por ahora 😊

3. ¿Qué pasa si no despliegas contenedores?

De acuerdo, sigues pensando que desplegar contenedores no es una opción para ti. ¿Deberías molestarte en cambiar tus herramientas de desarrollo? Yo digo: ¡sí!.

Y, ¿por qué? Porque con Docker Compose podrás emular tu entorno de producción. Si despliegas código dentro de una instancia tradicional o incluso en una máquina física, puedes crear una imagen usando el mismo sistema operativo y dependencias y usarlo para desarrollo. No solamente tendrás una imagen con todos los paquetes instalados en tu entorno de producción. Tendrás una imagen sin paquetes adicionales que no están presentes en producción.

Docker for Developers - CAPSiDE

He pasado mucho tiempo de mi vida intentando detectar errores causados por diferentes versiones de aplicaciones, dependencias, bibliotecas de sistemas, etc. instaladas en diferentes entornos. Es algo molesto de hacer y terminas sintiéndote estúpido por permitir que suceda desde el principio. Si mantienes tus Dockerfiles para tus servicios, tienes tus dependencias declaradas explícitamente (¡incluso dependencias del sistema!). Seguirás encontrando maneras de hacer que las cosas funcionen en una máquina y no en otra, pero será mucho más difícil.

Si no utilizas los contenedores en producción, tendrás que asegurarte que tus imágenes sean lo más similares posible a tu entorno de producción. Si puedes, usa las mismas herramientas para aprovisionar los servidores y construir tus imágenes. Estas estarán más hinchadas, pero no tendrás que mantener la sincronización manualmente. Recuerda que un proceso manual fallará en algún momento, simplemente que no sabes cuándo.

También puedes mantener tus herramientas de desarrollo almacenadas en contenedores. Si eres estricto en ese sentido, todo el equipo usará exactamente las mismas versiones y será una cosa menos a depurar. En cualquier caso, procura no confiar en herramientas o configuraciones fuera de tu repositorio. En algún momento se desincronizarán y tendrás problemas para saber el porqué. A veces solamente necesitas acceder a archivos fuera de tu repositorio (por ejemplo, un archivo de credenciales). En este caso, considera añadir una verificación automática para aquellos archivos que te impiden hacer algo si no están presentes/bien formados.

Hacer que tus entornos de desarrollo se parezcan a los de producción te permite pagar un pequeño precio por adelantado y así prevenir muchos pagos en el futuro. Tendrás muchos problemas en tu desarrollo diario que, de lo contrario, se habrían detectado durante un despliegue, o algo peor, por tus clientes.

4. Cómo entrenar a tu dragón

Plantéate tu aplicación como si fuera un hermoso dragón: como las aplicaciones, todos los dragones guais viven en la nube. Además, es una vergüenza ver a tu hermoso producto durmiendo en un montón de dinero generado en el pasado.

Sí, eso también me hace sentir mejor en mi trabajo.

Docker for Developers - CAPSiDE

¡Venga, Smaug! ¡Puedes hacerlo mejor!

Si tu dragón tiene que vivir en el Cloud, no tiene sentido retenerlo en una jaula en tu escritorio hasta el día que tenga que volar. Si no lo sueltas de la jaula pronto no podrá volar, o incluso peor, escupir fuego. Uno no puede convertirse en el rey del cielo sin un entrenamiento adecuado. A los Targaryen se les olvidó y terminaron matando a casi todos los dragones. No seas un Targaryen loco.

5. Prepara tu aplicación para su hábitat

Usar Docker Compose en desarrollo implica una limitación importante: tus servicios ya no están en la misma máquina.

Esto tiene un par de limitaciones en la manera en que codificas tu aplicación:

Este es uno de los casos donde las limitaciones te favorecen. Las aplicaciones listas en producción no pueden depender del disco compartido o del localhost para comunicarse entre servicios. ¿Cómo te ayuda permitirlo en desarrollo? No te ayuda para nada.

El uso de localhost o del sistema de archivos local te proporciona un atajo para evitar los problemas a los que te enfrentarás en producción, donde los errores son más costosos de resolver. No quieras tomar ese atajo. Aceptar esas limitaciones te llevará a tomar mejores decisiones arquitectónicas. Todos los componentes se construirán para vivir aislados, y no se agruparán en una sola «máquina». Así, harás que la comunicación entre componentes sea explícita y configurable.

A veces uno de los componentes de tu aplicación es un servicio a terceros. Por ejemplo, tu stack de producción puede usar balanceadores de carga o bases de datos como servicio de tu proveedor Cloud. Te recomiendo que emules esos servicios en tus entornos de desarrollo, aunque no sea al 100%. Una alternativa es tener un código condicional que se comporte de manera diferente en desarrollo y producción. Te lo desaconsejo encarecidamente. Eso significa que hay una ruta de acceso en tu código que no ejecutas en desarrollo, donde pasas la mayor parte del tiempo. En vez de eso, solo detectará errores en la parte «oculta» donde realmente duele: en producción.

Si tu infraestructura en producción tiene un Application LoadBalancer de AWS como front-end para dos servicios diferentes (digamos, API y web) puedes añadir un servicio en tu archivo docker-compose.yml que lleve el rol de ALB:

services:
  alb:
    image: nginx:alpine
    ports:
      - "8080:80"
    depends_on:
      - web
      - api
    command: |
      sh -c "sh -s <<'EOF' cat > /etc/nginx/conf.d/default.conf <<'EON'
      server {
        listen 80;

        location / {
          proxy_pass http://web:80;
        }

        location /api {
          proxy_pass http://api:80;
        }
    }
    EON
    nginx -g 'daemon off;'
    EOF"

Este es un buen truco para integrar la inline configuration de nginx dentro del comando en docker-compose.yml

De esta manera, la interacción entre componentes será más cercana al entorno de producción: el contenido web nunca hablará con el componente API, sino que en su lugar utilizará el componente alb. Este diseño te ayudará a crecer en el futuro.

Si usas una RDS Database, puedes añadir un contenedor que ejecute la misma versión de base de datos que ofrece tu proveedor Cloud. Esto te obligará a pensar en cómo arrancar y actualizar tu base de datos mientras estás en fase de desarrollo. Al final, habrás practicado tus actualizaciones en desarrollo cientos de veces. Eso te ayudará a descubrir cómo irán las cosas una vez el código pase a producción

6. Llévalo todo a desarrollo

Es importante tener en mente que tu producto no es el código que se ejecuta en tu portátil. Tu producto es lo que se ejecuta en producción. En ese entorno, a menudo tienes otros roles involucrados. Los especialistas en operaciones, seguridad o administración de sistemas también deberían dar forma al producto.

Un malentendido común en DevOps es que esta filosofía busca reemplazar esos roles. Mi entendimiento es que es justo lo contrario: DevOps es una gran oportunidad para hablar con expertos antes de tiempo, cuando se esté diseñando una solución y no más tarde, cuando el coste de solucionar un problema sea mayor. Forzarte a pensar en tu producto completo desde el principio generará muchas preguntas sobre cómo interactuarán los componentes.

Cuando tienes dos piezas que deberían trabajar juntas, quieres centrarte primero en la integración. Si no lo haces, necesitarás formular hipótesis cuando estés desarrollando cada componente. Y en algún momento, tus hipótesis serán incorrectas. Entonces tendrás que volver a hacer mucho trabajo y eso duele. Si usas Docker Compose, harás primero la integración y los contratos entre los componentes se definirán desde el principio.

Docker for Developers - CAPSiDE

¿Qué pasa si no lo integras primero?

Trabajar teniendo en cuenta todas las integraciones te ayudará de diferentes maneras:

Dos consejos a la hora de construir tus imágenes:

Vale, esto definitivamente ayuda a la hora de diseñar un nuevo sistema. Pero ¿qué pasa cuando ya tienes algo en su lugar?

Según mi experiencia, intentar construir un entorno de desarrollo usando Docker Compose es una manera genial de ganar conocimiento sobre el sistema. Durante del proceso, probablemente arregles un montón de posibles problemas esperando a explotar en el peor momento. Al final, tu producto será más robusto y tu conocimiento obtenido se extenderá por todo el equipo.

Docker for Developers - CAPSiDE

7. Nuestra vida ha mejorado usando Docker para desarrollo

Desconozco tu situación, pero te puedo contar algunos de los beneficios que hemos experimentado desde que decidimos usar Docker para desarrollo:

Tal vez ya se te den bien algunos de estos puntos, o quizás tengas otros problemas. Pero usar Docker (y Docker Compose) en desarrollo ha facilitado la vida de nuestros desarrolladores, y espero que también te ayude a ti. En cualquier caso, dedícale un momento de reflexión. Estoy seguro de que encontrarás casos donde estos pueden mejorar tu proceso.

TAGS: application, automation, development, docker, docker compose

speech-bubble-13-icon Created with Sketch.
Comentarios

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

*
*