Kubernetes straightforward — Archtecture (part 1) [Portuguese]

Sebastiao Ferreira de Paula Neto
15 min readMay 16, 2023

--

Bem-vindo ao conjunto de artigos sobre Kubernetes! Nesta série, exploraremos o que você precisa saber sobre essa plataforma de orquestração de contêineres líder de mercado. Vamos começar com uma breve introdução histórica ao Kubernetes e como ele evoluiu ao longo dos anos para se tornar uma das principais ferramentas para a implantação e gerenciamento de aplicativos em contêineres.

O Kubernetes foi criado pelo Google em 2014 e, posteriormente, em 2015, o projeto foi lançado como uma plataforma de código aberto. Desde então, o Kubernetes tem sido amplamente adotado por empresas de todos os setores, desde startups até grandes corporações, devido à sua capacidade de oferecer recursos poderosos para escalabilidade, gerenciamento de recursos, monitoramento e muito mais. Essa plataforma é considerada uma escolha estratégica para empresas que desejam aproveitar os benefícios dos contêineres, unificando suas implantações em uma única plataforma.

Este é o primeiro de uma série de artigo aonde abordaremos tópicos fundamentais do Kubernetes, como sua arquitetura, conceitos essenciais, monitoramento, serviços avançados e segurança. Neste em particular, apresentará o contexto histórico da criação do Kubernetes e como sua arquitetura funciona.

1. Contexto Histórico

No início do desenvolvimento de software se fazia conveniente a construção das aplicações em um único bloco de código, conhecido como sistema monolítico. Esse modelo tornava difícil realizar correções e a adição novas funcionalidades. Com a crescente construção de software tornou-se evidente que uma nova abordagem era necessária para lidar com a complexidade crescente dos sistemas e os meios de implantação.

Como resultado, emergiu a arquitetura conhecida como microserviços. Essa abordagem divide o aplicativo em pequenos serviços independentes, cada um com sua própria responsabilidade. Essa arquitetura escalável e fácil de manter é cada vez mais popular entre as empresas, e o Kubernetes é uma plataforma que pode ajudar a entregá-la de maneira eficiente. O Kubernetes permite gerenciar e orquestrar a implantação de contêineres em grande escala, garantindo que cada microserviço seja executado com eficiência e segurança em um ambiente distribuído

Dessa maneira, entender a evolução da tecnologia e dos modelos de arquitetura é fundamental para entendermos como o Kubernetes surgiu como solução para gerenciar ambientes de contêineres em grande escala e como ele mudou a forma como os aplicativos são desenvolvidos e implantados atualmente.

1.1 Monolithic systems

Os sistemas monolíticos adotam uma abordagem de desenvolvimento de software em que todas as funções e serviços são abrangidos por uma única base de código. Esse modelo de desenvolvimento de software foi amplamente utilizado durante a maior parte do século passado, em que programadores escreviam código que era compilado e executado como um único programa. Essa abordagem se popularizou por ser fácil de entender e gerenciar, além de permitir que desenvolvedores trabalhassem em equipes grandes e complexas.

No entanto, à medida que os aplicativos se tornaram mais complexos e exigiram mais recursos computacionais, o modelo monolítico passou a apresentar limitações. Os sistemas monolíticos tendem a ser volumosos, difíceis de escalar e desatualizados, pois todas as alterações e atualizações precisam ser feitas em uma única base de código.

Com o avanço do desenvolvimento de software, surgiram padrões para desagregar o sistema em blocos, mas ainda mantendo o produto final como uma entidade única. Mesmo com a desagregação, pequenas alterações ainda geravam impactos em todas as camadas. Dessa forma, foi proposto o desmembramento de cada um desses blocos em sistemas independentes, surgindo assim a abordagem de desenvolvimento de microserviços.

1.2 Microserviços

Os microserviços dividem o aplicativo em pequenos serviços independentes que podem ser implantados, gerenciados e atualizados separadamente. Cada serviço é responsável por uma função específica e se comunica com outros serviços por meio de APIs (interfaces de programação de aplicativos) ou pela mesma rede.

Essa abordagem permite que os aplicativos sejam altamente escaláveis e flexíveis, pois os serviços podem ser adicionados, atualizados ou removidos facilmente. Além disso, os microserviços permitem que os desenvolvedores trabalhem em equipes menores e mais ágeis, facilitando o desenvolvimento e a manutenção do software.

É fundamental compreender a alocação de recursos para cada modelo dentro da estrutura. Quando se busca um ambiente acessível a todos os desenvolvedores, no qual os recursos podem ser compartilhados, a utilização de Máquinas Virtuais (VMs) se tornou amplamente adotada. Além disso, com o crescimento do uso de contêineres, impulsionado principalmente pelo Docker, surgiu a possibilidade de isolar as aplicações de forma mais eficiente. Isso está em sintonia com as metodologias de desenvolvimento que buscam modularizar o software em unidades independentes, conhecidas como microserviços.

Você pode estar se questionando por que não utilizar as VMs como unidades isoladas. Para responder a essa pergunta, é preciso entender as diferenças entre as duas abordagens.

1.3 Virtual Machines vs Containers

Virtual Machines (VMs) e Containers são duas tecnologias importantes para a virtualização de servidores e aplicações. Embora compartilhem algumas semelhanças, elas têm abordagens diferentes para a criação de ambientes isolados para a execução de aplicativos.

Uma VM é uma instância virtual de um sistema operacional completo, que pode ser criada em cima de um hypervisor em um servidor físico. Cada VM é isolada das outras VMs e do sistema operacional hospedeiro, e possui seus próprios recursos, como CPU, memória e armazenamento. Os aplicativos são instalados dentro da VM, e a VM é gerenciada como uma entidade separada.

Por outro lado, os contêineres compartilham o kernel do sistema operacional hospedeiro, mas são isolados uns dos outros. Cada contêiner é uma instância isolada de um aplicativo específico e seus requisitos de biblioteca e sistema operacional. Eles são gerenciados como uma entidade única, mas podem ser escalados independentemente uns dos outros.

Portanto, as VMs oferecem maior isolamento e segurança, mas são mais pesadas e menos escaláveis do que os contêineres. Os contêineres oferecem maior flexibilidade e escalabilidade, mas com menos isolamento e segurança em comparação com as VMs. Cada tecnologia tem seus próprios casos de uso e deve ser escolhida com base nos requisitos específicos do ambiente de aplicação.

A utilização dos contêineres apresentaram ser uma ferramenta valiosa para virtualização de aplicativos, mas a complexidade de configurar e gerenciar esses ambientes isolados dificultou sua adoção em larga escala. Foi aí que o Docker entrou em cena, introduzindo uma interface simplificada para a virtualização de contêineres, o que permitiu que desenvolvedores e equipes de operações de TI criassem, implantassem e gerenciassem esses ambientes de forma eficiente e padronizada. Vamos conhecer mais um pouco como funciona esta ferramenta.

1.4 Docker

Para entender um pouco mais a estrutura interna do Docker e como ela funciona vamos começar com uma visão geral de alto nível do Docker e depois mergulhar nos detalhes de sua arquitetura.

A sua estrutura interna é baseada em uma tecnologia de virtualização chamada de “namespaces”. Os namespaces permitem que o Docker isole os processos em contêineres, criando um ambiente seguro e isolado para executar aplicativos. Além disso, o Docker usa imagens para criar contêineres que são como modelos que contêm todas as informações necessárias para executar um aplicativo em um contêiner. As imagens podem ser baixadas de repositórios públicos ou privados e são atualizadas e mantidas pelos desenvolvedores de software.

Observando a sua estrutura o primeiro ponto de atenção é o Docker Daemon ja que este é o componente central do sistema. Ele é responsável por gerenciar todos os aspectos dos contêineres e imagens do Docker, incluindo a criação, execução e remoção de contêineres, o gerenciamento de armazenamento e rede, a segurança e o controle de acesso. O Docker Daemon é executado em segundo plano como um processo do sistema e pode ser controlado usando a Docker CLI ou a Docker API.

A Docker CLI é a interface de linha de comando que os desenvolvedores usam para interagir com o Docker. Ele permite que os usuários executem comandos para criar, implantar, gerenciar e monitorar contêineres e imagens. A Docker CLI é uma ferramenta poderosa e flexível que pode ser usada para executar praticamente todas as tarefas relacionadas ao Docker.

A Docker API é uma interface de programação de aplicativos que permite que outros aplicativos se comuniquem com o Docker Daemon. A Docker API permite que os desenvolvedores criem aplicativos que se integram com o Docker e realizem operações como criar, iniciar, parar e remover contêineres e imagens. A Docker API é extremamente poderosa e flexível e é usada por muitos aplicativos e serviços para gerenciar contêineres Docker.

Olhando para dentro do Capô do docker temos que falar do seu gerenciador de recursos cgroups e seu motor o containerd.

O cgroups atua gerenciando os recursos do sistema, como memória e CPU, de forma eficiente. Os cgroups são um recurso do kernel do Linux que permite que os processos sejam limitados em termos de recursos do sistema que podem acessar. O Docker usa cgroups para garantir que os contêineres tenham acesso apenas aos recursos que precisam e não afetem o desempenho do sistema hospedeiro.

O Containerd é um componente do Docker que é responsável por gerenciar a criação, execução e destruição de contêineres. Ele é projetado para ser uma plataforma de contêineres leve e portátil que pode ser executada em qualquer ambiente. O Containerd é um componente fundamental do Docker e é usado por muitas outras ferramentas e serviços relacionados ao Docker.

O Containerd é composto por vários elementos, incluindo o runc, o shim e o snapshotter.

  • O runc é responsável por iniciar e gerenciar o processo dentro do contêiner.
  • O shim é um pequeno programa que atua como intermediário entre o Containerd e o runtime do contêiner.
  • O snapshotter é responsável por gerenciar os instantâneos dos sistemas de arquivos dos contêineres, permitindo que os contêineres sejam rapidamente criados e destruídos.

Entendemos a sua arquiteura agora é pensar em como colocar em produção as nossas aplicações. Neste ponto o quando escalonamos um larga escala os ontêineres, a simples implantação do Docker não é suficiente. Dessa forma se é imprescidível o uso de uma ferramenta que monitore e orquestre esse conjunto de aplicações. Para o nosso caso existe uma ferramenta do própio docker, o Docker Swarm e o como alternativa temos Kubernetes.

O Swarm é projetado para gerenciar clusters de contêineres Docker, distribuindo a carga de trabalho e garantindo que os contêineres sejam executados de maneira eficiente e escalável. O Swarm permite que os desenvolvedores definam o número de réplicas de um contêiner e o Swarm gerencia a escalabilidade, garantindo que as réplicas sejam criadas ou destruídas conforme necessário. Neste ponto vocês deve esta se perguntando:

Então, por que o Kubernetes se faz necessário em muitos casos se o Docker possui seu orquestrador o Swarm?

Bem, o Kubernetes oferece muitos recursos avançados que o Swarm não tem, como um modelo de objetos poderoso e flexível para descrever aplicativos, gerenciamento de armazenamento e rede avançado, suporte para implantações canárias, escalabilidade automática, atualizações de aplicativos sem tempo de inatividade e muito mais. O Kubernetes é um orquestrador de contêineres muito mais avançado do que o Swarm.

Um dos principais problemas que o Kubernetes veio resolver em relação ao Docker é o gerenciamento de contêineres em grande escala. Outro problema que o Kubernetes resolve é a falta de portabilidade. O Docker é um ambiente de tempo de execução, o que significa que depende de um sistema operacional e bibliotecas específicas. Isso torna o processo de implantação em diferentes ambientes muito desafiador.

Por estes motivos hoje vemos muitas aplicações rodando no kubernetes. Sendo assim, antes de conhecer um pouco como funciona precisamos entender o propósito de sua criação.

1.5. Line age kubernetes

Para compreendermos verdadeiramente a história do Kubernetes, devemos voltar ao início dos anos 2000, quando o Google estava enfrentando um desafio cada vez maior de gerenciar seus imensos clusters de servidores. Foi nesse contexto que o projeto interno do Google, conhecido como Borg, começou a ser desenvolvido. O Borg visava automatizar a implantação, o escalonamento e o gerenciamento de aplicações em escala, permitindo que os engenheiros do Google se concentrassem no desenvolvimento de software, em vez de se preocuparem com a infraestrutura subjacente.

Com o sucesso interno do Borg e do docker tinhamos naquele momento o interesse significativo da comunidade de desenvolvedores e das empresas em busca de soluções eficientes para gerenciar seus contêineres. Reconhecendo essa demanda, o Google decidiu lançar o Kubernetes em 2013 uma plataforma de código aberto baseada em sua experiência com o Borg para acelerar a adição de features para uso comercial.

À medida que o Kubernetes se consolidava como uma solução confiável e poderosa, várias empresas e provedores de nuvem começaram a oferecer suporte oficial para o Kubernetes em seus serviços. Esse suporte aumentou a adoção do Kubernetes em larga escala, tornando-o uma escolha popular tanto para startups quanto para grandes corporações. Dessa forma, vamos agora dar os primeiros passos no entendimento desta incrível ferramenta, começando por explorar sua estrutura interna de funcionamento. Para isso, vamos conhecer o nosso motor antes de realmente dirigir o carro.

2 Cluster Architecture

A arquitetura do kubernetes se baseia na interação entre dois elementos fundamentais: o Master Node e os Worker Nodes. Esses componentes trabalham em harmonia para garantir o gerenciamento eficiente, escalabilidade e estabilidade de clusters de contêineres.

O Master Node, como o cérebro do sistema, é responsável por coordenar e gerenciar todas as operações dentro do cluster. Ele atua como o centro de controle, tomando decisões inteligentes e distribuindo tarefas para os nós de trabalho. No coração do Master Node, encontramos componentes cruciais, como o API Server, que atua como interface principal para interações externas, e o etcd, um armazenamento de chave-valor distribuído, confiável e consistente, que mantém o estado do cluster.

Por outro lado, os Worker Nodes são os nós onde as cargas de trabalho são executadas e os contêineres são implantados. Esses nós fornecem os recursos computacionais necessários para que os pods funcionem corretamente. Dentre os componentes-chave dos Worker Nodes, destacam-se o Kube Proxy, que garante a conectividade e o balanceamento de carga entre os serviços, o Kubelet, que supervisiona e gerencia os pods em cada nó, e o controler runtime, que executa e gerencia os contêineres com segurança.

A interação entre o Master Node e os Worker Nodes é crucial para o funcionamento adequado do Kubernetes. Enquanto o Master Node coordena e distribui as tarefas, garantindo a estabilidade e a eficiência do sistema, os Worker Nodes executam as cargas de trabalho e fornecem os recursos necessários para a implementação de contêineres. Essa colaboração harmoniosa permite que o Kubernetes seja uma solução altamente escalável, flexível e confiável para empresas que desejam adotar a computação em contêineres em larga escala.

Um dos principais componentes do Master Node é o API Server. Ele atua como a interface principal para interações externas com o cluster. O API Server recebe solicitações e as encaminha para os componentes relevantes do sistema. Ele também autentica e autoriza as solicitações, garantindo a segurança do cluster. Além disso, o API Server é responsável por armazenar as definições dos objetos Kubernetes, como pods, serviços e deployments, permitindo que os desenvolvedores gerenciem e controlem suas aplicações de forma declarativa.

Outro componente essencial do Master Node é o etcd. Trata-se de um armazenamento de chave-valor distribuído, altamente confiável e consistente, usado pelo Kubernetes para armazenar o estado do cluster. O etcd é responsável por manter informações críticas, como os dados de configuração do cluster, o status dos nós e os detalhes dos serviços em execução. Ele garante a consistência dessas informações e as torna acessíveis para todos os componentes do sistema.

O Scheduler é mais um componente crucial no Master Node. Ele é responsável por atribuir as tarefas ou pods aos nós disponíveis dentro do cluster. O Scheduler analisa as exigências de recursos, políticas de balanceamento de carga, restrições de afinidade ou anti-afinidade e outras considerações para tomar decisões inteligentes sobre onde e como os pods serão executados. O Scheduler garante uma distribuição equilibrada das cargas de trabalho e otimiza a utilização dos recursos disponíveis no cluster.

Além desses componentes fundamentais, existem também o kube-controller-manager e o cloud-controller-manager, que desempenham papéis cruciais no gerenciamento do cluster.

O kube-controller-manager é responsável por executar e supervisionar vários controladores no Kubernetes. Esses controladores monitoram constantemente o estado do cluster e tomam ações adequadas para garantir que o cluster esteja em conformidade com as especificações desejadas. Por exemplo, o controlador de réplicas (replicaSet) garante que o número correto de réplicas de um determinado pod esteja em execução, enquanto o controlador de serviço mantém a conectividade de rede correta para os serviços dentro do cluster.

O cloud-controller-manager é um componente que se conecta a serviços específicos de cada provedor de nuvem. Ele estende as funcionalidades do Kubernetes para permitir a integração com os recursos de infraestrutura fornecidos pelos provedores de nuvem. O cloud-controller-manager lida com tarefas relacionadas a recursos de nuvem, como provisionamento de máquinas virtuais, balanceamento de carga externo e gerenciamento de volumes de armazenamento baseados na nuvem.

Em conjunto, esses componentes do Master Node do Kubernetes trabalham em harmonia para garantir a orquestração eficiente, a resiliência e a escalabilidade do cluster. Eles formam a espinha dorsal do sistema, permitindo que os usuários implantem, gerenciem e dimensionem seus aplicativos de forma confiável e consistente.

Um dos componentes essenciais em um Worker Node é o Kube Proxy. Ele atua como um proxy de rede e um balanceador de carga interno para os serviços que estão em execução nos pods. O Kube Proxy encaminha as solicitações de entrada para os pods apropriados, levando em consideração as regras de serviço e os políticas de balanceamento de carga definidos no cluster. Ele desempenha um papel crucial na garantia da conectividade adequada entre os diferentes componentes e serviços dentro do cluster Kubernetes.

Outro componente fundamental é o Kubelet, responsável por supervisionar e gerenciar cada nó individual no cluster. O Kubelet é executado em cada Worker Node e recebe as instruções do Master Node para iniciar, parar e monitorar os pods em execução no nó. Ele garante que os pods estejam em um estado saudável, respondendo a alterações na programação, monitorando o consumo de recursos e realizando ações necessárias para manter a integridade do nó.

Além disso, o Kubelet também é responsável por interagir com o container runtime (controler runtime), que é o componente que executa e gerencia os contêineres nos Worker Nodes. O controler runtime é responsável por gerenciar as operações de contêineres, como a criação, inicialização, pausa, reinicialização e encerramento dos mesmos. Ele também lida com questões de isolamento, segurança e monitoramento relacionadas à execução dos contêineres.

Em conjunto, esses componentes do Worker Node do Kubernetes trabalham em sincronia para garantir o funcionamento correto dos pods e a utilização eficiente dos recursos disponíveis. Eles desempenham um papel crucial no gerenciamento da infraestrutura de contêineres e na execução das cargas de trabalho. O Kube Proxy garante a conectividade e o balanceamento de carga adequados entre os serviços, o Kubelet supervisiona e gerencia os pods em cada nó, e o controler runtime executa e gerencia os contêineres de maneira segura.

3. Conclusão

Portanto, ao unir os Master Nodes e os Worker Nodes, o Kubernetes proporciona uma plataforma completa para a implantação, orquestração e gerenciamento de aplicativos baseados em contêineres. Essa arquitetura flexível e escalável permite que as organizações aproveitem os benefícios da computação em nuvem, garantindo uma experiência confiável e eficiente no desenvolvimento e na execução de suas aplicações. A interação harmoniosa entre os componentes do Worker Node desempenha um papel crucial nesse processo, permitindo que o Kubernetes seja uma escolha poderosa para implantações em escala.

Proximos passos

Para compreender melhor a estrutura de desenvolvimento de aplicações no Kubernetes, é importante conhecer os diferentes tipos de controladores disponíveis no kube-controller-manager, bem como os tipos de serviços alocados no proxy e os tipos de volumes utilizados.

4. Referências

  1. HIGHTOWER, Kelsey; BURNS, Brendan; BEDA, Joe. Kubernetes: Up and Running. 2ª ed. [S.l.]: O’Reilly Media, 2019.
  2. Kubernetes Documentation. Disponível em: https://kubernetes.io/docs/home/. Acesso em: 14 mai. 2023.
  3. LUKSA, Marko. Kubernetes in Action. 2ª ed. [S.l.]: Manning Publications, 2020.
  4. SAYFAN, Gigi. Mastering Kubernetes. [S.l.]: Packt Publishing, 2019.
  5. Vídeo: “Introduction to Kubernetes” por Kelsey Hightower. [Online]. Disponível em: https://youtu.be/BE77h7dmoQU. Publicado em 10 de outubro de 2017. Acesso em: 14 mai. 2023.
  6. Vídeo: “Kubernetes Explained” por TechWorld with Nana. [Online]. Disponível em: https://youtu.be/318elIq37PE. Publicado em 15 de março de 2019. Acesso em: 14 mai. 2023.

--

--

Sebastiao Ferreira de Paula Neto

Data engineer with a passion for data science, I write efficient code and optimize pipelines for successful analytics projects.