Kubernetes (K3Sup)
===

### Installation de kubectl ?

```bash
sudo apt-get update && sudo apt-get install -y apt-transport-https ca-certificates curl gnupg
sudo mkdir -p -m 755 /etc/apt/keyrings
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.33/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
sudo chmod 644 /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
sudo chmod 644 /etc/apt/sources.list.d/kubernetes.list
sudo apt-get update
sudo apt-get install -y kubectl
```

### Installation de k3sup :

```bash
# Avec curl
curl -sLS https://get.k3sup.dev | sh
sudo install k3sup /usr/local/bin/

# Ou téléchargement direct depuis GitHub
wget https://github.com/alexellis/k3sup/releases/download/0.13.11/k3sup
chmod +x k3sup
sudo mv k3sup /usr/local/bin/
```

#### Premier déploiement :

```bash
# Installation du master node
k3sup install --ip 192.168.1.14 --user pleb --ssh-key $HOME/.ssh/bikiniBottom

# Ajout des worker nodes
k3sup join --ip 192.168.1.13 --server-ip 192.168.1.14 --user pleb --ssh-key $HOME/.ssh/bikiniBottom
k3sup join --ip 192.168.1.16 --server-ip 192.168.1.14 --user pleb --ssh-key $HOME/.ssh/bikiniBottom
k3sup join --ip 192.168.1.19 --server-ip 192.168.1.14 --user pleb --ssh-key $HOME/.ssh/bikiniBottom
```

#### Vérification du cluster :

```bash
# Export du kubeconfig
export KUBECONFIG=~/delmar.bzh/kubernetes/kubeconfig

# Vérification des nœuds
kubectl get nodes -o wide

# Check des pods système
kubectl get pods -n kube-system
```

#### Setting labels:

```bash
# sudo k3s kubectl label nodes xxx kubernetes.io/role=worker
kubectl label nodes gary kubernetes.io/role=worker
kubectl label nodes sheldon kubernetes.io/role=worker
kubectl label nodes pearl kubernetes.io/role=worker

# sudo k3s kubectl label nodes sandy node-type=worker
kubectl label nodes gary node-type=worker
kubectl label nodes sheldon node-type=worker
kubectl label nodes pearl node-type=worker
```

```bash
kubectl get nodes
```

```
NAME      STATUS   ROLES           AGE   VERSION
gary      Ready    worker          82m   v1.35.5+k3s1
pearl     Ready    worker          81m   v1.35.5+k3s1
sandy     Ready    control-plane   84m   v1.35.5+k3s1
sheldon   Ready    worker          82m   v1.35.5+k3s1
```

### Helm

> On sandy

```bash
curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3
chmod 700 get_helm.sh
./get_helm.sh
helm version
```

#### [Headlamp](https://headlamp.dev/docs/latest/)

```bash
# first add our custom repo to your local helm repositories
helm repo add headlamp https://kubernetes-sigs.github.io/headlamp/

# now you should be able to install headlamp via helm
helm install bb-headlamp headlamp/headlamp --namespace kube-system
```

```
NAME: bb-headlamp
LAST DEPLOYED: Tue Feb 17 17:17:03 2026
NAMESPACE: kube-system
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
```

1. Get the application URL by running these commands:
```bash
export POD_NAME=$(kubectl get pods --namespace kube-system -l "app.kubernetes.io/name=headlamp,app.kubernetes.io/instance=bb-headlamp" -o jsonpath="{.items[0].metadata.name}")
export CONTAINER_PORT=$(kubectl get pod --namespace kube-system $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl --namespace kube-system port-forward $POD_NAME 8080:$CONTAINER_PORT
```

2. Get the token using
```bash
kubectl create token bb-headlamp --namespace kube-system
```

#### metallb

```bash
# Add MetalLB repository to Helm
helm repo add metallb https://metallb.github.io/metallb

# Check the added repository
helm search repo metallb

helm upgrade --install metallb metallb/metallb --create-namespace \
--namespace metallb-system --wait
```
```bash
Release "metallb" does not exist. Installing it now.
NAME: metallb
LAST DEPLOYED: Wed Feb 18 11:46:03 2026
NAMESPACE: metallb-system
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
MetalLB is now running in the cluster.

Now you can configure it via its CRs. Please refer to the metallb official docs
on how to use the CRs.
```
```bash
vim metallb-config.yaml

---
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: default-pool
  namespace: metallb-system
spec:
  addresses:
  - 192.168.1.21-192.168.1.30

---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: default
  namespace: metallb-system
spec:
  ipAddressPools:
  - default-pool
```

#### traefik

```bash
vim traefik-ingress.yml
```

```
---
apiVersion: v1
kind: Secret
metadata:
  name: traefik-basic-auth-secret
  namespace: kube-system
data:
  users: |2
    YWRtaW46JGFwcjEkMmp5TzMwYmskRE5IV0VEQW1VQXFVajVGOHNvdXNVMAoK

---
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: traefik-basic-auth-middleware
spec:
  basicAuth:
    secret: traefik-basic-auth-secret
    realm: "Traefik Dashboard"

---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: traefik-ingress
  namespace: kube-system
  annotations:
    spec.ingressClassName: traefik
    traefik.ingress.kubernetes.io/router.middlewares: kube-system-traefik-basic-auth-middleware@kubernetescrd
spec:
  serviceAccountName: traefik-ingress
  env:
    name: OVH_ENDPOINT
      value: ovh-eu
    name: OVH_APPLICATION_KEY
      value: 3f8bdfed17f848d8
    name: OVH_APPLICATION_SECRET
      value: 6946758d7515ecef108aeb286bf3c7d0
    name: OVH_CONSUMER_KEY
      value: 94b2ddf482d36421a33aa6b3aa51595
  args:
  - --configFile=/config/traefik.toml
  volumeMounts:
  - name: traefik-config
      mountPath: /config/
  - name: traefik-custom
      mountPath: /custom/
  - name: traefik-certs
      mountPath: /certs/
  ports:
    name: http
      containerPort: 80
    name: https
      containerPort: 443
    name: dashboard
      containerPort: 8080
  volumes:
  - name: traefik-config
  configMap:
  - name: traefik-config
  - name: traefik-custom
  - name: traefik-certs
  persistentVolumeClaim:
    claimName: traefik-certsrules:
  - http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: traefik-dashboard
            port:
              number: 8080

---
apiVersion: v1
kind: Service
metadata:
  name: traefik-dashboard
spec:
  ports:
  - name: http
    port: 8080
    targetPort: 8080
  selector:
    app: traefik-dashboard
  type: LoadBalancer

```

```bash
sudo k3s kubectl -n kube-system apply -f traefik-ingress.yml
```

#### [longhorn](https://longhorn.io)

```bash
helm repo add longhorn https://charts.longhorn.io
helm repo update
kubectl create namespace longhorn-system
helm install longhorn longhorn/longhorn --namespace longhorn-system

USER=admin; PASSWORD=v5bB4OQRDfY5tFJ1; echo "${USER}:$(openssl passwd -stdin -apr1 <<< ${PASSWORD})" >> auth

kubectl -n longhorn-system create secret generic basic-auth --from-file=auth

vim longhorn/longhorn-middelwares.yaml
````

```
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: longhorn-auth
  namespace: longhorn-system
spec:
  basicAuth:
    secret: basic-auth
---
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: longhorn-buffering
  namespace: longhorn-system
spec:
  buffering:
    # Allows backing image uploads up to 10,000MB
    maxRequestBodyBytes: 10485760000 
```

```bash
kubectl apply -f longhorn-middlewares.yml
```

```bash
vim longhorn/longhorn-ingress.yaml
```

```
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: longhorn-ingress
  namespace: longhorn-system
  annotations:
    # Connect the middlewares defined in step 2
    traefik.ingress.kubernetes.io/router.middlewares: 
      longhorn-system-longhorn-auth@kubernetescrd,
      longhorn-system-longhorn-buffering@kubernetescrd
spec:
  ingressClassName: traefik
  rules:
  - http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: longhorn-frontend
            port:
              number: 80
```

```bash
kubectl -n longhorn-system get pod

kubectl get storageclass
```

```
NAME                   PROVISIONER             RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
local-path (default)   rancher.io/local-path   Delete          WaitForFirstConsumer   false                  93m
longhorn (default)     driver.longhorn.io      Delete          Immediate              true                   59m
longhorn-static        driver.longhorn.io      Delete          Immediate              true                   59m
```

##### Unset default for "local-path" (emmc)

```bash
kubectl patch storageclass local-path -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"false"}}}'
```

##### Mark longhorn as "default"

```bash
kubectl patch storageclass longhorn -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
```

##### Apply ingress
```bash
kubectl -n longhorn-system apply -f longhorn/longhorn-ingress.yaml

kubectl -n longhorn-system get ingress
```
