O blog da AWS
Como Expor Múltiplas Aplicações no Amazon EKS Utilizando Um Único Application Load Balancer
Por Rubens Devito, Arquiteto de Soluções Sênior na AWS e
JP Santana é Arquiteto de Soluções Principal para Startups na AWS
Introdução
Arquiteturas de microsserviços já se tornaram padrão em aplicações nativas na nuvem. Maior granularidade de escabilidade, isolamento de funções e a habilidade de ter times independentes trabalhando em funcionalidades específicas da aplicação, são apenas algumas das razões pelo qual tal padrão de arquitetura vem sendo comumente utilizado. Junte isso com o fato de que as novas aplicações geralmente nascem na nuvem, você tem um casamento perfeito entre uma arquitetura modular e escalável com tecnologias que facilitam a implementação, operação e gestão de cada microsserviço que a nuvem oferece.
Um Padrão, Mas Várias Alternativas de Implementação
Na AWS, há pelo menos dois caminhos a serem seguidos para a implementação de uma arquitetura de microsserviços: 1) transformando componentes diferentes de uma aplicação ou serviço em um container ou conjunto de containers, e delegando a gestão deles para um orquestrador de containers, como o Amazon Elastic Kubernetes Service (EKS) e o Amazon Elastic Container Service (ECS); 2) transformando diferentes componentes da sua aplicação ou serviço em funções serverless, e delegando a gestão delas para o AWS Lambda.
O próximo passo é expor cada um desses microsserviços, sejam eles em containers ou em funções serverless, através de um endpoint para que um cliente ou uma API possa enviar requisições e receber respostas. Normalmente você vai querer que cada microsserviço tenha seu próprio endpoint. Por exemplo, cada sufixo (“/”) no final de um endereço aponta para um microsserviço diferente:
www.exemplo.com.br/servico1 > microsserviço1
www.exemplo.com.br/servico2 > microsserviço2
www.exemplo.com.br/servico3 > microsserviço3
…
Esse tipo de balanceamento ou roteamento é conhecido como Path-Based Routing (roteamento basaedo no caminho da URL).
Uma das principais vantagens dessa abordagem é o baixo custo e a simplicidade que se tem para expor dezenas de aplicações. Isso por que tanto o Application Load Balancer (ALB) quanto o Amazon API Gateway possuem essa funcionalidade. Ou seja, com um único ALB ou com um único API Gateway, é possível expor seus microsserviços que estão rodando em containers no Amazon EKS ou no Amazon ECS, ou em funções servereless do AWS Lambda.
Neste blog post vamos demonstrar como expor suas aplicações através de um Application Load Balancer que estão rodando em containers sendo orquestrados pelo Amazon EKS.
Arquitetura e Componentes
Amazon EKS Cluster é o cluster de Kubernetes onde irão rodar suas aplicações. O Amazon EKS é um serviço da AWS que abstrai a complexidade de gerenciar um control plane do Kubernetes, constituído principalmente por control plane nodes e etcd, permitindo que nossos clientes foquem no data plane, onde rodam as aplicações.
Auto Scaling Group é uma funcionalidade da nuvem da AWS que permite a adição ou remoção automática de instâncias Amazon EC2 baseado em uma métrica de monitoramento. Para nossa demo, ela será utilizada apenas para manter um número mínimo de instâncias EC2 rodando em alta disponibilidade. No entanto, o Auto Scaling também suporta o AWS Fargate. Dessa maneira você pode ter também todo o seu data plane gerenciado pela a AWS.
Application Load Balancer (ALB) automaticamente distribui o tráfego entre múltiplos destinos como instâncias EC2, containers ou endereços IP, em uma ou mais Zonas de Disponibilidade. O ALB trabalha na camada 7 (Aplicação) do modelo OSI (HTTP/HTTPs), e oferece, entre muitas funcionalidades, Path Conditions, possibilitando definir regras que roteiam requisições baseado na URL (também conhecido como Path-Based routing). O ALB é uma das três opções de balanceamento do Elastic Load Balancing.
Ingress é um resource do Kubernetes que gerencia acessos externos ao cluster, tipicamente HTTP. Um Ingress geralmente provê balanceamento de cargas, SSL e virtual hosting. Para ter a funcionalidade de um Ingress no cluster, é necessário instalar um Ingress Controller.
AWS Load Balancer Controller é um controller que ajuda a gerenciar Elastic Load Balancers para clusters de Kubernetes. Para nosso cenário, vamos utilizar o tipo Ingress para provisionar um ALB automaticamente e configurar as regras de roteamento necessárias neste ALB a serem definidas via manifestos do Kubernetes.
O objetivo final é termos aplicações diferentes respondendo por caminhos diferentes, mas utilizando um único ALB.
Pré-requisitos
Para implementar essa solução é necessário que você tenha os seguintes pré-requisitos:
- Um cluster do Amazon EKS provisionado com Node Groups, caso você opte por executar seus workloads em instancias EC2, ou um Fargate Profile, caso opte por executa-los em AWS Fargate;
- O AWS Load Balancer Controller configurado no seu cluster, para que um Application Load Balancer seja criado no momento em que criarmos o Ingress no Kubernetes;
- As imagens de container das suas aplicações disponíveis em um repositório do Amazon Elastic Container Registry (ECR) ou algum outro repositório de sua escolha. Neste blog post utilizaremos imagens de containers registradas no Amazon ECR, e demonstraremos o passo-a-passo de criação da imagem e envio ao respositório.
Criação do Ambiente
Criação da aplicação e imagem Docker
Vamos primeiramente criar nossas aplicações de exemplo e seus respectivos Dockerfiles. No nosso caso, por tratar-se de um ambiente de demonstração, utilizaremos uma aplicação extremamente simples em HTML que exibe um fundo amarelo e uma outra um fundo verde, simplesmente para simularmos dois microsserviços.
1. Crie um diretório chamado verde e outro chamado amarelo;
mkdir verde/ amarelo/
2. Copie o código de cada aplicação e salve como html em seus respectivos diretórios:
Aplicação verde:
echo '<html style="background-color: green;"></html>' > verde/index.html
Aplicação amarela:
echo '<html style="background-color: yellow;"></html>' > amarelo/index.html
3. Vamos agora criar os Dockerfiles nos mesmos diretórios que criamos os arquivos index.html.
Entenda o arquivo: utilizaremos uma base image do Nginx com Alpine, criaremos um diretório para a aplicação e copiaremos o arquivo index.html para este diretório. Faremos também a exposição da nossa aplicação na porta 80 (HTTP).
Aplicação verde:
cat <<EOF > verde/Dockerfile FROM nginx:alpine RUN mkdir -p /usr/share/nginx/html/green COPY ./index.html /usr/share/nginx/html/green/index.html EXPOSE 80 EOF
Aplicação amarela:
cat <<EOF > amarelo/Dockerfile FROM nginx:alpine RUN mkdir -p /usr/share/nginx/html/yellow COPY ./index.html /usr/share/nginx/html/yellow/index.html EXPOSE 80 EOF
4. Vamos agora criar um repositório do Amazon ECR para cada aplicação e enviar as respectivas imagens Docker.
Siga essa documentação para criar os repositórios green e yellow para cada uma das aplicações.
aws ecr create-repository --repository-name green
aws ecr create-repository --repository-name yellow
5. Tendo criado os repositórios, acesse-os e clique no botão View push commands.
Siga o passo-a-passo que será exibido para seu sistema operacional para criar a imagem Docker e enviá-la para o repositório. Neste exemplo, estamos usando us-east-1 como região. Altere o código da região caso não esteja utilizando N. Virginia.
export AWS_REGION=$(aws ec2 describe-availability-zones --output text --query 'AvailabilityZones[0].[RegionName]') export AWS_REGISTRY_ID=$(aws ecr describe-registry --query registryId --output text) export AWS_ECR_REPO=${AWS_REGISTRY_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com
aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin $AWS_ECR_REPO
cd amarelo/ docker build . -t yellow docker tag yellow:latest $AWS_ECR_REPO/yellow:latest docker push $AWS_ECR_REPO/yellow:latest cd .. cd verde/ docker build . -t green docker tag green:latest $AWS_ECR_REPO/green:latest docker push $AWS_ECR_REPO/green:latest cd ..
Lembre-se de fazer esse procedimento para ambas as aplicações.
Definição do arquivo de configuração do ambiente no Kubernetes
Vamos agora criar um arquivo de configuração do Kubernetes definindo os objetos do nosso ambiente.
1. Crie um arquivo com o nome color-app.yaml no seu editor de texto preferido e copie o conteúdo abaixo para ele. Caso não esteja utilizando o Amazon ECR, altere os dados de image para a URL do repositório da sua imagem Docker:
cat <<EOF > color-app.yaml apiVersion: v1 kind: Namespace metadata: name: color-app --- apiVersion: apps/v1 kind: Deployment metadata: name: green-app namespace: color-app labels: app: green-app spec: selector: matchLabels: app: green-app replicas: 2 template: metadata: labels: app: green-app spec: containers: - name: green-container image: $AWS_ECR_REPO/green:latest ports: - containerPort: 80 resources: limits: memory: "100Mi" cpu: "200m" --- apiVersion: apps/v1 kind: Deployment metadata: name: yellow-app namespace: color-app labels: app: yellow-app spec: selector: matchLabels: app: yellow-app replicas: 2 template: metadata: labels: app: yellow-app spec: containers: - name: yellow-container image: $AWS_ECR_REPO/yellow:latest ports: - containerPort: 80 resources: limits: memory: "100Mi" cpu: "200m" EOF
Entenda o arquivo: primeiramente criaremos um Namespace chamado collor-app e dois Deployments, um para cada aplicação. Nesses deployments definiremos 2 réplicas, adicionaremos alguns labels referenciando cada aplicação, indicaremos a imagem e definiremos limites para recursos de memória e CPU.
2. Vamos agora adicionar dois Services do tipo NodePort ao nosso arquivo, um para cada aplicação. Services do tipo NodePort servem para expormos as aplicações no Cluster de forma que elas possam ser acessadas pelo Ingress, que no nosso caso é feito através do Application Load Balancer (ALB) que é criado automaticamente pelo AWS Load Balancer Controller, mencionado nos pré-requisitos. Repare que nos Services estamos relacionando cada aplicação através dos Labels e Selectors:
cat <<EOF >> color-app.yaml --- apiVersion: v1 kind: Service metadata: namespace: color-app name: green-service labels: app: green-app annotations: alb.ingress.kubernetes.io/healthcheck-path: /green/index.html spec: type: NodePort selector: app: green-app ports: - port: 80 targetPort: 80 --- apiVersion: v1 kind: Service metadata: namespace: color-app name: yellow-service labels: app: yellow-app annotations: alb.ingress.kubernetes.io/healthcheck-path: /yellow/index.html spec: type: NodePort selector: app: yellow-app ports: - port: 80 targetPort: 80 EOF
3. Finalmente, vamos definir nosso Ingress. Como mencionado anteriormente, a função do Ingress será realizada pelo ALB. Com isso você tem a vantagem de não ter que gerenciar seus Ingresses através de Pods no seu cluster, não consumirá recursos do cluster para isso, e também poderá contar com todas as funcionalidades poderosas do ALB, como escalabilidade automática, recursos de segurança avançados e funcionalidades de roteamento, como a baseada no caminho da URL (path-based routing) que estamos demonstrando nesse blog post.
cat <<EOF >> color-app.yaml --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: color-app-ingress namespace: color-app labels: app: color-app annotations: kubernetes.io/ingress.class: alb alb.ingress.kubernetes.io/scheme: internet-facing alb.ingress.kubernetes.io/target-type: ip alb.ingress.kubernetes.io/healthcheck-protocol: HTTP alb.ingress.kubernetes.io/healthcheck-port: traffic-port alb.ingress.kubernetes.io/healthcheck-interval-seconds: '15' alb.ingress.kubernetes.io/healthcheck-timeout-seconds: '5' alb.ingress.kubernetes.io/success-codes: '200' alb.ingress.kubernetes.io/healthy-threshold-count: '2' alb.ingress.kubernetes.io/unhealthy-threshold-count: '2' spec: rules: - http: paths: - path: /yellow pathType: Prefix backend: service: name: yellow-service port: number: 80 - path: /green pathType: Prefix backend: service: name: green-service port: number: 80 EOF
Entenda o arquivo: repare que no nosso arquivo estamos definindo “Ingress annotations” para que ele seja provisionado através de um ALB público, o tráfego seja roteado diretamente para os Pods e as características de Health Check do ALB sejam configuradas. Dentro do parâmetro “spec” estamos definindo os caminhos de URL específicos para cada uma das aplicações e roteando o tráfego para seus respectivos Services.
Criação do ambiente no cluster do Amazon EKS
Após a criação do arquivo yaml, basta implementarmos nossa aplicação no cluster do Amazon EKS, através do kubectl.
1. Acesse o diretório onde o arquivo color-app.yaml foi salvo e execute o seguinte comando desde uma estação de trabalho que possua acesso ao cluster através do kubectl.
kubectl apply -f color-app.yaml
Se você tiver dúvidas sobre como configurar esse acesso, siga essa documentação para configuração do RBAC e essa para configuração local do contexto.
O ambiente é provisionado em alguns minutos.
2. Assim que ALB for provisionado, você poderá verificar as configurações feitas automaticamente no ALB indo na Console de Gerenciamento da AWS em Amazon EC2 > Load Balancers > selecione o ALB > clique na aba Listeners > clique em View/edit rules.
3. Após o provisionamento do ALB, execute o comando abaixo e copie a entrada de DNS atribuída ao ALB. Cole essa URL no navegador usando o /green ou /yellow no final, conforme as imagens abaixo:
kubectl get ingress color-app-ingress -n color-app -o=jsonpath="{'http://'}{.status.loadBalancer.ingress[].hostname}{'\n'}"
/green
/yellow
Próximos Passos
Com base neste exemplo, você pode agora utilizar o arquivo yaml para seu próprio workload. Você pode renomear os labels e componentes do Kubernetes (Namespace, Deployments, Services e Ingress) para seu ambiente e utilizar a imagem Docker da sua própria aplicação substituindo-a no Deployment. Além disso, esse passo a passo pode ser executado em um cluster de Kubernetes que roda puramente em Amazon EC2 ao invés do Amazon EKS, caso esse seja seu caso.
Conclusão
Neste blog post vimos que existem diferentes maneiras de abordar uma arquitetura de microsserviços dentro da AWS. Depois explicamos alguns conceitos principais da abordagem usando containers. Por fim, demonstramos o passo-a-passo de como implementá-la de maneira simples e econômica usando o Amazon EKS e apenas um único Application Load Balancer.
Sobre os autores
Rubens Devito é Arquiteto de Soluções Sênior na AWS.
JP Santana é Arquiteto de Soluções Principal para Startups na AWS.
Sobre os revisores
Davi Garcia é Arquiteto de Soluções Sênior especializado em Migrações na AWS.
Diego Voltz Fagundes é Arquiteto de Soluções para Empresas na AWS.
Explore mais conteúdos sobre Computação na página de Sessions On Demand.Acesse > |