
Kubernetes m’offre pas de service de balance de charge (load balancer externe au réseau K8s) pour plusieurs applications partagent le même point d’entrée (Une seule adresse IP/mêmePort).
La raison étant que ces services sont habituellement intégrés aux systèmes des fournisseurs Infonuagique; Google Cloud, Azure, AWS, …
En labo, nous avons utilisé le tunnel de minikube ou bien celui de Docker Desktop/K8s comme solution externe.
Pour le déploiement natif d’un amas K8S, il faut se rabattre sur des solutions tiers.
Par exemple, metallb, traefik proxy, …
2.1 –
# Sur le cluster K8S suivant: alain@k8s01:~$ kubectl get nodes NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP k8s01 Ready control-plane 155d v1.25.3 192.168.2.51 <none> k8s02 Ready worker 155d v1.25.3 192.168.2.52 <none> k8s03 Ready worker 155d v1.25.3 192.168.2.53 <none> k8s04 Ready worker 155d v1.25.3 192.168.2.54 <none> k8s05 Ready worker 155d v1.25.3 192.168.2.55 <none> # --------------------------------------------------------- # Installer metallb (LoadBalancer externe) alain@k8s01:~$ kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.13.9/config/manifests/metallb-native.yaml # Résultat: namespace/metallb-system created customresourcedefinition.apiextensions.k8s.io/addresspools.metallb.io created customresourcedefinition.apiextensions.k8s.io/bfdprofiles.metallb.io created customresourcedefinition.apiextensions.k8s.io/bgpadvertisements.metallb.io created customresourcedefinition.apiextensions.k8s.io/bgppeers.metallb.io created customresourcedefinition.apiextensions.k8s.io/communities.metallb.io created customresourcedefinition.apiextensions.k8s.io/ipaddresspools.metallb.io created customresourcedefinition.apiextensions.k8s.io/l2advertisements.metallb.io created serviceaccount/controller created serviceaccount/speaker created role.rbac.authorization.k8s.io/controller created role.rbac.authorization.k8s.io/pod-lister created clusterrole.rbac.authorization.k8s.io/metallb-system:controller created clusterrole.rbac.authorization.k8s.io/metallb-system:speaker created rolebinding.rbac.authorization.k8s.io/controller created rolebinding.rbac.authorization.k8s.io/pod-lister created clusterrolebinding.rbac.authorization.k8s.io/metallb-system:controller created clusterrolebinding.rbac.authorization.k8s.io/metallb-system:speaker created secret/webhook-server-cert created service/webhook-service created deployment.apps/controller created daemonset.apps/speaker created validatingwebhookconfiguration.admissionregistration.k8s.io/metallb-webhook-configuration created # --------------------------------------------------------- # Afficher les ressources de l'espace de nom du LB alain@k8s01:~$ k get all -n metallb-system -o wide NAME READY STATUS RESTARTS AGE IP NODE pod/controller-844979dcdc-64nms 1/1 Running 0 5m46s 10.244.77.5 k8s04 pod/speaker-7r8bw 1/1 Running 0 5m46s 192.168.2.55 k8s05 pod/speaker-8n5x5 1/1 Running 0 5m46s 192.168.2.52 k8s02 pod/speaker-md92s 1/1 Running 0 5m45s 192.168.2.53 k8s03 pod/speaker-rb4wh 1/1 Running 0 5m45s 192.168.2.54 k8s04 pod/speaker-sth9t 1/1 Running 0 5m46s 192.168.2.51 k8s01 NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR service/webhook-service ClusterIP 10.103.93.242 <none> 443/TCP 6m10s component=controller NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE CONTAINERS IMAGES SELECTOR daemonset.apps/speaker 5 5 5 5 5 kubernetes.io/os=linux 6m10s speaker quay.io/metallb/speaker:v0.13.9 app=metallb,component=speaker NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR deployment.apps/controller 1/1 1 1 6m10s controller quay.io/metallb/controller:v0.13.9 app=metallb,component=controller NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR replicaset.apps/controller-844979dcdc 1 1 1 5m46s controller quay.io/metallb/controller:v0.13.9 app=metallb,component=controller,pod-template-hash=844979dcdc
2.2 – Renseigner la plage IP
nano metallb-config.yaml
2.2.1 – Coller le manifeste suivant et sauvegarder:
NOTE: Pour la plage d’adresses, il faut utiliser les IP disponibles dans le laboratoire.
apiVersion: metallb.io/v1beta1 kind: IPAddressPool metadata: name: first-pool namespace: metallb-system spec: addresses: - 192.168.2.60-192.168.2.69 --- apiVersion: metallb.io/v1beta1 kind: L2Advertisement metadata: name: example namespace: metallb-system
2.2.2 – Appliquer le manifeste:
kubectl apply -f Metallb-config.yaml
3.1 – Déploiement d’un service ingress de type Nginx:
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.7.0/deploy/static/provider/cloud/deploy.yaml # --------------------------------------------------------- # Résultat: namespace/ingress-nginx created serviceaccount/ingress-nginx created serviceaccount/ingress-nginx-admission created role.rbac.authorization.k8s.io/ingress-nginx created role.rbac.authorization.k8s.io/ingress-nginx-admission created clusterrole.rbac.authorization.k8s.io/ingress-nginx created clusterrole.rbac.authorization.k8s.io/ingress-nginx-admission created rolebinding.rbac.authorization.k8s.io/ingress-nginx created rolebinding.rbac.authorization.k8s.io/ingress-nginx-admission created clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx created clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx-admission created configmap/ingress-nginx-controller created service/ingress-nginx-controller created service/ingress-nginx-controller-admission created deployment.apps/ingress-nginx-controller created job.batch/ingress-nginx-admission-create created job.batch/ingress-nginx-admission-patch created ingressclass.networking.k8s.io/nginx created validatingwebhookconfiguration.admissionregistration.k8s.io/ingress-nginx-admission created # --------------------------------------------------------- # Résultat: alain@k8s01:~$ k get all -n ingress-nginx NAME READY STATUS RESTARTS AGE pod/ingress-nginx-admission-create-57dl4 0/1 Completed 0 6m38s pod/ingress-nginx-admission-patch-phpss 0/1 Completed 0 6m38s pod/ingress-nginx-controller-7d9674b7cf-2dbrg 1/1 Running 0 6m38s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/ingress-nginx-controller LoadBalancer 10.109.153.164 192.168.2.61 80:32524/TCP,443:31844/TCP 6m39s service/ingress-nginx-controller-admission ClusterIP 10.99.155.93 <none> 443/TCP 6m39s NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/ingress-nginx-controller 1/1 1 1 6m39s NAME DESIRED CURRENT READY AGE replicaset.apps/ingress-nginx-controller-7d9674b7cf 1 1 1 6m38s NAME COMPLETIONS DURATION AGE job.batch/ingress-nginx-admission-create 1/1 5s 6m38s job.batch/ingress-nginx-admission-patch 1/1 5s 6m38s # --------------------------------------------------------- # Résultat: alain@k8s01:~/kubernetes/yamls$ kubectl get all -n kube-system NAME READY STATUS RESTARTS AGE pod/kube-proxy-486bn 1/1 Running 2 (26h ago) 156d pod/kube-proxy-49sgw 1/1 Running 2 (26h ago) 156d pod/kube-proxy-rvs7t 1/1 Running 2 (26h ago) 156d pod/kube-proxy-x6c6n 1/1 Running 2 (26h ago) 156d NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 156d NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE daemonset.apps/kube-proxy 4 4 4 4 4 kubernetes.io/os=linux 156d
Il y a maintenant un service de type LoadBalancer qui roule et qui a obtenu une adresse IP (192.168.2.61) de MetalLB:
service/ingress-nginx-controller LoadBalancer 10.98.108.0 192.168.2.61 80:30517/TCP,443:31700/TCP
Il est maintenant possible d’avoir accès au réseau k8s via cette adresse IP:

Note: Nous obtenons une erreur 404 car il n’y a pas encore de routes de définies. Par contre, cette réponse nous indique qu’il y a un service HTTP à l’entrée.
3.2 – Déployer un service Web (superMinou)
https://medium.com/ci-cd-devops/internal-error-occurred-failed-calling-webhook-validate-nginx-ingress-kubernetes-io-b5008e628e03
# Modifié pour la demo ingress
apiVersion: apps/v1
kind: Deployment
metadata:
name: superminou
labels:
app: un-superminou
spec:
replicas: 5
selector:
matchLabels:
mon-app: un-superminou
template:
metadata:
labels:
mon-app: un-superminou
spec:
containers:
- name: nginx
image: alainboudreault/superminou:latest
imagePullPolicy: Always
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: superminou-service
spec:
selector:
mon-app: un-superminou
# type: par defaut = ClusterIP, ce qui est requis pour le service ingress
ports:
- protocol: TCP
port: 80
targetPort: 80
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
mon-app: un-superpitou
name: super-pitou
spec:
replicas: 3
selector:
matchLabels:
mon-app: un-superpitou
template:
metadata:
labels:
mon-app: un-superpitou
spec:
volumes:
- name: webdata
emptyDir: {}
initContainers:
- name: web-content
image: busybox
volumeMounts:
- name: webdata
mountPath: "/webdata"
command: ["/bin/sh", "-c", 'echo "<h1>Je suis un super <font color=blue>PITOU</font></h1><hr/><h2>Servi par: <?php echo gethostname(); ?></h2>" > /webdata/index.php']
containers:
- image: php:8.0.3-apache-buster
name: php-apache
volumeMounts:
- name: webdata
mountPath: "/var/www/html"
---
apiVersion: v1
kind: Service
metadata:
name: superpitou-service
spec:
selector:
mon-app: un-superpitou
# type: par defaut = ClusterIP, ce qui est requis pour le service ingress
ports:
- protocol: TCP
port: 80
targetPort: 80
3.x – Fichier : ingress-demo.yml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-demo01
spec:
ingressClassName: nginx
rules:
- host: superminou.demo
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: superminou-service
port:
number: 80
- host: superpitou.demo
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: superpitou-service
port:
number: 80
$ k apply -f ingress-demo.yml
# -----------------------------------------------------------
$ k get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
ingress-demo01 nginx superminou.demo,superpitou.demo 192.168.2.61 80 106m
# -----------------------------------------------------------
$ k describe ingress ingress-demo01
Name: ingress-demo01
Labels: <none>
Namespace: default
Address: 192.168.2.61
Ingress Class: nginx
Default backend: <default>
Rules:
Host Path Backends
---- ---- --------
superminou.demo
/ superminou-service:80 (10.244.235.154:80,10.244.235.157:80,10.244.236.150:80 + 2 more...)
superpitou.demo
/ superpitou-service:80 (10.244.235.149:80,10.244.236.152:80,10.244.77.42:80)
Annotations: <none>
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Sync 13m (x7 over 107m) nginx-ingress-controller Scheduled for sync
3.x – Fichier /etc/hosts
192.168.2.61 superminou.demo superpitou.demo
3.x – Tester l’ingress (reverse proxy)

