Ingres

Ingres

Ingres ayuda a exponer un servicio de una manera mas sencilla para el cliente, es decir hasta ahora el cliente para acceder a un servicio del cluster, tenia que acceder a un puerto expuesto por nodeport que son del 30000-32767 o desde un Loadbalancer en aws o google cloud, lo malo de este ultimo que por cada puerto se abre un loadbalancer.

Ingres proporciona un método de con un solo puerto abierto exponer todas aplicaciones del cluster ( hace como de proxy ). configurando unas reglas tipo ruta o subdominio te redirige a una aplicación u otra.

Ejemplo de tipo reglas:

  • ruta: miapp.org/, miapp.org/nextcloud, miapp.org/ldap
  • subdominio: miapp.org, nextcloud.miapp.org, ldap.miapp.org
  • También admite ambas a la vez.

Ingres controller es el controlador que proporciona kubernetes para hacer su magia, da dos opciones nginx-controler y balanceadores de google cloud. Este es un deployment en el cluster que se encarga de leer las reglas de Ingres y exponerlas en el cluster o en el cloud según definamos.

instación del controlador

Nginx-controler

Si no queremos exponer el cluster a google cloud, aws o alguna plataforma externa nginx-controler es la opción perfecta para gestionar las apps de nuestro cluster desde un solo puerto. ( bueno dos puertos http y https )

nginx ya proporciona un yaml para la instalación del controler en nuestro cluster kubernetes, donde simplemente desplegando-lo se genera todo lo necesario.

https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/provider/baremetal/deploy.yaml

De todo lo que despliega, lo que realmente nos interesa es el objeto service ingress-nxinx-controller. este es el servicio que expone en nuestro cluster los puertos en modo nodePort desde donde conectaremos al interior del cluster.

# Source: ingress-nginx/templates/controller-service.yaml
apiVersion: v1
kind: Service
metadata:
  labels:
    helm.sh/chart: ingress-nginx-2.0.0
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/version: 0.30.0
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/component: controller
  name: ingress-nginx-controller
  namespace: ingress-nginx
spec:
  type: NodePort
  ports:
    - name: http
      port: 80
      protocol: TCP
      targetPort: http
    - name: https
      port: 443
      protocol: TCP
      targetPort: https
  selector:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/component: controller

Instalación y comprobación

La instalación genera diferentes objetos que se despliegan en el namespace ingress-nxinx.

➜ kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/provider/baremetal/deploy.yaml
namespace/ingress-nginx created
serviceaccount/ingress-nginx created
configmap/ingress-nginx-controller created
clusterrole.rbac.authorization.k8s.io/ingress-nginx created
clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx created
role.rbac.authorization.k8s.io/ingress-nginx created
rolebinding.rbac.authorization.k8s.io/ingress-nginx created
service/ingress-nginx-controller-admission created
service/ingress-nginx-controller created
deployment.apps/ingress-nginx-controller created
validatingwebhookconfiguration.admissionregistration.k8s.io/ingress-nginx-admission created
clusterrole.rbac.authorization.k8s.io/ingress-nginx-admission created
clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx-admission created
job.batch/ingress-nginx-admission-create created
job.batch/ingress-nginx-admission-patch created
role.rbac.authorization.k8s.io/ingress-nginx-admission created
rolebinding.rbac.authorization.k8s.io/ingress-nginx-admission created
serviceaccount/ingress-nginx-admission created

# compruevo que nxinx-controles se a puesto en marcha
➜ kubectl get pods -n ingress-nginx
NAME                                        READY   STATUS      RESTARTS   AGE
ingress-nginx-admission-create-zrdlr        0/1     Completed   0          2m31s
ingress-nginx-admission-patch-gcj9f         0/1     Completed   0          2m31s
ingress-nginx-controller-76679bcc4b-qgg4d   1/1     Running     0          2m41s

# tengo un nuevo servicio nginx-controler
➜ kubectl get svc -n ingress-nginx
NAME                                 TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)                      AGE
ingress-nginx-controller             NodePort    10.110.18.92   <none>        80:32698/TCP,443:31579/TCP   6m55s
ingress-nginx-controller-admission   ClusterIP   10.111.14.17   <none>        443/TCP                      6m55s

Para hacer los ejemplos de tipos de reglas de ingres utilizo el siguiente deployment y servicio, es un deployment que despliega pods nginx que en su index muestran el hostname del pod, el servicio balancea las ip de los pods a la ip del servicio en el puerto 8080.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-nginx
  labels:
    app: front
spec:
  replicas: 3
  selector:
    matchLabels:
      app: front
  template:
    metadata:
      labels:
        app: front
    spec:
      containers:
      - name: nginx
        image: nginx:alpine
        command: ["sh", "-c", "echo VERSION 1.0 desde $HOSTNAME > /usr/share/nginx/html/index.html && nginx -g 'daemon off;'"]
---
apiVersion: v1
kind: Service
metadata:
  name: app-nginx-v1
  labels:
    app: front
spec:
  type: ClusterIP
  selector:
    app: front
  ports:
    - protocol: TCP
      port: 8080
      targetPort: 80

Tipo ruta

Los ingres de tipo ruta, se especifica una ruta de entrada tipo 192.168.88.2/appv1 y el servicio donde se redirige dicha petición.

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: test-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - http:
      paths:
      - path: /appv1
        backend:
          serviceName: app-nginx-v1
          servicePort: 8080

Si despliego la app nginx solo tengo conexion dentro del cluster gracias al servicio app-nxinx-v1 que esta en modo clusterIP

# deplegar app nginx con su servicio
➜ kubectl apply -f ingres/app-ingres-example.yml 
deployment.apps/app-nginx created
service/app-nginx-v1 created

# veo la ip que a creado dentro del cluster y que expone el puerto 8080
➜ kubectl get svc
NAME           TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
app-nginx-v1   ClusterIP   10.98.154.19   <none>        8080/TCP   7m53s
kubernetes     ClusterIP   10.96.0.1      <none>        443/TCP    67d

# los pods funcionan correctamente
➜ kubectl get pods
NAME                         READY   STATUS    RESTARTS   AGE
app-nginx-5fddd97c47-kgk2b   1/1     Running   0          2m44s
app-nginx-5fddd97c47-tc8g2   1/1     Running   0          2m44s
app-nginx-5fddd97c47-zbrkl   1/1     Running   0          2m44s

# y desde dentro del cluster puedo hacer peticiones
➜ curl 10.98.154.19:8080                         
VERSION 1.0 desde app-nginx-5fddd97c47-kgk2b
Ahora toca aplicar las reglas del ingres, ya teniendo corriendo el nginx-controler simplemente añadiendo el objeto ingres, nginx-controler ya lo detecta y esta vlisto para aplicar sus reglas.

# miro que el controles esta en marcha y exponiendo puertos 80:32698/TCP,443:31579
➜ kubectl get svc -n ingress-nginx
NAME                                 TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)                      AGE
ingress-nginx-controller             NodePort    10.110.18.92   <none>        80:32698/TCP,443:31579/TCP   38m
ingress-nginx-controller-admission   ClusterIP   10.111.14.17   <none>        443/TCP                      38m

# espliego reglas de ingres
➜ kubectl apply -f ingres/ingres-rules.yml
ingress.networking.k8s.io/test-ingress configured

# desde la ip del cluster compruebo
➜ curl 192.168.88.2:32698/appv1
VERSION 1.0 desde app-nginx-5fddd97c47-kgk2b

nota: Hay que tener en cuenta que el servicio nginx-controler esta en modo nodePort y solo exporta a puertos de 30000-32767 de forma dinamica, si queremos cambiar esto, se tendra que modificar el servicio nginx-controler.

Tipo dominio

Igual que podemos indicar una ruta para redirigir a una app, también podemos especificar un dominio o subdominio tipo nginx.mydomain.org, nextcloud.mydomain.org, ...

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: test-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - http:
      paths:
      - path: /appv1
        backend:
          serviceName: app-nginx-v1
          servicePort: 8080
  - host: mydomain.org
    http:
      paths:
      - path: /
        backend:
          serviceName: app-nginx-v1
          servicePort: 8080

Una vez desplegado en el cluster la regla, desde un host externo compruebo el resultado.

# añado la resolución del dominio manualmente al no utilizar dns
[jorge@pc03 ~]$ sudo vim /etc/hosts

# desde un host externo accedo al cluster por el dominio indicado.
[jorge@pc03 ~]$ curl mydomain.org:32698
VERSION 1.0 desde app-nginx-5fddd97c47-tc8g2

TLS

Tls junto a ingres permite que la entrada al cluster por el proxy de ingres se hagan cifradas, en el siguiente ejemplo se muestra como añadir unas claves auto-firmadas a un objeto ingres.

Crear claves y crear secret:

➜ openssl genrsa -out clusterkey.pem
➜ openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout clusterkey.pem -out clustercrt.pem -subj "/CN=mydomain.org/O=mydomain.org"

# crear secret
➜ kubectl create secret tls cert-cluster --key clusterkey.pem --cert clustercrt.pem

También se puede añadir con un template

apiVersion: v1
kind: Secret
metadata:
  name: cert-cluster
  namespace: default
data:
  tls.crt: base64 encoded cert
  tls.key: base64 encoded key
type: kubernetes.io/tls

En el objeto ingres se añade la sección tls con la entrada y el certificado que utilizar

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: test-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  tls:
    - hosts:
      - nextcloud.mydomain.org
      secretName: cert-cluster
  rules:
  - host: nginx.mydomain.org
    http:
      paths:
      - path: /
        backend:
          serviceName: app-nginx
          servicePort: 8080
  - host: nextcloud.mydomain.org
    http:
      paths:
      - path: /
        backend:
          serviceName: nextcloud
          servicePort: 8080