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.
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
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 modonodePort
y solo exporta a puertos de30000-32767
de forma dinamica, si queremos cambiar esto, se tendra que modificar el servicionginx-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