GitOps with Flux

Flux is a tool that automatically ensures that the state of a cluster matches the config in git. It uses an operator in the cluster to trigger deployments inside Kubernetes, which means you don't need a separate CD tool. It monitors all relevant image repositories, detects new images, triggers deployments and updates the desired running configuration based on that (and a configurable policy).

Get started with Flux & Helm

In this article, we will be deploying helm in kube-system namespace and flux in flux namespace and our helm chart in demo namespace thats why giving them relative RBAC access, so if you want to change it you would need to modify the roles.

Helm with Limited RBAC

As we want flux & helm to have restrictive access so we will be giving tiller(helm part running on kubernetes cluster) access to only demo, flux and kube-system namespace.

As our helm also has limited access, so we cannot create CRDs from helm chart or even a user cant create them as they need to be applied from a user with cluster admin access, we will be needing them to be created manually first. Cluster admins have to deploy following manifests by creating a file lets say crd.yaml and copy the following manifest. And then run oc apply -f crd.yaml

apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  name: helmreleases.flux.weave.works
  labels:
    app: flux
    chart: flux-0.6.3
    release: flux
    heritage: Tiller
  annotations:
    "helm.sh/resource-policy": keep
spec:
  group: flux.weave.works
  names:
    kind: HelmRelease
    listKind: HelmReleaseList
    plural: helmreleases
    shortNames:
    - hr
  scope: Namespaced
  version: v1beta1
  versions:
    - name: v1beta1
      served: true
      storage: true
  validation:
    openAPIV3Schema:
      properties:
        spec:
          required: ['values', 'chart']
          properties:
            releaseName:
              type: string
              pattern: "^[a-z0-9]([-a-z0-9]*[a-z0-9])?$"
            timeout:
              type: integer
              format: int64
            resetValues:
              type: boolean
            skipDepUpdate:
              type: boolean
            forceUpgrade:
              type: boolean
            valueFileSecrets:
              type: array
              properties:
                items:
                  type: object
                  required: ['name']
                  properties:
                    name:
                      type: string
            values:
              type: object
            chart:
              oneOf:
              - required: ['git', 'path']
                properties:
                  git:
                    type: string
                    format: git # not defined by OAS
                  path:
                    type: string
                  ref:
                    type: string
              - required: ['repository', 'name', 'version']
                properties:
                  repository:
                    type: string
                    format: url # not defined by OAS
                  name:
                    type: string
                  version:
                    type: string
                    format: semver # not defined by OAS
                  chartPullSecret:
                    properties:
                      name:
                        type: string
---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  name: fluxhelmreleases.helm.integrations.flux.weave.works
  labels:
    app: flux
    chart: flux-0.6.3
    release: flux
    heritage: Tiller
  annotations:
    "helm.sh/resource-policy": keep
spec:
  group: helm.integrations.flux.weave.works
  names:
    kind: FluxHelmRelease
    listKind: FluxHelmReleaseList
    plural: fluxhelmreleases
    shortNames:
    - fhr
  scope: Namespaced
  version: v1alpha2
  versions:
    - name: v1alpha2
      served: true
      storage: true
  validation:
    openAPIV3Schema:
      properties:
        spec:
          required:
            - chartGitPath
            - values
          properties:
            releaseName:
              type: string
              pattern: "^[a-z0-9]([-a-z0-9]*[a-z0-9])?$"
            chartGitPath:
              type: string
            values:
              type: object
            valueFileSecrets:
              type: array
              items:
                type: object
                properties:
                  name:
                    type: string
---

The above manifest will create 2 crds

  • helmreleases.flux.weave.works
  • fluxhelmreleases.helm.integrations.flux.weave.works

which check for helm releases and deploy them automatically.

CRDs are a cluster-wide resource that can only be created by cluster-admins and the whole cluster has access on them.

Installing Helm

If you dont have helm installed in your cluster, first install it by applying the following manifest. Through the following manifest, we are deploying helm in kube-system namespace

apiVersion: v1
kind: ServiceAccount
metadata:
  name: tiller
  namespace: kube-system
---
# Role & Rolebinding for flux namespace to deploy flux
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: tiller-flux-binding
  namespace: flux
subjects:
- kind: ServiceAccount
  name: tiller
  namespace: kube-system
roleRef:
  kind: Role
  name: tiller-flux-role
  apiGroup: rbac.authorization.k8s.io
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: tiller-flux-role
  namespace: flux
rules:
- apiGroups: ["*"]
  resources: ["*"]
  verbs: ["*"]
---
# Role & Rolebinding for demo namespace where it will be deploying applications
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: tiller-demo-binding
  namespace: demo
subjects:
- kind: ServiceAccount
  name: tiller
  namespace: kube-system
roleRef:
  kind: Role
  name: tiller-demo-role
  apiGroup: rbac.authorization.k8s.io
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: tiller-demo-role
  namespace: demo
rules:
- apiGroups: ["*"]
  resources: ["*"]
  verbs: ["*"]
---
# Role & Rolebinding for kube-system namespace for handling the configmaps.
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: tiller-system-binding
  namespace: kube-system
subjects:
- kind: ServiceAccount
  name: tiller
  namespace: kube-system
roleRef:
  kind: Role
  name: tiller-system-role
  apiGroup: rbac.authorization.k8s.io
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: tiller-system-role
  namespace: kube-system
rules:
- apiGroups: ["*"]
  resources: ["*"]
  verbs: ["*"]

This can be deployed through following commands:

kubectl apply -f tiller.yaml            # above file
helm init --service-account tiller      # by default namespace is kube-system, you can specify it by passing a flag --tiller-namespace

The above commands will install tiller(helm) with limited access in kube-system namespace.

Installing Flux

The default chart of flux requires cluster-admin clusterrole, and we want limited access so we are not using the rbac provided by the chart but will be deploying the rbac separately.

Now, we will deploy the rbac required for flux instance.

apiVersion: v1
kind: ServiceAccount
metadata:
  name: flux
  namespace: flux
---
# Role & Rolebinding for flux namespace
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: flux-binding
  namespace: flux
subjects:
- kind: ServiceAccount
  name: flux
  namespace: flux
roleRef:
  kind: Role
  name: flux-role
  apiGroup: rbac.authorization.k8s.io
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: flux-role
  namespace: flux
rules:
- apiGroups: ["*"]
  resources: ["*"]
  verbs: ["*"]
---
# Role & Rolebinding for demo namespace where helm operator will deploy HelmReleases
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: flux-demo-binding
  namespace: demo
subjects:
- kind: ServiceAccount
  name: flux
  namespace: flux
roleRef:
  kind: Role
  name: flux-demo-role
  apiGroup: rbac.authorization.k8s.io
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: flux-demo-role
  namespace: demo
rules:
- apiGroups: ["*"]
  resources: ["*"]
  verbs: ["*"]
---
# Role & RoleBinding for kube-system namespace so helm operator can talk to tiller.
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: flux-system-binding
  namespace: kube-system
subjects:
- kind: ServiceAccount
  name: flux
  namespace: flux
roleRef:
  kind: Role
  name: flux-system-role
  apiGroup: rbac.authorization.k8s.io
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: flux-system-role
  namespace: kube-system
rules:
- apiGroups: ["*"]
  resources: ["services"]
  verbs: ["get","list","watch"]

---

The above manifest will create a service account named flux and will give it complete permission over the demo and flux namespaces.

Now to deploy flux using helm, create a values file i.e. values.yaml with following content:

rbac:
  create: false
serviceAccount:
  create: false
  name: flux
helmOperator:
  create: true
  createCRD: false
  updateChartDeps: false
git:
  url: ssh://git@github.com/stakater/flux-helm-test
  pollInterval: "10s"
registry:
  pollInterval: "200m"
  excludeImage: "*"
additionalArgs:
  - --k8s-namespace-whitelist=demo

You can modify any value you want, in the above file we are setting the git url to git@github.com/stakater/flux-helm-test and to include only demo namespace.

Now run the following command:

helm install --name flux --namespace flux weaveworks/flux -f values.yaml

The above command will deploy flux which will be looking into stakater/flux-helm-test repo, you can change that to your repo.

After this command, run kubectl -n flux logs deployment/flux | grep identity.pub | cut -d '"' -f2 to get the ssh key and add that in the repo's deploy keys by going to Settings -> Deploy Keys -> Add Deploy Key. Give Write access to the key. Now flux will be able to read and write to your git repo.

Deploying above flux instance will deploy helm chart present in stakater/flux-helm-test, currently it has a umbrella chart that deploys Xposer(a utility developed to create/update/delete Ingresses directly from Services). So xposer will be deployed in demo namespace.