Descomplicando o Kubernetes
DAY-9: Descomplicando o Ingress no Kubernetes
Conteúdo do Day-9
O que iremos ver hoje?
Se você está aqui, provavelmente já tem alguma noção do que o Kubernetes faz. Mas como expor seus serviços ao mundo externo de forma eficiente e segura? É aí que entra o nosso protagonista do dia: o Ingress. Nesta seção, vamos desvendar o que é o Ingress, para que serve e como ele se diferencia de outras formas de expor aplicações no Kubernetes.
Conteúdo do Day-9
- Descomplicando o Kubernetes
- O Que é o Ingress?
- Componentes do Ingress
- Componentes Chave
- Ingress Controller
- Ingress Resources
- Annotations e Customizations
- Instalando um Nginx Ingress Controller
- Instalando o Giropops-Senhas no Cluster
- Criando um Recurso de Ingress
- O que está acontecendo com o nosso Ingress?
- Configurando um Ingress para a nossa aplicação em Flask com Redis
- Criando múltiplos Ingresses no mesmo Ingress Controller
- Componentes Chave
- Instalando um cluster EKS para os nossos testes com Ingress
- Final do Day-9
O Que é o Ingress?
O que é Ingress?
O Ingress é um recurso do Kubernetes que gerencia o acesso externo aos serviços dentro de um cluster. Ele funciona como uma camada de roteamento HTTP/HTTPS, permitindo a definição de regras para direcionar o tráfego externo para diferentes serviços back-end. O Ingress é implementado através de um controlador de Ingress, que pode ser alimentado por várias soluções, como NGINX, Traefik ou Istio, para citar alguns.
Tecnicamente, o Ingress atua como uma abstração de regras de roteamento de alto nível que são interpretadas e aplicadas pelo controlador de Ingress. Ele permite recursos avançados como balanceamento de carga, SSL/TLS, redirecionamento, reescrita de URL, entre outros.
Principais Componentes e Funcionalidades: Controlador de Ingress: É a implementação real que satisfaz um recurso Ingress. Ele pode ser implementado através de várias soluções de proxy reverso, como NGINX ou HAProxy.
Regras de Roteamento: Definidas em um objeto YAML, essas regras determinam como as requisições externas devem ser encaminhadas aos serviços internos.
Backend Padrão: Um serviço de fallback para onde as requisições são encaminhadas se nenhuma regra de roteamento for correspondida.
Balanceamento de Carga: Distribuição automática de tráfego entre múltiplos pods de um serviço.
Terminação SSL/TLS: O Ingress permite a configuração de certificados SSL/TLS para a terminação de criptografia no ponto de entrada do cluster.
Anexos de Recurso: Possibilidade de anexar recursos adicionais como ConfigMaps ou Secrets, que podem ser utilizados para configurar comportamentos adicionais como autenticação básica, listas de controle de acesso etc.
Componentes do Ingress
Agora que já sabemos o que é o Ingress e o porquê de usá-lo, é hora de mergulharmos nos componentes que o compõem. Como um bom "porteiro" do nosso cluster Kubernetes, o Ingress não trabalha sozinho; ele é composto por várias "peças" que orquestram o tráfego. Vamos explorá-las!
Componentes Chave
Ingress Controller
O Ingress Controller é o motor por trás do objeto Ingress. Ele é responsável por aplicar as regras de roteamento definidas no recurso de Ingress. Exemplos populares incluem Nginx Ingress Controller, Traefik e HAProxy Ingress.
Ingress Resources
Os Ingress Resources são as configurações que você define para instruir o Ingress Controller sobre como o tráfego deve ser roteado. Estas são definidas em arquivos YAML e aplicadas no cluster.
Annotations e Customizations
Annotations permitem personalizar o comportamento padrão do seu Ingress. Você pode, por exemplo, forçar o redirecionamento de HTTP para HTTPS, ou ainda adicionar políticas de segurança, como proteção contra ataques DDoS.
Instalando um Nginx Ingress Controller
Vamos instalar o Nginx Ingress Controller. É importante observar a versão do Ingress Controller que você está instalando, pois as versões mais recentes ou mais antigas podem não ser compatíveis com o Kubernetes que você está usando. Para este tutorial, vamos usar a versão 1.9.5. No seu terminal, execute os seguintes comandos:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.9.5/deploy/static/provider/cloud/deploy.yaml
Verifique se o Ingress Controller foi instalado corretamente:
kubectl get pods -n ingress-nginx
Você pode utilizar a opção wait do kubectl, assim quando os pods estiverem prontos, ele irá liberar o shell, veja:
kubectl wait --namespace ingress-nginx \
--for=condition=ready pod \
--selector=app.kubernetes.io/component=controller \
--timeout=90s
No comando acima, estamos esperando que os pods do Ingress Controller estejam prontos, com o label app.kubernetes.io/component=controller, no namespace ingress-nginx, e caso não estejam prontos em 90 segundos, o comando irá falhar.
Instalando o Nginx Ingress Controller no Kind
KinD é uma ferramenta muito útil para testes e desenvolvimento com Kubernetes. Nesta seção atualizada, fornecemos detalhes específicos para garantir que o Ingress funcione como esperado em um cluster KinD.
Criando o Cluster com Configurações Especiais
Ao criar um cluster KinD, podemos especificar várias configurações que incluem mapeamentos de portas e rótulos para nós.
- Crie um arquivo chamado
kind-config.yamlcom o conteúdo abaixo:
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
kubeadmConfigPatches:
- |
kind: InitConfiguration
nodeRegistration:
kubeletExtraArgs:
node-labels: "ingress-ready=true"
extraPortMappings:
- containerPort: 80
hostPort: 80
protocol: TCP
- containerPort: 443
- Em seguida, crie o cluster usando este arquivo de configuração:
kind create cluster --config kind-config.yaml
Instalando um Ingress Controller
Vamos continuar usando o Nginx Ingress Controller como exemplo, que é amplamente adotado e bem documentado.
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/provider/kind/deploy.yaml
Você pode utilizar a opção wait do kubectl, assim quando os pods estiverem prontos, ele irá liberar o shell, veja:
kubectl wait --namespace ingress-nginx \
--for=condition=ready pod \
--selector=app.kubernetes.io/component=controller \
--timeout=90s
No comando acima, estamos esperando que os pods do Ingress Controller estejam prontos, com o label app.kubernetes.io/component=controller, no namespace ingress-nginx, e caso não estejam prontos em 90 segundos, o comando irá falhar.
Instalando o Giropops-Senhas no Cluster
Para a instalação do Giropops-Senhas, vamos utilizar os arquivos abaixo:
Arquivo: app-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: giropops-senhas
name: giropops-senhas
spec:
replicas: 2
selector:
matchLabels:
app: giropops-senhas
template:
metadata:
labels:
app: giropops-senhas
spec:
containers:
- image: linuxtips/giropops-senhas:1.0
name: giropops-senhas
env:
- name: REDIS_HOST
value: redis-service
ports:
- containerPort: 5000
imagePullPolicy: Always
Arquivo: app-service.yaml
apiVersion: v1
kind: Service
metadata:
name: giropops-senhas
labels:
app: giropops-senhas
spec:
selector:
app: giropops-senhas
ports:
- protocol: TCP
port: 5000
targetPort: 5000
name: tcp-app
type: ClusterIP
Arquivo: redis-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: redis
name: redis-deployment
spec:
replicas: 1
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
containers:
- image: redis
name: redis
ports:
- containerPort: 6379
resources:
limits:
memory: "256Mi"
cpu: "500m"
requests:
memory: "128Mi"
cpu: "250m"
Arquivo: redis-service.yaml
apiVersion: v1
kind: Service
metadata:
name: redis-service
spec:
selector:
app: redis
ports:
- protocol: TCP
port: 6379
targetPort: 6379
type: ClusterIP
Com os arquivos acima, estamos criando um Deployment e um Service para o Giropops-Senhas, e um Deployment e um Service para o Redis.
Para aplicar, basta executar:
kubectl apply -f app-deployment.yaml
kubectl apply -f app-service.yaml
kubectl apply -f redis-deployment.yaml
kubectl apply -f redis-service.yaml
Para verificar se os pods estão rodando, execute:
kubectl get pods
Para verificar se os serviços estão rodando, execute:
kubectl get services
Você pode acessar a app do Giropops-Senhas através do comando:
kubectl port-forward service/giropops-senhas 5000:5000
Isso se você estiver usando o Kind, caso contrário, você precisa pegar o endereço IP do seu Ingress, que veremos mais adiante.
Para testar, você pode acessar o endereço http://localhost:5000 no seu navegador.
Criando um Recurso de Ingress
Agora, vamos criar um recurso de Ingress para nosso serviço giropops-senhas criado anteriormente. Crie um arquivo chamado ingress-1.yaml:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: giropops-senhas
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- http:
paths:
- path: /giropops-senhas
pathType: Prefix
backend:
service:
name: giropops-senhas
port:
number: 5000
Após criar o arquivo, aplique-o:
kubectl apply -f ingress-1.yaml
Agora vamos ver se o nosso Ingress foi criado corretamente:
kubectl get ingress
Para ver com mais detalhes, você pode usar o comando describe:
kubectl describe ingress giropops-senhas
Tanto na saída do comando get quanto na saída do comando describe, você deve ver o endereço IP do seu Ingress no campo Address.
Você pode pegar esse IP através do comando:
kubectl get ingress giropops-senhas -o jsonpath='{.status.loadBalancer.ingress[0].hostname}'
Caso você esteja utilizando um cluster gerenciado por algum provedor de nuvem, como o GKE, você pode utilizar o comando:
kubectl get ingress giropops-senhas -o jsonpath='{.status.loadBalancer.ingress[0].ip}'
Isso porque quando você possui um cluster EKS, AKS, GCP, etc, o Ingress Controller irá criar um LoadBalancer para você, e o endereço IP do LoadBalancer será o endereço IP do seu Ingress, simples assim.
Para testar, você pode usar o comando curl com o IP, hostname ou load balancer do seu Ingress:
curl ENDEREÇO_DO_INGRESS/giropops-senhas
O que está acontecendo com o nosso Ingress?
Se você tentar acessar o endereço do seu Ingress, você verá que a aplicação não está funcionando corretamente. Para resolvermos isso precisamos entender melhor como o Ingress funciona.
Isso está acontecendo porque o Ingress Controller está encaminhando as requisições para o serviço giropops-senhas, mas a aplicação está esperando que as requisições sejam feitas para /, e não para /giropops-senhas.
Poderíamos resolver isso em contato com o time de desenvolvimento, colocando em práctica a cultura DevOps, alterando o código da aplicação para que ela funcione com o Ingress.
Mas vamos supor que o time de desenvolvimento não tenha tempo para isso, ou que a aplicação seja de terceiros, e não tenhamos acesso ao código fonte. Nesse caso, podemos "resolver" criando um novo recurso de Ingress, que irá encaminhar as requisições do /static para o / removendo a anotação nginx.ingress.kubernetes.io/rewrite-target: /
Crie um arquivo chamado ingress-2.yaml:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: giropops-senhas-static
annotations:
spec:
rules:
- http:
paths:
- path: /static
pathType: Prefix
backend:
service:
name: giropops-senhas
port:
number: 5000
Agora vamos aplicar esse novo recurso de Ingress:
kubectl apply -f ingress-2.yaml
Podemos testar novamente:
curl ENDEREÇO_DO_INGRESS/static
Agora sim, a aplicação está funcionando. Não é a melhor solução, mas resolveu o problema. Lembrando que isso é apenas um exemplo, e que o ideal é que o time de desenvolvimento faça as alterações necessárias para que a aplicação funcione corretamente com o Ingress.
Configurando um Ingress para a nossa aplicação em Flask com Redis
Nossa aplicação agora está carregando o CSS e o JS, mas ainda não está funcionando corretamente. Isso porque a aplicação está tentando se conectar ao Redis através do endereço localhost, e não está encontrando o Redis.
Então vamos criar um novo recurso de Ingress, indicando que o nosso path agora é / e não mais o /giropops-senhas.
Comece removendo os recursos que criamos anteriormente:
kubectl delete ingress giropops-senhas giropops-senhas-static
Agora crie um novo arquivo chamado ingress-3.yaml:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: giropops-senhas
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: giropops-senhas
port:
number: 5000
Agora vamos aplicar esse novo recurso de Ingress:
kubectl apply -f ingress-3.yaml
Podemos testar novamente:
curl ENDEREÇO_DO_INGRESS
Com isso, a nossa aplicação está funcionando corretamente. Você pode acessar o endereço do seu Ingress no navegador, e testar a aplicação, inclusive gerando senhas.
Criando múltiplos Ingresses no mesmo Ingress Controller
No exemplo anterior, criamos um Ingress para a nossa aplicação rodar no endereço /. Mas e se quisermos rodar mais de uma aplicação no mesmo Ingress Controller? Como faríamos?
Vamos supor que queremos rodar a nossa aplicação do NGINX no endereço giropops.nginx.io, enquanto a nossa aplicação em Flask com Redis continua rodando no localhost.
A primeira coisa que precisamos é criar o nosso Pod e o nosso Service para o NGINX.
kubectl run nginx --image=nginx --port=80
kubectl expose pod nginx
Agora vamos criar o nosso Ingress para o NGINX. Crie um arquivo chamado ingress-4.yaml:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: giropops.nginx.io
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx
port:
number: 80
Agora vamos aplicar esse novo recurso de Ingress:
kubectl apply -f ingress-4.yaml
Como estamos usando o Kind, precisamos editar o arquivo /etc/hosts para que o endereço giropops.nginx.io aponte para o endereço IP do nosso Ingress. Para isso, execute:
sudo vim /etc/hosts
Adicione a linha abaixo no arquivo:
ENDEREÇO_IP_DO_INGRESS giropops.nginx.io
Agora vamos testar:
curl giropops.nginx.io
Podemos adicionar um novo Ingress para a nossa aplicação em Flask com Redis. Crie um arquivo chamado ingress-5.yaml:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: giropops-senhas
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: giropops-senhas.io
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: giropops-senhas
port:
number: 5000
Agora vamos aplicar esse novo recurso de Ingress:
kubectl apply -f ingress-5.yaml
Não se esqueça de editar o arquivo /etc/hosts para que o endereço giropops-senhas.io aponte para o endereço IP do nosso Ingress. Para isso, execute:
sudo vim /etc/hosts
Adicione a linha abaixo no arquivo:
ENDEREÇO_IP_DO_INGRESS giropops-senhas.io
Podemos testar que as duas aplicações estão funcionando corretamente acessando os endereços giropops.nginx.io e giropops-senhas.io no navegador.
Instalando um cluster EKS para os nossos testes com Ingress
Instalando um cluster EKS para os nossos testes com Ingress
Agora que já sabemos como criar um Ingress, e como ele funciona, vamos criar um cluster EKS para testar o Ingress utilizando o eksctl, que é uma ferramenta oficial da AWS para criar clusters EKS.
Para instalar o eksctl, siga as instruções do link: https://eksctl.io/installation/
Após instalar o eksctl, podemos criar o nosso cluster EKS com o comando:
eksctl create cluster --name=eks-cluster --version=1.24 --region=us-east-1 --nodegroup-name=eks-cluster-nodegroup --node-type=t3.medium --nodes=2 --nodes-min=1 --nodes-max=3 --managed
Entendendo os Contexts do Kubernetes para gerenciar vários clusters
Quando você está trabalhando com mais de um cluster Kubernetes, é importante entender como os contextos funcionam. Um contexto é um conjunto de parâmetros que determinam como interagir com um cluster Kubernetes. Isso inclui o cluster, o usuário e o namespace.
Você pode listar os contextos disponíveis no seu ambiente com o comando:
kubectl config get-contexts
Você pode ver qual é o contexto atual com o comando:
kubectl config current-context
Você pode mudar o contexto atual com o comando:
kubectl config use-context NOME_DO_CONTEXTO
Instalando o Ingress Nginx Controller no EKS
Com o nosso cluster EKS criado, podemos instalar o Ingress Nginx Controller e fazer o deploy da nossa aplicação.
Para instalar o Ingress Nginx Controller no EKS, vamos seguir o comando da documentação oficial do Nginx Ingress Controller para AWS:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.8.2/deploy/static/provider/aws/deploy.yaml
Você pode utilizar a opção wait do kubectl, assim quando os pods estiverem prontos, ele irá liberar o shell, veja:
kubectl wait --namespace ingress-nginx \
--for=condition=ready pod \
--selector=app.kubernetes.io/component=controller \
--timeout=90s
A instalação do Ingress Nginx Controller no EKS já cria um LoadBalancer automaticamente na AWS, então podemos ver o endereço público do LoadBalancer com o comando:
kubectl get services -n ingress-nginx
Sempre utilize os logs para verificar se o Ingress Controller está funcionando corretamente:
kubectl logs -f -n ingress-nginx POD_DO_INGRESS_CONTROLLER
Acessando o endereço público do LoadBalancer no navegador, você verá a página padrão do Nginx Ingress Controller. Mas não é isso que queremos ver, queremos ver a nossa aplicação rodando. Então vamos fazer o deploy da nossa aplicação e criar um recurso de Ingress para ela.
kubectl apply -f app-deployment.yaml
kubectl apply -f app-service.yaml
kubectl apply -f redis-deployment.yaml
kubectl apply -f redis-service.yaml
Conhecendo o ingressClassName e configurando um novo Ingress
O Ingress Class é um recurso do Kubernetes que permite que você defina qual controlador de Ingress deve ser utilizado para um determinado recurso de Ingress. Isso é útil quando você tem mais de um controlador de Ingress no seu cluster, e quer que um recurso de Ingress seja tratado por um controlador específico.
Até agora, nós não definimos um Ingress Class, já que no Kind temos apenas um controlador de Ingress, o Nginx Ingress Controller. Mas quando estamos trabalhando com um cluster EKS, precisamos obrigatoriamente definir um Ingress Class.
Vamos utilizar o arquivo ingress-6.yaml para criar um novo recurso de Ingress para a nossa aplicação:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: giropops-senhas
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: giropops-senhas
port:
number: 5000
Agora vamos aplicar esse novo recurso de Ingress:
kubectl apply -f ingress-6.yaml
Como não definimos um domínio válido para o nosso Ingress, vamos acessar a aplicação através do endereço do LoadBalancer. Você pode obter o endereço através do comando:
kubectl get ingress
Configurando um domínio válido para o nosso Ingress no EKS
Já que estamos trabalhando com um cluster EKS, e queremos acessar a nossa aplicação através de um domínio, precisamos primeiro ter um domínio válido. Vamos utilizar como exemlo o https://containers.expert para criarmos o subdomínio https://giropops.containers.expert.
Após configurar o subdomínio no seu provedor de DNS, você pode criar um novo recurso de Ingress com o domínio configurado. Vamos utilizar o arquivo ingress-7.yaml para criar um novo recurso de Ingress para a nossa aplicação:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: giropops-senhas
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- host: giropops.containers.expert
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: giropops-senhas
port:
number: 5000
Agora vamos aplicar esse novo recurso de Ingress:
kubectl apply -f ingress-7.yaml
Com nosso domínio e o Ingress configurados, podemos acessar a aplicação através do endereço https://giropops.containers.expert.
Final do Day-9
Com isso, finalizamos o nosso Day-9. Nós vimos o que é o Ingress, como ele funciona, o que são as classes de Ingress, e como configurar um Ingress no Kubernetes, no Kind e na AWS com EKS. Espero que você tenha aprendido bastante sobre o Ingress, e que esteja pronto para aplicar esse conhecimento no seu dia a dia. Não esqueça de praticar tudo o que aprendeu, e de compartilhar esse conhecimento com outras pessoas.