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.
- 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 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.
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!
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.
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 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.
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.
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.
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.yaml
com 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
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.
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.
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
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.
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.
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.
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
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
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
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
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.
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.