Kubernetes series (Article 4): Deploying Traefik Ingress and cert-manager in Kubernetes
After completing the initial setup of my Kubernetes cluster, I needed an Ingress controller. Kubernetes doesn’t include an Ingress controller by default; it’s up to the user to choose and deploy one that best fits their use case.
Traefik
My main options were NGINX and Traefik, two of the most popular choices in the community. While NGINX is well-documented and widely adopted, I decided to go with Traefik, primarily because of my previous experience using it in Docker-based environments. You can read more about that in my Traefik with Docker article.
That familiarity, Traefik’s powerful dynamic configuration, native support for Let’s Encrypt, and integration with modern cloud-native tools made it the right choice for my Kubernetes setup.
That said, deploying Traefik in Kubernetes slightly differs from deploying it in Docker. It involves configuring it via Helm charts and managing its CRDs (Custom Resource Definitions), middleware, and routing rules.
Helm-Driven Deployment
Since we already installed Helm in the previous part of this series (Helm, MetalLB, and Longhorn article), I used Helm to deploy Traefik. This simplifies the installation and makes upgrading, configuring, and version controlling the deployment easier.
Managing SSL Certificates
To handle automatic TLS/SSL certificate provisioning, I integrated cert-manager, a native Kubernetes certificate management controller that works well with Traefik using ACME protocols like Let’s Encrypt. This setup allows me to automate the issuance and renewal of certificates for any domain exposed via my Ingress.
In this article, I’ll walk through:
- Installing Traefik via Helm
- Configuring it as the default Ingress controller
- Integrating cert-manager for SSL certificate management
Traefik Deployment in Kubernetes with cert-manager (Cloudflare DNS)
This guide documents deploying Traefik with HTTPS using cert-manager, Let’s Encrypt, and Cloudflare’s DNS for DNS-01 challenge validation.
Installation Steps
1. Install cert-manager CRDs
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.17.2/cert-manager.crds.yaml
Bash2. Add Jetstack Helm Repo
helm repo add jetstack https://charts.jetstack.io --force-update
helm repo update
Bash3. Create cert-manager-values.yaml
extraArgs:
- --dns01-recursive-nameservers-only
- --dns01-recursive-nameservers=8.8.8.8:53,1.1.1.1:53
- --dns01-check-retry-period=30s
resources:
requests:
cpu: 200m
memory: 256Mi
limits:
cpu: 2000m
memory: 1Gi
YAMLThe 30s retry delay resolves DNS propagation issues with Cloudflare.
4. Install or Upgrade cert-manager
helm install cert-manager jetstack/cert-manager \
--namespace cert-manager \
--create-namespace \
--version v1.17.2 \
-f cert-manager-values.yaml
# Or upgrade:
helm upgrade cert-manager jetstack/cert-manager \
-n cert-manager \
-f cert-manager-values.yaml
Bash5. Create Cloudflare API Token Secret
# cloudflare-api-token-secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: cloudflare-api-token
namespace: cert-manager
type: Opaque
stringData:
api-token: YOUR_CLOUDFLARE_API_TOKEN
YAMLApply it:
kubectl apply -f cloudflare-api-token-secret.yaml
BashCreate this before installing Traefik so it can use the token during certificate resolution.
DNS-01 Challenge with Cloudflare
ClusterIssuer (Staging)
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: cloudflare
spec:
acme:
server: https://acme-staging-v02.api.letsencrypt.org/directory
email: youremail
privateKeySecretRef:
name: cloudflare-key
solvers:
- dns01:
cloudflare:
apiTokenSecretRef:
name: cloudflare-api-token
key: api-token
YAMLApply it:
kubectl apply -f clusterissuer.yaml
kubectl describe clusterissuer cloudflare
BashTraefik Certificate (Staging)
staging-certificate-traefik.yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: traefik-cert
namespace: traefik
spec:
secretName: traefik-tls
commonName: yourdomain.uk
dnsNames:
- yourdomain.uk
- '*.yourdomain.uk'
issuerRef:
name: cloudflare
kind: ClusterIssuer
duration: 2160h # 90 days
renewBefore: 168h # 7 days
YAMLField | Description |
---|---|
secretName | Secret Traefik uses for TLS |
dnsNames | Includes base and wildcard domains |
issuerRef | Refers to the ClusterIssuer cloudflare |
duration | 90-day cert |
renewBefore | Auto-renew 7 days before expiry |
Switching to Production Certs
1. Create Production ClusterIssuer
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: cloudflare-prod
spec:
acme:
email: youremail
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: cloudflare-prod-key
solvers:
- dns01:
cloudflare:
apiTokenSecretRef:
name: cloudflare-api-token
key: api-token
YAMLApply:
kubectl apply -f clusterissuer-prod.yaml
Bash2. Update the Certificate
issuerRef:
name: cloudflare-prod
kind: ClusterIssuer
YAMLApply:
kubectl apply -f production-certificate.yaml
BashVerify:
kubectl describe certificate traefik-cert -n traefik
kubectl get secret traefik-tls -n traefik
BashInstall Traefik via Helm
helm repo add traefik https://traefik.github.io/charts
helm repo update
helm install traefik traefik/traefik \
--namespace traefik \
--create-namespace \
--values traefik-values.yaml
BashAdd to values.yaml
tlsStore:
default:
defaultCertificate:
secretName: traefik-tls
YAMLTraefik Dashboard IngressRoute
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: traefik-dashboard
namespace: traefik
spec:
entryPoints:
- websecure
routes:
- match: Host(`traefik.yourdomain.uk`) && (PathPrefix(`/dashboard`) || PathPrefix(`/api`))
kind: Rule
services:
- name: api@internal
kind: TraefikService
middlewares:
- name: dashboard-auth
tls:
secretName: traefik-tls
YAMLApply:
kubectl apply -f traefik-ingressroute.yaml
BashBasic Auth for Dashboard
1. Generate Credentials
htpasswd -nbB yourusername yourpassword
BashBase64 encode:
echo -n 'yourusername:<hashed-password>' | base64
Bash2. Create Secret
apiVersion: v1
kind: Secret
metadata:
name: authsecret2
namespace: traefik
type: Opaque
data:
users: <base64-output>
YAMLApply:
kubectl apply -f traefik-middleware-secret.yaml
Bash3. Create Middleware
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: dashboard-auth
namespace: traefik
spec:
basicAuth:
secret: authsecret2
realm: "Traefik Dashboard"
YAMLApply:
kubectl apply -f traefik-middleware.yaml
BashMaintenance Tips
Upgrade Traefik
helm upgrade traefik traefik/traefik \
--namespace traefik \
-f traefik-values.yaml
BashRestart Deployment
kubectl rollout restart deployment traefik -n traefik
BashCheck Logs
kubectl logs -l app.kubernetes.io/name=traefik -n traefik --tail=100
BashDebug cert-manager
kubectl get certificaterequests -n traefik
kubectl describe certificaterequest <name> -n traefik
kubectl get orders -n traefik
kubectl describe order <name> -n traefik
kubectl get challenges -n traefik
BashFor Longhorn, Nextcloud, or additional IngressRoutes, see their respective documentation or reach out to extend this guide.