Reverse Proxy¶
Since we only have a single public IPv4, if we want to set up multiple public services we will need a reverse proxy to redirect the requests to the correct services. Our proxy will also handle the ssl termination, to simplify the set up of the services.
For managing our certificates we will be using cert-manager and as a proxy we
will be using Traefik.
Note
Traefik is the default proxy from k3s, but to have more granular control we are disabling it and we are going to deploy it as Helm chart
Traefik¶
Similarly, to deploy Traefik we have to execute:
kubectl create namespace proxy
helm repo add traefik https://helm.traefik.io/traefik
helm repo update
helm install -n proxy traefik traefik/traefik -f traefik-values.yaml --version 40.0.0
Note
In the logs we might have a warning and we might have to increase the rmeem_max
ansible all -b -m shell -a "sysctl -w net.core.rmem_max=2500000". To retrieve
the logs do kubectl -n proxy logs -f -l "app.kubernetes.io/name=traefik"
# https://github.com/traefik/traefik-helm-chart/blob/master/traefik/values.yaml
image:
#tag: "v2.11.0"
pullPolicy: IfNotPresent
deployment:
enabled: true
kind: Deployment
replicas: 2
ingressClass:
# needed from cert-manager to create certificates
enabled: true
isDefaultClass: false
# We will create our IngressRoute for the dashboard
ingressRoute:
dashboard:
enabled: false
providers:
kubernetesCRD:
enabled: true
allowCrossNamespace: true
allowExternalNameServices: true
kubernetesIngress:
enabled: true
allowExternalNameServices: true
kubernetesGateway:
enabled: false
# This option currently enables support for TCPRoute and TLSRoute.
experimentalChannel: false
gatewayClass: # @schema additionalProperties: false
name: "default"
gateway:
# Do not enable for the moment since we are not using it
enable: false
# This gateway will be mainly be used from cert-manager
# to create certificates for the other gateways
name: "default-gateway"
annotations:
cert-manager.io/issuer: selfsigned-issuer
external-dns.alpha.kubernetes.io/target: zh.anagno.dev
listeners:
web:
protocol: HTTP
port: 80
namespacePolicy:
from: All
# We can not activate by default the https in the default
# because we need to have certificates defined
# So we activate the HTTP, to be able to get certificates
# with let`s encrypt and then we can define new gateways
# specific to the domains we are interested
# websecure:
# protocol: HTTPS
# namespacePolicy:
# from: All
# certificateRefs:
# mode: "Terminate"
logs:
general:
level: INFO
format: json
access:
enabled: true
format: json
metrics:
prometheus:
entryPoint: metrics
addEntryPointsLabels: true
addRoutersLabels: true
addServicesLabels: true
manualRouting: false
service:
enabled: false
ports:
web:
port: 80
expose:
default: true
ipv6-1: true
ipv6-2: true
allowACMEByPass: true
http:
redirections:
entryPoint:
to: websecure
scheme: https
websecure:
port: 443
expose:
default: true
ipv6-1: true
ipv6-2: true
http3:
enabled: true
metrics:
# It has to be the same with the traefik-dashboard-service.yaml in monitoring
port: 9100
service:
enabled: true
type: LoadBalancer
spec:
# https://metallb.io/usage/#cluster-traffic-policy
externalTrafficPolicy: Local
annotations:
metallb.io/loadBalancerIPs: "192.168.142.240,fd93:142::240"
ipFamilyPolicy: RequireDualStack
additionalServices:
ipv6-1:
# https://github.com/traefik/traefik-helm-chart/issues/1233#issuecomment-2435187894
single: true
type: LoadBalancer
spec:
# https://metallb.io/usage/#cluster-traffic-policy
externalTrafficPolicy: Local
annotations:
metallb.io/loadBalancerIPs: "2a02:169:3af:7::240"
ipFamilies: [ "IPv6" ]
ipv6-2:
single: true
type: LoadBalancer
spec:
# https://metallb.io/usage/#cluster-traffic-policy
externalTrafficPolicy: Local
annotations:
metallb.io/loadBalancerIPs: "2a02:169:3af:6::240"
ipFamilies: [ "IPv6" ]
resources:
requests:
cpu: "250m"
memory: "100Mi"
autoscaling:
enabled: true
minReplicas: 1
maxReplicas: 5
Now that our proxy is running we can define some Middlewares to simplify the deployment of services:
kubectl apply -f security_headers.yaml
Traefik will be my main proxy that will forward requests to other services. So we also deploy these requirements:
kubectl apply -f grigoris_proxy.yaml
Cert-manager¶
Since we want high availability, we need also to handle our certificates in a way that can be hanlded from traefik. Traefik offers this support in the enteprise version, but since I am cheap, I will use an another manager (i.e. cert-manager)
kubectl create namespace cert-manager
helm repo add jetstack https://charts.jetstack.io
helm repo update
helm install cert-manager jetstack/cert-manager --namespace cert-manager -f cert-values.yaml --version v1.20.2
kubectl apply -f cert-vpa.yaml
With cert-values.yaml:
# https://github.com/jetstack/cert-manager/blob/master/deploy/charts/cert-manager/values.yaml
crds:
enabled: true
replicaCount: 1
enableCertificateOwnerRef: true
#https://github.com/jetstack/cert-manager/issues/959
podDnsPolicy: "Default"
serviceIPFamilyPolicy: "RequireDualStack"
webhook:
serviceIPFamilyPolicy: "RequireDualStack"
prometheus:
enabled: true
servicemonitor:
enabled: true
Note
Initially the prometheus monitoring should not be activate until we deploy the monitoring stack. Afterwards we can activate it.
Now that the cert-manager is running we can create our certificate issuers:
kubectl apply -f self_signed.yaml
kubectl apply -f letenrcypt_stagging.yaml
kubectl apply -f letenrcypt.yaml
kubectl apply -f traefik-dashboard.yaml
Testing that everything works¶
To test that everything works, we can deploy a testing whoami service:
kubectl apply -f whoami.yaml
# Check that everything works and the delete the service
kubectl delete -f whoami.yaml
# Forcing renew. Good practice when updating the cert-manager to make sure that
# everything still works
kubectl cert-manager status certificate test.anagno.dev -n general
kubectl cert-manager renew test.anagno.dev -n authentication
Gateway API vs Ingress¶
The Gateway API is the next generation of Kubernetes Ingress and it was investigate to see if it should be used in the deployment of the services. From the experimentations I did unfortunatelly, it did not fit yet my uses cases (see gateway_api folder).
The main problem I faced was that for each Gateway I could only have a single certificate to decrypt the HTTPS traffic. That means that I would need to either setup * DNS01 resolver for cert-manager * or use supbaths.
The DNS resolver would introduce that I would have an extra service like cloudflare or depend on obsolete plugins of cert-manager. Both not ideal for the moment.
The subpaths could lead to complexities with the deployed services. Although most services, have the possibility to adapt the subpath, some might expect to be on the root of the domain name.
Alternative for each subdomain I could create a new Gateway Kubernetes Object, but that result in more complicated setups.
In the future there might be better support of my uses and it might be worth it switching to it.
The problems I faced:
-
Each Gateway can have only one certificate to decrypt the HTTPS traffik. Pontial solutions for this are:
- https://github.com/kubernetes-sigs/gateway-api/issues/3249
- https://github.com/kubernetes-sigs/gateway-api/issues/2111
- https://github.com/kubernetes-sigs/gateway-api/discussions/3418
- https://gateway-api.sigs.k8s.io/geps/gep-1713/
- https://github.com/kubernetes-sigs/gateway-api/issues/1713
The most promising solution probably is the ListenerSets, but that is not still
supported in Traefik.
* The TLSRoute does not support externalName services. The TLSRoute will be used in grigoris_proxy
-
The Middlewares of traefik can not still be defined in the Gateway API. So we still need the specific CDRs from Traefik. Pontential solution for this one is:
- https://gateway-api.sigs.k8s.io/geps/gep-1767/
-
The authentik has only experimental support for the Gateway API
Since there no plan yet to deprecate the Ingress API, I will remain for the moment with the Ingress API logic
Resources:
- https://medium.com/dev-genius/setup-traefik-v2-for-ha-on-kubernetes-20311204fa6f
- https://traefik.io/blog/install-and-configure-traefik-with-helm/
- https://kubernetes.github.io/ingress-nginx/deploy/baremetal/
- https://www.thebookofjoel.com/k3s-cert-manager-letsencrypt
- https://cert-manager.io/docs/usage/kubectl-plugin/