Post

Utilize GitOps with FluxCD in Kubernetes Part 2

Managing Kubernetes with GitOps using Flux CD Part 2

Now that cert-manager is configured, we’ll deploy Traefik as our ingress controller by first creating its namespace, Helm repository configuration, and dashboard authentication secret. We’ll add the helm-repo.yaml to access the official Traefik Helm charts, and then update the secret with our actual dashboard password using kubectl. This will establish the foundational resources needed before deploying Traefik itself.

Create the Traefik namespace and secret

1
2
fluxcd/clusters/home on  main
mkdir traefik

namespace.yaml

1
2
3
4
apiVersion: v1
kind: Namespace
metadata:
  name: traefik

helm-repo.yaml

1
2
3
4
5
6
7
8
apiVersion: source.toolkit.fluxcd.io/v1beta1
kind: HelmRepository
metadata:
  name: traefik
  namespace: flux-system
spec:
  interval: 1m
  url: https://helm.traefik.io/traefik

traefik-secrets.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
apiVersion: v1
kind: Secret
metadata:
  name: traefik-dashboard-auth-secret
  namespace: traefik
  annotations:
    kustomize.toolkit.fluxcd.io/reconcile: disabled
type: kubernetes.io/basic-auth
stringData:
  username: admin
  password: "RANDOM_PASSWORD"
# Update password with:
# kubectl create secret generic traefik-dashboard-auth-secret --namespace traefik \
#   --from-literal=username=admin \
#   --from-literal=password=YOUR_NEW_PASSWORD \
#   --type=kubernetes.io/basic-auth \
#   --dry-run=client -o yaml | kubectl apply -f -


kubectl create secret generic traefik-dashboard-auth-secret -n traefik \
 --from-literal=username=admin \
 --from-literal=password=YOUR_NEW_PASSWORD \
 --type=kubernetes.io/basic-auth \
 --dry-run=client -o yaml | kubectl apply -f -

Create the Traefik deployment

This HelmRelease configuration sets up Traefik with automatic HTTPS redirection, security headers, basic authentication for the dashboard, and proper resource management. You’ll need to replace all instances of schenk.tech with your own domain name to ensure the dashboard and security configurations work correctly for your environment.

helm-release.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
  name: traefik
  namespace: traefik
spec:
  interval: 1m
  timeout: 20m
  install:
    crds: CreateReplace
  upgrade:
    crds: CreateReplace
  chart:
    spec:
      chart: traefik
      version: 24.0.0
      sourceRef:
        kind: HelmRepository
        name: traefik
        namespace: flux-system
  values:
    autoscaling:
      enabled: true
      minReplicas: 1
      maxReplicas: 3
      metrics:
        - type: Resource
          resource:
            name: cpu
            target:
              type: Utilization
              averageUtilization: 80
    resources:
      requests:
        cpu: 500m
        memory: 150Mi
      limits:
        cpu: 1
        memory: 500Mi
    deployment:
      replicas: null
      strategy:
        type: RollingUpdate
        rollingUpdate:
          maxSurge: 1
          maxUnavailable: 0
    #   logs:
    #   access:
    #     enabled: true
    #     format: json
    metrics:
      prometheus:
        enabled: true
        addEntryPointsLabels: true
        addServicesLabels: true
    ingressClass:
      enabled: true
      fallbackApiVersion: v1
      isDefaultClass: true
    ssl:
      enabled: true
      certManager:
        enabled: true
      enforced: true
    tlsStore: # Enable once certificates are created
      default:
        defaultCertificate:
          secretName: wildcard-schenk-tech
    ports:
      metrics:
        expose: true
        port: 9100
      web:
        redirectTo: websecure
      websecure:
        tls:
          enabled: true
      traefik:
        expose: true
    service:
      spec:
        externalTrafficPolicy: Local
    providers:
      kubernetesCRD:
        enabled: true # This is so certificates work
        allowCrossNamespace: true
        allowExternalNameServices: true
      kubernetesIngress:
        enabled: false
    ingressRoute:
      dashboard:
        enabled: false # We set up a manual ingress route below - do not enable this!!
    entryPoints:
      metrics:
        expose: true
        port: 9100
      web:
        http:
          redirections:
            entryPoint:
              to: https
              scheme: https
      websecure:
        # address: ":443"
        forwardedHeaders:
          insecure: true
        trustedIPs:
          - "127.0.0.1/32"
          - "10.0.0.0/8"
          - "192.168.0.0/16"
          - "172.16.0.0/12"
        http:
          middlewares:
            # - www-redir@kubernetescrd
            - traefik-security@kubernetescrd
    additionalArguments:
      - "--api.insecure=false"
    extraObjects:
      - apiVersion: traefik.io/v1alpha1
        kind: Middleware
        metadata:
          name: security
        spec:
          headers:
            accessControlAllowMethods:
              - "*"
            accessControlAllowHeaders:
              - "*"
            accessControlAllowOriginListRegex:
              - "https://(.*)?.schenk\\.tech"
            accessControlMaxAge: 100
            addVaryHeader: true
            accessControlAllowCredentials: true
            frameDeny: false
            referrerPolicy: "same-origin"
            contentSecurityPolicy: "*"
            customResponseHeaders:
              x-aspnet-version: ""
              X-Powered-By: ""
              Server: ""
      - apiVersion: traefik.io/v1alpha1
        kind: Middleware
        metadata:
          name: dashboard-auth
          namespace: traefik
        spec:
          basicAuth:
            secret: traefik-dashboard-auth-secret
      - apiVersion: traefik.io/v1alpha1
        kind: IngressRoute
        metadata:
          name: traefik-dashboard
          namespace: traefik
        spec:
          entryPoints:
            - websecure
          routes:
            - match: Host(`traefik.schenk.tech`) && (PathPrefix(`/dashboard`) || PathPrefix(`/api`))
              kind: Rule
              middlewares:
                - name: dashboard-auth
                  namespace: traefik
              services:
                - name: api@internal
                  kind: TraefikService

The kustomization.yaml file ties together all our Traefik components - the namespace, HelmRelease, and secrets - ensuring they’re deployed in the correct order and maintaining the complete desired state of our ingress controller configuration.

kustomization.yaml

1
2
3
4
5
6
7
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - traefik-secrets.yaml
  - helm-repo.yaml
  - helm-release.yaml
  - namespace.yaml

After committing and pushing these configuration files to your Git repository, FluxCD will automatically detect the changes and begin deploying Traefik. You can force an immediate reconciliation using flux reconcile source git flux-system if you don’t want to wait for the next sync interval.

You can now check if all the resources have been deployed using:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
flux get all -A
NAMESPACE   NAME                      REVISION           SUSPENDED READY MESSAGE
flux-system gitrepository/flux-system main@sha1:d373c323 False     True  stored artifact for revision 'main@sha1:d373c323'

NAMESPACE   NAME                        REVISION        SUSPENDED READY MESSAGE
flux-system helmrepository/cert-manager sha256:c10b5e02 False     True  stored artifact: revision 'sha256:c10b5e02'
flux-system helmrepository/traefik      sha256:62a21791 False     True  stored artifact: revision 'sha256:62a21791'

NAMESPACE   NAME                                REVISION SUSPENDED READY MESSAGE
flux-system helmchart/cert-manager-cert-manager v1.17.2  False     True  pulled 'cert-manager' chart with version 'v1.17.2'
flux-system helmchart/traefik-traefik           24.0.0   False     True  pulled 'traefik' chart with version '24.0.0'

NAMESPACE    NAME                     REVISION SUSPENDED READY MESSAGE
cert-manager helmrelease/cert-manager v1.17.2  False     True  Helm install succeeded for release cert-manager/cert-manager.v1 with chart cert-manager@v1.17.2
traefik      helmrelease/traefik      24.0.0   False     True  Helm upgrade succeeded for release traefik/traefik.v3 with chart traefik@24.0.0

NAMESPACE   NAME                      REVISION           SUSPENDED READY MESSAGE
flux-system kustomization/flux-system main@sha1:d373c323 False     True  Applied revision: main@sha1:d373c323

Verifying the Traefik Deployment

Let’s verify that Traefik has been deployed correctly. First, check if the Traefik pods are running in the correct namespace:

1
2
3
kubectl get pods -n traefik
NAME                       READY   STATUS    RESTARTS   AGE
traefik-5f48b964d5-h7mlh   1/1     Running   0          21h

Let’s verify the Traefik service and endpoints:

1
2
3
4
5
6
7
8
9
# Check if the Traefik service is properly configured
kubectl get svc -n traefik

NAME      TYPE           CLUSTER-IP     EXTERNAL-IP      PORT(S)                                                    AGE
traefik   LoadBalancer   10.43.58.137   192.168.10.200   9100:30340/TCP,9000:32058/TCP,80:32666/TCP,443:32273/TCP   21h
# Verify the endpoints are correctly set up
kubectl get endpoints -n traefik
NAME      ENDPOINTS                                                        AGE
traefik   10.42.3.102:9000,10.42.3.102:8000,10.42.3.102:8443 + 1 more...   21h

Finally, you can test the dashboard access by visiting https://traefik.your-domain.com/dashboard/ in your browser. You’ll be prompted for the basic authentication credentials we configured earlier.

Connect to Traefik Dashboard

In this part, we’ve successfully deployed Traefik as our ingress controller using FluxCD, setting up automatic HTTPS redirection, security headers, and a protected dashboard interface. This deployment not only gives us a robust way to manage incoming traffic to our services but also serves as a practical example of how to deploy and configure services in our GitOps-driven homelab. With both cert-manager and Traefik now in place, we have a solid foundation for deploying additional services with automatic SSL/TLS certificate management and secure ingress routing. In the next part, we’ll migrate our AWX instance to this Kubernetes cluster, demonstrating how to move existing services into our new GitOps infrastructure while maintaining their functionality and security.


Part 1: Setting up cert-manager with FluxCD

This post is licensed under CC BY 4.0 by the author.