IT & Engineering

Devgun: criação de ambientes de desenvolvimento com Kubernetes

Quando começamos a lidar com o problema da criação de ambientes de desenvolvimento locais, recorremos a ferramentas comuns, como o vagrant. Mas, como na maioria dos ambientes criados no vagrant, os tempos de compilação são longos. Isso significa que as imagens do vagrant têm vida longa e tendem a divergir com o tempo.
Imagem para Devgun: criação de ambientes de desenvolvimento com Kubernetes

Quando começamos a lidar com o problema da criação de ambientes de desenvolvimento locais, recorremos a ferramentas comuns, como o vagrant. Mas, como na maioria dos ambientes criados no vagrant, os tempos de compilação são longos. Isso significa que as imagens do vagrant têm vida longa e tendem a divergir com o tempo.

Nossos serviços e infraestrutura mudam constantemente, de forma que as compilações no vagrant estavam quase sempre com falhas. Queríamos evitar o tradicional “rito de passagem para novos membros da equipe de desenvolvimento”, que muitas vezes implica dias de trabalho até conseguir que o vagrant crie uma nova VM de desenvolvimento com sucesso.

Idealmente, profissionais recém-contratados podem ser produtivos poucas horas após a contratação, e não após dias ou semanas.

Tudo isso era agravado pelo fato de termos muitos microsserviços que precisavam rodar no ambiente de desenvolvimento de forma perfeitamente integrada.

Os objetivos do projeto eram simples:

  • Configurar e destruir um ambiente de desenvolvimento rapidamente e de forma reprodutível.
  • Configuração e desmontagem do ambiente de desenvolvimento em uma única etapa.
  • Iniciar e interromper serviços, incluindo suas dependências, de acordo com a necessidade.

Avaliação de plataformas de orquestração

Como nossos microsserviços já estavam rodando em contêineres, sabíamos que precisaríamos escolher um sistema de orquestração.

Várias pessoas da nossa equipe de desenvolvimento tinham interesse no Mesos Marathon, então o testamos primeiro. Infelizmente, os requisitos de hardware e memória necessários para rodar o marathon em um ambiente de desenvolvimento local pequeno eram muito restritivos para os nossos propósitos. Na época em que testamos, o minimesos também não conseguia conectar corretamente os contêineres do Marathon à rede local – um grande obstáculo para o nosso projeto. Esses problemas deixaram claro que o Mesos seria inviável para as nossas necessidades.

Em seguida, avaliamos o Kubernetes e o Minikube pois a comunidade ativa em torno desses projetos nos atraiu. Descobrimos que o consumo de memória era mínimo e a rede funcionava perfeitamente. A maioria dos recursos do nosso interesse funcionou de imediato, e rodar nossos aplicativos de terceiros dentro do Minikube acabou sendo mais fácil do que o esperado.

Assim, com o Minikube como plataforma escolhida, conseguimos avançar rápido com o projeto e passar a maior parte do nosso tempo desenvolvendo o que viria a ser o Devgun.

Criação de uma CLI

Para alcançar os objetivos do nosso projeto, decidimos criar uma interface de linha de comando completa escrita em Golang. Queríamos uma CLI que pudesse ser distribuída à nossa equipe de desenvolvimento como um único binário, então criamos uma chamada Devgun.

Minikube and Mailgun logos with plus symbol in between

O Devgun não faz nenhuma suposição sobre o ambiente de desenvolvimento. Ele baixa automaticamente todas as ferramentas exigidas, incluindo o Minikube, o kubectl e ferramentas específicas do Mailgun, no diretório /.devgun/bin. Tudo o que você precisa fazer é adicionar seu caminho após a conclusão da configuração inicial. A instalação de tudo em um único diretório torna a desinstalação tão simples quanto rodar rm -rf ~/devgun.

Compilamos todos os arquivos de manifesto do kubernetes no binário estático usando o projeto go-bindata, permitindo baixar e executar um único arquivo para instalar um ambiente de desenvolvimento.

A execução do Devgun fica assim:

                                

                                    $ 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
                                
                            

Além de criar um ambiente no Kubernetes, o Devgun também adiciona algumas rotas de rede na máquina local. Por exemplo, no OS X, as rotas a seguir são adicionadas:

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

Isso permite que a nossa equipe de desenvolvimento rode e teste aplicativos nas suas máquinas locais com conectividade total aos contêineres no cluster k8, como se estivessem rodando no próprio cluster. Nós também habilitamos a pesquisa de DNS utilizando o recurso de resolução integrado ao OS X. Criamos o /etc/resolver/local com o seguinte conteúdo:

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

Isso habilita a resolução de DNS dos serviços do 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  
                                
                            

Gerenciamento de serviços personalizados e de terceiros com uma especificação

Como o Devgun precisa gerenciar uma mistura de serviços personalizados e de terceiros, desenvolvemos um arquivo de especificação customizado no formato yaml para definirmos cada serviço. O arquivo de especificação é mais ou menos assim:

                                

                                    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
                                
                            

Ele define um serviço personalizado chamado “scout”, que lê os eventos do Kafka e grava análises sobre esses eventos no Cassandra. A especificação diz ao devgun de quais serviços personalizados e de terceiros ele depende e quais ganchos devem rodar em contêineres diferentes antes de iniciar o serviço scout.

A chave resources faz referência aos arquivos de manifesto do kubernetes, como mapas de configuração, implementações e descrições de serviço, definidos em outras partes do arquivo de especificação e usados pelo devgun para iniciar os contêineres no K8.

Os próximos passos… planos futuros

Quando criamos o Devgun, começamos de baixo para cima, sem considerar o contexto mais amplo das histórias de desenvolvimento e implementação. Agora que tivemos tempo de usar o Devgun, estamos nos perguntando se acertamos nas abstrações.

Começamos a nos questionar: qual é a experiência que queremos proporcionar à nossa equipe de desenvolvimento na hora de criar e implementar um novo serviço? Onde terminam as responsabilidades da equipe de desenvolvimento e começam as da equipe de operações? O quanto das operações podemos automatizar e o quanto exige interação humana? Como podemos facilitar o repasse de informações entre a equipe de desenvolvimento e a de operações?

Começamos a definir histórias e personas que vão moldar como o Devgun evoluirá de agora em diante. Na minha próxima publicação, vou compartilhar um pouco do nosso trabalho e de nossas ideias sobre como a experiência de desenvolvimento pode evoluir à medida que continuarmos nosso trabalho com o Kubernetes e o Devgun. Não deixe de assinar nosso blog para não perder nada.