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 pode fornecer balanceamento de carga, terminação SSL e hospedagem virtual baseada em nome.

Configurando o Kind para usar o Ingress

Por padrão, o Kind não vem com o Ingress habilitado. Para habilitá-lo, precisamos criar um arquivo de configuração do Kind com o seguinte conteúdo:

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
    hostPort: 443
    protocol: TCP

O arquivo de configuração acima habilita o Ingress e mapeia as portas 80 e 443 do host para as portas 80 e 443 do container.

Para criar o cluster com o arquivo de configuração acima, execute o seguinte comando:

kind create cluster --config kind-ingress.yaml

Instalando o Ingress NGINX Controller no Kind

Para instalar o Ingress NGINX Controller, execute o seguinte comando:

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml

Aguarde a instalação do Ingress NGINX Controller:

kubectl wait --namespace ingress-nginx \
  --for=condition=ready pod \
  --selector=app.kubernetes.io/component=controller \
  --timeout=90s

Para instalar o Ingress NGINX Controller em um cluster que não seja o Kind, você pode seguir as instruções ds documentação oficial.

Criando um Ingress

Para criar um Ingress, precisamos ter um serviço rodando no cluster. Para isso, vamos criar um deployment e um serviço do Giropops Senha + Redis com os seguintes comandos (execute os comandos no diretório kubernetes/Day-11/manisfests pois os arquivos de configuração estão nesse diretório):

kubectl apply -f app-deployment.yaml
kubectl apply -f app-service.yaml
kubectl apply -f redis-deployment.yaml
kubectl apply -f redis-service.yaml

Agora, vamos criar o Ingress propriamente dito. Para isso, vamos utilizar o arquivo ingress.yaml:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: giropops-senhas-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: giropops-senhas
            port:
              number: 5000
kubectl apply -f ingress.yaml

Criando multiplos Ingress no mesmo Ingress Controller

Para criar multiplos Ingress no mesmo Ingress Controller, precisamos utilizar o recurso host do Ingress.

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
kubectl apply -f ingress-nginx.yaml

Instalando o Ingress NGINX Controller no EKS

Para instalar o Ingress NGINX Controller no EKS, precisamos executar os seguintes comandos. Não esqueça de mudar o contexto para o cluster EKS antes de executar os comandos:

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v0.44.0/deploy/static/provider/aws/deploy.yaml

Criando um Ingress no EKS

Para criar um Ingress no EKS, precisamos criar um arquivo de configuração do Ingress ingress-eks.yaml com o seguinte conteúdo:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: giropops-senhas-eks-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx
  rules:
  - host: {DOMAIN_NAME}
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: giropops-senhas
            port:
              number: 5000

Para que o Ingress funcione corretamente, precisamos substituir o valor {DOMAIN_NAME} por um domínio válido. Inserindo uma entrada do tipo ‘CNAME’ no seu provedor de DNS, apontando para o endereço do Load Balancer do Ingress.

Adicionando Autenticação no Ingress

Para adicionar autenticação no ingress, vamos começar adicionando 2 annotations no ingress:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: giropops-senhas-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
    nginx.ingress.kubernetes.io/auth-type: basic
    nginx.ingress.kubernetes.io/auth-secret: basic-auth
    nginx.ingress.kubernetes.io/auth-realm: 'Authentication Required'
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  ingressClassName: nginx
  tls:
  - hosts:
      - giropops.containers.expert
    secretName: giropops-containers-expert-tls
  rules:
  - host: giropops.containers.expert
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: giropops-senhas
            port:
              number: 5000

Vamos utilizar o htpasswd para criar o arquivo de autenticação:

sudo apt-get update && sudo apt-get install apache2-utils -y
htpasswd -c auth raphael
kubectl create secret generic basic-auth --from-file=auth

O que são Affinity Cookies?

Affinity Cookies são cookies que são adicionados ao navegador do usuário para que ele seja redirecionado sempre para o mesmo pod. Isso é muito útil para aplicações que não são stateless e precisam manter o estado de uma sessão.

Configurando Affinity Cookies no Ingress

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: giropops-senhas-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
    nginx.ingress.kubernetes.io/auth-type: basic
    nginx.ingress.kubernetes.io/auth-secret: basic-auth
    nginx.ingress.kubernetes.io/auth-realm: 'Authentication Required'
    nginx.ingress.kubernetes.io/affinity: "cookie"
    nginx.ingress.kubernetes.io/session-cookie-name: "giropops-cookie"
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  ingressClassName: nginx
  tls:
  - hosts:
      - giropops.containers.expert
    secretName: giropops-containers-expert-tls
  rules:
  - host: giropops.containers.expert
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: giropops-senhas
            port:
              number: 5000

O que é o Upstream Hash?

O Upstream Hash é um método de balanceamento de carga que utiliza o hash do IP do cliente para determinar para qual pod o tráfego será enviado. Isso é muito útil para aplicações que não são stateless e precisam manter o estado de uma sessão.

Configurando o Upstream Hash no Ingress

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: giropops-senhas-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
    nginx.ingress.kubernetes.io/auth-type: basic
    nginx.ingress.kubernetes.io/auth-secret: basic-auth
    nginx.ingress.kubernetes.io/auth-realm: 'Authentication Required'
    nginx.ingress.kubernetes.io/upstream-hash-by: "$request_uri"
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  ingressClassName: nginx
  tls:
  - hosts:
      - giropops.containers.expert
    secretName: giropops-containers-expert-tls
  rules:
  - host: giropops.containers.expert
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: giropops-senhas
            port:
              number: 5000

O que é Canary Deployment com o Ingress?

Canary Deployment é uma técnica de deploy que consiste em enviar uma pequena porcentagem do tráfego para uma nova versão da aplicação para testar se ela está funcionando corretamente antes de enviar todo o tráfego para a nova versão.

A regra do Canary Deployment deve ser adicionada no Ingress do novo serviço que está sendo testado.

É importante lembrar que o Canary Deployment deve ser utilizado em conjunto com o Affinity Cookie para que o usuário seja redirecionado sempre para o mesmo pod.

Configurando Canary Deployment com o Ingress

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: giropops-senhas-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-weight: "10"  # 10% do tráfego será enviado para o novo serviço
    nginx.ingress.kubernetes.io/affinity: "cookie"
    nginx.ingress.kubernetes.io/session-cookie-name: "giropops-cookie"
spec:
  ingressClassName: nginx
  tls:
  - hosts:
      - giropops.containers.expert
    secretName: giropops-containers-expert-tls
  rules:
  - host: giropops.containers.expert
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: giropops-senhas
            port:
              number: 5000

Limitando o número de requisições com o Ingress

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: giropops-senhas-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
    nginx.ingress.kubernetes.io/auth-type: basic
    nginx.ingress.kubernetes.io/auth-secret: basic-auth
    nginx.ingress.kubernetes.io/auth-realm: 'Authentication Required'
    nginx.ingress.kubernetes.io/upstream-hash-by: "$request_uri"
    nginx.ingress.kubernetes.io/limit-rps: "10" # 10 requisições por segundo
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  ingressClassName: nginx
  tls:
  - hosts:
      - giropops.containers.expert
    secretName: giropops-containers-expert-tls
  rules:
  - host: giropops.containers.expert
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: giropops-senhas
            port:
              number: 5000