Skip to main content
This quickstart guide will walk you through setting up a Kubernetes cluster from scratch with Cilium CNI and FluxCD GitOps. By the end, you’ll have a fully functional cluster with automatic synchronization from your Git repository.

Prerequisites

Before you begin, ensure you have:
  • A Linux machine with root access
  • Basic familiarity with Kubernetes concepts
  • A GitHub account and repository for your Flux configuration
  • GitHub Personal Access Token with repo permissions

System Preparation

1

Enable IP forwarding

IP forwarding is required for Kubernetes networking:
# Permanent configuration
echo "net.ipv4.ip_forward=1" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
2

Disable swap

Kubernetes requires swap to be disabled:
sudo swapoff -a
sudo sed -i '/swap/s/^/#/' /etc/fstab
sudo systemctl mask swap.target

# Verify swap is disabled
swapon --show
3

Configure containerd

Create or modify /etc/containerd/config.toml:
sudo containerd config default > /etc/containerd/config.toml
Update the configuration to enable SystemdCgroup:
version = 2

[plugins]
  [plugins."io.containerd.grpc.v1.cri"]
    [plugins."io.containerd.grpc.v1.cri".containerd]
      [plugins."io.containerd.grpc.v1.cri".containerd.runtimes]
        [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
          runtime_type = "io.containerd.runc.v2"
          [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
            SystemdCgroup = true
Restart containerd:
sudo systemctl restart containerd

Install Kubernetes Components

1

Install kubeadm, kubelet, and kubectl

Install Kubernetes v1.33.0:
sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl gpg

# Add Kubernetes apt repository
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.33/deb/Release.key | \
  sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg

echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.33/deb/ /' | \
  sudo tee /etc/apt/sources.list.d/kubernetes.list

# Install specific version
sudo apt-get update
sudo apt-get install -y kubelet=1.33.0-1.1 kubeadm=1.33.0-1.1 kubectl=1.33.0-1.1
sudo apt-mark hold kubelet kubeadm kubectl
2

Initialize the cluster

Replace 192.168.0.101 with your control plane node’s IP address. The --skip-phases=addon/kube-proxy flag is crucial because Cilium will replace kube-proxy.
sudo kubeadm init \
  --skip-phases=addon/kube-proxy \
  --apiserver-advertise-address=192.168.0.101 \
  --pod-network-cidr="10.1.0.0/16" \
  --upload-certs
Configure kubectl access:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
3

Add worker nodes (optional)

If you want to add worker nodes, use the kubeadm join command that was output from the kubeadm init command. It will look similar to:
kubeadm join 192.168.0.101:6443 --token <token> \
  --discovery-token-ca-cert-hash sha256:<hash>

Install Cilium CNI

Cilium provides advanced networking capabilities and replaces kube-proxy.
1

Install Cilium CLI

Download and install the Cilium CLI tool:
CILIUM_CLI_VERSION=$(curl -s https://raw.githubusercontent.com/cilium/cilium-cli/main/stable.txt)
CLI_ARCH=amd64
if [ "$(uname -m)" = "aarch64" ]; then CLI_ARCH=arm64; fi

curl -L --fail --remote-name-all \
  https://github.com/cilium/cilium-cli/releases/download/${CILIUM_CLI_VERSION}/cilium-linux-${CLI_ARCH}.tar.gz{,.sha256sum}

sha256sum --check cilium-linux-${CLI_ARCH}.tar.gz.sha256sum
sudo tar xzvfC cilium-linux-${CLI_ARCH}.tar.gz /usr/local/bin
rm cilium-linux-${CLI_ARCH}.tar.gz{,.sha256sum}
For more installation options, see the Cilium documentation.
2

Install Cilium with Gateway API support

Replace 192.168.0.101 with your control plane node’s IP address.
cilium install \
  --set kubeProxyReplacement=true \
  --set k8sServiceHost=192.168.0.101 \
  --set k8sServicePort=6443 \
  --set nodePort.enabled=true \
  --set gatewayAPI.enabled=true
This configuration:
  • Enables kube-proxy replacement
  • Configures the API server address
  • Enables NodePort support
  • Enables Gateway API support for advanced ingress capabilities
3

Verify Cilium installation

Wait for Cilium to be ready:
cilium status --wait
You should see output indicating all components are healthy.

Bootstrap FluxCD

FluxCD will continuously synchronize your cluster state with your Git repository.
1

Set up your GitHub repository

Make sure you have:
  • A GitHub repository (can be private or public)
  • A GitHub Personal Access Token with repo permissions
  • Your repository contains the FluxCD configuration structure
2

Bootstrap Flux

Replace the placeholders with your actual GitHub username, repository name, and path to the cluster configuration.
export GITHUB_TOKEN="<your-github-token>"

flux bootstrap github \
  --owner=<your-github-username> \
  --repository=<your-repo-name> \
  --private=false \
  --personal=true \
  --path=cluster/kimawesome \
  --token-auth=false \
  --read-write-key=true \
  --components-extra='image-reflector-controller,image-automation-controller'
This command:
  • Creates a deploy key in your repository
  • Installs FluxCD components in the cluster
  • Sets up continuous synchronization
  • Includes image automation controllers for automatic image updates
3

Verify Flux installation

Check that all Flux components are running:
flux check
kubectl -n flux-system get pods
You should see pods for:
  • source-controller
  • kustomize-controller
  • helm-controller
  • notification-controller
  • image-reflector-controller
  • image-automation-controller
4

Monitor synchronization

Watch Flux synchronize your cluster:
flux get kustomizations --watch
This will show the status of all Kustomizations being applied to your cluster.

Verify Your Cluster

1

Check node status

kubectl get nodes
All nodes should show Ready status.
2

Check Flux resources

kubectl get gitrepositories -A
kubectl get kustomizations -A
kubectl get helmreleases -A
These commands show the GitOps resources that Flux is managing.
3

View cluster components

kubectl get pods -A
You should see pods in various namespaces including:
  • flux-system - FluxCD controllers
  • kube-system - Kubernetes system components and Cilium

Next Steps

Now that your cluster is running with FluxCD, you can:

Configure Infrastructure

Set up MetalLB, cert-manager, and other infrastructure components

Deploy Applications

Deploy your applications using GitOps workflows

Manage Secrets

Configure sealed-secrets for secure secret management

Set Up Monitoring

Deploy the Grafana stack for observability

Troubleshooting

Check Cilium status:
cilium status
cilium connectivity test
Review Cilium logs:
kubectl -n kube-system logs -l k8s-app=cilium
Check Flux logs:
flux logs --all-namespaces
Verify Git repository access:
flux get sources git
Common issues:
  • Ensure swap is disabled: swapon --show
  • Check if ports 6443, 10250, 10259, 10257 are available
  • Verify containerd is running: sudo systemctl status containerd
View kubeadm logs:
journalctl -xeu kubelet

Reference Configuration

The repository structure used in this guide:
.
├── cluster/
│   └── kimawesome/
│       ├── flux-system/          # Flux system components
│       ├── kustomization.yaml    # Cluster-level kustomization
│       └── kustomization.flux.yaml  # Overlay kustomization
├── overlays/
│   ├── base/                     # Base configurations
│   │   ├── cert-manager/
│   │   ├── metallb/
│   │   ├── sealed-secrets/
│   │   ├── kgateway/
│   │   └── grafana/
│   └── kimawesome/               # Environment-specific overlays
│       ├── infrastructure/
│       ├── applications/
│       └── site/
└── cilium-values.yaml            # Cilium configuration
The kustomization.flux.yaml in your cluster directory points to the overlays for your environment, enabling GitOps management of all infrastructure and applications.

Build docs developers (and LLMs) love