Arquitetura de Microsserviços: Desenvolvimento de Software Escalável e Flexível

A arquitetura de microsserviços permite desenvolvimento ágil e escalável, dividindo aplicações em serviços independentes.

blog-detail-hero

Até cerca de 2013, as empresas geralmente desenvolviam software empresarial construindo aplicativos como unidades únicas com grandes bases de código, uma arquitetura monolítica. À medida que o software se tornou mais complexo e a computação em nuvem ganhou popularidade, essa abordagem tornou-se menos prática.

A chegada dos produtos software-as-a-service (aplicações entregues pela nuvem) permitiu que as empresas utilizassem provedores, como Amazon Web Services, para criar novos servidores e adicionar redundância rapidamente. Isso garantiu que os serviços permanecessem online durante atualizações e inaugurou uma nova era de velocidade e agilidade. Os usuários começaram a esperar atualizações e melhorias rápidas, incentivando as empresas a mudarem seus processos de desenvolvimento.

As empresas começaram a dividir aplicações em serviços menores e independentes, ou microsserviços. Por exemplo, em vez de incluir uma caixa de mensagens como parte de uma plataforma de e-commerce monolítica, poderiam criar um microsserviço separado para essa funcionalidade.

Este novo modelo parece bastante popular, já que [85% das empresas]1 estão utilizando microsserviços como parte de sua arquitetura.

Paralelamente, desenvolvedores começaram a trabalhar em grupos menores e mais especializados que modificavam e melhoravam serviços individuais sem risco para toda a aplicação. Esses grupos frequentemente assumiam a responsabilidade pelas operações de seu código, um modelo chamado DevOps. Para facilitar essas mudanças, gerentes de projeto começaram a desenvolver novas metodologias, como Agile, que divide projetos em lançamentos menores e mais frequentes.

Modernizar aplicações no mundo atual frequentemente significa migrar para aplicações nativas em nuvem construídas como microsserviços. Elas são então implantadas usando tecnologias de container, como Docker e Kubernetes. Isso ocorre porque uma arquitetura de microsserviços melhora a escalabilidade, a velocidade de desenvolvimento e a iteração de serviços.

O que são microsserviços?

Microsserviços são funções modulares responsáveis por um único aspecto específico de uma aplicação. Múltiplos microsserviços trabalham juntos para criar aplicações distribuídas. Esta arquitetura contrasta com estruturas monolíticas, que agrupam todas as funcionalidades em uma única unidade. Cada microsserviço em um sistema opera de forma independente e interage através de APIs, facilitando a escalabilidade e acelerando o desenvolvimento de novas funcionalidades.

Tipos de microsserviços

Existem três tipos de microsserviços:

  1. Microsserviços de domínio: desacoplam serviços com funcionalidades relacionadas.
  2. Microsserviços de integração: facilitam a interação entre aplicações não relacionadas.
  3. Microsserviços de unidade de trabalho: lidam com funções singulares.

Princípios-chave dos microsserviços

A arquitetura baseada em microsserviços possui várias características distintivas. Desenvolvedores podem desenvolver e implantar seus serviços independentemente, utilizando as linguagens e tecnologias que melhor se adequam a seus componentes.

A comunicação entre microsserviços é baseada em APIs, permitindo o acesso a dados de diversas fontes sem modificações. Serviços individuais podem escalar com base na demanda, economizando custos e garantindo disponibilidade.

Algumas características-chave de uma arquitetura de microsserviços são:

  1. Múltiplos serviços componentes: Microsserviços consistem em serviços individuais, fracamente acoplados, que podem ser desenvolvidos, implantados, operados, alterados e reimplantados sem comprometer a função de outros serviços ou a integridade da aplicação.

  2. Altamente manutenível e testável: Microsserviços permitem que equipes experimentem com novas funcionalidades e revertam mudanças caso não funcionem. Isso facilita a atualização de código e acelera o tempo de lançamento de novas funcionalidades, além de simplificar o processo de isolar e corrigir falhas e bugs em serviços individuais.

  3. Possuídos por pequenas equipes: Pequenas equipes independentes geralmente desenvolvem um serviço dentro dos microsserviços, incentivando a adoção de práticas ágeis e DevOps. As equipes são capacitadas a trabalhar de forma independente e rápida, reduzindo os ciclos de desenvolvimento.

  4. Organizados em torno de capacidades de negócios: Uma abordagem de microsserviços organiza serviços em torno de capacidades de negócios. Equipes multifuncionais têm todas as habilidades necessárias para o desenvolvimento, trabalhando para cumprir funcionalidades específicas.

  5. Infraestrutura automatizada: Equipes que constroem e mantêm microsserviços geralmente utilizam práticas de automação de infraestrutura, como integração contínua (CI), entrega contínua (CD) e implantação contínua (também CD). Isso permite que equipes construam e implantem cada serviço independentemente, sem afetar outras equipes.

Esses atributos tornam aplicações distribuídas baseadas em microsserviços flexíveis e fáceis de manter.

Microsserviços vs. Arquitetura Monolítica

Para melhor compreender a arquitetura de microsserviços, vamos compará-la com a abordagem tradicional: arquitetura monolítica. Em resumo, microsserviços são coleções de serviços menores e independentemente implantáveis, enquanto monólitos são construídos como sistemas unificados.

monoliths x microservices

Segundo

A arquitetura de microsserviços oferece maior flexibilidade e escalabilidade em comparação com monólitos. -- [Martin Fowler]2

Monólitos são grandes bases de código que funcionam como um único sistema. Eles requerem tempo de inatividade para atualizações e depuração. Arquiteturas de microsserviços são aplicações distribuídas com funcionalidades menores e independentes. Desenvolvedores podem atualizar, melhorar e depurar esses módulos sem tirar a aplicação inteira do ar, simplificando a escalabilidade e auxiliando na velocidade de desenvolvimento.

Prós e Contras

Arquitetura Monolítica

Vantagens:

  • Implantação fácil: Um único arquivo executável ou diretório facilita a implantação.
  • Desenvolvimento: Com uma base de código única, o desenvolvimento é mais simples.
  • Desempenho: Em uma base de código centralizada, uma API única pode realizar funções que várias APIs em microsserviços.
  • Testes simplificados: Como a aplicação monolítica é uma única unidade centralizada, testes de ponta a ponta podem ser realizados mais rapidamente do que em aplicações distribuídas.
  • Depuração fácil: Com todo o código localizado em um único lugar, é mais fácil seguir uma requisição e encontrar um problema.

Desvantagens:

  • Velocidade de desenvolvimento mais lenta: Uma aplicação monolítica grande torna o desenvolvimento mais complexo e mais lento.
  • Escalabilidade: Não é possível escalar componentes individuais.
  • Confiabilidade: Se houver um erro em qualquer módulo, pode afetar a disponibilidade de toda a aplicação.
  • Barreira para adoção de novas tecnologias: Mudanças no framework ou linguagem afetam toda a aplicação, tornando as mudanças frequentemente caras e demoradas.
  • Falta de flexibilidade: Um monólito é limitado pelas tecnologias já usadas.
  • Implantação: Uma pequena mudança requer a reimplantação de todo o monólito.

Arquitetura Microsserviço

Vantagens:

  • Agilidade: Promove formas de trabalho ágeis com pequenas equipes que implantam frequentemente.
  • Escalabilidade flexível: Se um microsserviço atinge sua capacidade de carga, novas instâncias podem ser rapidamente implantadas para aliviar a pressão.
  • Implantação contínua: Ciclos de lançamento mais frequentes e rápidos.
  • Altamente manutenível e testável: Equipes podem experimentar com novas funcionalidades e reverter se algo não funcionar.
  • Independente de implantação: Serviços individuais permitem implantação rápida e fácil de funcionalidades específicas.
  • Flexibilidade tecnológica: Liberdade para selecionar as ferramentas desejadas.
  • Alta confiabilidade: Implantação de mudanças em serviços específicos sem ameaçar toda a aplicação.
  • Equipes mais satisfeitas: Equipes mais autônomas e capazes de construir e implantar sem longos períodos de espera.

Desvantagens:

  • Desenvolvimento desordenado: Microsserviços adicionam mais complexidade, resultando em menor velocidade de desenvolvimento se não forem gerenciados adequadamente.
  • Custos de infraestrutura exponenciais: Cada microsserviço pode ter seu próprio custo de suíte de testes, playbooks de implantação, infraestrutura de hospedagem, ferramentas de monitoramento, etc.
  • Sobrecarga organizacional: Necessidade de comunicação e colaboração adicionais para coordenar atualizações e interfaces.
  • Desafios de depuração: Cada microsserviço possui seus próprios logs, complicando a depuração.
  • Falta de padronização: Sem uma plataforma comum, pode haver proliferação de linguagens, padrões de logging e monitoramento.
  • Falta de propriedade clara: Com mais serviços, aumenta o número de equipes, dificultando saber quais serviços estão disponíveis e quem contatar para suporte.

Embora muitas empresas prefiram cada vez mais a arquitetura de microsserviços, é possível superar obstáculos operacionais e fomentar a resiliência dentro de um sistema baseado em microsserviços seguindo as melhores práticas de DevOps.

Exemplos de Arquitetura de Microsserviços

Cada microsserviço é composto por um serviço e um banco de dados. Os serviços lidam com a API REST, implementam a lógica de negócios e armazenam dados em um banco de dados. Para microsserviços, isolamos seus recursos como bancos de dados e filas uns dos outros, seguindo o contrato 12 Factor App.

Casos de Uso

Simplificando: a arquitetura de microsserviços torna o desenvolvimento de aplicativos mais rápido e eficiente. Capacidades de implantação ágil combinadas com a aplicação flexível de diferentes tecnologias reduzem drasticamente a duração do ciclo de desenvolvimento. A seguir estão algumas das aplicações mais vitais da arquitetura de microsserviços:

  • Processamento de dados: Aplicações em arquitetura de microsserviços podem lidar com mais requisições simultâneas, processando grandes quantidades de informação em menos tempo.
  • Conteúdo de mídia: Empresas como Netflix e Amazon Prime Video lidam com bilhões de requisições de API diariamente. Plataformas OTT que oferecem aos usuários um vasto conteúdo de mídia se beneficiam da implantação de uma arquitetura de microsserviços, garantindo que as inúmeras requisições para diferentes subdomínios globais sejam processadas sem atrasos ou erros.
  • Migração de websites: Envolve mudanças substanciais e redesenvolvimento de áreas principais de um website. Usar microsserviços ajuda a evitar tempo de inatividade que pode prejudicar os negócios e garante que os planos de migração sejam executados suavemente.
  • Transações e faturas: Microsserviços são perfeitos para aplicações que lidam com altos volumes de pagamentos e transações e geram faturas. A falha em processar pagamentos pode causar grandes perdas para as empresas. Com microsserviços, a funcionalidade de transações pode ser fortalecida sem alterar o restante da aplicação.

Implementações

Com os avanços recentes em tecnologia de nuvem, muitas grandes marcas passaram a adotar a migração de uma arquitetura monolítica para microsserviços para melhor funcionalidade. Vamos olhar para duas dessas empresas que melhoraram significativamente seus negócios ao usar microsserviços.

  • Amazon: O site de varejo da Amazon em 2001 funcionava como uma aplicação monolítica única. A falta de flexibilidade dificultava o trabalho dos desenvolvedores ao desvincular dependências durante atualizações ou escalonamentos. Para resolver esse problema, a equipe de desenvolvimento da Amazon dividiu a grande aplicação monolítica em serviços menores e independentes, gerenciados por equipes de desenvolvimento separadas. Isso levou à criação de uma arquitetura orientada a serviços altamente desacoplada, conhecida hoje como arquitetura de microsserviços.

  • Netflix: A Netflix iniciou seu negócio de streaming de filmes em 2007 e enfrentou graves problemas de escalabilidade e interrupções de serviços em apenas um ano. Em 2008, a Netflix falhou em enviar DVDs para clientes por três dias consecutivos. Foi então que decidiram mudar para um sistema distribuído na nuvem com Amazon Web Services (AWS) como provedor de nuvem. Em 2009, a Netflix começou a migrar sua arquitetura de monolito para microsserviços, concluindo esse processo em 2012. Essa mudança permitiu que a Netflix superasse seus desafios de escalabilidade e oferecesse seus serviços a milhões de pessoas globalmente. Em 2015, o API gateway da Netflix processava com sucesso 2 bilhões de requisições de API diariamente, graças a um grupo de mais de 500 microsserviços hospedados na nuvem, reduzindo custos de streaming e gerando ganhos financeiros significativos.

Como Construir Microsserviços

Construir uma arquitetura de microsserviços é um processo que envolve várias etapas estratégicas e técnicas. A seguir, detalhamos um guia abrangente para ajudar sua organização a migrar de uma arquitetura monolítica para microsserviços de forma eficiente e eficaz, utilizando um exemplo hipotético simples: uma aplicação de gerenciamento de biblioteca online.

Exemplo Hipotético: Sistema de Gerenciamento de Biblioteca Online

Imagine que você está desenvolvendo um sistema de gerenciamento de biblioteca online chamado LibManage, que permite aos usuários pesquisar livros, fazer reservas, gerenciar suas contas e processar pagamentos de multas. Inicialmente, LibManage foi desenvolvido como uma aplicação monolítica, mas agora você deseja migrar para uma arquitetura de microsserviços para melhorar a escalabilidade e a manutenção.

Avaliação e Planejamento

Antes de iniciar a migração para microsserviços, é fundamental realizar uma avaliação completa do sistema atual e definir objetivos claros.

  1. Análise do Sistema Atual
  • Mapeamento de Dependências: No monólito LibManage, funcionalidades como busca de livros, reservas, gerenciamento de contas e processamento de pagamentos estão todas interligadas em uma única base de código. Identificar essas interdependências ajuda a planejar a divisão em microsserviços.

  • Identificação de Gargalos: A funcionalidade de processamento de pagamentos está sobrecarregada durante picos de uso, causando lentidão no sistema. Este é um gargalo que pode ser resolvido isolando essa funcionalidade em um microsserviço separado.

  • Avaliação de Complexidade: O código do monólito tornou-se difícil de manter devido ao crescimento das funcionalidades e à falta de modularidade, aumentando a necessidade de migração.

  1. Definição de Objetivos
  • Escalabilidade: Permitir que o serviço de processamento de pagamentos escale independentemente para lidar com altos volumes de transações durante períodos de pico.

  • Flexibilidade: Facilitar a adição de novas funcionalidades, como recomendações personalizadas de livros, sem impactar o restante do sistema.

  • Resiliência: Aumentar a resiliência do sistema para que falhas em um microsserviço (por exemplo, reservas) não afetem outros serviços (como busca de livros).

Identificação e Definição de Serviços

Dividir a aplicação em microsserviços exige uma compreensão profunda dos domínios de negócio e das funcionalidades da aplicação.

  1. Definição de Limites de Serviço
  • Bounded Context: Utilizando o conceito de Domain-Driven Design (DDD), definimos limites claros para cada serviço. Por exemplo:
    • Serviço de Busca de Livros: Responsável por indexar e pesquisar livros.
    • Serviço de Reservas: Gerencia as reservas de livros pelos usuários.
    • Serviço de Gerenciamento de Contas: Cuida das informações de perfil e histórico de empréstimos dos usuários.
    • Serviço de Pagamentos: Processa multas e transações financeiras.
  1. Mapeamento de Domínios de Negócio
  • Identificação de Domínios Principais:
    • Processamento de Pagamentos: Separar esta funcionalidade permite que o serviço escale conforme necessário sem afetar outros componentes.
    • Gerenciamento de Contas: Isolar esta funcionalidade facilita a manutenção e futuras integrações com sistemas de autenticação.
  • Relacionamento entre Domínios: Definimos como os serviços interagem. Por exemplo, o Serviço de Reservas precisa comunicar-se com o Serviço de Busca de Livros para verificar a disponibilidade.

Design da API e Comunicação

A comunicação eficiente entre microsserviços é crucial para o sucesso da arquitetura.

  1. Definição de APIs RESTful
  • Contratos de API:
    • Serviço de Busca de Livros:
      • GET /books: Buscar livros com base em critérios de pesquisa.
      • GET /books/{id}: Obter detalhes de um livro específico.
    • Serviço de Reservas:
      • POST /reservations: Fazer uma reserva de um livro.
      • GET /reservations/{id}: Verificar o status de uma reserva.
    • Serviço de Pagamentos:
      • POST /payments: Processar um pagamento de multa.
      • GET /payments/{id}: Verificar o status de um pagamento.
  • Versionamento de APIs: Implementamos versionamento nas APIs para permitir atualizações futuras sem interromper os serviços existentes, por exemplo, v1/books, v2/books.
  1. Protocolos de Comunicação
  • Sincrona vs. Assíncrona:

    • Sincrona: Utilizamos HTTP/REST para comunicações que requerem respostas imediatas, como a busca de livros.
    • Assíncrona: Implementamos mensageria com RabbitMQ para comunicações que podem ser processadas de forma assíncrona, como notificações de reservas e confirmações de pagamento.
  • Mensageria: O Serviço de Reservas publica eventos no RabbitMQ quando uma reserva é feita, que o Serviço de Pagamentos consome para verificar multas associadas.

Desenvolvimento e Implementação

Nesta etapa, você realmente começa a desenvolver os microsserviços definidos.

  1. Escolha de Tecnologias e Linguagens
  • Polyglot Programming:
    • Serviço de Busca de Livros: Desenvolvido em Python usando o framework Flask para rápida implementação de APIs.
    • Serviço de Reservas: Desenvolvido em Java com Spring Boot para robustez e integração com sistemas corporativos.
    • Serviço de Pagamentos: Desenvolvido em Node.js para facilidade de integração com serviços financeiros e alta performance em I/O.
  • Frameworks e Ferramentas: Escolhemos frameworks modernos que facilitam o desenvolvimento de microsserviços, como Spring Boot, Express.js e Flask.
  1. Implementação de Serviços
  • Desenvolvimento Independente: Cada equipe desenvolve, testa e implanta seus microsserviços de forma independente. Por exemplo, a equipe do Serviço de Pagamentos pode implantar atualizações sem afetar o Serviço de Reservas.

  • Princípios de SOLID: Adotamos princípios de design de software para garantir que cada serviço seja coeso e de fácil manutenção. Por exemplo, o Serviço de Gerenciamento de Contas segue o Princípio da Responsabilidade Única, cuidando apenas das informações do usuário.

Testes e Validação

Garantir a qualidade e a funcionalidade dos microsserviços é essencial.

  1. Testes Unitários e de Integração
  • Cobertura de Testes: Cada microsserviço, como o Serviço de Reservas, possui uma cobertura adequada de testes unitários para funções individuais e testes de integração para interações com outros serviços.

  • Testes de Contrato: Implementamos testes de contrato para garantir que as APIs do Serviço de Pagamentos cumpram os contratos definidos e que as mudanças não quebrem a comunicação com o Serviço de Reservas.

  1. Testes de Performance
  • Simulação de Carga: Realizamos testes de carga no Serviço de Pagamentos para garantir que ele possa lidar com picos de transações durante períodos de alta demanda.

  • Monitoramento de Latência: Monitoramos a latência das APIs do Serviço de Busca de Livros para identificar e resolver gargalos de performance, garantindo respostas rápidas para os usuários.

Implantação e Automação

A implantação contínua e a automação são fundamentais para uma arquitetura de microsserviços eficiente.

  1. Uso de CI/CD
  • Pipelines de CI/CD: Configuramos pipelines de Integração Contínua e Entrega Contínua para automatizar o build, os testes e a implantação dos microsserviços. Por exemplo, cada commit no repositório do Serviço de Reservas dispara um pipeline que executa testes e, se aprovados, implanta automaticamente em produção.

  • Automação de Deploy: Utilizamos ferramentas como Jenkins e GitLab CI para automatizar o processo de implantação, reduzindo erros humanos e acelerando o tempo de entrega.

  1. Containers e Orquestração
  • Containerização com Docker: Empacotamos cada microsserviço em containers Docker para garantir consistência entre ambientes de desenvolvimento e produção. Por exemplo, o Serviço de Pagamentos é containerizado com todas as suas dependências, garantindo que rode da mesma forma em qualquer ambiente.

  • Orquestração com Kubernetes: Utilizamos Kubernetes para gerenciar, escalar e monitorar os containers de forma eficiente. Configuramos pods para cada microsserviço e definimos políticas de escalonamento para que, durante picos de uso, o Serviço de Pagamentos possa escalar automaticamente.

Monitoramento e Manutenção

Manter uma arquitetura de microsserviços requer monitoramento constante e manutenção proativa.

  1. Ferramentas de Monitoramento
  • Prometheus e Grafana: Utilizamos Prometheus para coleta de métricas e Grafana para visualização. Monitoramos métricas como tempo de resposta das APIs e uso de recursos para identificar problemas em tempo real.

  • ELK Stack: Implementamos a stack ELK (Elasticsearch, Logstash, Kibana) para gerenciamento e análise de logs. Centralizamos os logs de todos os microsserviços, facilitando a depuração e a análise de erros.

  1. Estratégias de Logging
  • Logs Centralizados: Centralizamos os logs do Serviço de Reservas e de outros microsserviços no Elasticsearch, permitindo buscas rápidas e correlacionadas entre diferentes serviços.

  • Tracing Distribuído: Utilizamos ferramentas de tracing como Jaeger para monitorar o fluxo de requisições entre microsserviços, identificando onde ocorrem latências ou falhas.

  1. Manutenção Proativa
  • Atualizações Regulares: Mantemos os microsserviços atualizados com as últimas dependências e patches de segurança. Por exemplo, atualizamos regularmente o Serviço de Busca de Livros para incorporar melhorias no mecanismo de pesquisa.

  • Gerenciamento de Erros: Implementamos estratégias robustas de gerenciamento de erros, como circuit breakers no Serviço de Pagamentos, para minimizar o impacto de falhas e garantir a resiliência do sistema.

Considerações de Equipe e Cultura

A migração para microsserviços não é apenas uma mudança técnica, mas também cultural.

  1. Organização de Equipes
  • Equipes Autônomas: Estruturamos as equipes de forma que cada uma seja responsável por um ou mais microsserviços específicos. Por exemplo, a equipe do Serviço de Reservas é totalmente responsável por desenvolver, implantar e manter esse serviço.

  • Propriedade de Serviços: Cada equipe tem propriedade completa sobre os serviços que desenvolve, incluindo desenvolvimento, implantação e manutenção, promovendo responsabilidade e agilidade.

  1. Adoção de DevOps
  • Cultura de Colaboração: Promovemos uma cultura de colaboração entre desenvolvedores e operações para facilitar a entrega contínua. As equipes trabalham juntas para resolver problemas e melhorar processos.

  • Automação de Processos: Automatizamos o máximo possível dos processos de desenvolvimento e implantação para aumentar a eficiência e reduzir erros humanos. Isso inclui automação de testes, builds e implantações.

Ferramentas e Tecnologias Recomendadas

Para apoiar o desenvolvimento e a manutenção de uma arquitetura de microsserviços, recomendamos as seguintes ferramentas e tecnologias:

  • Desenvolvimento: Spring Boot, Express.js, Flask
  • Containerização: Docker
  • Orquestração: Kubernetes, Docker Swarm
  • CI/CD: Jenkins, GitLab CI, GitHub Actions
  • Monitoramento: Prometheus, Grafana, ELK Stack
  • Mensageria: RabbitMQ, Kafka

Boas Práticas

  • Desacoplamento: Mantenha os microsserviços desacoplados para facilitar a manutenção e a escalabilidade.
  • Resiliência: Implemente padrões como Circuit Breaker para aumentar a resiliência dos microsserviços.
  • Documentação: Mantenha uma documentação clara e atualizada das APIs e dos fluxos de comunicação entre os serviços.
  • Segurança: Adote práticas de segurança desde o início, como autenticação e autorização robustas, além de criptografia de dados sensíveis.

Containerização

Containerização é um processo de implantação de software que agrupa o código de uma aplicação com todos os arquivos e bibliotecas necessários para executá-la em qualquer infraestrutura. Tradicionalmente, para rodar uma aplicação no seu computador, você precisava instalar a versão que correspondia ao sistema operacional da sua máquina. Por exemplo, era necessário instalar a versão Windows de um pacote de software em uma máquina Windows. Com a containerização, é possível criar um único pacote de software, ou container, que roda em todos os tipos de dispositivos e sistemas operacionais. Isso significa que containers incluem todos os binários, bibliotecas e configurações que uma aplicação requer. No entanto, containers NÃO incluem hardware virtualizado ou recursos de kernel.

A containerização permite que desenvolvedores criem e implantem aplicações de forma mais rápida e segura. Com métodos tradicionais, desenvolvedores escrevem código em um ambiente de computação específico, o que, ao ser transferido para um novo local, frequentemente resulta em bugs e erros. Por exemplo, isso pode acontecer ao transferir código de um computador desktop para uma VM ou de um sistema Linux® para Windows. A containerização elimina esse problema ao agrupar o código da aplicação com os arquivos de configuração, bibliotecas e dependências necessárias para sua execução. Esse pacote único de software ou "container" é abstraído do sistema operacional host, tornando-o portátil e capaz de rodar em qualquer plataforma ou nuvem sem problemas.

O conceito de containerização e isolamento de processos é antigo. No entanto, o surgimento em 2013 do Docker, um projeto open-source que se tornou um padrão da indústria para containers com ferramentas de desenvolvedor simples e uma abordagem universal de empacotamento, acelerou a adoção dessa tecnologia. Hoje, organizações usam cada vez mais a containerização para criar novas aplicações e modernizar aplicações existentes para a nuvem.

Organizações que buscam construir aplicações na nuvem com microsserviços necessitam da tecnologia de containerização. Uma aplicação moderna na nuvem consiste em múltiplos microsserviços. A containerização fornece a ferramenta de software para empacotar microsserviços como programas implantáveis em diferentes plataformas. Elas frequentemente utilizam gateways de API entre microsserviços e seus clientes, que realizam funções de tráfego de API como autenticação, controle de acesso e balanceamento de carga.

O mais importante, a containerização permite que aplicações sejam "escritas uma vez e rodem em qualquer lugar" em data centers on-premises, ambientes de nuvem híbrida e multicloud. Essa portabilidade acelera o desenvolvimento, previne o lock-in de provedores de nuvem e oferece outros benefícios notáveis como isolamento de falhas, facilidade de gerenciamento, segurança simplificada e mais.

Os conceitos por trás de microsserviços e containerização são similares. Ambos são práticas de desenvolvimento de software que transformam aplicações em coleções de serviços ou componentes menores que são portáveis, escaláveis, eficientes e mais fáceis de gerenciar. Além disso, microsserviços e containerização funcionam bem quando usados juntos. Containers fornecem uma encapsulação leve de qualquer aplicação, seja um monólito tradicional ou um microsserviço modular. Um microsserviço, desenvolvido dentro de um container, ganha todos os benefícios inerentes da containerização, como portabilidade.

No geral, containers, microsserviços e computação em nuvem se uniram, elevando o desenvolvimento e a entrega de aplicações a um novo nível. Essas tecnologias simplificam fluxos de trabalho de DevOps e suportam pipelines de integração contínua e entrega contínua (CI/CD) para um desenvolvimento de software acelerado. Essas abordagens de próxima geração trouxeram agilidade, eficiência e confiabilidade para o ciclo de vida do desenvolvimento de software, levando a entregas mais rápidas de aplicações containerizadas e melhorias para usuários e mercado.

Container Image

A containerização envolve a criação de pacotes de software autossuficientes que funcionam de forma consistente, independentemente das máquinas em que rodam. Desenvolvedores criam e implantam imagens de container — arquivos que contêm as informações necessárias para rodar uma aplicação containerizada. Ferramentas de containerização são usadas para construir imagens de container com base na especificação de imagem do Open Container Initiative (OCI). O OCI é um grupo open-source que fornece um formato padronizado para a criação de imagens de container. Imagens de container são de somente leitura e não podem ser alteradas pelo sistema computacional. Imagens são templates de somente leitura contendo instruções para criar um container.

Containers encapsulam uma aplicação como um único pacote executável de software que agrupa o código da aplicação com todos os arquivos de configuração, bibliotecas e dependências necessárias para sua execução. Aplicações containerizadas são "isoladas", significando que não incluem uma cópia do sistema operacional. Em vez disso, um runtime de container ou engine de container (como o Docker runtime engine) é instalado no sistema operacional host, tornando-se o condutor para que containers compartilhem o sistema operacional com outros containers no mesmo sistema computacional.

A arquitetura de containerização consiste em quatro camadas de componentes essenciais:

  • Infraestrutura: É a camada de hardware do modelo de container. Refere-se ao computador físico ou servidor bare-metal que executa a aplicação containerizada.
  • Sistema operacional: A segunda camada da arquitetura de containerização é o sistema operacional. Linux é um sistema operacional popular para containerização em computadores on-premises. Em computação em nuvem, desenvolvedores usam serviços de nuvem como AWS EC2 para rodar aplicações containerizadas.
  • Engine de container: O engine de container, ou runtime de container, é um programa de software que fornece o ambiente de execução para imagens de container. Atua como um agente intermediário entre os containers e o sistema operacional, fornecendo e gerenciando recursos que a aplicação necessita. Por exemplo, engines de container podem gerenciar múltiplos containers no mesmo sistema operacional mantendo-os independentes da infraestrutura subjacente e entre si.
  • Aplicação e dependências: A camada superior da arquitetura de containerização é o código da aplicação e os demais arquivos necessários para sua execução, como dependências de bibliotecas e arquivos de configuração relacionados. Essa camada também pode conter um sistema operacional convidado leve que é instalado sobre o sistema operacional host.

Outras camadas de container, como binários comuns (bins) e bibliotecas, podem ser compartilhadas entre múltiplos containers. Essa característica elimina a sobrecarga de rodar um sistema operacional dentro de cada aplicação, tornando os containers menores em capacidade e mais rápidos para iniciar do que VMs, aumentando a eficiência dos servidores. O isolamento das aplicações como containers também reduz a chance de que código malicioso em um container impacte outros containers ou invada o sistema host.

A abstração do sistema operacional host torna aplicações containerizadas portáveis e capazes de rodar uniformemente e consistentemente em qualquer plataforma ou nuvem. Containers podem ser facilmente transportados de um computador desktop para uma máquina virtual (VM) ou de um sistema Linux para Windows. Containers também rodarão consistentemente em infraestruturas virtualizadas ou servidores bare-metal tradicionais, seja on-premises ou em um data center de nuvem.

A containerização permite que desenvolvedores criem e implantem aplicações de forma mais rápida e segura, seja a aplicação um monólito tradicional (uma aplicação de software de camada única) ou uma aplicação modular construída em uma arquitetura de microsserviços. Desenvolvedores podem construir novas aplicações baseadas na nuvem desde o início como microsserviços containerizados, dividindo uma aplicação complexa em uma série de serviços menores, especializados e gerenciáveis. Eles também podem reempacotar aplicações existentes em containers (ou microsserviços containerizados) que usam recursos de computação de forma mais eficiente.

Virtualização vs. Containerização

Containers são frequentemente comparados a máquinas virtuais (VMs) porque ambas as tecnologias permitem eficiências significativas de computação ao permitir que múltiplos tipos de software (baseados em Linux ou Windows) rodem em um único ambiente.

A virtualização utiliza um hipervisor, uma camada de software colocada em um computador ou servidor físico que permite que o computador físico separe seu sistema operacional e aplicações do hardware. A tecnologia de virtualização permite que múltiplos sistemas operacionais e aplicações de software rodem simultaneamente e compartilhem os recursos de um único computador ou máquina host (por exemplo, CPU, armazenamento e memória). Por exemplo, uma organização de TI pode rodar tanto Windows quanto Linux ou múltiplas versões de um sistema operacional, juntamente com diversas aplicações no mesmo servidor.

Cada aplicação e seu sistema de arquivos, bibliotecas e outras dependências — incluindo uma cópia do sistema operacional — são empacotados juntos como uma VM. Com múltiplas VMs rodando em uma única máquina física, podem-se alcançar economias significativas em custos de capital, operacionais e de energia.

A containerização, por outro lado, utiliza recursos de computação de forma ainda mais eficiente. Um container cria um único pacote executável de software que agrupa o código da aplicação com todas as dependências necessárias para sua execução. Diferentemente das VMs, containers não empacotam uma cópia do sistema operacional. Em vez disso, o engine de runtime de container é instalado no sistema operacional host, tornando-se o condutor através do qual todos os containers no sistema computacional compartilham o mesmo sistema operacional.

Containers são frequentemente chamados de "leves" — eles compartilham o kernel do sistema operacional da máquina e não requerem a sobrecarga de associar um sistema operacional dentro de cada aplicação (como acontece com uma VM). Outras camadas de container (bins e bibliotecas comuns) também podem ser compartilhadas entre múltiplos containers, tornando containers inerentemente menores em capacidade do que uma VM e mais rápidos para iniciar. Múltiplos containers podem rodar na mesma capacidade de computação de uma única VM, aumentando ainda mais a eficiência dos servidores e reduzindo custos de servidores e licenciamento.

Gerenciamento de Containers

Com o crescimento de soluções baseadas em containers, surgiu a necessidade de padrões ao redor da tecnologia de container e da abordagem de empacotamento de código de software. O Open Container Initiative (OCI), um projeto Linux estabelecido em junho de 2015 pela Docker e outros líderes da indústria, surgiu como uma forma de promover padrões comuns, mínimos e abertos ao redor da tecnologia de container. Desde então, o OCI ajudou a ampliar as escolhas de engines open-source para que usuários possam evitar o lock-in de fornecedores. Desenvolvedores também podem aproveitar tecnologias certificadas pelo OCI que lhes permitem construir aplicações containerizadas usando um conjunto diversificado de ferramentas DevOps e rodá-las consistentemente na infraestrutura de sua escolha.

Para esclarecer qualquer confusão, Docker também se refere à Docker, Inc., a empresa que desenvolve ferramentas de produtividade em torno da tecnologia de container Docker. Também se refere ao projeto open-source Docker ao qual Docker, Inc. e muitas outras organizações e indivíduos contribuem. Embora Docker seja a tecnologia de engine de container mais conhecida e amplamente usada, o ecossistema mais amplo padronizou em containerd e outras alternativas como CoreOS rkt, Mesos Containerizer, LXC Linux Containers, OpenVZ e crio-d.

Orquestração de Containers

Hoje, uma organização pode ter centenas ou milhares de containers — um número quase impossível de ser gerenciado manualmente pelas equipes. É aqui que a orquestração de containers entra.

A orquestração de containers é uma tecnologia de software que permite o gerenciamento automático de containers. Isso é necessário para o desenvolvimento de aplicações modernas na nuvem, pois uma aplicação pode conter milhares de microsserviços em seus respectivos containers. A grande quantidade de microsserviços containerizados torna impossível para desenvolvedores de software gerenciá-los manualmente.

Desenvolvedores usam ferramentas de orquestração de containers para iniciar, parar e gerenciar containers automaticamente. Orquestradores de containers permitem que desenvolvedores escalem aplicações na nuvem com precisão e evitem erros humanos. Por exemplo, você pode verificar se os containers estão sendo implantados com recursos adequados a partir da plataforma host.

[Kubernetes]3, também conhecido como K8s, é uma ferramenta popular para ajudar a escalar e gerenciar implantações de containers. Software de containerização como Docker ou LXC não possuem a funcionalidade para orquestrar implantações maiores de containers, e K8s preenche essa lacuna. Embora existam outras ferramentas de orquestração de containers (como Apache Mesos e Docker Swarm), K8s é de longe a mais popular.

Mas o que exatamente o Kubernetes pode fazer?

  • Rollouts e rollbacks: K8s permite automatizar a criação e implantação de novos containers ou remoção de containers existentes em um cluster de containers com base em regras pré-definidas sobre utilização de recursos.
  • Montagem de armazenamento: Com Kubernetes, você pode montar automaticamente recursos de armazenamento para seus containers.
  • Alocação de recursos: Balancear consumo de CPU e RAM em escala é uma tarefa desafiadora. K8s permite definir requisitos de CPU e RAM e então gerencia automaticamente a implantação ideal de seus containers dentro das restrições de seus recursos (nós).
  • Auto-recuperação: Com K8s, você pode definir verificações de saúde e, se seus containers não atenderem aos requisitos, eles serão automaticamente restaurados ou substituídos.
  • Gerenciamento de configuração: K8s ajuda a gerenciar de forma segura as configurações de containers, incluindo dados sensíveis como tokens e chaves SSH.
  • Balanceamento de carga: Kubernetes pode automaticamente realizar balanceamento de carga entre múltiplos containers para permitir desempenho eficiente e utilização de recursos.

Pode-se pensar que, por serem isolados, containers são "seguros". Infelizmente, não é tão simples. Embora seja verdade que containers estão isolados uns dos outros no espaço do usuário, configurações incorretas, vulnerabilidades e atores maliciosos representam ameaças. Simplificando: proteger seus containers é essencial.

img

Existem muitas considerações específicas de segurança de container que devem ser levadas em conta ao containerizar aplicações. Por exemplo, monitoramento contínuo de registries de containers para novas vulnerabilidades e utilização de firewalls de container são aspectos importantes de uma segurança abrangente de container. Além disso, proteger o sistema operacional host onde seu engine de container roda é essencial.

Proteger aplicações containerizadas significa também que você deve levar a segurança da aplicação (appsec) a sério. Isso significa ter uma visão holística do seu ambiente, criar perfis de segurança, identificar ameaças e utilizar ferramentas como soluções de Teste de Segurança de Aplicações Interativas (IAST) e Firewalls de Aplicação Web (WAFs) quando apropriado.

Segurança

A mudança gradual para arquiteturas baseadas em microsserviços no desenvolvimento de software e na computação em nuvem reflete o constante jogo de gato e rato entre medidas de segurança e um cenário de ameaças em constante evolução. À medida que ambientes de nuvem se tornam cada vez mais complexos e heterogêneos, proteger-se contra ameaças conhecidas e desconhecidas torna-se uma tarefa árdua e nebulosa. Práticas de segurança para ambientes containerizados requerem uma estratégia que abranja todo o ciclo de vida do container, incluindo desenvolvimento, testes e implantação.

Essas práticas devem abordar todas as camadas da stack, incluindo a plataforma de containerização, imagens de container, plataforma de orquestração e containers e aplicações individuais. Primeiramente, políticas de segurança de container devem girar em torno de um framework de confiança zero. Este modelo verifica e autoriza cada conexão de usuário e garante que a interação atenda aos requisitos condicionais das políticas de segurança da organização. Uma estratégia de segurança de confiança zero também autentica e autoriza cada dispositivo, fluxo de rede e conexão com base em políticas dinâmicas, usando contexto de o maior número possível de fontes de dados.

A segurança de containers tornou-se uma preocupação mais significativa à medida que mais organizações passaram a depender da tecnologia de containerização, incluindo plataformas de orquestração, para implantar e escalar suas aplicações. Segundo um relatório da Red Hat, vulnerabilidades e configurações incorretas são as principais preocupações de segurança em ambientes de container e Kubernetes.

Como mencionado anteriormente, aplicações containerizadas possuem um nível de segurança inerente, já que podem rodar como processos isolados e operar independentemente de outros containers. Esse isolamento pode prevenir que código malicioso afete outros containers ou invada o sistema host. No entanto, camadas de aplicação dentro de um container são frequentemente compartilhadas entre containers. Em termos de eficiência de recursos, isso é um benefício, mas também abre portas para interferências e brechas de segurança entre containers. O mesmo vale para o sistema operacional compartilhado, já que múltiplos containers podem estar associados ao mesmo sistema operacional host. Ameaças de segurança ao sistema operacional comum podem impactar todos os containers associados; por outro lado, uma violação em um container pode potencialmente invadir o sistema operacional host.

E quanto aos riscos e vulnerabilidades associados à própria imagem de container? Uma estratégia robusta de containerização inclui uma abordagem "segura por padrão", significando que a segurança deve ser inerente à plataforma e não uma solução separadamente implantada e configurada. Para isso, o engine de container suporta todas as propriedades de isolamento padrão inerentes ao sistema operacional subjacente. Permissões de segurança podem ser definidas para bloquear automaticamente componentes indesejados de entrarem nos containers ou limitar comunicações com recursos desnecessários.

Por exemplo, Linux Namespaces ajuda a fornecer uma visão isolada do sistema para cada container; isso inclui redes, pontos de montagem, IDs de processo, IDs de usuário, comunicação entre processos e configurações de hostname. Namespaces podem limitar o acesso a qualquer um desses recursos através de processos dentro de cada container. Tipicamente, subsistemas que não possuem suporte a Namespaces não são acessíveis a partir de dentro de um container. Administradores podem facilmente criar e gerenciar essas "restrições de isolamento" em cada aplicação containerizada através de uma interface de usuário simples.

Além disso, uma ampla gama de soluções de segurança de containers está disponível para automatizar a detecção e resposta a ameaças em uma empresa. Essas ferramentas ajudam a monitorar e impor políticas de segurança e a cumprir padrões da indústria para garantir o fluxo seguro de dados. Por exemplo, ferramentas de software de gerenciamento de segurança podem ajudar a automatizar pipelines de CI/CD, bloquear vulnerabilidades antes da produção e investigar atividades suspeitas com visibilidade em tempo real. Essa abordagem se enquadra no DevSecOps, o processo de aplicação e desenvolvimento que automatiza a integração de práticas de segurança em todos os níveis do ciclo de vida do desenvolvimento de software.

Gerenciamento de Configuração

Durante a década de 1950, o Departamento de Defesa dos Estados Unidos desenvolveu uma disciplina de gestão técnica para rastrear mudanças no desenvolvimento de sistemas complexos. Esse sistema e suas várias iterações receberam nomes muito técnicos, até que em 2001 foi publicado um guia consolidado que estabeleceu o sistema de gestão técnica agora chamado de gerenciamento de configuração. Hoje, o gerenciamento de configuração não é usado apenas pelo departamento de defesa, mas também no desenvolvimento de software, gestão de serviços de TI, engenharia civil, engenharia industrial e muito mais.

O que é Gerenciamento de Configuração?

Gerenciamento de configuração é um processo de engenharia de sistemas para estabelecer a consistência dos atributos de um produto ao longo de sua vida útil. No mundo da tecnologia, o gerenciamento de configuração é um processo de gestão de TI que rastreia itens individuais de configuração de um sistema de TI. Sistemas de TI são compostos por ativos de TI que variam em granularidade. Um ativo de TI pode representar um pedaço de software, um servidor ou um cluster de servidores. A seguir, focamos no gerenciamento de configuração conforme se aplica diretamente a ativos de software de TI e CI/CD de ativos de software.

Gerenciamento de Configuração de Software

O gerenciamento de configuração de software é um processo de engenharia de sistemas que rastreia e monitora mudanças nos metadados de configuração de sistemas de software. No desenvolvimento de software, o gerenciamento de configuração é comumente usado junto com controle de versão e infraestrutura de CI/CD. Este post foca em sua aplicação moderna e uso em ambientes de software ágeis de CI/CD.

O gerenciamento de configuração ajuda equipes de engenharia a construir sistemas robustos e estáveis através do uso de ferramentas que gerenciam e monitoram automaticamente atualizações nos dados de configuração. Sistemas de software complexos são compostos por componentes que diferem em granularidade de tamanho e complexidade. Para um exemplo mais concreto, considere uma arquitetura de microsserviços. Cada serviço em uma arquitetura de microsserviços usa metadados de configuração para se registrar e inicializar. Alguns exemplos de metadados de configuração de software são:

  • Especificações das alocações de recursos de hardware computacional para CPU, RAM, etc.
  • Endpoints que especificam conexões externas para outros serviços, bancos de dados ou domínios
  • Segredos como senhas e chaves de criptografia

É fácil que esses valores de configuração se tornem uma reflexão posterior, levando a configuração a se tornar desorganizada e dispersa. Imagine inúmeros post-its com senhas e URLs espalhados por um escritório. O gerenciamento de configuração resolve esse desafio criando uma "fonte de verdade" com um local central para a configuração.

Ferramentas de Gerenciamento de Configuração

Existem diversas ferramentas que facilitam o gerenciamento de configuração. A seguir, listamos algumas das mais utilizadas:

  • Git: É o sistema de controle de versão líder da indústria para rastrear mudanças de código. Adicionar dados de gerenciamento de configuração ao lado do código em um repositório Git proporciona uma visão holística de controle de versão de todo o projeto. O Git é uma ferramenta fundamental no gerenciamento de configuração de nível superior.

  • Docker: Introduziu a containerização, uma forma avançada de gerenciamento de configuração semelhante a um bloqueio de configuração. O Docker é baseado em arquivos de configuração chamados Dockerfiles, que contêm uma lista de comandos para reconstruir o estado esperado do sistema operacional. Os Dockerfiles são cometidos em um repositório Git para rastreamento de versão e precisam de gerenciamento de configuração adicional para implantação na infraestrutura.

  • Terraform: Plataforma de gerenciamento de configuração open source da HashiCorp. O Terraform usa IaC (Infraestrutura como Código) para provisionar e gerenciar clusters, infraestrutura em nuvem ou serviços. Suporta Amazon Web Services (AWS), Microsoft Azure e outras plataformas de nuvem, permitindo que equipes escrevam definições reproduzíveis de sua infraestrutura.

  • Ansible, Salt Stack, Chef, Puppet: São frameworks de automação de TI que automatizam muitos processos tradicionais de administradores de sistemas. Utilizam arquivos de dados de configuração (geralmente YAML ou XML) que especificam uma sequência de ações para configurar um sistema. Esses frameworks facilitam a automação necessária para alcançar CI/CD.

Considerações Finais

Para recapitular, microsserviços é uma estratégia benéfica tanto para o processo de desenvolvimento técnico de código bruto quanto para a estratégia geral de organização de negócios. Microsserviços ajudam a organizar equipes em unidades que focam no desenvolvimento e na posse de funções de negócios específicas. Esse foco granular melhora a comunicação geral de negócios e a eficiência. Há trade-offs para os benefícios dos microsserviços. É importante que os limites de serviço sejam claramente definidos antes de migrar para uma arquitetura de microsserviços.

A arquitetura de microsserviços resolve vários desafios principais que desenvolvedores enfrentavam com soluções monolíticas tradicionais. No entanto, desenvolvimento desordenado e fadiga de alertas podem criar seus próprios desafios.

Portanto, é importante ter uma plataforma de observabilidade construída especificamente para a arquitetura de microsserviços. Gerenciando o influxo de logs e destacando os insights mais importantes, a observabilidade pode ajudar desenvolvedores e engenheiros a obter o melhor dos dois mundos — a flexibilidade e escalabilidade dos microsserviços com a estrutura e visibilidade de um monólito.

O gerenciamento de configuração é uma ferramenta essencial para gerenciar sistemas de software complexos. A falta de gerenciamento de configuração pode causar sérios problemas de confiabilidade, tempo de atividade e capacidade de escalar um sistema. Ao implementar um sistema robusto de gerenciamento de configuração, utilizando ferramentas como Git, Docker, Terraform e frameworks de automação, sua equipe de desenvolvimento pode garantir uma operação estável, segura e eficiente.


Referências

Footnotes

  1. Statista, "Microservices Usage per Organization Size", 2024. Link

  2. Fowler, Martin. "Monolith vs Microservices". Link

  3. Kubernetes Documentation, "What is Kubernetes?", 2024. Link

Artigos relacionados

NEWSLETTER

NEWSLETTER

assine nossa newsletter