Skip to content

Complex repo setup example #89

@tbondarchuk

Description

@tbondarchuk

TL;DR - are there any other examples of complex flux config repo with multiple clusters/apps/envs/tenants?

I really like FluxCD documentation - guides, apis - everything you need to get going and improve along the way. But one extremely frustrating missing piece is complex flux repo example. Both flux2-kustomize-helm-example and flux2-multi-tenancy are just POC to be honest - nice to try locally on kind cluster but not really suitable to run on live cluster imo. All examples seem to focus on either single cluster usage or multiple but fully/almost identical clusters. I've tried to find something more complex, but no much luck so far. Well, there is bootstrap-repo but it seems to be an enhanced version of current repo.

Don't take me wrong - it all works perfectly, but as soon as you start to scale - add clusters, apps, tenants, etc - it became quite cumbersome.

Like this repo's readme:

├── clusters
│   ├── production
│   └── staging
├── infrastructure
│   ├── kyverno
│   └── kyverno-policies
└── tenants
    ├── base
    ├── production
    └── staging

it assumes both clusters will use same exact version of infrastructure - for example save values for helm releases. Of course we can add base/overlays to infrastructure but when it scales out it became unwieldy. We need monitoring stack - prometheus, grafana, loki, promtail. Private/public ingress, can't live without cert-manager and external-dns, then EKS is no good without aws-load-balancer-controller and karpenter/autoscaler, add some kubernetes-dashboard, weave-gitops, etc - and here you are with 10 to 20 helm releases just to get cluster to be ready for an actual app deployment. (then deploy single-pod app and proudly watch all those machinery running static website with enormous 50Mb/100m resources consumption :))

Having infrastructure/base with 20 helm releases plus help helm repos files isn't that bad, but in my case with multiple EKS clusters in different accounts I need different values for most helm releases (irsa roles, increased replicas for prod, etc) So it results in infrastructure/dev folder having 20 values/secrets files and long list of kustomize's configMapGenerators.

I guess possible solution is to use variables substitution and put all values inside helm releases and just keep one/few configmaps with per-cluster variables, but I've found out that keeping plan value/secret file for helm release is really useful when maintainers release breaking change patch and you need to quickly run helm template -f values.yaml to see what's changed. (I really like Flux's helm charts autoupdate feature but sometimes reading alerts channel in the morning after nightly updates is no fun at all)

Second issue/inconvenience is dependencies or rather lack of dependency between helm release/kustomization at this moment (hope it will be possible to implement this soon/ever, subscribed to existing issue already). For example, in order to deploy cert-manager from helm release and cluster-issuer from kustomization I need to wrap hr into kustomization and then set dependency between two ks resources. So deploying from a single large folder full of helm releases and kustomzations and plain manifests is just not possible, unless you want to spend some time during cluster's bootstrap manually reconciling and suspending/resuming.

And "single folder" approach does not work well with plain/kustmized manifests either - recently tried approach with multiple apps in base folder and then single dev/kustomization.yaml deploying them all - quickly realized that one failing deployment blocks all others since wrapper Kustomization is unhealthy. Plus you'd need to suspend everything even if single deployment needs maintenance/etc.

So I ended up with "multiple proxy kustomizations, multiple components" setup which worked quite well until I got to explain it to somebody else :)

Flux-fleet repo
.
├── clusters
│   └── dev
│       ├── flux-system
│       │   ├── gotk-components.yaml
│       │   ├── gotk-sync.yaml
│       │   └── kustomization.yaml
│       ├── infrastructure
│       │   ├── cert-issuer.yaml
│       │   ├── ingress.yaml
│       │   ├── kustomization.yaml
│       │   ├── monitoring.yaml
│       │   └── system.yaml
│       └── kustomization.yaml
└── infrastructure
    ├── cert-issuer
    │   ├── base
    │   │   ├── cluster-issuer.yaml
    │   │   └── kustomization.yaml
    │   └── dev
    │       └── kustomization.yaml
    ├── ingress
    │   ├── base
    │   │   ├── hr-ingress-nginx-private.yaml
    │   │   ├── hr-ingress-nginx-public.yaml
    │   │   ├── kustomization.yaml
    │   │   ├── namespace.yaml
    │   │   └── source-ingress-nginx.yaml
    │   └── dev
    │       ├── ingress-nginx-private-values.yaml
    │       ├── ingress-nginx-public-values.yaml
    │       ├── kustomization.yaml
    │       └── kustomizeconfig.yaml
    ├── monitoring
    │   ├── base
    │   │   ├── hr-grafana.yaml
    │   │   ├── hr-kube-prometheus-stack.yaml
    │   │   ├── hr-loki.yaml
    │   │   ├── hr-promtail.yaml
    │   │   ├── kustomization.yaml
    │   │   ├── namespace.yaml
    │   │   ├── source-grafana.yaml
    │   │   └── source-prometheus-community.yaml
    │   └── dev
    │       ├── grafana-secrets.yaml
    │       ├── grafana-values.yaml
    │       ├── kube-prometheus-stack-secrets.yaml
    │       ├── kube-prometheus-stack-values.yaml
    │       ├── kustomization.yaml
    │       ├── kustomizeconfig.yaml
    │       ├── loki-values.yaml
    │       └── promtail-values.yaml
    └─── system
        ├── base
        │   ├── hr-aws-load-balancer-controller.yaml
        │   ├── hr-cert-manager.yaml
        │   ├── hr-external-dns.yaml
        │   ├── hr-metrics-server.yaml
        │   ├── kustomization.yaml
        │   ├── namespace.yaml
        │   ├── source-eks.yaml
        │   ├── source-external-dns.yaml
        │   ├── source-jetstack.yaml
        │   └── source-metrics-server.yaml
        └── dev
            ├── aws-load-balancer-controller-values.yaml
            ├── cert-manager-values.yaml
            ├── external-dns-values.yaml
            ├── kustomization.yaml
            └── kustomizeconfig.yaml

Where clusters/dev/infrastructure is bunch of flux Kustomizations referencing dev folders in infrastructure/, grouped roughly by purpose (monitoring together, ingress together)

Got very similar setup for tenant's apps repos as well:

Flux-tenant repo
├── apps
│   └── webpage
│       ├── base
│       │   ├── deployment.yaml
│       │   ├── ingress.yaml
│       │   ├── kustomization.yaml
│       │   ├── service-account.yaml
│       │   └── service.yaml
│       └── dev
│           ├── ingress.yaml
│           └── kustomization.yaml
└── clusters
    └── dev
        └── apps
            ├── kustomization.yaml
            └── webpage.yaml

I guess "if it works don't touch it" but those long chains of KS => kustomization => KS => kustomization => HR are becoming hard to keep track of. Plus all of official examples seems to be completely opposite to this. I have a strong feeling I've overengineered this but can't seem to find a way to do a simpler but still flexible setup.

So I'm looking for some different example of "prod-like" complex setup tested on live clusters, anybody is willing to share? :)
Any suggestions are much appreciated.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions