Buenas!! Siguiendo con los posts de Kubernetes, hoy hablaremos de como crear un Ingress Controller y para que sirve.
Un ingress controler, es un servicio que se encarga de gestionar las peticiones que llegan desde fuera y redirigirlas al contenedor adecuado. Para hacer esto, cuenta con varios elementos. Ingress, LoadBalancer Service (puede ser NodePort) y un POD de controller (en este caso utilizaremos Nginx Ingress Controller). Para los controllers, hay diferentes herramientas como; Traefik, Istio, HAproxy…
Una comparación entre los diferentes Ingress Controllers:
https://docs.google.com/spreadsheets/d/16bxRgpO1H_Bn-5xVZ1WrR_I-0A-GOI6egmhvqqLMOmg/edit#gid=1612037324
Como podemos ver en la imagen, el workflow es el siguiente: Se despliega un servicio que es de tipo LoadBalancer(1) en Kubernetes, que crea un Balanceador en el proveedor cloud con los puertos que se le hayan indicado, en este caso el 80. Luego se despliega el Nginx Ingress Controller(2) que será el que se encargue de recepcionar las requests y consultar al Ingress (3) donde están definidas las rutas y la lógica para enviárselas a los servicios(4) y estos a sus contenedores(5) correspondientes.
Let’s Go
Para ver esto un poco mas a fondo, vamos a basarnos en el ejemplo que usamos en el anterior post y vamos a añadirle la parte del Ingress.
LoadBalancer Service
Como hemos dicho, este servicio solo se puede utilizar con proveedores de cloud (AWS, GCP, Azure). No es un servicio obligatorio ya que se puede sustituir por NodePort.
92-ingress-service.yaml
---
kind: Service
apiVersion: v1
metadata:
name: ingress-nginx
namespace: production
spec:
type: LoadBalancer
selector:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
ports:
- name: http
port: 80
targetPort: http
- name: https
port: 443
targetPort: http
Nginx Controller RBAC
Para que el Nginx Controller pueda funcionar correctamente, hay que darle permisos tanto a nivel de namespace como a nivel de cluster. Para esto, están los Roles y los ClusterRoles. A estos se les da una serie de permisos y luego se vinculan a una ServiceAccount que se le añadirá al POD. No vamos a entrar en profundidad en esto por que lo explicaré mejor en el siguiente post.
Más info: https://kubernetes.github.io/ingress-nginx/deploy/rbac/
90-ingress-rbac.yaml
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: nginx-ingress-serviceaccount
namespace: production
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
name: nginx-ingress-clusterrole
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
rules:
- apiGroups:
- ""
resources:
- configmaps
- endpoints
- nodes
- pods
- secrets
verbs:
- list
- watch
- apiGroups:
- ""
resources:
- nodes
verbs:
- get
- apiGroups:
- ""
resources:
- services
verbs:
- get
- list
- watch
- apiGroups:
- "extensions"
resources:
- ingresses
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- events
verbs:
- create
- patch
- apiGroups:
- "extensions"
resources:
- ingresses/status
verbs:
- update
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: Role
metadata:
name: nginx-ingress-role
namespace: production
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
rules:
- apiGroups:
- ""
resources:
- configmaps
- pods
- secrets
- namespaces
verbs:
- get
- apiGroups:
- ""
resources:
- configmaps
resourceNames:
- "ingress-controller-leader-nginx"
verbs:
- get
- update
- apiGroups:
- ""
resources:
- configmaps
verbs:
- create
- apiGroups:
- ""
resources:
- endpoints
verbs:
- get
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: RoleBinding
metadata:
name: nginx-ingress-role-nisa-binding
namespace: production
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: nginx-ingress-role
subjects:
- kind: ServiceAccount
name: nginx-ingress-serviceaccount
namespace: production
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: nginx-ingress-clusterrole-production-binding
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: nginx-ingress-clusterrole
subjects:
- kind: ServiceAccount
name: nginx-ingress-serviceaccount
namespace: production
Nginx Ingress Controller
Este será el que se encargue de gestionar las redirecciones del tráfico. Lo que hace es leer del Ingress y actuar como proxy aplicando la lógica definida.
En este caso, se va a desplegar como Deployment, pero también se podría desplegar como un DaemonSet para que corra uno en cada nodo.
93-ingress-deployment.yaml
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: nginx-ingress-controller
namespace: production
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
template:
metadata:
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
spec:
serviceAccountName: nginx-ingress-serviceaccount
containers:
- name: nginx-ingress-controller
image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.24.1
args:
- /nginx-ingress-controller
- --configmap=$(POD_NAMESPACE)/nginx-configuration
- --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services
- --udp-services-configmap=$(POD_NAMESPACE)/udp-services
- --publish-service=$(POD_NAMESPACE)/ingress-nginx
- --annotations-prefix=nginx.ingress.kubernetes.io
- --force-namespace-isolation
- --watch-namespace=$(POD_NAMESPACE)
securityContext:
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE
runAsUser: 33
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
ports:
- name: http
containerPort: 80
- name: https
containerPort: 443
livenessProbe:
failureThreshold: 3
httpGet:
path: /healthz
port: 10254
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
readinessProbe:
failureThreshold: 3
httpGet:
path: /healthz
port: 10254
scheme: HTTP
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
Ingress
Por último, queda desplegar el Ingress. Aquí se definen las reglas que se quiere aplicar tanto por dominio como por path. Por defecto, el Ingress se acopla a todos los Controllers, se puede gestionar para que no lo haga a todos mediante anotaciones.
https://kubernetes.github.io/ingress-nginx/user-guide/multiple-ingress/
91-ingress.yaml
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress
namespace: production
spec:
rules:
- host: test.info
http:
paths:
- path: /
backend:
serviceName: nginx
servicePort: 80
Nota: Si se quiere utilizar en Minikube, hay que realizar varios cambios.
https://medium.com/@Oskarr3/setting-up-ingress-on-minikube-6ae825e98f82
Revisión
Para terminar, vamos a comprobar que todo esté funcionando correctamente
kubectl -n production get ingresses
NAME HOSTS ADDRESS PORTS AGE
ingress test.info 130.211.49.70 80 91m
kubectl -n production get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx LoadBalancer 10.19.254.75 130.211.49.70 80:31426/TCP,443:30622/TCP 79m
mysql ClusterIP 10.19.245.211 <none> 3306/TCP 109m
nginx ClusterIP 10.19.254.100 <none> 80/TCP 109m
phpfpm ClusterIP 10.19.253.52 <none> 9000/TCP 109m
kubectl -n production get pods
NAME READY STATUS RESTARTS AGE
mysql-0 1/1 Running 0 18m
nginx-55bfcc5f59-tjnsq 1/1 Running 0 19m
nginx-ingress-controller-6d676dc446-645rt 1/1 Running 2 14m
phpfpm-fd548b6d5-jxwtb 1/1 Running 0 19m
Y con esto ya tendríamos un Ingress controller despegado y funcionando. Solo quedaría crear un registro DNS apuntando a la IP pública del balanceador.
En los próximos posts, haremos algo parecido pero con Istio, certificados con Let’s Encrypt y más seguridad.
Also published on Medium.