Tutorials & Guides

Kubernetes

From fundamentals to advanced operations: namespaces, RBAC, pod security, workloads, service meshes, multi-cluster, backups, and disaster recovery. Each lesson includes ready-to-run commands and practical tips.

Kyverno

Author, test, and ship policies for validation, mutation, and generation. Enforce image signatures, mandate labels and annotations, restrict capabilities, and standardize configurations across teams.

GitOps & CI/CD

Build reliable delivery with Argo CD or Flux, templating with Helm and Kustomize, progressive delivery, and secure supply chains. Learn patterns for environments, rollbacks, and secrets management.

How this site works

Each module contains a short concept overview and a set of copy-paste commands you can run locally or in a lab cluster. Content targets Kubernetes v1.27+ and Kyverno v1.10+, with frequent updates as new releases ship.

K3s + Helm + Kyverno Quickstart

Install K3s

curl -sfL https://get.k3s.io | sh -

sudo systemctl restart k3s
sudo systemctl status k3s

mkdir -p ~/.kube
sudo cp /etc/rancher/k3s/k3s.yaml ~/.kube/config
sudo chown $USER:$USER ~/.kube/config
export KUBECONFIG=~/.kube/config
echo 'export KUBECONFIG=~/.kube/config' >> ~/.bashrc

Install Helm

curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash

Install Kyverno

helm repo add kyverno https://kyverno.github.io/kyverno/
helm repo update
helm install kyverno kyverno/kyverno -n kyverno --create-namespace --wait

Install Policy Reporter

helm repo add policy-reporter https://kyverno.github.io/policy-reporter
helm repo update

helm install policy-reporter policy-reporter/policy-reporter \
  --create-namespace -n policy-reporter \
  --set ui.enabled=true \
  --set kyverno-plugin.enabled=true

Access the UI

kubectl port-forward service/policy-reporter-ui 8082:8080 -n policy-reporter

ssh -L 8082:localhost:8082 sama@[this-vm-ip]

http://localhost:8082/

(Optional) Install the Pod Security Standard policy library

helm install kyverno-policies kyverno/kyverno-policies -n kyverno
kubectl get cpol

Install workloads

1. A basic compliant workload

Create file nginx-compliant.yaml with the following:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-compliant
  namespace: demo
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx-compliant
  template:
    metadata:
      labels:
        app: nginx-compliant
    spec:
      containers:
        - name: nginx
          image: nginx:1.27
          resources:
            limits:
              cpu: \"200m\"
              memory: \"256Mi\"
            requests:
              cpu: \"100m\"
              memory: \"128Mi\"

Apply it:
kubectl create namespace demo
kubectl apply -f nginx-compliant.yaml

2. A non-compliant workload (no resource limits)

Create file redis-noncompliant.yaml with the following:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: redis-noncompliant
  namespace: demo
spec:
  replicas: 1
  selector:
    matchLabels:
      app: redis-noncompliant
  template:
    metadata:
      labels:
        app: redis-noncompliant
    spec:
      containers:
        - name: redis
          image: redis:7

Apply it:
kubectl apply -f redis-noncompliant.yaml

Check Kyverno policies

kubectl get cpol

Example output:
NAME  ADMISSION  BACKGROUND  READY  AGE  MESSAGE
disallow-capabilities  true  true  True  15m  Ready
...
restrict-sysctls  true  true  True  15m  Ready

More workloads

kubectl create deployment busybox --image=busybox --namespace=demo -- sleep 3600
kubectl run standalone-pod --image=alpine --namespace=demo -- sleep 3600

Every container image reference has this shape:
[registry]/[namespace]/[image]:[tag]

If you omit parts, defaults kick in silently:
No registry -> docker.io (Docker Hub)
No namespace -> library (official images)
No tag -> :latest

Equivalent explicit forms:
kubectl create deployment busybox --image=docker.io/library/busybox:latest --namespace=demo -- sleep 3600
kubectl run standalone-pod --image=docker.io/library/alpine:latest --namespace=demo -- sleep 3600

Check pod image path:
kubectl get pod standalone-pod -n demo -o jsonpath='{.status.containerStatuses[0].image}'

Check Kyverno registry endpoint:
curl -I https://reg.kyverno.io/v2/

Keycloak deployment (dev)

kubectl create namespace keycloak

Create file keycloak.yaml with the following (Deployment + Service):

apiVersion: apps/v1
kind: Deployment
metadata:
  name: keycloak
  namespace: keycloak
spec:
  replicas: 1
  selector:
    matchLabels:
      app: keycloak
  template:
    metadata:
      labels:
        app: keycloak
    spec:
      containers:
        - name: keycloak
          image: quay.io/keycloak/keycloak:26.0
          args: ["start-dev"]
          env:
          - name: KEYCLOAK_ADMIN
            value: "admin"
          - name: KEYCLOAK_ADMIN_PASSWORD
            value: "admin"
          ports:
          - containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: keycloak
  namespace: keycloak
spec:
  type: NodePort
  selector:
    app: keycloak
  ports:
    - port: 8080
      targetPort: 8080

Apply and verify:
kubectl apply -f keycloak.yaml
kubectl -n keycloak get pods
kubectl -n keycloak get svc keycloak

Get this VM's IP:
ip a | grep "inet " | grep -v 127.0.0.1

Port-forward to access admin console:
kubectl port-forward -n keycloak service/keycloak 8080:8080

Or SSH tunnel:
ssh -L 8080:localhost:8080 sama@192.168.142.130

Troubleshooting pods crashing

Check node resource pressure
kubectl describe node sama | grep -A 5 "Conditions:"
kubectl top node

Disk space
df -h /

sudo du -sh /var/lib/rancher/* 2>/dev/null | sort -rh
sudo du -sh /var/log/* 2>/dev/null | sort -rh | head -10
sudo journalctl --disk-usage

sudo du -sh /var/lib/rancher/k3s/* 2>/dev/null | sort -rh
sudo du -sh /var/lib/rancher/k3s/agent/* 2>/dev/null | sort -rh

Logs
kubectl -n keycloak logs deployment/keycloak

Configure Keycloak

Add your realm, client, and users here. I can expand this section with specific steps you provide.