Compartilhar via


Como aproveitar contêineres e orquestradores

Dica

Esse conteúdo é um trecho do livro eletrônico, para Projetar os Aplicativos .NET nativos de nuvem para o Azure, disponível no .NET Docs ou como um PDF para download gratuito que pode ser lido offline.

Cloud Native .NET apps for Azure eBook cover thumbnail.

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 individuais, mesmo que eles sejam compostos por vários módulos ou conjuntos, é conhecida como arquitetura monolítica, conforme mostrado na Figura 3-1.

Monolithic architecture.

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 pode afetar temporariamente a disponibilidade se as técnicas de tempo de inatividade zero não forem aplicadas durante a implantação.

Scaling

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 colocação em escala, outra cópia de todo o aplicativo deverá ser implantada em outro computador. Com um monólito, você não pode escalar componentes de aplicativo individualmente, é tudo ou nada. A colocação em escala de componentes que não exigem escala resulta em uso ineficiente e caro de recursos.

Ambiente

Normalmente, os 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 tenha alto acoplamento entre 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 serem implementados. 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. Ao oferecer 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. Um risco a longo prazo é que sua pilha de tecnologia fique desatualizada e obsoleta. A reorganização 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?

Apresentamos contêineres no Capítulo 1. Destacamos como o CNCF (Cloud Native Computing Foundation) classifica a contêinerização como a primeira etapa em seu Mapa de Trilhas Nativas de Nuvem. Diretrizes para empresas que iniciam sua jornada nativa de nuvem. Nesta seção, abordaremos 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 compilados 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 é possível simplesmente implantar as partes que alteram com mais frequência? Diferentes recursos e preocupações entre cortes de um aplicativo podem ser divididos em unidades separadas. A Figura 3-2 mostra como um aplicativo monolítico pode tirar proveito de contêineres e microsserviços delegando determinados recursos ou funcionalidades. A funcionalidade restante no próprio aplicativo também foi conteinerizada.

Breaking up a monolithic app to use microservices in the back end.

Figura 3-2. Decompor um aplicativo monolítico para abranger 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 ambientes de desenvolvimento, teste e produção e com fácil controle de versão. O acoplamento entre diferentes áreas do aplicativo ocorre explicitamente como chamadas ou mensagens entre serviços, não como dependências de tempo de compilação dentro do monolito. Você também pode escolher a tecnologia que melhor combina 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 a seguintes tarefas:

  • Como as instâncias de contêiner serão provisionadas em um cluster de vários computadores?
  • Depois de implantados, como os contêineres descobrirão e se comunicarão entre si?
  • Como os contêineres podem aumentar ou reduzir sob demanda?
  • Como monitorar a integridade de cada contêiner?
  • Como proteger um contêiner contra falhas de hardware e software?
  • Como atualizar contêineres para um aplicativo ao vivo com tempo de inatividade zero?

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

No ecosistema nativo de nuvem, o Kubernetes tornou-se o orquestrador de contêiner de fato. É uma plataforma de software de código aberto gerenciada pelo CNCF (Cloud Native Computing Foundation). O Kubernetes automatiza a implantação, a colocação em escala e os tratos operacionais de cargas de trabalho em contêineres em um cluster de máquinas. No entanto, instalar e gerenciar o Kubernetes é notoriamente complexo.

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 gerenciado intitulada como 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 ela. 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. Em segundo plano, o AKS implanta seus serviços em contêineres nesses nós seguindo uma estratégia predefinida que distribui uniformemente a carga.

Quais são os benefícios da colocação em escala?

Os serviços compilados em contêineres podem aproveitar os benefícios de colocação em escala fornecidos por ferramentas de orquestração como o Kubernetes. Por design, 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 em 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.

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

A colocação em escala de cargas de trabalho em contêineres é um recurso fundamental dos orquestradores de contêineres. O AKS dá suporte à escala automática em duas dimensões: instâncias de contêiner e nós de computação. Juntos, eles dão ao AKS a habilidade de responder de forma rápida e eficiente a picos de demanda e adicionar recursos adicionais. Discutiremos a escala em 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á tiver configurado 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 a configuração declarativa, você pode pré-visualizar as alterações que serão feitas antes de confirmá-las usando kubectl diff -f FOLDERNAME a pasta em que os 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, sendo uma delas implantações. Implantações declarativas ajudam a gerenciar versões, atualizações e escalabilidade. Eles instruem o controlador de implantação do Kubernetes sobre como implantar novas alterações, expandir 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 código que pode ser check-in e com 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 o uso de contêineres e orquestradores.

Aplicativos que exigem alto tempo de atividade e escalabilidade

Aplicativos individuais que têm requisitos de alto tempo de atividade e escalabilidade são candidatos ideais para arquiteturas nativas de nuvem usando os microsserviços, contêineres e orquestradores. Eles podem ser desenvolvidos em contêineres, testados em ambientes com versão 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 de configuração de ambientes em contêineres e clusters do 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 da manutenção de aplicativos personalizados excede manualmente o custo de implementar uma solução usando contêineres e orquestradores.

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

Se você não conseguir 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 autonomizar 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ções sobre como criar seu aplicativo de arquitetura de microsserviços nativos 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 na produção. Há várias ferramentas que podem ajudar: Minikube e Docker Desktop. O Visual Studio também fornece ferramentas para desenvolvimento do Docker.

Minikube

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

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

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

Docker Desktop

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. A Figura 3-4 mostra como habilitar o suporte local do Kubernetes ao executar o Docker Desktop.

Configuring Kubernetes in Docker Desktop

Figura 3-4. Configurar 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 no mesmo conjunto de imagens de contêiner do Docker que implantará na produção. O Docker Desktop foi projetado para “criar, testar e enviar” aplicativos em contêiner localmente. Ele dá suporte aos contêineres do Linux e Windows. Depois de enviar suas imagens por push para um registro de imagem, como Registro de Contêiner do Azure ou Docker Hub, o AKS poderá efetuar pull e implantá-las na produção.

Ferramentas do Docker do 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 a opção de configurá-lo com o suporte do Docker, conforme mostrado na Figura 3-5.

Visual Studio Enable Docker Support

Figura 3-5. Habilitar suporte ao Docker do Visual Studio

Quando essa opção é selecionada, o projeto é criado com um Dockerfile na raiz, que pode ser usada 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 de um novo projeto de ASP.NET Core criado com o suporte do Docker adicionado.

Visual Studio Docker Run Options

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

Além disso, a qualquer momento você pode adicionar o suporte do 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 do Docker, conforme mostrado na Figura 3-8.

Visual Studio Add Docker Support

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

Ferramentas do Docker do Visual Studio Code

Há muitas extensões disponíveis para o Visual Studio Code que suportam o desenvolvimento do Docker.

A Microsoft fornece a extensão do Docker para Visual Studio Code. Essa extensão simplifica o processo de adição de suporte de contêiner aos aplicativos. Ele organiza arquivos necessários, compila imagens do Docker e permite que você depure seu aplicativo dentro de um contêiner. A extensão apresenta um gerenciador 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.