Um olhar sobre minha infraestrutura Kubernetes

12 Jan 2025 . category: article . Comments
#k8s #kubernetes #infra #cluster #cloud #digitalocean #k8s-ops

Introdução

Desde que comecei a estudar computação em 2005, sempre desenvolvi projetos para mim mesmo. Muitos deles foram abandonados ao longo do caminho, mas alguns evoluíram com o tempo. Um deles é a minha infraestrutura pessoal.

Apesar de me considerar bastante organizado, nunca dediquei muito tempo à documentação do meu ambiente. Há algum tempo, comecei a me perder em algumas integrações e lembrei da famosa Lei de Linus, descrita no livro “A Catedral e o Bazar” de Eric S. Raymond, que diz:

“Given enough eyeballs, all bugs are shallow.”

Então, decidi começar a documentar meu ambiente e compartilhar com vocês. Em outras ocasiões, já escrevi sobre meu ambiente, como nos textos:

Quero retomar esse trabalho e pensei em uma série de textos sobre os projetos que desenvolvi. O primeiro deles será sobre minha infraestrutura Kubernetes. Em breve, pretendo escrever sobre atualizações em meus fluxos de trabalho, meus sistemas de monitoramento, tópicos sobre segurança e gestão de caos, além de análise de dados e métricas.

Considerações

Existem configurações e tecnologias que estão mais aí para aprendizado do que por necessidade. E existem coisas que não estão disponíveis por falta de verba.

Todos os recursos utilizados como base desse texto fazem parte da configuração do meu cluster. Nada aqui se relaciona com qualquer cliente ou empresa com a qual eu tenha trabalhado ou trabalhe. Tudo aqui é de minha responsabilidade e de minha autoria.

Sei que existem muitos pontos de melhoria. Vou pontuar alguns durante o texto. Algumas dessas melhorias já foram identificadas, mas outras não serão possíveis de serem implementadas devido ao custo.

Uma visão geral

Meu cluster está hospedado na DigitalOcean. Tenho usado essa hospedagem desde 2015, depois de ter tido problemas com um serviço anterior que cheguei a usar por uns 3 anos.

Durante esses quase 10 anos, não tive nenhum problema com meus servidores e realmente não tenho nada a reclamar do serviço deles. Dentro dessa hospedagem também fui evoluindo minhas configurações com o tempo, cheguei a manter alguns servidores CentOS e fazendo deploy através de aplicações como Capistrado, Fabric e pacotes rpm. Cheguei a utilizar CoreOS, fazendo a gestão de containers Docker com Fabric. Mas desde 2021 venho utilizando Kubernetes.

Com o tempo fui evoluindo a forma que gerenciava as aplicações e suas configurações. Essa é uma visão de como está o meu cluster atualmente.

CD

Antes de entrar propriamente no fluxo de Continous Deployment, quero falar um pouco sobre o meu fluxo de Continous Integration atual.

Para disponibilizar meus artefatos eu utilizo o GitHub Actions e o Docker Hub. Todas as minhas aplicações estão em repositórios no GitHub e o GitHub Actions é responsável por fazer o build e o push das imagens para o Docker Hub.

Após o push da imagem, uma action é disparado para atualizar um repositório onde faço a gestão das aplicações que estão rodando no cluster. Esse repositório contém os arquivos de configuração do Kubernetes. Em um fluxo de GitOps, esse repositório é a fonte da verdade das aplicações que estão em execução no cluster. Nesse repositório estão os arquivos de Values do Helm Chart que utilizo para gerar os manifestos do Kubernetes. A action basicamente faz um commit informado a nova versão da imagem.

CI/CD

Nesse repositório também estão contido os arquivos de configuração de ApplicationSets, que são monitorados pelo ArgoCD que está instalado no cluster. O ArgoCD é responsável por fazer o deploy das aplicações no cluster.

Abaixo um exemplo de um arquivo de configuração de um ApplicationSet:

Helm e ApplicationSets

Na figura acima é possível ver a estrutura de diretórios que estou utilizando para organizar minhas aplicações. Basicamente estou adotando um namespace por aplicação (uma aplicação pode ter mais de um repositório, imagem docker, deploment, etc…). Cada arquivo de ApplicationSet cuida de um namespace. Poderia ter feito essa organização de outra forma, mas essa foi a forma que mais me agradou.

Storage

Esse é o ponto mais crítico do meu cluster atualmente. A configuração atual funciona muito bem, porém não existe uma redundância. Para melhorar esse ponto eu precisaria investir mais, o que não farei no momento.

Tenho tratado a falta de redundância com backups frequentes. E tenho uma boa confiança no esquema de backups que montei. Mas antes de falar um pouco sobre os backups, vou explicar um pouco sobre a configuração de storage.

Fora do cluster, eu tenho uma máquina para servir pontos de montagem NFS. A possui instalado o FreeBDS como sistema operacional. Nela eu tenho alguns discos virtuais que são montados em pontos de montagem NFS. Esses pontos de montagem são montados no cluster e são utilizados para armazenar os dados das aplicações. Estou com essas instancia desde 2020 e tive zero problemas com ela. Nunca nem precisei reiniciá-la por alguma indisponibilidade. Possui carinhosamente o nome de pandora.

As aplicações que necessitam de armazenamento persistente são configuradas para utilizar esses pontos de montagem. A configuração é feita através dos resources StorageClass e PersistentVolumeClaim.

Como mostrarei mais para frente, possuo algumas instancia de databases que estão utilizando esse modelo de armazenamento. São instancias de MariaDB, Postgres, MongoDB e Redis. E nesses anos nunca tive nenhum dado corrompido ou perdido.

De qualquer, sei que é uma configuração sensível e que poderia ser melhorada (com dinheiro). Como isso não será feito no momento, tenho me preocupado em manter os backups.

Backups

Primeiramente, dentro do próprio servidor (pandora) eu tenho um job que faz um sync de todo o storage para outro repositório que é executado de tempos em tempos utilizando cron e o rsync. No momento faz esse sync para outro diretório mas ainda no mesmo disco (meu próximo investimento será este, adicionar um novo disco só para backups, mas ai vão mais 10 dólares por mês).

Também criei uma aplicação, chamada ChupaCabra, que de tempos em tempos (um cronjob do Kubernetes) faz um backup de todos os dados dos bancos de dados, gera pacotes tar.gz, criptografa e envia para o Google Drive. Esse processo também é executado para todos os arquivos gerados pelas aplicações (copiados, compactador, criptografados e enviados ao Google Drive). Apesar de manter os últimos pacotes de cada um, através do Drive eu consigo restaurar qualquer pacote gerado nos últimos 30 dias.

Além disso eu também faço o download constantemente de todo meu Google Drive para um HD externo, criptografado, que tenho comigo. Atualmente tenho cerca de quase 1TB de dados salvos dessa forma.

E além disso, os arquivos mais críticos como certificados e chaves, são salvos no Proton Drive também.

Bom, tem mais coisas que gostaria de escrever sobre o assunto, mas vou deixar isso para um próximo artigo.

Monitoria e Observabilidade

Atualmente a colheita de logs das aplicações é feita através do Filebeat, sendo executado como um DaemonSet no cluster. Os logs são enviados para o ElasticSearch e visualizados através do Kibana.

Escolhei usar o ElasticSearch por já fornecer também recursos de APM, que também utilizo para monitorar as aplicações. Através do APM consigo monitorar o tempo de resposta das aplicações, erros, etc.

APM

Cheguei a usar o Prometheus e o Grafana para monitorar as aplicações, mas por questões de custo, acabei desativando.

Outra ferramenta de observabilidade que está em uso é o Lifeguard. Nele eu tenho algumas validações de sites de disponibilizo através do cluster e também faço uso do plugin para Kubernetes que monitora as pods. Qualquer problema que for encontrado eu sou notificado pelo Telegram.

Lifeguard in Telegram

Gestão de Configurações

Para manter as configurações sensíveis (como tokens, senhas, etc) que vão para secrets, comecei a testar o Infisical. Todas as entradas é feita através de um interface e ele possui um operator que cria os secrets no cluster.

Ingress e Cert Manager

Os ingresses são disponibilizados utilizando o Ingress Controller do Nginx. Também utilizo o Cert Manager para gerar os certificados SSL para os sites. O Cert Manager é configurado para utilizar o Let's Encrypt como autoridade certificadora.

Com essa configuração, consigo disponibilizar meus sites com HTTPS e com redirecionamento de HTTP para HTTPS.

Aplicações

Para comportar as aplicações, atualmente o cluster possui 3 nodepools. Fiz a seguinte divisão:

  • highlands: aqui rodam as aplicações mais criticas e necessitam de mais recursos.
  • midlands: aqui rodam as aplicações que não são tão criticas e que não necessitam de muitos recursos.
  • outlands: aqui rodam recursos que não fazem parte das minhas aplicações, como o ArgoCD, ElasticSearch, Kibana, Infisical, etc.

Abaixo uma visão geral das aplicações que estão rodando no cluster.

Cluster Applications

Tentei dar uma simplificada em algumas integrações para não ficar muito confuso.

Grande parte das aplicações foram desenvolvidas utilizando Python e Ruby. Neste momento estou portando algumas coisas para Go.

Tenho uma aplicação feita usando PHP e Laravel que nasceu depois de um estudo que precisei fazer. Ela é bem simples, mas é funcional então ficou.

Outro aplicação que quero destacar é o Run My Source. Ainda está em execução mais para mostrar mesmo, não que seja muito util. Eu falo um pouco dessa aplicação em um post anterior. Aprendi Erlang desenvolvendo essa aplicação.

Em um próximo texto pretendo entrar em detalhes sobre outras aplicações, principalmente as que fazer parte do que chamei de lake. Muitas aplicações interagem com essas, com o objetivo de gerarem métricas. Bom, mas falo sobre isso em um futuro.

Conclusão

Bom, com esse texto espero ter dado uma visão geral de ondem minhas aplicações rodam. Nos próximos textos quero falam um pouco mais dos fluxos implementados, por partes, e as formas que são utilizados no meu fluxo de trabalho. Espero ter vencido meu hiato sem publicar nada nesse site.

Por fim, estou sempre aberto a conversas sobre o assunto.


Me

Tenho estudado esse mundo mágico da programação desde 2005. Já consegui sustentar minha família usando Ruby, Java, Python, C++ e Javascript. O resto tenho usado para diversão ou aprendizado.