Kubernetes: Nginx Ingress Controller setup

Ismael Chasco

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) o con servicios adicionales en bare-metal. 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 quieren 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 ingressesNAME      HOSTS       ADDRESS         PORTS   AGE
ingress test.info 130.211.49.70 80 91m
kubectl -n production get svcNAME 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 podsNAME 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.


Originally published at blog.ichasco.com.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade