Compartilhar via


Como aproveitar contêineres e orquestradores

Dica

Esse conteúdo é um trecho do eBook, Architecting Cloud Native .NET Applications for Azure, disponível no .NET Docs ou como um PDF para download gratuito que pode ser lido offline.

Miniatura de capa do eBook

Contêineres e orquestradores foram projetados para resolver problemas comuns a abordagens de implantação monolíticas.

Desafios com implantações monolíticas

Tradicionalmente, a maioria dos aplicativos tem sido implantada como uma única unidade. Esses aplicativos são chamados de monolito. Essa abordagem geral de implantação de aplicativos como unidades simples, mesmo que eles sejam compostos por vários módulos ou assemblies, é conhecida como arquitetura monolítica, conforme mostrado na Figura 3-1.

Arquitetura monolítica.

Figura 3-1. Arquitetura monolítica.

Embora tenham o benefício da simplicidade, as arquiteturas monolíticas enfrentam muitos desafios:

Implantação

Além disso, eles exigem uma reinicialização do aplicativo, o que poderá afetar temporariamente a disponibilidade se as técnicas de tempo de inatividade zero não forem aplicadas durante a implantação.

Escalonamento

Um aplicativo monolítico é hospedado inteiramente em uma única instância de computador, muitas vezes exigindo hardware de alta capacidade. Se qualquer parte do monólito exigir dimensionamento, outra cópia de todo o aplicativo deverá ser implantada em outro computador. Com um monólito, você não pode dimensionar os componentes do aplicativo individualmente - é tudo ou nada. O dimensionamento de componentes que não exigem dimensionamento resulta em uso de recursos ineficientes e caros.

Ambiente

Normalmente, aplicativos monolíticos são implantados em um ambiente de hospedagem com dependências de sistema operacional, runtime e biblioteca pré-instaladas. Esse ambiente pode não corresponder ao que o aplicativo foi desenvolvido ou testado. Inconsistências em ambientes de aplicativo são uma fonte comum de problemas para implantações monolíticas.

Acoplamento

É provável que um aplicativo monolítico experimente alto acoplamento em seus componentes funcionais. Sem limites rígidos, as alterações no sistema geralmente resultam em efeitos colaterais não intencionais e caros. Novos recursos/correções tornam-se complicados, demorados e caros de implementar. As atualizações exigem testes extensivos. O acoplamento também dificulta a refatoração de componentes ou a troca em implementações alternativas. Mesmo quando construída com uma separação rigorosa de preocupações, a erosão arquitetônica se instala à medida que a base de código monolítica se deteriora com “casos especiais” intermináveis.

Bloqueio de plataforma

Um aplicativo monolítico é construído com uma única pilha de tecnologia. Embora ofereça uniformidade, esse compromisso pode se tornar uma barreira à inovação. Novos recursos e componentes serão criados usando a pilha atual do aplicativo, mesmo quando tecnologias mais modernas podem ser uma escolha melhor. O risco no longo prazo é que seu stack tecnológico se torne desatualizado e obsoleto. A rearquitecagem de um aplicativo inteiro para uma plataforma nova e mais moderna é, na melhor das hipóteses, cara e arriscada.

Quais são os benefícios de contêineres e orquestradores?

Introduzimos contêineres no Capítulo 1. Destacamos como o CNCF (Cloud Native Computing Foundation) classifica a contêinerização como a primeira etapa em seus Cloud-Native Mapa de Trilhas – diretrizes para empresas que iniciam seu percurso nativo de nuvem. Nesta seção, discutiremos os benefícios dos contêineres.

O Docker é a plataforma de gerenciamento de contêiner mais popular. Ele funciona com contêineres no Linux ou no Windows. Os contêineres fornecem ambientes de aplicativo separados, mas reproduzíveis, que são executados da mesma maneira em qualquer sistema. Esse aspecto os torna perfeitos para desenvolver e hospedar serviços nativos de nuvem. Os contêineres são isolados uns dos outros. Dois contêineres no mesmo hardware de host podem ter versões diferentes de software, sem causar conflitos.

Os contêineres são definidos por arquivos simples baseados em texto que se tornam artefatos de projeto e são verificados no controle do código-fonte. Embora servidores completos e máquinas virtuais exijam esforço manual para atualizar, os contêineres são facilmente controlados por versão. Os aplicativos criados para execução em contêineres podem ser desenvolvidos, testados e implantados usando ferramentas automatizadas como parte de um pipeline de build.

Os contêineres são imutáveis. Depois de definir um contêiner, você poderá recriá-lo e executá-lo exatamente da mesma maneira. Essa imutabilidade se presta ao design baseado em componentes. Se algumas partes de um aplicativo evoluem de forma diferente de outras, por que reimplantar todo o aplicativo quando você pode simplesmente implantar as partes que mudam com mais frequência? Diferentes funcionalidades e interesses transversais de um aplicativo podem ser divididos em módulos distintos. A Figura 3-2 mostra como um aplicativo monolítico pode aproveitar contêineres e microsserviços delegando determinados recursos ou funcionalidades. A funcionalidade restante no próprio aplicativo também foi conteinerizada.

Interromper um aplicativo monolítico para usar microsserviços no back-end.

Figura 3-2. Decompondo um aplicativo monolítico para adotar microsserviços.

Cada serviço nativo de nuvem é criado e implantado em um contêiner separado. Cada um pode atualizar conforme necessário. Serviços individuais podem ser hospedados em nós com recursos apropriados para cada serviço. O ambiente em que cada serviço é executado é imutável, compartilhado entre os ambientes de desenvolvimento, teste e produção, e facilmente versionado. O acoplamento entre diferentes áreas do aplicativo ocorre explicitamente como chamadas ou mensagens entre serviços, não dependências de tempo de compilação dentro do monolito. Você também pode escolher a tecnologia que melhor agrupa uma determinada funcionalidade sem exigir alterações no restante do aplicativo.

Os serviços em contêineres exigem gerenciamento automatizado. Não seria viável administrar manualmente um grande conjunto de contêineres implantados de forma independente. Por exemplo, considere as seguintes tarefas:

  • Como as instâncias de contêiner serão provisionadas em um cluster de muitos computadores?
  • Uma vez implantados, como os contêineres descobrirão e se comunicarão entre si?
  • Como os contêineres podem aumentar ou reduzir sob demanda?
  • Como você monitora a integridade de cada contêiner?
  • Como proteger um contêiner contra falhas de hardware e software?
  • Como atualizar contêineres para um aplicativo dinâmico sem tempo de inatividade?

Os orquestradores de contêiner abordam e automatizam essas e outras preocupações.

No ecossistema nativo de nuvem, o Kubernetes tornou-se o orquestrador de contêiner de fato. É uma plataforma de software livre gerenciada pelo CNCF (Cloud Native Computing Foundation). O Kubernetes automatiza a implantação, o dimensionamento e as preocupações operacionais de cargas de trabalho em contêineres em um cluster de máquinas. No entanto, a instalação e o gerenciamento do Kubernetes são notoriamente complexos.

Uma abordagem muito melhor é aproveitar o Kubernetes como um serviço gerenciado de um fornecedor de nuvem. A nuvem do Azure apresenta uma plataforma kubernetes totalmente gerenciada intitulada AKS (Serviço de Kubernetes do Azure). O AKS abstrai a complexidade e a sobrecarga operacional do gerenciamento do Kubernetes. Você consome o Kubernetes como um serviço de nuvem; A Microsoft assume a responsabilidade de gerenciar e dar suporte a ele. O AKS também se integra fortemente a outros serviços do Azure e ferramentas de desenvolvimento.

O AKS é uma tecnologia baseada em cluster. Um pool de máquinas virtuais federadas, ou nós, é implantado na nuvem do Azure. Juntos, eles formam um ambiente ou cluster altamente disponível. O cluster aparece como uma entidade única e perfeita para seu aplicativo nativo de nuvem. Nos bastidores, o AKS implanta seus serviços containerizados através desses nós seguindo uma estratégia predefinida que distribui uniformemente a carga.

Quais são os benefícios de dimensionamento?

Os serviços criados em contêineres podem aproveitar os benefícios de dimensionamento fornecidos por ferramentas de orquestração como o Kubernetes. Por natureza, os contêineres só sabem sobre si mesmos. Depois de ter vários contêineres que precisam trabalhar juntos, você deve organizá-los em um nível mais alto. Organizar um grande número de contêineres e suas dependências compartilhadas, como a configuração de rede, é onde as ferramentas de orquestração entram para salvar o dia! O Kubernetes cria uma camada de abstração sobre grupos de contêineres e os organiza em pods. Os pods são executados em computadores de trabalho conhecidos como nós. Essa estrutura organizada é conhecida como um cluster. A Figura 3-3 mostra os diferentes componentes de um cluster do Kubernetes.

Componentes de cluster do Kubernetes. Figura 3-3. Componentes de cluster do Kubernetes.

O dimensionamento de cargas de trabalho em contêineres é um recurso fundamental dos orquestradores de contêineres. O AKS dá suporte ao dimensionamento automático em duas dimensões: instâncias de contêiner e nós de computação. Juntos, eles dão ao AKS a capacidade de responder de forma rápida e eficiente a picos de demanda e adicionar recursos adicionais. Discutiremos o dimensionamento no AKS mais adiante neste capítulo.

Declarativo versus imperativo

O Kubernetes dá suporte à configuração declarativa e imperativa. A abordagem imperativa envolve a execução de vários comandos que informam ao Kubernetes o que fazer a cada etapa do caminho. Execute esta imagem. Exclua este pod. Exponha essa porta. Com a abordagem declarativa, você cria um arquivo de configuração, chamado de manifesto, para descrever o que deseja em vez do que fazer. O Kubernetes lê o manifesto e transforma o estado final desejado em estado final real.

Comandos imperativos são ótimos para aprendizado e experimentação interativa. No entanto, você desejará criar declarativamente arquivos de manifesto do Kubernetes para adotar uma infraestrutura como abordagem de código, fornecendo implantações confiáveis e repetíveis. O arquivo de manifesto se torna um artefato de projeto e é usado em seu pipeline de CI/CD para automatizar implantações do Kubernetes.

Se você já configurou seu cluster usando comandos imperativos, poderá exportar um manifesto declarativo usando kubectl get svc SERVICENAME -o yaml > service.yaml. Esse comando produz um manifesto semelhante ao mostrado abaixo:

apiVersion: v1
kind: Service
metadata:
  creationTimestamp: "2019-09-13T13:58:47Z"
  labels:
    component: apiserver
    provider: kubernetes
  name: kubernetes
  namespace: default
  resourceVersion: "153"
  selfLink: /api/v1/namespaces/default/services/kubernetes
  uid: 9b1fac62-d62e-11e9-8968-00155d38010d
spec:
  clusterIP: 10.96.0.1
  ports:
  - name: https
    port: 443
    protocol: TCP
    targetPort: 6443
  sessionAffinity: None
  type: ClusterIP
status:
  loadBalancer: {}

Ao usar configuração declarativa, você pode visualizar as alterações que serão feitas antes de confirmá-las executando kubectl diff -f FOLDERNAME na pasta onde seus arquivos de configuração estão localizados. Depois de ter certeza de que deseja aplicar as alterações, execute kubectl apply -f FOLDERNAME. Adicione -R para processar recursivamente uma hierarquia de pastas.

Você também pode usar a configuração declarativa com outros recursos do Kubernetes, um dos quais são implantações. Implantações declarativas ajudam a gerenciar versões, atualizações e dimensionamento. Eles instruem o controlador de implantação do Kubernetes sobre como implantar novas alterações, dimensionar a carga ou reverter para uma revisão anterior. Se um cluster for instável, uma implantação declarativa retornará automaticamente o cluster de volta a um estado desejado. Por exemplo, se um nó falhar, o mecanismo de implantação reimplantará uma substituição para atingir o estado desejado

O uso da configuração declarativa permite que a infraestrutura seja representada como um código que pode ser verificado e com controle de versão junto com o código do aplicativo. Ele fornece melhor controle de alterações e melhor suporte para implantação contínua usando um pipeline de build e implantação.

Quais cenários são ideais para contêineres e orquestradores?

Os cenários a seguir são ideais para usar contêineres e orquestradores.

Aplicativos que exigem alto tempo de atividade e escalabilidade

Aplicativos individuais que têm altos requisitos de tempo de atividade e escalabilidade são candidatos ideais para arquiteturas nativas de nuvem usando microsserviços, contêineres e orquestradores. Eles podem ser desenvolvidos em contêineres, testados em ambientes com versões e implantados em produção sem tempo de inatividade. O uso de clusters do Kubernetes garante que esses aplicativos também possam ser dimensionados sob demanda e se recuperar automaticamente de falhas de nó.

Grande número de aplicativos

As organizações que implantam e mantêm um grande número de aplicativos se beneficiam de contêineres e orquestradores. O esforço inicial para configurar ambientes em contêineres e clusters Kubernetes é, principalmente, um custo fixo. Implantar, manter e atualizar aplicativos individuais tem um custo que varia de acordo com o número de aplicativos. Além de alguns aplicativos, a complexidade de manter manualmente aplicativos personalizados excede o custo de implementar uma solução utilizando contêineres e orquestradores.

Quando você deveria evitar o uso de contêineres e orquestradores?

Se não for possível criar seu aplicativo seguindo os princípios do aplicativo Twelve-Factor, considere evitar contêineres e orquestradores. Nesses casos, considere uma plataforma de hospedagem baseada em VM ou possivelmente algum sistema híbrido. Com ele, você sempre pode transformar determinadas partes da funcionalidade em contêineres separados ou até mesmo funções sem servidor.

Recursos de desenvolvimento

Esta seção mostra uma pequena lista de recursos de desenvolvimento que podem ajudá-lo a começar a usar contêineres e orquestradores para seu próximo aplicativo. Se você estiver procurando orientação sobre como projetar seu aplicativo de arquitetura de microsserviços nativo de nuvem, leia o complemento deste livro, Microsserviços do .NET: Arquitetura para aplicativos .NET em contêineres.

Desenvolvimento local do Kubernetes

As implantações do Kubernetes fornecem um grande valor em ambientes de produção, mas também podem ser executadas localmente em seu computador de desenvolvimento. Embora você possa trabalhar em microsserviços individuais de forma independente, pode haver momentos em que você precisará executar todo o sistema localmente , assim como ele será executado quando implantado em produção. Há várias ferramentas que podem ajudar: Minikube e Docker Desktop. O Visual Studio também fornece ferramentas para o desenvolvimento do Docker.

Minikube

O que é Minikube? O projeto minikube diz que "o Minikube implementa um cluster kubernetes local no macOS, Linux e Windows". Suas principais metas são "ser a melhor ferramenta para o desenvolvimento de aplicativos kubernetes locais e dar suporte a todos os recursos do Kubernetes adequados". A instalação do Minikube é separada do Docker, mas o Minikube dá suporte a hipervisores diferentes dos suportes do Docker Desktop. Atualmente, os seguintes recursos do Kubernetes têm suporte do Minikube:

  • Sistema de Nomes de Domínio (DNS)
  • NodePorts
  • ConfigMaps e segredos
  • Painéis
  • Runtimes de contêiner: Docker, rkt, CRI-O e contêiner
  • Habilitando a Interface de Rede de Contêiner (CNI)
  • Entrada

Depois de instalar o Minikube, você pode começar a usá-lo rapidamente executando o minikube start comando, que baixa uma imagem e inicia o cluster kubernetes local. Depois que o cluster for iniciado, você interagirá com ele usando os comandos padrão do Kubernetes kubectl .

Área de Trabalho do Docker

Você também pode trabalhar com o Kubernetes diretamente do Docker Desktop no Windows. É sua única opção se você estiver usando contêineres do Windows e for uma ótima opção para contêineres que não são do Windows também. A Figura 3-4 mostra como habilitar o suporte local do Kubernetes ao executar o Docker Desktop.

Configurando o Kubernetes no Docker Desktop

Figura 3-4. Configurando o Kubernetes no Docker Desktop.

O Docker Desktop é a ferramenta mais popular para configurar e executar aplicativos em contêineres localmente. Ao trabalhar com o Docker Desktop, você pode desenvolver localmente utilizando exatamente o mesmo conjunto de imagens de contêineres Docker que será implantado em produção. O Docker Desktop foi projetado para "criar, testar e enviar" aplicativos em contêiner localmente. Ele dá suporte a contêineres do Linux e do Windows. Depois de enviar suas imagens para um registro de imagens, como o Registro de Contêiner do Azure ou o Docker Hub, o AKS pode puxá-las e implantá-las em produção.

Ferramentas de Integração do Docker com o Visual Studio

O Visual Studio dá suporte ao desenvolvimento do Docker para aplicativos baseados na Web. Ao criar um novo aplicativo ASP.NET Core, você tem uma opção para configurá-lo com suporte do Docker, conforme mostrado na Figura 3-5.

Habilitar suporte do Docker para o Visual Studio

Figura 3-5. Habilitar suporte do Docker para o Visual Studio

Quando essa opção é selecionada, o projeto é criado com um Dockerfile na raiz, que pode ser usado para criar e hospedar o aplicativo em um contêiner do Docker. Um exemplo de Dockerfile é mostrado na Figura 3-6.

FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443

FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build
WORKDIR /src
COPY ["eShopWeb/eShopWeb.csproj", "eShopWeb/"]
RUN dotnet restore "eShopWeb/eShopWeb.csproj"
COPY . .
WORKDIR "/src/eShopWeb"
RUN dotnet build "eShopWeb.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "eShopWeb.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "eShopWeb.dll"]

Figura 3-6. Dockerfile gerado pelo Visual Studio

Depois que o suporte for adicionado, você poderá executar seu aplicativo em um contêiner do Docker no Visual Studio. A Figura 3-7 mostra as diferentes opções de execução disponíveis em um novo projeto do ASP.NET Core criado com o suporte do Docker adicionado.

Opções de execução do Docker do Visual Studio

Figura 3-7. Opções de execução do Docker do Visual Studio

Além disso, a qualquer momento, você pode adicionar suporte ao Docker a um aplicativo ASP.NET Core existente. No Gerenciador de Soluções do Visual Studio, clique com o botão direito do mouse no projeto e selecione Adicionar>Suporte ao Docker, conforme mostrado na Figura 3-8.

Adicionar suporte ao Docker do Visual Studio

Figura 3-8. Adicionando suporte do Docker ao Visual Studio

Ferramentas de Docker para Visual Studio Code

Há muitas extensões disponíveis para o Visual Studio Code que dão suporte ao desenvolvimento do Docker.

A Microsoft fornece a extensão docker para Visual Studio Code. Essa extensão simplifica o processo de adição de suporte de contêiner a aplicativos. Ele estrutura os arquivos necessários, constrói as imagens Docker e permite que você depure seu aplicativo dentro de um contêiner. A extensão apresenta um explorador visual que facilita a execução de ações em contêineres e imagens, como iniciar, parar, inspecionar, remover e muito mais. A extensão também dá suporte ao Docker Compose, permitindo que você gerencie vários contêineres em execução como uma única unidade.