Files
container.training/slides/k8s/M6-R01-flux_configure-ROCKY-deployment.md
2025-06-11 19:22:04 +02:00

12 KiB

R01- Configuring 🎸ROCKY deployment with Flux

The ⚙️OPS team manages 2 distinct envs: ⚗️TEST et 🚜PROD

Thanks to Kustomize

  1. it creates a base common config
  2. this common config is overwritten with a ⚗️TEST tenant-specific configuration
  3. the same applies with a 🚜PROD-specific configuration

💡 This seems complex, but no worries: Flux's CLI handles most of it.


Creating the 🎸ROCKY-dedicated tenant in ⚗️TEST env

  • Using the flux CLI, we create the file configuring the 🎸ROCKY team's dedicated tenant
  • … this file takes place in the base common configuration for both envs

.lab[

k8s@shpod:~/fleet-config-using-flux-XXXXX$ \
    mkdir -p ./tenants/base/rocky &&       \
    flux create tenant rocky               \
        --with-namespace=rocky-test        \
        --cluster-role=rocky-full-access   \
        --export > ./tenants/base/rocky/rbac.yaml

]


class: extra-details

📂 ./tenants/base/rocky/rbac.yaml

Let's see our file…

3 resources are created: Namespace, ServiceAccount, and ClusterRoleBinding

Flux impersonates as this ServiceAccount when it applies any resources found in this tenant-dedicated source(s)

  • By default, the ServiceAccount is bound to the cluster-admin ClusterRole
  • The team maintaining the sourced Github repository is almighty at cluster scope

A not that much isolated tenant! 😕

That's why the ⚙️OPS team enforces specific ClusterRoles with restricted permissions

Let's create these permissions!


namespace isolation for 🎸ROCKY

.lab[

  • Here are the restricted permissions to use in the rocky-test Namespace
k8s@shpod:~/fleet-config-using-flux-XXXXX$ \
    cp ~/container.training/k8s/M6-rocky-cluster-role.yaml ./tenants/base/rocky/

]

💡 Note that some resources are managed at cluster scope (like PersistentVolumes). We need specific permissions, then…


Creating Github source in Flux for 🎸ROCKY app repository

A specific branch of the Github repository is monitored by the Flux source

.lab[

  • ⚠️ you may change the repository URL to the one of your own clone
k8s@shpod:~/fleet-config-using-flux-XXXXX$ flux create source git rocky-app \
    --namespace=rocky-test                                                  \
    --url=https://github.com/Musk8teers/container.training-spring-music/    \
    --branch=rocky  --export > ./tenants/base/rocky/sync.yaml

]


Creating kustomization in Flux for 🎸ROCKY app repository

.lab[

k8s@shpod:~/fleet-config-using-flux-XXXXX$ flux create kustomization rocky \
    --namespace=rocky-test                                                 \
    --service-account=rocky                                                \
    --source=GitRepository/rocky-app                                       \
    --path="./k8s/" --export >> ./tenants/base/rocky/sync.yaml

k8s@shpod:~/fleet-config-using-flux-XXXXX$ \
    cd ./tenants/base/rocky/ &&            \
    kustomize create --autodetect &&       \
    cd -

]


class: extra-details

📂 Flux config files

Let's review our Flux configuration files

.lab[

k8s@shpod:~/fleet-config-using-flux-XXXXX$ \
    cat ./tenants/base/rocky/sync.yaml &&  \
    cat ./tenants/base/rocky/kustomization.yaml

]


Adding a kustomize patch for ⚗️TEST cluster deployment

💡 Remember the DRY strategy!

  • The Flux tenant-dedicated configuration is looking for this file: .tenants/test/rocky/kustomization.yaml

  • It has been configured here: clusters/CLOUDY/tenants.yaml

  • All the files we just created are located in .tenants/base/rocky

  • So we have to create a specific kustomization in the right location

k8s@shpod:~/fleet-config-using-flux-XXXXX$ \ 
    mkdir -p ./tenants/test/rocky &&       \
    cp ~/container.training/k8s/M6-rocky-test-patch.yaml ./tenants/test/rocky/ && \
    cp ~/container.training/k8s/M6-rocky-test-kustomization.yaml ./tenants/test/rocky/kustomization.yaml

Synchronizing Flux config with its Github repo

Locally, our Flux config repo is ready
The ⚙️OPS team has to push it to Github for Flux controllers to watch and catch it!

.lab[

k8s@shpod:~/fleet-config-using-flux-XXXXX$ \
    git add . && \
    git commit -m':wrench: :construction_worker: add ROCKY tenant configuration' && \
    git push

]


class: pic

Running Mario


class: pic

rocky config files


class: extra-details

Flux resources for ROCKY tenant 1/2

.lab[

k8s@shpod:~$ flux get all -A
NAMESPACE       NAME                            REVISION                SUSPENDED
    READY   MESSAGE
flux-system     gitrepository/flux-system       main@sha1:8ffd72cf      False
    True    stored artifact for revision 'main@sha1:8ffd72cf'
rocky-test      gitrepository/rocky-app         rocky@sha1:ffe9f3fe     False
    True    stored artifact for revision 'rocky@sha1:ffe9f3fe'
()

]


class: extra-details

Flux resources for ROCKY tenant 2/2

.lab[

k8s@shpod:~$ flux get all -A
()
NAMESPACE       NAME                            REVISION                SUSPENDED
    READY   MESSAGE
flux-system     kustomization/flux-system       main@sha1:8ffd72cf      False    
    True    Applied revision: main@sha1:8ffd72cf
flux-system     kustomization/tenant-prod                               False    
    False   kustomization path not found: stat /tmp/kustomization-1164119282/tenants/prod: no such file or directory
flux-system     kustomization/tenant-test       main@sha1:8ffd72cf      False    
    True    Applied revision: main@sha1:8ffd72cf
rocky-test      kustomization/rocky                                     False    
    False   StatefulSet/db dry-run failed (Forbidden): statefulsets.apps "db" is forbidden: User "system:serviceaccount:rocky-test:rocky" cannot patch resource "statefulsets" in API group "apps" at the cluster scope

]

And here is our 2nd Flux error(s)! 😅


class: extra-details

Flux Kustomization, mutability, …

🔍 Notice that none of the expected resources is created:
the whole kustomization is rejected, even if the StatefulSet is this only resource that fails!

🔍 Flux Kustomization uses the dry-run feature to templatize the resources and then applying patches onto them
Good but some resources are not completely mutable, such as StatefulSets

We have to fix the mutation by applying the change without having to patch the resource.

🔍 Simply add the spec.targetNamespace: rocky-test to the Kustomization named rocky


class: extra-details

And then it's deployed 1/2

You should see the following resources in the rocky-test namespace

.lab[

k8s@shpod-578d64468-tp7r2 ~/$ k get pods,svc,deployments -n rocky-test
NAME                       READY   STATUS         RESTARTS      AGE
pod/db-0                   1/1     Running        0             47s
pod/web-6c677bf97f-c7pkv   0/1     Running        1 (22s ago)   47s
pod/web-6c677bf97f-p7b4r   0/1     Running        1 (19s ago)   47s

NAME          TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)    AGE
service/db    ClusterIP   10.32.6.128   <none>        5432/TCP   48s
service/web   ClusterIP   10.32.2.202   <none>        80/TCP     48s

NAME                  READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/web   0/2     2            0           47s

]


class: extra-details

And then it's deployed 2/2

You should see the following resources in the rocky-test namespace

.lab[

k8s@shpod-578d64468-tp7r2 ~/$ k get statefulsets,pvc,pv -n rocky-test
NAME                       READY   AGE
statefulset.apps/db        1/1     47s

NAME                                         STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
persistentvolumeclaim/postgresql-data-db-0   Bound    pvc-c1963a2b-4fc9-4c74-9c5a-b0870b23e59a   1Gi        RWO            sbs-default    <unset>                 47s

NAME                                                        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM                             STORAGECLASS   VOLUMEATTRIBUTESCLASS   REASON   AGE
persistentvolume/postgresql-data                            1Gi        RWO,RWX        Retain           Available                                                    <unset>                          47s
persistentvolume/pvc-150fcef5-ebba-458e-951f-68a7e214c635   1G         RWO            Delete           Bound       shpod/shpod                       sbs-default    <unset>                          4h46m
persistentvolume/pvc-c1963a2b-4fc9-4c74-9c5a-b0870b23e59a   1Gi        RWO            Delete           Bound       rocky-test/postgresql-data-db-0   sbs-default    <unset>                          47s

]


class: extra-details

PersistentVolumes are using a default StorageClass

💡 This managed cluster comes with custom StorageClasses leveraging on Cloud IaaS capabilities (i.e. block devices)

Flux configuration waterfall

  • a default StorageClass is applied if none is specified (like here)
  • for 🏭PROD purpose, ops team might enforce a more performant StorageClass
  • on a bare-metal cluster, 🏭PROD team has to configure and provide StorageClasses on its own

class: pic

Flux configuration waterfall


Upgrading ROCKY app

The Git source named rocky-app is pointing at

This branch deploy the v1.0.0 of the Web app: spec.template.spec.containers.image: ghcr.io/musk8teers/container.training-spring-music:1.0.0

What happens if the 🎸ROCKY team upgrades its branch to deploy v1.0.1 of the Web app?


tenant 🏭PROD

💡 🏭PROD tenant is still waiting for its Flux configuration, but don't bother for it right now.


🗺️ Where are we in our scenario?

%%{init:
    {
      "theme": "default",
      "gitGraph": {
        "mainBranchName": "OPS",
        "mainBranchOrder": 0
      }
    }
}%%
gitGraph
    commit id:"0" tag:"start"
    branch ROCKY order:3
    branch MOVY order:4
    branch YouRHere order:5

    checkout OPS
    commit id:'Flux install on CLOUDY cluster' tag:'T01'
    branch TEST-env order:1
    commit id:'FLUX install on TEST' tag:'T02' type: HIGHLIGHT

    checkout OPS
    commit id:'Flux config. for TEST tenant' tag:'T03'
    commit id:'namespace isolation by RBAC'
    checkout TEST-env
    merge OPS id:'ROCKY tenant creation' tag:'T04'

    checkout OPS
    commit id:'ROCKY deploy. config.' tag:'R01'

    checkout TEST-env
    merge OPS id:'TEST ready to deploy ROCKY' type: HIGHLIGHT tag:'R02'

    checkout ROCKY
    commit id:'ROCKY' tag:'v1.0.0'

    checkout TEST-env
    merge ROCKY tag:'ROCKY v1.0.0'

    checkout YouRHere
    commit id:'x'
    checkout OPS
    merge YouRHere id:'YOU ARE HERE'

    checkout OPS
    commit id:'Ingress-controller config.' tag:'T05'
    checkout TEST-env
    merge OPS id:'Ingress-controller install' type: HIGHLIGHT tag:'T06'

    checkout OPS
    commit id:'ROCKY patch for ingress config.' tag:'R03'
    checkout TEST-env
    merge OPS id:'ingress config. for ROCKY app'

    checkout ROCKY
    commit id:'blue color' tag:'v1.0.1'
    checkout TEST-env
    merge ROCKY tag:'ROCKY v1.0.1'

    checkout ROCKY
    commit id:'pink color' tag:'v1.0.2'
    checkout TEST-env
    merge ROCKY tag:'ROCKY v1.0.2'

    checkout OPS
    commit id:'FLUX config for MOVY deployment' tag:'M01'
    checkout TEST-env
    merge OPS id:'FLUX ready to deploy MOVY' type: HIGHLIGHT tag:'M02'

    checkout MOVY
    commit id:'MOVY' tag:'v1.0.3'
    checkout TEST-env
    merge MOVY tag:'MOVY v1.0.3' type: REVERSE

    checkout OPS
    commit id:'Network policies'
    checkout TEST-env
    merge OPS type: HIGHLIGHT