Skip to content

Migrate to GitOps#24

Merged
clofour merged 13 commits intomainfrom
dev
May 1, 2026
Merged

Migrate to GitOps#24
clofour merged 13 commits intomainfrom
dev

Conversation

@clofour
Copy link
Copy Markdown
Owner

@clofour clofour commented Apr 30, 2026

…migration

Summary by CodeRabbit

  • New Features

    • Implemented Flux CD-based GitOps for infrastructure management and deployments
    • Added automated SSL/TLS certificate provisioning and renewal
    • Enabled automatic DNS record management for configured domains
    • Deployed integrated Envoy Gateway and GitLab services with all dependencies
  • Chores

    • Migrated infrastructure tooling from Helm provider to Flux CD provider

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 30, 2026

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 084bc9b8-23ae-43c3-94d3-266c0dc6da77

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

This PR transitions cluster deployment from Terraform-managed Helm releases to a Flux CD GitOps model. It introduces Flux bootstrap configuration, manifests for infrastructure components (cert-manager, envoy-gateway, external-dns, gitlab, reflector), package sources (Git/Helm/OCI repositories), configuration values via Kubernetes ConfigMaps, and removes equivalent Terraform Helm provider code.

Changes

Cohort / File(s) Summary
Flux Bootstrap & Kustomization
flux/bootstrap/cluster-kustomization.yaml, flux/bootstrap/shared-values.yaml, flux/kustomization.yaml
Establishes Flux cluster kustomization with 10m reconciliation interval, pruning enabled, and variable substitution from ConfigMaps (shared-values and runtime-values).
Flux Source Repositories
flux/repositories/{cert-manager,emberstack,envoy-proxy,external-dns,github,gitlab}.yaml
Defines package sources: Git repository (github), Helm repositories (emberstack, external-dns, gitlab), and OCI repositories (cert-manager, envoy-proxy) with pinned versions/tags.
Flux Helm Release Deployments
flux/releases/{cert-manager,cluster-issuer,dns01-certificate,envoy-gateway,external-dns,gateway-config,gitlab,reflector}.yaml
Configures 8 HelmReleases with 1m reconciliation, dependency ordering, namespace management, and chart-specific values (e.g., GitLab with PostgreSQL/Redis/S3/SMTP/monitoring, external-dns with DigitalOcean provider).
Terraform Flux Bootstrap & Configuration
terraform/fluxcd.tf, terraform/variables.tf
Adds flux_bootstrap_git resource pointing to local flux/ directory and kubernetes_config_map_v1.runtime_values ConfigMap populated from Terraform variables (domain, hosts, email, cluster name, database/Redis/R2 bucket credentials).
Terraform Provider Migration
terraform/providers.tf, terraform/versions.tf
Replaces helm provider with flux provider (fluxcd/flux ~> 1.8.6), removes time provider; updates provider configuration to use Kubernetes cluster details and git repository URL.
Terraform Helm Release Removal
terraform/helm.tf
Removes all Terraform-managed Helm releases (reflector, external-dns, cert-manager, cluster-issuer, dns01-certificate, envoy-gateway, gateway-config, gitlab, kube-prometheus-stack) and their templated values/dependencies (163 lines deleted).
Terraform Infrastructure Cleanup
terraform/kubernetes.tf, terraform/dns.tf
Removes Envoy Gateway synchronization logic (time_sleep wait, Kubernetes Service lookup for gateway), removes commented-out DNS record management.

Sequence Diagram

sequenceDiagram
    participant Git as Git Repository
    participant Flux as Flux Bootstrap
    participant K8s as Kubernetes Cluster
    participant Kustomization as Cluster Kustomization
    participant Sources as Package Sources
    participant Releases as Helm Releases
    participant Apps as Applications

    Flux->>Git: Clone flux/ directory
    Git-->>Flux: Return manifests
    Flux->>K8s: Apply bootstrap configuration
    K8s->>Kustomization: Process cluster-kustomization.yaml
    Kustomization->>K8s: Load shared-values & runtime-values ConfigMaps
    Kustomization->>Sources: Reference cert-manager, envoy-proxy, external-dns, gitlab repositories
    Sources->>K8s: Register HelmRepository & OCIRepository resources
    Kustomization->>Releases: Apply HelmRelease manifests with dependency ordering
    Releases->>Releases: Resolve dependencies (cert-manager → cluster-issuer → dns01-certificate → envoy-gateway → external-dns)
    Releases->>Sources: Fetch Helm charts from repositories
    Sources-->>Releases: Return chart artifacts
    Releases->>K8s: Deploy applications via Helm with templated values
    K8s->>Apps: Create namespaces, deployments, services, configmaps
    Apps-->>K8s: Services ready
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • PR #5: Modifies Terraform/Helm/Flux provisioning surfaces by adjusting helm provider and time-based synchronization, contrasting with this PR's migration away from Terraform Helm management.
  • PR #7: Adjusts certificate provisioning flow (cluster-issuer/ACME/wildcard-certificate configuration) that this PR references in its Flux HelmReleases.
  • PR #2: Introduces GitLab Helm deployment via Terraform that this PR re-implements as a Flux-managed HelmRelease manifest.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'Migrate to GitOps' is generic and vague. While it loosely describes the overall migration theme, it does not convey the specific architectural change from Helm/Terraform to Flux CD GitOps, and lacks sufficient detail for meaningful understanding of the primary technical changes. Consider a more specific title such as 'Migrate infrastructure provisioning from Helm/Terraform to Flux CD' to better reflect the scope and primary architectural change of this significant migration.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@clofour
Copy link
Copy Markdown
Owner Author

clofour commented May 1, 2026

@coderabbitai full review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 1, 2026

✅ Actions performed

Full review triggered.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 24


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: c6fd6f0c-898f-4448-aeee-3d984089afb5

📥 Commits

Reviewing files that changed from the base of the PR and between 46b0515 and 55202b1.

📒 Files selected for processing (24)
  • flux/bootstrap/cluster-kustomization.yaml
  • flux/bootstrap/shared-values.yaml
  • flux/kustomization.yaml
  • flux/releases/cert-manager.yaml
  • flux/releases/cluster-issuer.yaml
  • flux/releases/dns01-certificate.yaml
  • flux/releases/envoy-gateway.yaml
  • flux/releases/external-dns.yaml
  • flux/releases/gateway-config.yaml
  • flux/releases/gitlab.yaml
  • flux/releases/reflector.yaml
  • flux/repositories/emberstack.yaml
  • flux/repositories/envoy-proxy.yaml
  • flux/repositories/external-dns.yaml
  • flux/repositories/github.yaml
  • flux/repositories/gitlab.yaml
  • flux/repositories/jetstack.yaml
  • terraform/dns.tf
  • terraform/fluxcd.tf
  • terraform/helm.tf
  • terraform/kubernetes.tf
  • terraform/providers.tf
  • terraform/variables.tf
  • terraform/versions.tf
💤 Files with no reviewable changes (3)
  • terraform/dns.tf
  • terraform/helm.tf
  • terraform/kubernetes.tf
📜 Review details
🧰 Additional context used
🪛 Checkov (3.2.525)
flux/bootstrap/shared-values.yaml

[low] 1-6: The default namespace should not be used

(CKV_K8S_21)

flux/releases/gitlab.yaml

[low] 31-32: Base64 High Entropy String

(CKV_SECRET_6)


[low] 62-63: Base64 High Entropy String

(CKV_SECRET_6)


[low] 71-72: Base64 High Entropy String

(CKV_SECRET_6)


[low] 82-83: Base64 High Entropy String

(CKV_SECRET_6)


[low] 119-120: Base64 High Entropy String

(CKV_SECRET_6)

🪛 Trivy (0.69.3)
flux/bootstrap/shared-values.yaml

[warning] 1-1: ConfigMap with sensitive content

ConfigMap 'shared-values' in 'default' namespace stores sensitive contents in key(s) or value(s) '{"key"}'

Rule: KSV-01010

Learn more

(IaC/Kubernetes)

🪛 YAMLlint (1.38.0)
flux/releases/dns01-certificate.yaml

[error] 25-25: too many blank lines (1 > 0)

(empty-lines)

🔇 Additional comments (4)
terraform/variables.tf (1)

52-54: LGTM.

New variable is consistent with the existing style in the file.

flux/repositories/external-dns.yaml (1)

1-7: LGTM — correct apiVersion, valid repository URL, namespace scoped to flux-system.

flux/repositories/gitlab.yaml (1)

1-7: LGTM — correct apiVersion, valid https://charts.gitlab.io URL.

flux/releases/reflector.yaml (1)

12-15: ⚠️ Potential issue | 🟠 Major

Correct the Emberstack HelmRepository URL — singular "helm-chart" will cause chart fetch to fail.

The URL in flux/repositories/emberstack.yaml is https://emberstack.github.io/helm-chart (singular), but the official Emberstack Helm repository is at https://emberstack.github.io/helm-charts (plural). The incorrect singular form will return a 404 when Flux's source-controller attempts to fetch the chart index, causing the reflector HelmRelease to fail.

Update the URL in flux/repositories/emberstack.yaml:

diff
 spec:
-  url: https://emberstack.github.io/helm-chart
+  url: https://emberstack.github.io/helm-charts
			> Likely an incorrect or invalid review comment.

Comment thread flux/bootstrap/cluster-kustomization.yaml Outdated
Comment thread flux/bootstrap/cluster-kustomization.yaml
Comment thread flux/bootstrap/shared-values.yaml
Comment thread flux/kustomization.yaml
Comment thread flux/releases/cert-manager.yaml Outdated
Comment thread flux/repositories/cert-manager.yaml
Comment thread terraform/fluxcd.tf Outdated
Comment thread terraform/fluxcd.tf Outdated
Comment thread terraform/providers.tf
Comment thread terraform/versions.tf
@clofour
Copy link
Copy Markdown
Owner Author

clofour commented May 1, 2026

@coderabbitai full review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 1, 2026

✅ Actions performed

Full review triggered.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

♻️ Duplicate comments (8)
flux/repositories/github.yaml (1)

1-9: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Add required spec.interval field.

The spec.interval field remains missing and is required by the Flux GitRepository v1 API. Without it, this resource will fail CRD validation and prevent reconciliation of dependent resources (cluster-issuer, dns01-certificate, gateway-config HelmReleases).

🔧 Proposed fix
 spec:
+  interval: 1m
   url: https://github.com/clofour/gitlab-kubernetes
   ref:
     branch: main
flux/repositories/cert-manager.yaml (2)

1-9: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Add required spec.interval field.

The spec.interval field is required in Flux OCIRepository resources. Without it, the resource will fail CRD validation and the cert-manager HelmRelease cannot reconcile.

🔧 Proposed fix
 spec:
+  interval: 5m
   url: oci://quay.io/jetstack/charts/cert-manager
   ref:
     tag: 1.20.2

6-9: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Consider adding layerSelector for Helm chart OCI sources.

When using an OCIRepository as a Helm chart source, specifying a layerSelector with the Helm chart media type is recommended to explicitly target the correct OCI layer and improve supply-chain clarity.

♻️ Proposed addition
 spec:
   interval: 5m
   url: oci://quay.io/jetstack/charts/cert-manager
+  layerSelector:
+    mediaType: "application/vnd.cncf.helm.chart.content.v1.tar+gzip"
+    operation: copy
   ref:
     tag: 1.20.2
flux/bootstrap/shared-values.yaml (1)

6-7: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Replace placeholder content with actual substitution variables.

The data: key: value placeholder provides no real substitution variables. References like ${email} in cluster-issuer.yaml and other ${...} tokens in HelmRelease values will remain unresolved at runtime, breaking cluster configuration.

🔧 Proposed fix (populate with actual values)
 data:
-  key: value
+  email: "admin@example.com"
+  domain_name: "example.com"
+  # Add other shared variables referenced in HelmReleases
flux/repositories/emberstack.yaml (1)

1-7: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Add required spec.interval field.

The spec.interval field is required in Flux HelmRepository resources. Without it, the resource will fail CRD validation and the reflector HelmRelease cannot reconcile.

🔧 Proposed fix
 spec:
+  interval: 10m
   url: https://emberstack.github.io/helm-charts
flux/releases/cert-manager.yaml (1)

8-13: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

spec.chart.spec.chartRef is an invalid field placement — the cert-manager HelmRelease will not reconcile.

The previous review flagged that fields were misplaced inside spec.chart.spec. While targetNamespace, install, and values have been moved to spec level, chartRef is still nested inside spec.chart.spec.

HelmChartTemplateSpec (the type of spec.chart.spec) only accepts: chart, version, sourceRef, interval, reconcileStrategy, valuesFiles, ignoreMissingValuesFiles, and verify. spec.chart.spec values are used by the helm-controller as a template to create a new HelmChart resource. chartRef is not valid there and will be pruned, leaving the controller unable to locate any chart source.

spec.chartRef is used to reference an OCIRepository directly — it belongs at the top-level spec, not inside spec.chart. spec.chart and spec.chartRef are mutually exclusive; remove spec.chart entirely.

🔧 Proposed fix
 spec:
   interval: 1m
-  chart:
-    spec:
-      chartRef:
-        kind: OCIRepository
-        name: cert-manager
-        namespace: flux-system
+  chartRef:
+    kind: OCIRepository
+    name: cert-manager
+    namespace: flux-system
   targetNamespace: cert-manager
terraform/providers.tf (1)

27-29: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Missing Git authentication — flux_bootstrap_git will fail to clone/push to the private repository.

The git block only sets url; no ssh or http authentication sub-block is present. Without credentials, the Flux provider cannot authenticate to the private repository during bootstrap.

🔒 Proposed fix (SSH example)
     git = {
         url = var.git_repo
+        ssh = {
+            username    = "git"
+            private_key = var.flux_git_ssh_private_key
+        }
     }

Or for HTTPS:

     git = {
         url = var.git_repo
+        http = {
+            username = "oauth2"
+            password = var.flux_git_token
+        }
     }
flux/releases/cluster-issuer.yaml (1)

21-21: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Verify ${email} is defined in the runtime-values ConfigMap.

The Flux kustomize substitution for ${email} relies on this key being present in one of the referenced ConfigMaps. The shared-values ConfigMap has no email key; if the runtime-values ConfigMap (created by Terraform) also omits it, substitution will silently produce an empty string and the ClusterIssuer will be created with a blank email, breaking Let's Encrypt ACME registration.

#!/bin/bash
# Verify that terraform/fluxcd.tf creates the runtime-values ConfigMap with an email key
fd "fluxcd.tf" --exec cat {}

# Also check all ConfigMap definitions for an 'email' key
rg -n "email" --type yaml flux/

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: b26f23b6-690e-4521-a4fc-e64ddfb066e1

📥 Commits

Reviewing files that changed from the base of the PR and between 46b0515 and cd8553e.

📒 Files selected for processing (24)
  • flux/bootstrap/cluster-kustomization.yaml
  • flux/bootstrap/shared-values.yaml
  • flux/kustomization.yaml
  • flux/releases/cert-manager.yaml
  • flux/releases/cluster-issuer.yaml
  • flux/releases/dns01-certificate.yaml
  • flux/releases/envoy-gateway.yaml
  • flux/releases/external-dns.yaml
  • flux/releases/gateway-config.yaml
  • flux/releases/gitlab.yaml
  • flux/releases/reflector.yaml
  • flux/repositories/cert-manager.yaml
  • flux/repositories/emberstack.yaml
  • flux/repositories/envoy-proxy.yaml
  • flux/repositories/external-dns.yaml
  • flux/repositories/github.yaml
  • flux/repositories/gitlab.yaml
  • terraform/dns.tf
  • terraform/fluxcd.tf
  • terraform/helm.tf
  • terraform/kubernetes.tf
  • terraform/providers.tf
  • terraform/variables.tf
  • terraform/versions.tf
💤 Files with no reviewable changes (3)
  • terraform/kubernetes.tf
  • terraform/helm.tf
  • terraform/dns.tf
📜 Review details
🧰 Additional context used
🪛 Checkov (3.2.525)
flux/releases/gitlab.yaml

[low] 31-32: Base64 High Entropy String

(CKV_SECRET_6)


[low] 62-63: Base64 High Entropy String

(CKV_SECRET_6)


[low] 71-72: Base64 High Entropy String

(CKV_SECRET_6)


[low] 82-83: Base64 High Entropy String

(CKV_SECRET_6)


[low] 119-120: Base64 High Entropy String

(CKV_SECRET_6)

🪛 Trivy (0.69.3)
flux/bootstrap/shared-values.yaml

[warning] 1-1: ConfigMap with sensitive content

ConfigMap 'shared-values' in 'flux-system' namespace stores sensitive contents in key(s) or value(s) '{"key"}'

Rule: KSV-01010

Learn more

(IaC/Kubernetes)

🔇 Additional comments (14)
terraform/variables.tf (1)

52-54: LGTM!

The git_repo variable is correctly defined for the Flux provider's Git URL configuration.

terraform/versions.tf (1)

17-19: Orphaned provider "helm" block has been successfully removed.

The helm provider configuration block in terraform/providers.tf has been removed along with its removal from required_providers. No action needed.

flux/repositories/external-dns.yaml (1)

1-7: LGTM!

Correct HelmRepository definition pointing at the official external-dns Helm index.

flux/releases/cluster-issuer.yaml (1)

1-21: LGTM — structural issues from the previous review are resolved.

All spec-level fields (interval, dependsOn, targetNamespace, install, values) are now correctly placed, and dependsOn uses the required - name: format.

flux/releases/external-dns.yaml (1)

1-36: LGTM — all critical structural issues from the previous review are resolved.

interval, dependsOn, targetNamespace, install, and values are correctly positioned at spec level; dependsOn uses the required - name: reflector format; spec.chart.spec contains only the valid HelmChartTemplateSpec fields.

flux/releases/dns01-certificate.yaml (1)

1-24: LGTM — critical structural issues from the previous review are resolved.

interval, dependsOn (with correct - name: format for both dependencies), targetNamespace, install, and values are all correctly placed at spec level.

flux/releases/reflector.yaml (1)

1-18: LGTM — critical structural issues from the previous review are resolved.

targetNamespace and install are now at spec level, and spec.chart.spec contains only valid HelmChartTemplateSpec fields. The emberstack HelmRepository URL also shows the corrected plural path (/helm-charts).

flux/releases/gateway-config.yaml (1)

1-22: LGTM — all critical structural issues from the previous review are resolved.

interval, dependsOn (- name: envoy-gateway), targetNamespace, install, and values are all at spec level; spec.chart.spec contains only valid HelmChartTemplateSpec fields.

flux/bootstrap/cluster-kustomization.yaml (2)

9-11: sourceRef.name: github now correctly matches the bootstrap GitRepository.

The previous gitlab-kubernetes reference (non-existent) is resolved. The github GitRepository in flux/repositories/github.yaml provides the correct source.


13-17: runtime-values is now created by Terraform — root cause resolved; optional: true still missing for bootstrap window.

The ConfigMap is created in terraform/fluxcd.tf with depends_on = [flux_bootstrap_git.flux_cd], so it will exist for steady-state reconciliations. However, the very first reconciliation cycle after flux_bootstrap_git completes (before Terraform creates the ConfigMap) will still fail without optional: true. Consider adding optional: true for robustness during the bootstrap window.

flux/kustomization.yaml (1)

3-5: bootstrap/shared-values.yaml and repositories/github.yaml additions resolve the previous reconciliation blockers.

Both past issues (missing shared-values ConfigMap and missing bootstrap GitRepository) are now fixed.

terraform/fluxcd.tf (1)

1-34: Both previously flagged issues are resolved: depends_on added, and bucket values correctly flattened to individual string keys.

The depends_on = [flux_bootstrap_git.flux_cd] ordering guard is in place, and the bucket entries (buckets_artifacts, buckets_uploads, etc.) now match the flat ${buckets_*} substitution keys used across the HelmRelease values files.

flux/releases/gitlab.yaml (2)

1-14: All three previously flagged critical issues are resolved: namespace corrected, spec structure fixed, and bucket variable syntax flattened.

  • namespace: flux-system
  • dependsOn, targetNamespace, install, and values are correctly placed at spec level ✓
  • Bucket substitution now uses ${buckets_artifacts} / ${buckets_uploads} / etc., matching the flat keys in the Terraform ConfigMap ✓

26-128: Checkov CKV_SECRET_6 findings are false positives — no action needed.

The flagged lines (31–32, 62–63, 71–72, 82–83, 119–120) all follow the pattern secret: <k8s-secret-name> / key: password. The string literal "password" is a Kubernetes Secret key name, not a credential value. No secrets are embedded in this file.

Comment thread flux/bootstrap/cluster-kustomization.yaml
Comment thread flux/kustomization.yaml
Comment thread flux/releases/envoy-gateway.yaml Outdated
Comment thread flux/repositories/envoy-proxy.yaml
Comment thread flux/repositories/gitlab.yaml
@clofour clofour merged commit cfe4b48 into main May 1, 2026
3 checks passed
@clofour clofour deleted the dev branch May 2, 2026 11:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant