Ingress
Qual a diferença entre service e ingress?
Vamos imaginar o seguinte cenário.
Temos um app deployado no cluster. Para acessar o seu banco de dados ele aponta para o service do banco de dados que é do tipo ClusterIP que só é acessível dentro do cluster.
Para que a aplicação seja acessível fora do cluster precisamos criar um service do tipo NodePort. Uma porta alta entre 30000 e 32767 foi escolhida. Toda vez que um node receber uma requisição nesta porta irá encaminhar para o service do app.
Um service do tipo NodePort cria um outro service do tipo ClusterIP.
Se lembramos que um service são regras, então ele cria duas regras, uma para todos os nodes na porta que devem apontar para o service normal que é do tipo ClusterIP.
Para acessar a aplicação precisamos digitar o IP de algum dos nodes do Kubernetes e a porta. Poderia ser o IP de qualquer node.
Se o tráfego aumentar o número de pods podemos aumentar o número de réplicas e o service se encarregará de dividir o tráfego entre os pods.
Mas não queremos que o usuário digite o endereço utilizando o IP e a porta dos nossos nodes. Como só podemos usar portas altas no NodePort o que poderíamos fazer para ter algo do tipo http://app.com?
Poderíamos fazer um proxy. Um servidor que escutasse esse endereço na porta 80 que o usuário não precisasse digitar e encaminhasse para app.com:30080
Mas esse cenário é aquele que você tem o cluster hospedado no seu datacenter.
No caso de um cluster hospedado em uma cloud por exemplo, poderíamos criar o service que é do tipo NodePort como sendo LoadBalancer.
Quando fazemos isso em uma cloud, automaticamente os serviços da cloud cria um load balancer que será usado para roteador todo o tráfego para o seu cluster na nodeport que você definiu.
Se você criar um outro aplicativo e definir novamente um service do tipo LoadBalancer, outro load balancer será criado na cloud apontando para um novo nodeport. E no fim você irá pagar horrores.
Para resolver esse cenário poderíamos ter uma única aplicação dentro do nosso cluster que atua como um proxy reverso. Analisa a url e encaminha para o service correto. Dessa forma iriamos ter somente um load balancer na cloud.
Ao invés de configuramos essa aplicação manualmente o ingress é um objeto que configura isso para nós de forma que seja um objeto no kubernetes.
É necessário deployar uma solução para ser o proxy reverso. Podemos usar vários, mas algumas estão aqui.
- Nginx (É o mais popular)
- Istio
- Traefik
- HAProxy
Esses controllers são programados para monitorar o kubernetes em busca dos objetos ingress para configurar suas entradas.
Se você não tiver uma dessas aplicações no seu cluster um objeto de ingress não irá funcionar.
O que estamos fazendo, é trazer um proxy para dentro do kubernetes e criar objetos que configurem o mesmo de forma fácil. Ter um ponto de entrada que possa ser filtrado e disparado para qual service deve responder.
Vamos nos concentrar no nginx ingress controller que é o mais famoso. Como deployar o nginx?
Normalmente utilizaríamos o helm para isso, mas vamos da maneira tradicional.
A primeira coisa que precisamos é ter um configmap que terá todos os parâmetros afim de evitar passar todos os args no deployment. Também fica mais fácil de fazer modificações.
Um resumo do que precisaríamos.

Uma vez configurado precisamos dos objetos do ingress.
O objeto se resume em algo bem simples.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: meu-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
# O nome do ingress class que vamos usar
ingressClassName: nginx
# A lista de regras que vamos passar
rules: []
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-app
spec:
rules:
# Neste caso estamos analisando também o domínio.
- host: "app.meusite.com"
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: service-app1
port:
number: 8080 # Porta do service que irá redirecionar para a porta do app.
# aqui estamos analisando somente o do caminho da url passada sem se importar qual o domínio.
- http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: service-app2
port:
number: 8080 # Porta do service que irá redirecionar para a porta do app.
# Aqui seria uma ideia de que se a primeira regra não for resolvida, passamos para a segunda. Ótima para colocar algo para responder caso a url não exista como um error 404.
- host: "*.foo.com"
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: service-404
port:
number: 8989
A ordem da regra importa.
Também poderíamos dividir isso em vários ingresses separados, que seria boa prática.