Inúmeras são as vantagens obtidas ao empregar containers Docker em projetos de software. Isolamento de aplicações, utilização mais racional de recursos computacionais, velocidade no deployment e uma menor dependência em relação aos ambientes operacionais estão entre os fatores que contribuem para o crescimento no uso desta tecnologia.
Por mais que as vantagens trazidas pelo Docker sejam inegáveis, existem também dificuldades decorrentes de sua adoção:
- Como escalar containers?
- Como garantir o trabalho coordenado entre os diferentes containers de uma aplicação?
- Como detectar containers com falhas e corrigir isso automaticamente?
As respostas a tais questões estão em soluções voltadas ao gerenciamento e uso orquestrado de containers Docker. Dentre as alternativas mais populares neste segmento, temos o Kubernetes, o Docker Swarm e o DC/OS da Mesosphere. O próprio Microsoft Azure não ficou alheio a este tipo de demanda, contando com um serviço conhecido como Azure Container Service e que suporta essas três tecnologias.
Mais recentemente (Outubro/2017) a Microsoft disponibilizou uma nova opção no Azure, voltada ao uso de Kubernetes: trata-se do Azure Kubernetes Service (AKS), solução que visa simplificar o gerenciamento e operação de ambientes baseados em Kubernetes.
Este artigo é a primeira parte de uma série na qual abordarei a utilização combinada do ASP.NET Core, do Microsoft Azure e do Kubernetes (através do serviço AKS) para a implementação de projetos que dependam da orquestração de containers. Neste artigo estão os principais conceitos envolvendo o Kubernetes, bem como descrita a aplicação ASP.NET Core, que servirá de base para os testes com o AKS.
Kubernetes: uma visão geral
Também conhecido como K8s ou kube, o Kubernetes é um projeto open source escrito na linguagem Go e desenvolvido originalmente pela Google. Mantido atualmente pela Cloud Native Computing Foundation, o Kubernetes conta com recursos de gerenciamento que viabilizam a orquestração, auto recuperação, reinício, replicação e escalonamento de containers Docker.
Assim como acontece com outras tecnologias populares na atualidade, o Kubernetes possui também uma ferramenta de linha de comando: o kubectl, utilitário que permite a execução de instruções voltadas ao gerenciamento de clusters e containers.
As diferentes estruturas controladas via Kubernetes serão criadas a partir de arquivos no formato YAML e por meio da execução de comandos via kubectl. Um ambiente para testes pode ser disponibilizado através da instalação do Minikube (software que possibilita a criação de um cluster local para uso do Kubernetes).
Dentro da arquitetura adotada pelo Kubernetes, merecem destaque os seguintes elementos:
- Master;
- Nodes;
- Pod;
- Deployment;
- Service;
- Replication Controller;
- Kubelet.
Um cluster no Kubernetes está dividido em:
- Master: máquina que controla e tem por responsabilidade a atribuição de tarefas aos diferentes Nodes;
- Nodes (nós): uma ou mais máquinas que realizam as tarefas atribuídas pelo Master.
Já um Pod é uma estrutura que agrupa um ou mais containers. A implantação deste elemento (Pod) acontece em algum dos Nodes disponíveis, com os containers que compõem o mesmo, compartilhando o mesmo endereço de IP, nome de host e outros recursos.
A figura a seguir traz a representação esquemática de um Pod:
Um objeto Deployment é uma abstração de um Pod, contando ainda com recursos adicionais:
A essa estrutura está associado um mecanismo de gerenciamento de estados controlado pelo Kubernetes, o qual permitirá a recuperação automática de um objeto deste tipo (Deployment) quando o mesmo se encontrar em um estado de falha;
Ao se falar da criação de um Pod, do ponto de vista prático, estamos, na verdade, definindo a geração de um novo objeto do tipo Deployment.
Na próxima imagem temos a representação de um objeto Deployment:
Um objeto do tipo Service é uma estrutura que funciona como um Load Balancer, cuidando assim do acesso aos diferentes Pods de uma aplicação. Trata-se de um elemento mais estável, até porque Pods são criados ou removidos continuamente ao se escalar uma aplicação.
Dentro da arquitetura do Kubernetes, o elemento conhecido como Replication Controller determinará quantas cópias idênticas de um Pod serão executadas e em quais locais (Nodes) do cluster. Já o Kubelet, é o serviço que garante a inicialização e execução dos containers nos diferentes Nodes.
A imagem a seguir traz mais uma representação do Kubernetes, com Pods distribuídos entre os diferentes Nodes de um cluster:
Implementando a aplicação para testes
Para os testes envolvendo o uso do Kubernetes a partir do Microsoft Azure, será criada uma API REST baseada no ASP.NET Core 2.0. Esta aplicação produzirá como retorno a quantidade de acessos à API, além de exibir o nome do host/máquina e do sistema operacional utilizado pelo container Docker.
Na próxima listagem está a implementação da classe Contador, a qual armazenará a contagem de acessos à API REST de testes:
namespace APIContagem { public class Contador { private int _valorAtual = 0; public int ValorAtual { get => _valorAtual; } public void Incrementar() { _valorAtual++; } } }
Já o tipo ContadorController receberá solicitações HTTP através da Action Get, controlando a utilização sincronizada de uma instância de Contador (via instrução lock) e devolvendo o número de acessos à API, o nome da máquina/host e a versão do sistema operacional em uso:
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; namespace APIContagem.Controllers { [Route("api/[controller]")] public class ContadorController : Controller { private static Contador _CONTADOR = new Contador(); [HttpGet] public object Get() { lock (_CONTADOR) { _CONTADOR.Incrementar(); return new { _CONTADOR.ValorAtual, Environment.MachineName, Sistema = Environment.OSVersion.VersionString }; } } } }
A seguir, temos um exemplo de execução desta API por meio do Visual Studio 2017:
As demais etapas envolvendo a publicação da aplicação no Kubernetes serão detalhadas na segunda parte desta série. Os fontes deste projeto de testes já estão disponíveis no GitHub: