IT & Engineering

Devgun: creación de entornos de desarrollo con Kubernetes

Cuando abordamos por primera vez el problema de crear entornos de desarrollo locales, recurrimos a herramientas comunes como vagrant. Pero, como ocurre con la mayoría de los entornos creados con vagrant, los tiempos de compilación son largos. Esto significa que las imágenes de vagrant tienen una larga vida útil y tienden a desfasarse con el tiempo.
Imagen para Devgun: creación de entornos de desarrollo con Kubernetes

Cuando abordamos por primera vez el problema de crear entornos de desarrollo locales, recurrimos a herramientas comunes como vagrant. Pero, como ocurre con la mayoría de los entornos creados con vagrant, los tiempos de compilación son largos. Esto significa que las imágenes de vagrant tienen una larga vida útil y tienden a desfasarse con el tiempo.

Nuestros servicios e infraestructura cambian constantemente, por lo que la compilación de vagrant casi siempre fallaba. Queríamos evitar el tradicional “rito de iniciación de las nuevas incorporaciones al equipo de desarrollo”, que fácilmente conlleva días de trabajo para lograr que vagrant compile con éxito una nueva máquina virtual de desarrollo.

Lo ideal es que el nuevo personal de desarrollo pueda ser productivo a las pocas horas de su contratación, y no en días o semanas.

A todo esto se sumaba el hecho de que tenemos muchos microservicios que deben ejecutarse en el entorno de desarrollo e integrarse a la perfección.

Los objetivos del proyecto eran sencillos:

  • Configurar y destruir un entorno de desarrollo rápidamente y de forma reproducible.
  • Configuración y desmantelamiento del entorno de desarrollo en un solo paso.
  • Iniciar y detener servicios, incluidas sus dependencias, a voluntad.

Evaluación de plataformas de orquestación

Como nuestros microservicios ya se ejecutaban en contenedores, sabíamos que necesitábamos elegir un sistema de orquestación.

Varias personas de nuestro equipo de desarrollo estaban interesadas en Mesos Marathon, así que lo probamos primero. Por desgracia, los requisitos de memoria y hardware necesarios para ejecutar marathon en un pequeño entorno de desarrollo local eran demasiado restrictivos para nuestros fines. En el momento de las pruebas, minimesos tampoco era capaz de conectar correctamente en red los contenedores de Marathon con la red local, un obstáculo importante para nuestro proyecto. Estos problemas dejaron claro que Mesos resultaría poco práctico para nuestras necesidades.

A continuación, evaluamos Kubernetes y Minikube ya que nos atraía la activa comunidad que rodeaba a estos proyectos. Descubrimos que el consumo de memoria era mínimo y que la conexión de red funcionaba a la perfección. La mayoría de las funciones que nos interesaban funcionaban de forma predeterminada, y lograr que nuestras aplicaciones de terceros se ejecutaran en Minikube resultó más fácil de lo esperado.

Así que, con Minikube como plataforma elegida, pudimos avanzar en el proyecto rápidamente y dedicar la mayor parte de nuestro tiempo a desarrollar lo que se convertiría en Devgun.

Creación de una CLI

Para alcanzar los objetivos de nuestro proyecto, decidimos crear una interfaz de línea de comandos todo en uno escrita en Golang. Queríamos una CLI que se pudiera distribuir como un único binario a nuestro equipo de desarrollo, así que creamos una llamada Devgun.

Minikube and Mailgun logos with plus symbol in between

Devgun no da nada por sentado sobre el entorno de desarrollo. Descarga automáticamente todas las herramientas que necesita, incluidas Minikube, kubectl y herramientas específicas de Mailgun, en el directorio /.devgun/bin. Lo único que tienes que hacer es añadir tu ruta tras completar la configuración inicial. Instalar todo en un único directorio hace que desinstalar sea tan sencillo como rm -rf ~/devgun.

Compilamos todos los archivos de manifiesto de kubernetes en el binario estático mediante el proyecto go-bindata, lo que permite descargar y ejecutar un solo archivo para instalar un entorno de desarrollo.

La ejecución de Devgun es la siguiente:

                                

                                    $ devgun startrnPulling kubectl                              [done]  rnPulling minikube                             [done]  rnWriting Minikube configuration               [done after 0.702698 seconds]  rnBooting Minikube environment                 [done after 77.297039 seconds]  rnWaiting for Kubernetes..                     [done]  rnINFO[0148] Setting up minikube routes -- enter your sudo password if prompted  rnModifying routes                             [done after 0.012867 seconds]  rnAdding kube-dns resolver entry               [done after 0.002070 seconds]  rnApplying kube-dns-external configuration     [done after 0.212881 seconds]  rnEnabling Heapster                            [done after 37.506335 seconds]  rn========================================================rnMinikube is now configured and running....rnrn# Set up path for our bin directory with dev toolsrnexport PATH="$PATH:/Users/thrawn/.devgun/bin"rnrnNext you should choose a mailgun service to start using <code data-enlighter-language="generic" class="EnlighterJSRAW">devgun service start</code>rnrn* Use <code data-enlighter-language="generic" class="EnlighterJSRAW">devgun service list</code> to see a list of services to startrn* Use <code data-enlighter-language="generic" class="EnlighterJSRAW">devgun service start</code> to start a service and its dependenciesrn* Use <code data-enlighter-language="generic" class="EnlighterJSRAW">kubectl get pods</code> to list running podsrn* Use <code data-enlighter-language="generic" class="EnlighterJSRAW">kubectl describe pod <pod-name></code> to inspect a pod and see the pod logrn* Use <code data-enlighter-language="generic" class="EnlighterJSRAW">kubectl log <pod-name></code> to see the container logsrn========================================================rn
                                
                            

Además de crear un entorno de Kubernetes, Devgun también añade algunas rutas de red a la máquina local. Por ejemplo, en OS X se añaden las siguientes rutas:

route -n add 172.17.0.0/16
route -n add 10.0.0.0/24

Esto permite a nuestro equipo de desarrollo ejecutar y probar aplicaciones en sus máquinas locales con conectividad total a los contenedores del clúster k8, como si se estuvieran ejecutando en el propio clúster. También habilitamos la búsqueda de DNS mediante la función de resolución integrada en OS X. Creamos /etc/resolver/local con el contenido:

search cluster.local svc.cluster.local default.svc.cluster.local
nameserver 172.17.0.3

De este modo, se habilita la resolución de DNS de los servicios de kubernetes.

                                

                                    $ devgun service start etcdrnStarting service: etcd                       [done after 7.084730 seconds]rnrn$ ping etcdrnPING etcd.default.svc.cluster.local (172.17.0.4): 56 data bytes  rn64 bytes from 172.17.0.4: icmp_seq=0 ttl=63 time=0.220 ms  rn^Crn--- etcd.default.svc.cluster.local ping statistics ---rn1 packets transmitted, 1 packets received, 0.0% packet loss  rnround-trip min/avg/max/stddev = 0.220/0.220/0.220/0.000 ms  
                                
                            

Gestión de servicios personalizados y de terceros con una especificación

Como Devgun tiene que gestionar una combinación de servicios personalizados y de terceros, desarrollamos un archivo de especificación yaml personalizado que definimos para cada servicio. El archivo de especificación tiene este aspecto:

                                

                                    ervice:  rn  name: scoutrn  resources:rn    <<: *k8s_deploy_resourcesrn  depends_on:rn  - name: vulcandrn  - name: cassandrarn  - name: kafka-pixyrn  - name: kafkarn  - name: etcdrn  - name: metricsrn  hooks:rn    pre:rn      start:rn        - exec: >rn            cqlsh -e "CREATE KEYSPACE IF NOT EXISTS scout WITH REPLICATION={'class':'SimpleStrategy','replication_factor':1}" $POD_IPrn          where: service:cassandra:cassandra
                                
                            

Define un servicio personalizado llamado “scout” que lee eventos de Kafka y registra analíticas sobre dichos eventos en Cassandra. La especificación le indica a devgun de qué servicios personalizados y de terceros depende, y qué hooks ejecutar en los distintos contenedores antes de iniciar el servicio scout.

La clave resources hace referencia a los archivos de manifiesto de kubernetes, como mapas de configuración, implementaciones y descripciones de servicios, definidos en otra parte del archivo de especificación que devgun utiliza para iniciar los contenedores en K8.

Siguientes pasos: trabajo futuro

Cuando diseñamos Devgun, empezamos desde cero sin tener en cuenta las historias más amplias de desarrollo e implementación. Ahora que hemos tenido tiempo de usar Devgun, nos preguntamos si hicimos bien las abstracciones.

Empezamos a hacernos preguntas: ¿qué experiencia queremos que tenga nuestro equipo de desarrollo cuando se siente a crear e implementar un nuevo servicio? ¿Dónde terminan las responsabilidades del equipo de desarrollo y empiezan las de operaciones? ¿Qué parte de las operaciones podemos automatizar y qué parte requiere interacción humana? ¿Cómo facilitamos la transmisión de información entre el equipo de desarrollo y el de operaciones?

Hemos empezado a definir historias y perfiles que darán forma a la evolución de Devgun de cara al futuro. En mi próxima publicación, compartiré parte de nuestro trabajo y reflexiones sobre cómo podría evolucionar la experiencia de desarrollo a medida que sigamos trabajando con Kubernetes y Devgun. No olvides suscribirte a nuestro blog para no perderte nada.