À medida que mais empresas migram suas aplicações para a nuvem, surge a decisão entre fazer um "lift and shift" ou repensar a arquitetura para torná-la "cloud-native" — um conceito cuja definição varia. Este post foca na segunda abordagem e, mais especificamente, em uma técnica útil que pode ajudar a mover aplicações para containers (ou seja, Docker) e orquestrá-las com Kubernetes.

Fonte: iStockPhoto
O desafio do bootstrapping
Uma das promessas do DevOps e das migrações para a nuvem é reduzir o trabalho repetitivo das operações tradicionais por meio da automação de processos manuais. A natureza declarativa do Kubernetes, que garante automaticamente o estado desejado das suas aplicações, é extremamente poderosa. Em alguns casos, porém, as aplicações precisam de etapas de "bootstrapping" antes de rodar corretamente, ou precisam ser iniciadas em uma ordem específica para lidar com dependências de outros sistemas, como filas ou bancos de dados.
Para que a aplicação rode sem problemas, você poderia reescrevê-la com uma lógica de retry personalizada até que as condições ideais existam — mas isso pode atrasar sua migração. Uma alternativa para evitar reescritas de código é criar pequenos apps, scripts ou comandos e adicioná-los como InitContainers.
Possíveis casos de uso para Init Containers
- Uma aplicação blockchain que precisa se registrar entre seus pares
- Uma aplicação que precisa obter um token de acesso de um provedor de identidade
- Dados dinâmicos buscados em um banco de dados e armazenados em cache para a aplicação rodar após a inicialização
- Buscar segredos criptografados em um cofre e gravá-los no sistema de arquivos
- Bloquear a inicialização da aplicação até que outro sistema esteja disponível (por exemplo, um servidor de fila ou banco de dados)
Exemplo simples usando duas imagens Busybox
Neste exemplo, vamos supor que uma aplicação precise ser populada dinamicamente com alguns dados antes de iniciar (como nos cenários acima). Daria para fazer isso com um ConfigMap, mas, para ilustrar o poder dessa técnica, deixe a imaginação correr solta sobre o que mais você poderia fazer.
- Crie um PersistentVolumeClaim
Primeiro, precisamos de algum volume de armazenamento que possamos acessar
Persistent Volume Claim
$ kubectl apply -f test-pvc.yamlpersistentvolumeclaim/test-pvc created
2. Faça o bootstrap de um arquivo YAML de configuração do Deployment
$ kubectl create deployment test-app --image=busybox:1.28.0 -o yaml --dry-run > test-app.yaml
3. Edite o Deployment e adicione o volume e o Init Container conforme abaixo
Deployment com Init Container
Note que neste arquivo adicionamos o volume e, em seguida, incluímos outra imagem Busybox no initContainer. Poderia ser literalmente qualquer imagem, mas, para este exemplo, eu só queria gravar algum conteúdo em um arquivo dentro do sistema de arquivos montado para que, quando a aplicação iniciasse com a outra imagem Busybox, ela acessasse o arquivo e lesse seu conteúdo.
4. Execute o Deployment e monitore os logs
# deploy app
$ kubectl apply -f test-app.yamldeployment.apps/test-app configured# monitor logs
$ kubectl logs -f deployment/test-appFile content: Hello, World!
Se você vir "File content: Hello, World!", deu certo. A partir deste exemplo básico, você pode customizar sua aplicação para substituir a imagem do container principal e adicionar quantos init containers quiser para garantir que ela inicie com tudo o que precisa. A vantagem dessa técnica é poder automatizar o deploy das suas aplicações sem precisar escrever lógica de retry complexa ou tratamento de erros para resolver dependências que antes eram manuais.
Para mais informações sobre Init Containers, confira a documentação oficial do Kubernetes: