O blog da AWS
Utilizando multi-container Pods para logs de aplicações stateful no Amazon EKS
Por Lucas Duarte, Arquiteto Especialista Containers AWS
Vinicius Silva, Arquiteto de Soluções AWS
Atualmente existem muitas organizações que já trabalham com aplicações em containers e muitas outras que estão em um processo de migração para utilizá-los em produção, porém existem algumas premissas básicas que devemos considerar ao containerizar uma aplicação e uma das mais importante é trabalhar com aplicações stateless invés de stateful.
Sabemos que muitas vezes aplicar mudanças dentro de nossas aplicações pode ser um trabalho oneroso e difícil para a equipe de desenvolvimento visto que, na maior parte das vezes, a prioridade desse tipo de atividade, quando não crítica, é baixa. E em aplicações stateful, um dos problemas mais comuns que podemos destacar são os logs, que em boa parte das aplicações legadas são persistidos em discos e não enviados para o stdout (standard out) como indica as boas práticas do Twelve-Factor App.
Neste blogpost mostraremos de maneira simples como utilizar um Pod com múltiplos containers (multi-container Pod) para fazer com que os logs das aplicações que são persistidos em disco sejam enviados para o stdout e coletados por um processador de logs como por exemplo o Fluentd ou Fluent Bit em um cluster do Amazon EKS.
O que é multi-container Pod?
Por definição na documentação oficial do Kubernetes, os Pods são as menores unidades de computação implantáveis que você pode criar e gerenciar.
Um Pod do Kubernetes pode ter um ou múltiplos containers associados, esses containers dentro deste Pod compartilham alguns recursos como armazenamento e rede por exemplo. Dessa maneira ocorre a Cross-Container Interaction (interação entre containers), que são containers que compartilham o mesmo Pod e que interagem uns com os outros utilizando recursos compartilhados.
Caso de uso
Em nosso cenário nós criaremos uma aplicação stateful em Python que utiliza uma biblioteca de geração de logs, portanto a aplicação persiste alguns dados em disco e em nosso caso os logs. Dessa forma nós utilizaremos multi-container Pods para coletar os logs dessa aplicação que são persistidos em disco e enviá-los para o stdout, e então uma vez que enviados para o standard out serão coletados por um Daemonset do Fluent Bit e enviados para o Amazon CloudWatch Logs. Toda demonstração será realizada utilizando um cluster de Kubernetes do Amazon EKS.
Pré-requisitos
Para implementar a solução, é necessário os seguintes pré-requisitos:
- Ter uma conta da AWS. Se você não tem uma, você pode criar aqui e aproveitar o nível gratuito da AWS
- AWS CLI instalado e configurado com credenciais da sua conta AWS
- Dockerpara build da imagem
- kubectlpara executar comandos e gerenciar nosso cluster do Amazon EKS
- eksctlpara criar de maneira simples um cluster do Amazon EKS
Solução
Abaixo temos uma arquitetura representativa (figura 1.1) da nossa solução utilizando multi-container em um Pod para coleta de logs e envio para o stdout, dessa forma podemos utilizar um log forwarder para então capturá-los e enviá-los para um agregador de logs como o Amazon CloudWatch Logs ou Amazon Elasticsearch. Utilizaremos um volume compartilhado entre os containers para conseguir mapear os logs da nossa aplicação para a saída stdout do container sidecar. Esse mapeamento é feito utilizando o comando Linux tail no arquivo de logs montado no volume compartilhado entre os containers (figura 1.2)
Observação: Para a implementação desta solução nós utilizaremos a região us-east-1 (N. Virgínia), então suas credenciais AWS CLI devem estar configuradas para utilizar esta região. É possível utilizar outras regiões desde que seja alterado alguns parâmetros no manifesto de deployment do cluster do Amazon EKS. Embora também possamos atualizar o manifesto para utilizar variáveis de ambiente de acordo com a região selecionada na hora de configuração de suas credenciais.
Os passos abaixo serão utilizados para guiar o usuário durante a implementação da solução.
Passo 1: Provisionar o Cluster do Amazon EKS
- Clone o repositório git disponível aqui
git clone https://github.com/aws-samples/eks-multi-container-pod-logging.git
- Execute o comando para criar o Cluster do Amazon EKS:
eksctl create cluster -f kubernetes-cluster-us-east-1.yaml
Esse passo leva cerca de 15 minutos para provisionamento do cluster. Enquanto aguardamos a criação do cluster, em paralelo podemos executar o passo 2.
- Atualizar o contexto do arquivo ~/.kube/config para acessar nosso cluster via kubectl:
aws eks --region us-east-1 update-kubeconfig —name kubelogs-cluster
- Teste seu acesso ao cluster EKS:
kubectl get nodes
Passo 2: Criar uma imagem Docker e fazer push para o Amazon ECR
- Crie um repositório ECR para que possamos fazer o push da imagem docker:
aws ecr create-repository —repository-name multi-container-pod-demo
- Faça o build da imagem Docker:
cd log-app && docker build -t multi-container-pod-demo .
- Vamos autenticar nosso cliente Docker ao registry Amazon ECR:
aws ecr get-login-password --region <REGION> | docker login --username AWS --password-stdin <ACCOUNT_ID>.dkr.ecr.us-east-1.amazonaws.com
Substitua no comando acima e nos comandos seguintes as <variáveis> de acordo com a região (em nosso caso a região utilizada é us-east-1) e o ID da sua conta AWS
- Faça o tag da sua imagem para que então façamos o push:
docker tag multi-container-pod-demo:latest <ACCOUNT_ID>.dkr.ecr.<REGION>.amazonaws.com/multi-container-pod-demo:latest
- Por fim faça o push da imagem para o repositório do Amazon-ECR:
docker push <ACCOUNT_ID>.dkr.ecr.<REGION>.amazonaws.com/multi-container-pod-demo:latest
Passo 3: Implantando a aplicação em nosso cluster criado previamente
-
Abra o arquivo log-app/eks/01-deployment.yamle altere __IMAGE_URI__para a URL da imagem que fizemos o push
Antes:
containers: - name: python-app image: __IMAGE_URI__ ports: - containerPort: 5000
Depois:
containers: - name: python-app image: <ACCOUNT_ID>.dkr.ecr.<region>.amazonaws.com/multi-container-pod-demo:latest ports: - containerPort: 5000
- Implante a aplicação no cluster do Amazon EKS:
kubectl apply -f eks/
Passo 4: Confira o log da aplicação
- Veja se o pod está running e anote o nome do pod para utilizar o nome anotado em substituição nas variáveis abaixo <POD_NAME>
kubectl get pods -n prd
- Veja o log da nossa aplicação Python:
kubectl logs po/<POD_NAME> -c python-app -n prd
O comando acima vai retornar os logs da inicialização do servidor, enquanto os logs das requisições são gravados em um arquivo.
- Obtenha os logs do container responsável pelo output dos logs para o stdout:
kubectl logs po/<POD_NAME> -c sidecar -n prd -f
Como você pode ver, são mostrados os logs das requisições.
- Abra um novo terminal e copie a URL do serviço, que será utilizada em substituição à variável <SERVICE_URL> do comando do passo abaixo:
kubectl get svc -n prd | awk '{print $4}'
- Agora execute uma requisição para a URL pública do serviço:
curl -IL -XGET http:///<SERVICE_URL>/log
Como visto acima, novos logs aleatórios serão gerados.
Conclusão
Como mencionado no Twelve-Factor App, logs são fluxos de eventos agregados e ordenados por tempo de coleta destes fluxos de saída de todos os processos em execução e serviços de apoio. Uma aplicação cloud native não deveria se preocupar com o roteamento e o armazenamento desses logs, portanto ela deveria enviar seu fluxo de eventos para o stdout.
Neste blog vimos que é possível realizar essa implementação mesmo que suas aplicações ainda façam a persistência dos logs em disco, e que com poucas modificações em seu manifesto de Deployment podemos tratar todas as aplicações e seus fluxos de eventos iguais centralizando os logs no Amazon CloudWatch Logs.
Sobre os autores
Lucas Duarte é um Arquiteto Especialista em Containers na AWS com focos em clientes LATAM. Entusiasta de automação, Cloud, e cultura DevOps. Com experiência prévia em projetos focados nesse segmento em empresas como IFood, Guiabolso e Mandic. Tem trabalhado em diferentes projetos relacionados principalmente a orquestração de containers e microsserviços.
Vinicius Silva é um arquiteto de Soluções na AWS e apoia clientes do setor de energia e utilidades a atingirem seus objetivos com a nuvem da AWS. Interessado em desenvolvimento e na cultura DevOps, possui contribuições anteriores no desenvolvimento de plataformas web distribuídas e escaláveis.