Skip to content

Latest commit

 

History

85 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Kubernetes GitOps with K3s, ArgoCD and Proxmox VM

A hands-on Kubernetes homelab built with K3s running on Proxmox VMs and managed using a GitOps workflow with ArgoCD.

The repository contains Kubernetes manifests and infrastructure configuration for deploying and managing the cluster declaratively, including:

- K3s — Lightweight Kubernetes distribution
- Proxmox VE — Virtualization platform hosting the Kubernetes nodes
- ArgoCD — GitOps-based continuous delivery
- Longhorn — Distributed persistent storage
- MetalLB — LoadBalancer implementation for the bare-metal cluster
- GitHub — Source of truth for Kubernetes configuration

The goal is to build a practical Kubernetes environment while learning and documenting cluster operations, GitOps, networking, storage, and workload deployment.

kubernetes-gitops/
├── root-application.yaml
│
├── infrastructure/
│   ├── metallb/
│   │   └── application.yaml
│   └── longhorn/
│       └── application.yaml
│
└── infrastructure-config/
    └── metallb/
        ├── ipaddresspool.yaml
        └── l2advertisement.yaml

Environments

  • 1 VM for master node k3s-master01
    (2 vCPU, +8GB RAM, +50GB Storage) - IP Addr 192.168.31.4 (set according to your local subnet)
  • 1 VM for worker node k3s-worker01
    (2 vCPU, +8GB RAM, +50GB Storage) - IP Addr 192.168.31.5 (set according to your local subnet)
  • Tested on Debian 13 and Ubuntu 26.04 server

  1. In k3s-master01

    Install K3s master/control plane without servicelb. We will replace it with Metal LB

    curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--disable servicelb" sh -s - --write-kubeconfig-mode 644
    

    Verify with

    systemctl status k3s
    

    Get K3s token for worker node installation

    cat /var/lib/rancher/k3s/server/node-token
    
  2. In k3s-worker01

    Install K3s worker/agent

    curl -sfL https://get.k3s.io | K3S_URL=https://<mymasternode>:6443 K3S_TOKEN=<mymasternodetoken> sh -
    

    <mymasternode> is k3s-master01 IP Address or hostname
    <mymasternodetoken> is the token from step 1

    If you want to run kubectl in worker node, copy /etc/rancher/k3s/k3s.yaml from master node.
    Modify server: https://127.0.0.1:6443 to server: https://<MASTER_NODE_IP>:6443
    Then run

    mkdir -p ~/.kube
    mv k3s.yaml ~/.kube/config
    chmod 600 ~/.kube/config
    
  3. From k3s-master01 install ArgoCD to the cluster

    Check status both nodes

    kubectl get nodes
    

    Create namespace and install ArgoCD

    kubectl create namespace argocd     
    kubectl apply -n argocd --server-side --force-conflicts -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
    

    Wait few minutes to complete ArgoCD deployment, check with kubectl get all -n argocd

    Get ArgoCD secret

    kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d; echo
    

    Port Forwarding for tunneling

    kubectl port-forward svc/argocd-server -n argocd 8081:443
    
  4. From you computer

    Tunneling to k3s-master01_IP_ADDRESS with existing USERNAME

    ssh -L 8081:127.0.0.1:8081 USERNAME@k3s-master01_IP_ADDRESS
    

    Access ArgoCD Web UI from web browser with user admin and secret from step 3

    https://127.0.0.1:8081
    
    

Note

Prepare your own repo as source of ArgoCD to deploy apps, you can clone this repo to your github account.
If you don't want to deploy Longhorn, remove longhorn from infrastructure directory

For Private Repo, you need to generate key for ArgoCD so it can access your repo

  1. In k3s-master01 create key for git repo. Skip passphrase (leave it empty)

    ssh-keygen -t ed25519 -f ~/.ssh/argocd-github -C "argocd-kubernetes-gitops"
    

    Copy content of public key

    cat ~/.ssh/argocd-github.pub
    
  2. Add it to GitHub

    In your repo example tobing/kubernetes-gitops repository:
    Go to Settings → Deploy keys → Add deploy key
    Set:
    Title: ArgoCD
    Key: paste the contents of argocd-github.pub
    Allow write access: OFF
    We only want ArgoCD to read Git.

  3. From k3s-master01 create secret:

    kubectl create secret generic repo-kubernetes-gitops \
    -n argocd \
    --from-literal=type=git \
    --from-literal=url=git@github.com:tobing/kubernetes-gitops.git \
    --from-file=sshPrivateKey=$HOME/.ssh/argocd-github
    

    Modifygit@github.com:tobing/kubernetes-gitops.git to your git repo

  4. Then label it so ArgoCD recognizes it as a repository credential:

    kubectl label secret repo-kubernetes-gitops \
    -n argocd \
    argocd.argoproj.io/secret-type=repository
    
  1. Check infrastructure-config/metallb/ipaddresspool.yaml for your Metal LB IP Address pool.
    I am using 192.168.31.240-192.168.31.250. Set them based on your local subnet.

  2. Create a temporary file root-application.yaml ⚠️ This file for ArgoCD initialization.
    Modify repoURL according to your git repo. $\color{red}{\text{CHECK CAREFULLY}}$

    Run kubectl apply -f root-application.yaml and check ArgoCD Web UI.

    After few minutes from k3s-master01 check if all running and no issue

    kubectl get all -A
    

    $\color{red}{\text{If you did not remove longhorn from infrastructure directory in your github repo, you will deploy longhorn also}}$ $\color{red}{\text{Make sure to follow Longhorn instruction in the bottom}}$

  3. Try to modify metallb version targetRevision: 0.16.1 in infrastructure/metallb/application.yaml to something else like 0.16.0.
    After git push, ArgoCD will syncing.

Note

Longhorn - Distributed Block Storage System for Kubernetes

Details
  1. Install iSCSI in both k3s-master01 and k3s-worker01

    apt update
    apt install -y open-iscsi
    

    Enable the services

    systemctl enable --now iscsid
    systemctl enable --now open-iscsi
    

    Check

    systemctl status iscsid.socket --no-pager
    systemctl status iscsid --no-pager
    
  2. Because we use 2 nodes only, but Longhorn default replica is 3

    kubectl -n longhorn-system get settings.longhorn.io default-replica-count -o yaml
    
    value: '{"v1":"3","v2":"3"}'
    

    Change to 2

    kubectl -n longhorn-system patch settings.longhorn.io default-replica-count \
    --type=merge \
    -p '{"value":"{\"v1\":\"2\",\"v2\":\"2\"}"}'
    

    Verify

    kubectl -n longhorn-system get settings.longhorn.io default-replica-count -o yaml
    
  3. Create a test Persistant Volume Claim (PVC)

    kubectl create -f - <<'EOF'
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: longhorn-test
    spec:
      storageClassName: longhorn
      accessModes:
        - ReadWriteOnce
      resources:
        requests:
          storage: 2Gi
    EOF
    

    Check

    kubectl get pvc longhorn-test
    

    Result

    STATUS   Bound
    
  4. Create a test pods

    kubectl create -f - <<'EOF'
    apiVersion: v1
    kind: Pod
    metadata:
      name: longhorn-test
    spec:
      containers:
        - name: test
          image: busybox
          command: ["sh", "-c", "echo 'Longhorn works!' > /data/test.txt && sleep 3600"]
          volumeMounts:
            - name: data
              mountPath: /data
      volumes:
        - name: data
          persistentVolumeClaim:
            claimName: longhorn-test
    EOF
    

    Check if running

    kubectl get pod longhorn-test
    

    If running

    kubectl exec longhorn-test -- cat /data/test.txt
    

    Expected result

    Longhorn works!
    

    To delete the pod

    kubectl delete pod longhorn-test
    
  5. Access Longhorn Web UI

    From k3s-master01

    kubectl port-forward -n longhorn-system svc/longhorn-frontend 8090:80
    

    From you computer tunneling to k3s-master01_IP_ADDRESS with existing USERNAME

    ssh -L 8090:127.0.0.1:8090 USERNAME@k3s-master01_IP_ADDRESS
    

    Access Longhorn Web UI from web browser

    http://127.0.0.1:8090
    
    
  6. Troubleshooting "Degraded" volume because step 13

    kubectl -n longhorn-system get volume
    
    kubectl -n longhorn-system get volumes.longhorn.io <pvc-id> -o jsonpath='{.spec.numberOfReplicas}{"\n"}'
    
    kubectl -n longhorn-system patch volumes.longhorn.io <pvc-id> --type=merge -p '{"spec":{"numberOfReplicas":2}}'
    

About

K3s Kubernetes homelab on Proxmox VMs, managed with ArgoCD GitOps, Longhorn storage, and MetalLB networking.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Contributors