Traefik Kubernetes Ingress Provider with cert-manager

The Traefik Kubernetes Ingress provider is an open-source Ingress controller for Kubernetes. It works together with cert-manager to automatically issue TLS certificates, ensuring that internal Kubernetes Services are securely exposed.

In this guide, you will set up the Traefik Ingress controller on your Kubernetes cluster. You will also integrate cert-manager to provide TLS certificates, create a demo application, configure a Service for it, expose it with an Ingress resource, and issue a TLS certificate using cert-manager.

Prerequisites

Before continuing, ensure that you:

  • Have access to a Kubernetes cluster.
  • Have kubectl installed locally.
  • Have the Helm client installed on your machine.
  • Own a domain name. This guide uses example.com—replace it with your real domain.

Install and Configure Traefik

Create a dedicated namespace for Traefik resources:

$ kubectl create namespace traefik-namespace

Add the official Traefik Helm repository:

$ helm repo add traefik https://helm.traefik.io/traefik

Update the Helm repositories:

Install the Traefik Ingress controller using Helm:

$ helm install --namespace=traefik-namespace traefik traefik/traefik

The above command deploys the Traefik Ingress controller in the traefik-namespace namespace.

Check the Service created for the Traefik Ingress controller to obtain its external IP:

$ kubectl get services -n traefik-namespace

Example output while the external IP is still pending:

NAME      TYPE           CLUSTER-IP       EXTERNAL-IP   PORT(S)                      AGE
traefik   LoadBalancer   10.108.209.185   <pending>     80:30046/TCP,443:30279/TCP   78s

After some time, the Service receives an external IP:

NAME      TYPE           CLUSTER-IP     EXTERNAL-IP     PORT(S)                      AGE
traefik   LoadBalancer   10.107.61.70   192.0.2.10      80:30351/TCP,443:32047/TCP   9m34s

Now, log in to your domain registrar’s DNS panel and create an A record pointing your domain to the Traefik LoadBalancer’s external IP.

Install cert-manager

cert-manager is a Kubernetes add-on that issues TLS certificates from various Certificate Authorities (CAs), such as Let’s Encrypt, HashiCorp Vault, Venafi, and more. It ensures certificates remain valid by automatically renewing them before expiration. In this step, you will deploy cert-manager on your cluster.

Install cert-manager version v1.17.2 with the following command:

$ kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.17.2/cert-manager.yaml

This installs cert-manager v1.17.2. To check the most recent version, refer to the cert-manager GitHub repository.

Verify that cert-manager pods are up and running:

$ kubectl get pods --namespace cert-manager

You should see resources with cert-manager in their names.

Create a ClusterIssuer

A ClusterIssuer is a cluster-wide resource provided by cert-manager. It issues TLS certificates for Ingress objects. Next, you will configure a ClusterIssuer to request Let’s Encrypt certificates.

Create a file called cluster-issuer.yaml:

$ nano cluster-issuer.yaml

Insert the following configuration:

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    email: hello@example.com
    server: https://acme-v02.api.letsencrypt.org/directory
    privateKeySecretRef:
      name: letsencrypt-prod-key
    solvers:
      - http01:
          ingress:
            class: traefik

Note: Replace hello@example.com with a valid email address. Using the example.com domain will prevent the ClusterIssuer from functioning properly.

Explanation of the configuration:

  • acme: Defines ACME settings for Let’s Encrypt.
  • email: The email address linked to your Let’s Encrypt account.
  • server: The ACME endpoint URL.
  • privateKeySecretRef: References the Kubernetes Secret that stores the account’s private key.
  • solvers: Defines how the ACME challenge will be solved.
  • http01: Uses HTTP-01 for domain validation.
  • ingress: Specifies Traefik as the Ingress class used for validation.

Save and exit the file, then apply it:

$ kubectl apply -f cluster-issuer.yaml

Confirm the ClusterIssuer status:

$ kubectl get clusterissuer

Example output:

NAME               READY   AGE
letsencrypt-prod   True    2m44s

The READY field being True confirms that the ClusterIssuer is properly set up and ready to issue certificates.

Deploy a Sample Application

In this section, you will deploy a test application using the Nginx web server. This setup allows you to validate the Traefik configuration and cert-manager’s certificate issuance process.

Create a namespace called example-app-namespace to hold the resources of the application:

$ kubectl create namespace example-app-namespace

Create a Deployment file named example-app-deployment.yaml:

$ nano example-app-deployment.yaml

Insert the following content:

apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: example-app-namespace
  name: example-app-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: example-app
  template:
    metadata:
      labels:
        app: example-app
    spec:
      containers:
        - name: web-app
          image: nginx
          ports:
            - containerPort: 80

This Deployment, named example-app-deployment, uses the official Nginx image and runs three replicas.

Explanation of the configuration:

  • replicas: Number of pod instances created.
  • selector: Labels used to identify pods managed by the Deployment.
  • template: Defines how new pods are created.
  • metadata: Labels assigned to pods.
  • spec: Pod specifications.
  • containers: Container definitions for each pod.
  • name: Container name.
  • image: Container image (nginx).
  • ports: Opened ports inside the container.

Apply the Deployment:

$ kubectl apply -f example-app-deployment.yaml

Check that the pods are running:

$ kubectl get pods -n example-app-namespace

You should see three pods with names beginning with example-app-deployment-.

Create an Ingress Resource

Now create a Service for the Deployment and then configure an Ingress resource to expose it with a TLS certificate.

Create a Service file named example-app-service.yaml:

$ nano example-app-service.yaml

Insert the following content:

apiVersion: v1
kind: Service
metadata:
  namespace: example-app-namespace
  name: example-app-service
spec:
  selector:
    app: example-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80

This Service, example-app-service, exposes the pods of the Deployment.

Explanation of the configuration:

  • spec: Defines the Service’s configuration.
  • selector: Labels used to select the pods for routing traffic.
  • app: Matches the label app=example-app.
  • ports: Exposed ports for the Service.
  • protocol: Communication protocol (TCP).
  • port: Port exposed by the Service.
  • targetPort: Destination port in the pods.

Apply the Service manifest:

$ kubectl apply -f example-app-service.yaml

Verify creation of the Service:

$ kubectl get services -n example-app-namespace

Example output:

NAME                  TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
example-app-service   ClusterIP   10.97.221.68   <none>        80/TCP    81s

Next, create an Ingress file named example-app-ingress.yaml. Replace example.com with your own domain.

$ nano example-app-ingress.yaml

Insert the following Ingress configuration:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: web-app-ingress
  namespace: example-app-namespace
  annotations:
    traefik.ingress.kubernetes.io/router.entrypoints: websecure
    traefik.ingress.kubernetes.io/router.tls: "true"
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  rules:
    - host: example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: example-app-service
                port:
                  number: 80
  tls:
    - secretName: web-app-cert
      hosts:
        - example.com

This Ingress resource exposes the Service example-app-service under the domain example.com.

Explanation of the configuration:

  • annotations: Define Traefik and cert-manager-specific behavior.
  • traefik.ingress.kubernetes.io/router.entrypoints: websecure — Routes traffic through the HTTPS entrypoint.
  • traefik.ingress.kubernetes.io/router.tls: “true” — Enables TLS termination for secure traffic.
  • cert-manager.io/cluster-issuer: letsencrypt-prod — Links the Ingress to the ClusterIssuer for certificate generation.
  • rules: Define how requests are routed.
  • host: Specifies the domain name.
  • paths: Define request paths.
  • backend: Routes traffic to the Service.
  • tls: TLS configuration for the Ingress.
  • secretName: Secret that stores the issued TLS certificate.

Apply the Ingress manifest:

$ kubectl apply -f example-app-ingress.yaml

Verify the Ingress creation:

$ kubectl get ingress -n example-app-namespace

Example output:

NAME              CLASS     HOSTS         ADDRESS   PORTS    AGE
web-app-ingress   traefik   example.com             80, 443  9s

Initially, the ADDRESS field will be empty. After a short delay, it populates with the external IP of the Traefik Service.

Check that Let’s Encrypt has issued a certificate for your domain:

$ kubectl get certificates -n example-app-namespace

Example output:

NAME           READY   SECRET         AGE
web-app-cert   True    web-app-cert   41s

If the READY field shows True, the SSL certificate has been successfully issued. Certificate readiness may take a few minutes.

To confirm auto-renewal, describe the certificate resource:

$ kubectl describe -n example-app-namespace certificate web-app-cert

Look for the Renewal Time field in the output:

...
Renewal Time:            2023-09-17T15:23:45Z
...

Finally, open your browser and visit your domain over HTTPS:

https://example.com

You should see the default Nginx welcome page displayed securely.

Troubleshooting

Here are some common troubleshooting tips to help you manage Traefik and cluster resources effectively.

Unable to get Let’s Encrypt Certificate: If the certificate READY column shows False, ensure that your domain is pointing to the Traefik LoadBalancer external IP. To dig deeper, check the cert-manager logs with:

$ kubectl logs deployment/cert-manager -n cert-manager --tail=15 -f

Check Traefik logs: If Traefik is not functioning as expected, view the pod logs for any errors or warnings:

$ kubectl logs -n <namespace> <traefik-pod>

Verify DNS configuration: Ensure your domain name is correctly mapped to the external IP address of your Traefik LoadBalancer. Incorrect DNS settings will prevent Traefik from serving requests properly.

Verify Ingress configuration: If Traefik is not routing requests, review your Ingress YAML configuration. Confirm that all necessary annotations for Traefik and cert-manager are present:

Inspect Traefik resources: Periodically check the status of Traefik-related resources like pods, Services, and Ingress objects to confirm they are healthy:

$ kubectl get pods -n traefik-namespace

Conclusion

In this guide, you installed the Traefik Ingress Controller, deployed a sample web application, and securely exposed it using Traefik, cert-manager, and Let’s Encrypt. For further learning and advanced configuration details, consult the official documentation:

Source: vultr.com

Create a Free Account

Register now and get access to our Cloud Services.

Posts you might be interested in: