A simple example of managing local K3s cluster including example applications using Flux2, Helm and Kustomize.
- Local K3s cluster using K3d
- Example applications (separate repositories) including Single-page Application and REST API
- Continuous Delivery with GitOps workflow using Flux2
- Scheduled upgrade check of Flux2 using Renovate
- Policies to secure Kubernetes Pods using Kyverno
- Network traffic flow control using Network Policies
- Easy installation using go-task
- YAML validation using yamllint
The applications are located in separated GitHub repositories and are deployed to the K3s cluster using Flux2.
The example applications consist from:
- Single-page Application (Create React App)
- REST API with in-memory data store (Node.js + Express.js + Redis)
The folders are structured based on the Flux2 example.
├── infrastructure
│ ├── calico
│ ├── kyverno
│ ├── kyverno-policies
│ ├── nginx
│ ├── redis
│ └── sources
└── clusters
└── cluster-1
Includes calico, kyverno, kyverno-policies, nginx and redis configurations as well as Helm Repository definitions. It also includes example applications Git Repository definitions (api.yaml and client.yaml)
└── infrastructure
├── calico
│ └── calico.yaml
├── kyverno
│ └── kustomization.yaml
├── kyverno-policies
│ ├── kustomization.yaml
│ └── pod-security-restricted.yaml
├── nginx
│ ├── kustomization.yaml
│ ├── namespace.yaml
│ └── release.yaml
├── redis
│ ├── kustomization.yaml
│ ├── kustomizeconfig.yaml
│ ├── namespace.yaml
│ ├── release.yaml
│ └── values.yaml
└── sources
├── api.yaml
├── bitnami.yaml
├── client.yaml
└── kustomization.yaml
Includes the Flux configuration per cluster.
└── clusters
└── cluster-1
├── apps.yaml
└── infrastructure.yaml
The clusters/<CLUSTER_ENVIRONMENT>/apps.yaml defines the path for Kustomize patch which includes the environment specific values. Note that the path refers to a directory which is at different GitHub repository.
apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
kind: Kustomization
metadata:
name: api
namespace: flux-system
spec:
interval: 1m
dependsOn:
- name: infrastructure
path: "./k8s/staging" # https://github.com/terotuomala/k8s-express-api-example/tree/main/k8s/staging
.....
---
apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
kind: Kustomization
metadata:
name: client
namespace: flux-system
spec:
interval: 1m
dependsOn:
- name: infrastructure
path: "./k8s/staging" # https://github.com/terotuomala/k8s-create-react-app-example/tree/main/k8s/staging
.....NB. The setup is tested on
macOS Monterey.
The first prerequisite is to install go-task in order to make the setup a bit easier:
brew install go-task/tap/go-taskNB. The tasks used in the setup are defined in Taskfile.yml.
The following prerequisites are used in order to create and manage the local K3s cluster(s):
- Docker Desktop
- Kubectl
- Flux CLI
- K3d (at least version v5.4.3)
If you don't have them installed yet you can install them using install-prerequisites task:
task install-prerequisitesFork your own copy of this repository to your GitHub account and create a personal access token and export the following variables:
export GITHUB_TOKEN=<YOUR_PERSONAL_ACCESS_TOKEN>
export GITHUB_USER=<YOUR_GITHUB_USERNAME>
export GITHUB_REPO=<YOUR_FORKED_GITHUB_REPO_NAME>NB. The K3s cluster is using Calico instead of Flannel in order to be able to use Network Policies.
Create the cluster:
task k8s:create-cluster1Verify that Calico controller deployment is ready:
task k8s:verify-calicoVerify that k3s cluster-1 satisfies flux2 prerequisites:
task flux:check-prerequisitesInstall Flux and configure it to manage itself from a Git repository:
task flux:bootstrap-cluster1Flux2 is configured to deploy content of the infrastructure items using Helm before the application. Verify that the infrastructure Helm releases are synchronized to the cluster:
task flux:get-helmreleasesVerify that the api and client applications are synchronized to the cluster:
task flux:get-kustomizationsYou can also check Helm and Git repositories and their status:
task flux:get-helmrepositories
task flux:get-gitrepositoriesThe example applications should be accessible via Ingress:
- Single-page Application:
http://localhost:8080 - REST API:
http://api.localhost:8080
Inspired by these excellent projects: