Install Grafana-operator using Flux and Kustomize
As a part of grafana-operator v5.0.0-rc1 we introduce Kustomize as a way of installing the operator.
To showcase this new feature, I thought why not use GitOps?
GitOps is a rather well-used term nowadays, but you can summarize it in 4 steps.
- Declarative
- Versioned and immutable
- Pulled automatically
- Continuously reconciled
To find out more about GitOps look at the CNCF GitOps working groups documentation.
In this case I have decided to use Flux to deploy grafana-operator through GitOps, but there are other options. For example ArgoCD which is also a graduated CNCF project just like Flux.
This blog’s focus is to showcase how you can use Kustomize to install the grafana-operator, I will take many shortcuts to keep this blog simple, read the official Flux documentation for best practices.
What we will do?
We will install the grafana-operator using Flux and to manage our grafana instance and dashboard.
Assuming that you follow the instructions of this blog, your Flux fleet-infra repository will look something like this.
├── clusters
│ └── my-cluster
│ ├── flux-system
│ │ ├── gotk-components.yaml
│ │ ├── gotk-sync.yaml
│ │ └── kustomization.yaml
│ ├── grafana
│ │ ├── dashboard.yaml
│ │ ├── grafana.yaml
│ │ └── kustomization.yaml
│ ├── grafana-operator.yaml
│ └── grafana.yaml
You can find all the files available to copy in the grafana-operator repository, or you can just copy paste them from the blog.
Prerequisite
In this example, I will use Kind as my cluster because I think it’s simple, but the walkthrough should work with any Kubernetes solution. I will use GitHub for my GitOps repository but Flux supports multiple source control management (SCM) providers.
So what will you need?
Setup cluster
Create a Kind cluster with ingress support.
cat <<EOF | kind create cluster --config=-
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
kubeadmConfigPatches:
- |
kind: InitConfiguration
nodeRegistration:
kubeletExtraArgs:
node-labels: "ingress-ready=true"
extraPortMappings:
- containerPort: 80
hostPort: 80
protocol: TCP
- containerPort: 443
hostPort: 443
protocol: TCP
EOF
When the cluster is up, install ingress-nginx.
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml
# Wait for ingress-nginx to become ready
kubectl wait --namespace ingress-nginx \
--for=condition=ready pod \
--selector=app.kubernetes.io/component=controller \
--timeout=90s
Bootstrap Flux
Read the official documentation on how to bootstrap your Flux setup, as I mentioned earlier, I will use github.
Before bootstrapping your cluster, you need to create a github PAT(Personal Access Token) with enough access.
I have been unable to find exactly what the minimal access needed for the token, so I just created a PAT with all the access. You should not do the same.
export GITHUB_TOKEN=github_pat_soooLongAndSecretPAT
flux bootstrap github --owner=<github-username> --repository=fleet-infra --private=false --personal=true --path=clusters/my-cluster
This will create a repository called fleet-infra in your GitHub account, install Flux to your cluster and setup an autosync to GitHub.
You should now be able to view Flux running in the fleet-infra
namespace.
Install operator using Flux and Kustomize
We are using Flux to package our Kustomize files through OCI, and they are built and released just as our helm solution.
There are two ways of installing the operator, either with namespace access or cluster access,
take a look at our documentation for more information.
Add the following file to your Flux repo under clusters/my-cluster/grafana-operator.yaml
.
apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: OCIRepository
metadata:
name: grafana-operator
namespace: flux-system
spec:
interval: 10m
url: oci://ghcr.io/grafana/kustomize/grafana-operator
ref:
tag: v5.0.0-rc3
---
apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
kind: Kustomization
metadata:
name: grafana-operator
namespace: flux-system
spec:
interval: 10m
targetNamespace: grafana
images:
- name: ghcr.io/grafana/grafana-operator
newTag: v5.0.0-rc3
prune: true
sourceRef:
kind: OCIRepository
name: grafana-operator
path: ./overlays/namespace_scoped
Depending on if you want to install cluster scoped or namespace scoped, you need to change the path.
Install operator using Kustomize
If you want to install the grafana-operator without using GitOps, you can also download the generated artifact and install it manually. For example, you can run the following Flux command to download the artifact and unpack it. Then you can run a normal kubectl apply command.
flux pull artifact oci://ghcr.io/grafana/kustomize/grafana-operator:v5.15.1 -output ./grafana-opreator
But of course we recommend that you manage your grafana-operator installation through your GitOps solution, no matter if it’s Flux or some other solution.
Install Grafana
Okay great, we got grafana-operator installed, but don’t we actually want to install a Grafana instance as well?
Let’s setup a Grafana instance and some dashboard trough code.
Since we already setup our kind cluster with ingress-nginx I will use one of our basic HTTP examples.
Let’s not make this more complicated than it has to be, you should have your secrets in some KMS/vault/sealed-secrets, SOAP or similar solution, but definitely not checked in to your GitOps repository non-encrypted. But this is an example, so for this time let’s create our admin and password secrets manual.
cat <<EOF | kubectl apply -f -
kind: Secret
apiVersion: v1
metadata:
name: credentials
namespace: grafana
stringData:
GF_SECURITY_ADMIN_PASSWORD: secret
GF_SECURITY_ADMIN_USER: root
type: Opaque
EOF
Now create our Grafana instance together with a very basic dashboard.
The Grafana instance should be stored in clusters/my-cluster/grafana/grafana.yaml
apiVersion: grafana.integreatly.org/v1beta1
kind: Grafana
metadata:
name: grafana
namespace: grafana
labels:
dashboards: "grafana"
spec:
config:
log:
mode: "console"
auth:
disable_login_form: "false"
deployment:
spec:
template:
spec:
containers:
- name: grafana
env:
- name: GF_SECURITY_ADMIN_USER
valueFrom:
secretKeyRef:
key: GF_SECURITY_ADMIN_USER
name: credentials
- name: GF_SECURITY_ADMIN_PASSWORD
valueFrom:
secretKeyRef:
key: GF_SECURITY_ADMIN_PASSWORD
name: credentials
ingress:
spec:
ingressClassName: nginx
rules:
- host: grafana.127.0.0.1.nip.io
http:
paths:
- backend:
service:
name: grafana-service
port:
number: 3000
path: /
pathType: Prefix
The Grafana dashboard should be stored in clusters/my-cluster/grafana/dashboard.yaml
apiVersion: grafana.integreatly.org/v1beta1
kind: GrafanaDashboard
metadata:
name: grafanadashboard-sample
namespace: grafana
spec:
resyncPeriod: 30s
instanceSelector:
matchLabels:
dashboards: "grafana"
json: >
{
"id": null,
"title": "Simple Dashboard",
"tags": [],
"style": "dark",
"timezone": "browser",
"editable": true,
"hideControls": false,
"graphTooltip": 1,
"panels": [],
"time": {
"from": "now-6h",
"to": "now"
},
"timepicker": {
"time_options": [],
"refresh_intervals": []
},
"templating": {
"list": []
},
"annotations": {
"list": []
},
"refresh": "5s",
"schemaVersion": 17,
"version": 0,
"links": []
}
We also need a Kustomization file to clusters/my-cluster/grafana/kustomization.yaml
to help Flux to find the files.
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- grafana.yaml
- dashboard.yaml
And finally create the Flux kustomization file (yes, the naming is a bit confusing).
Lets store it in clusters/my-cluster/grafana.yaml
apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
kind: Kustomization
metadata:
name: grafana
namespace: flux-system
spec:
force: false
dependsOn:
- name: grafana-operator # Depends on the grafana-operator being synced
healthChecks: # Check that grafana-deployment comes up
- apiVersion: apps/v1
kind: Deployment
name: grafana-deployment
namespace: grafana
interval: 10m0s
targetNamespace: grafana
path: ./clusters/my-cluster/grafana
prune: true
sourceRef:
kind: GitRepository
name: flux-system
After pushing the changes to your Flux repository, the changes should be applied to your cluster.
If you don’t want to wait for the automatic reconcile, you can run which will trigger a reconcile of the git repo.
flux reconcile source git flux-system -n flux-system
You should now be able to go to the Grafana URL that you defined, in my case http://grafana.127.0.0.1.nip.io
And you should see the simple dashboard among your dashboards.
Conclusion
We have used very basic setup of Flux to install grafana-operator to our cluster. When that was done, we installed a basic Grafana instance and a dashboard giving us dashboards as code.
The dashboard wasn’t the prettiest, but it’s an easy example. Hopefully someone will make a more in depth blog on how to use grafana-operator to bootstrap entire clusters monitoring in the future.