4 - Registering a pod and routing with traefik
If you have control over your DHCP, you can install a metalLB (Load balancer) and attribut an available IP range. This would be the production stack in that case:
Internet → MetalLB (IP) → Traefik (routing) → Ingress → Service → Pod
Install metalLB in your kubernetes controler like this:
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.14.5/config/manifests/metallb-native.yaml
# Wait for it to be ready
kubectl wait --namespace metallb-system \
--for=condition=ready pod \
--selector=app=metallb \
--timeout=90sThen create the metalLb configuration
# /home/gitlabci/conf/metalLB/pool.yaml
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: lan-pool
namespace: metallb-system
spec:
addresses:
- 192.168.1.200-192.168.1.210 # ← pick free IPs on your LAN
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: l2-advert
namespace: metallb-system
spec:
ipAddressPools:
- lan-poolkubectl apply -f /home/gitlabci/conf/metalLB/pool.yamlFor our purpose we are doing this in a externally managed network so we’ll be using the node IPs. Our stack:
Internet → DNS (multiple node IPs) → Traefik DaemonSet → Ingress → Service → Pod
Pod and service registration
First lets create the pod and service for our hello-world app (an empty nginx container) Either manualy or with CI add this file in your controler server:
# /home/gitlabci/conf/websites/my-app.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: my-app
image: nginx:alpine
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: my-app-svc
namespace: default
spec:
selector:
app: my-app
ports:
- port: 80
targetPort: 80
type: ClusterIP kubectl apply -f /home/gitlabci/conf/websites/my-app.yamlTraefik
Install Traefik:
snap install helm --classic
helm repo add traefik https://helm.traefik.io/traefik
helm repo updatemetalLB will take care of the rest
helm install traefik traefik/traefik \
--namespace traefik \
--create-namespace \
--set service.type=LoadBalancer kubectl get svc -n traefikYou should see the TYPE LoadBalancer and your externalIPs listed there or
Create a values.yaml for Traefik with your real server IP(s): This configuration works with the traefik v40.2.0, sometimes major upgrades also require slightly different config formats
There are multiple options like choosing only one node to be responsible for the traefik for example but this creates a sigle failure point. With a LoadBalancer we could create a DaemonSet which will create a traefik node in every specified node then the load balancer would automatically forward to one of the nodes.
For ou situation withoutbthe loadBalancer we will still use the DeamonSet and the traffic will be forwarded depending on DNS settings
# /home/gitlabci/conf/traefik/values.yaml
deployment:
kind: DaemonSet
service:
spec:
type: ClusterIP
externalIPs:
- 10.95.35.4 # node-1
# - x.x.x.x # node-2
# add control plane IP here only if untainted
ports:
web:
port: 80
hostPort: 80
websecure:
port: 443
hostPort: 443
ingressClass:
enabled: true
isDefaultClass: trueinstall:
helm install traefik traefik/traefik \
--namespace traefik \
--create-namespace \
--values /home/gitlabci/conf/traefik/values.yamlverify:
kubectl get pods -n traefik
kubectl get svc -n traefik
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
# traefik ClusterIP 10.96.150.110 10.95.35.4 80/TCP,443/TCP 10sYou should see the TYPE clusterIP and your externalIPs listed there
Create Ingress
# /home/gitlabci/conf/ingress/my-app.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app-ingress
namespace: default
annotations:
traefik.ingress.kubernetes.io/router.entrypoints: web
spec:
ingressClassName: traefik
rules:
- host: ipese-test.epfl.ch # ← your domain
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-app-svc
port:
number: 80kubectl apply -f /home/gitlabci/conf/ingress/my-app.yaml$ curl http://ipese-test.epfl.ch
# <!DOCTYPE html>
# <html>
# <head>
# <title>Welcome to nginx!</title>
# <style>
# html { color-scheme: light dark; }
# body { width: 35em; margin: 0 auto;
# font-family: Tahoma, Verdana, Arial, sans-serif; }
# </style>
# </head>
# <body>
# <h1>Welcome to nginx!</h1>
# ...TLS — Manual Certificates
Create secrets with your crt and private key. In our case those files are saved at /home/gitlabci/conf/certs/ipese-test.epfl.ch.crt and /home/gitlabci/conf/certs/ipese-test.epfl.ch.key
kubectl create secret tls myapp-tls \
--cert=/home/gitlabci/conf/certs/ipese-test.epfl.ch.crt \
--key=/home/gitlabci/conf/certs/ipese-test.epfl.ch.key \
--namespace defaultRecrete the ingress with TLS
# /home/gitlabci/conf/ingress/my-app.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app-ingress
namespace: default
annotations:
traefik.ingress.kubernetes.io/router.entrypoints: websecure # web-> websecure
spec:
ingressClassName: traefik
tls: # Add TLS part
- hosts:
- ipese-test.epfl.ch # ← your domain
secretName: myapp-tls # ← matches the secret created above
rules:
- host: ipese-test.epfl.ch
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-app-svc
port:
number: 80kubectl apply -f /home/gitlabci/conf/ingress/my-app.yaml