View on GitHub

A collection of How-To to install and operate a Personal Cloud

Install Kubernetes

On each node

apt install gnupg2 apt-transport-https curl iptables
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf 
overlay 
br_netfilter 
EOF
modprobe overlay
modprobe br_netfilter
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf 
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1 
EOF
sysctl --system

cri-o

OS=Debian_12
VERSION=1.27
echo "deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/$OS/ /" > /etc/apt/sources.list.d/devel-kubic-libcontainers-stable-$VERSION.list
echo "deb http://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable:/cri-o:/$VERSION/$OS/ /" > /etc/apt/sources.list.d/devel-kubic-libcontainers-stable-cri-o-$VERSION.list
curl -L https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable:/cri-o:/$VERSION/$OS/Release.key | gpg --dearmor | tee /etc/apt/trusted.gpg.d/devel-kubic-libcontainers-$VERSION.gpg > /dev/null
curl -L https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/$OS/Release.key | gpg --dearmor | tee /etc/apt/trusted.gpg.d/devel-kubic-libcontainers-cri-o-$VERSION.gpg > /dev/null
apt-get update
apt-get install cri-o cri-o-runc cri-tools
apt-mark hold cri-o cri-o-runc
systemctl enable crio

K8s

curl -L https://packages.cloud.google.com/apt/doc/apt-key.gpg | gpg --dearmor | tee /etc/apt/trusted.gpg.d/kubernetes.gpg > /dev/null
echo "deb https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list
apt update
apt-get install kubelet=1.27.2-00 kubeadm=1.27.2-00 kubectl=1.27.2-00
apt-mark hold kubelet kubeadm kubectl
service crio start

On the master node

kubeadm init --pod-network-cidr=10.86.0.0/16
To start using your cluster, you need to run the following as a regular user:

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

Alternatively, if you are the root user, you can run:

  export KUBECONFIG=/etc/kubernetes/admin.conf

You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
  https://kubernetes.io/docs/concepts/cluster-administration/addons/

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join 192.168.7.117:6443 --token x36skg.hkyg3vqd8s3hbfoc \
	--discovery-token-ca-cert-hash sha256:d63dfb51ff1e98a55e7042844ffe7fa9df8f1b126f06156487e22c212dbf7084

On the other nodes

kubeadm join 192.168.7.117:6443 --token x36skg.hkyg3vqd8s3hbfoc \
	--discovery-token-ca-cert-hash sha256:d63dfb51ff1e98a55e7042844ffe7fa9df8f1b126f06156487e22c212dbf7084

On the master node

kubectl label node k8s1node1 node-role.kubernetes.io/worker=worker
kubectl label node k8s1node2 node-role.kubernetes.io/worker=worker
kubectl label node k8s1node3 node-role.kubernetes.io/worker=worker
kubectl label node k8s1node4 node-role.kubernetes.io/worker=worker

antrea

On each node

apt install openvswitch-switch

On the master node

kubectl apply -f https://github.com/antrea-io/antrea/releases/download/v1.12.0/antrea.yml

metallb

kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.13.10/config/manifests/metallb-native.yaml
vi metallb-pool.yaml
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: default
  namespace: metallb-system
spec:
  addresses:
  - 192.168.7.50-192.168.7.59
kubectl apply -f metallb-pool.yaml
vi metallb-adv.yaml
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: default
  namespace: metallb-system
kubectl apply -f metallb-adv.yaml

ingress-haproxy

Install helm as root

sudo -i
curl https://baltocdn.com/helm/signing.asc | gpg --dearmor | sudo tee /usr/share/keyrings/helm.gpg > /dev/null
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/helm.gpg] https://baltocdn.com/helm/stable/debian/ all main" | tee /etc/apt/sources.list.d/helm-stable-debian.list
apt-get update
apt-get install helm
exit

Install ingress-haproxy as a kubernetes user

helm repo add haproxy-ingress https://haproxy-ingress.github.io/charts
vi haproxy-ingress-values.yaml
controller:
  hostNetwork: true
helm install haproxy-ingress haproxy-ingress/haproxy-ingress\
  --create-namespace --namespace ingress-controller\
  --version 0.14.2\
  -f haproxy-ingress-values.yaml

Rook / Ceph

On each storage node

apt install lvm2 ntp

On the master node

apt install git
git clone --single-branch --branch v1.11.4 https://github.com/rook/rook.git
cd rook/deploy/examples
cp operator.yaml ../../../init/
cp cluster.yaml ../../../init/
cp toolbox.yaml ../../../init/
cp crds.yaml ../../../init/
cp common.yaml ../../../init/
cd ../../../init
kubectl get nodes --show-labels
kubectl label node k8s1node1 storage-node=true
kubectl label node k8s1node2 storage-node=true
kubectl label node k8s1node3 storage-node=true

Modify operator.yaml and cluster.yaml

kubectl create -f crds.yaml -f common.yaml -f operator.yaml

Wait orchestrator running

kubectl create -f cluster.yaml
kubectl create -f toolbox.yaml
kubectl -n rook-ceph exec -it deploy/rook-ceph-tools -- bash

Check that Ceph status is OK

ceph status
ceph osd status

cert-manager

kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.12.0/cert-manager.yaml

PKI

apt install coreutils
cat intermediate_ca.crt root_ca.crt > bundle_ca.crt
cat bundle_ca.crt | base64 -w0
openssl ec -in intermediate_ca_key -out intermediate_ca.key
cat intermediate_ca.key | base64 -w0
kubectl create namespace cert-manager
vi intermediate-ca-key-pair.yaml
apiVersion: v1
kind: Secret
metadata:
  name: intermediate-ca-key-pair
  namespace: cert-manager
data:
  tls.crt: YOUR_CRT
  tls.key: YOUR_KEY
kubectl apply -f intermediate-ca-key-pair.yaml
vi intermediate-ca-issuer.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: intermediate-ca-issuer
  namespace: cert-manager
spec:
  ca:
    secretName: intermediate-ca-key-pair
kubectl apply -f intermediate-ca-issuer.yaml

Ceph objectstore

vi s3-cert.yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: s3-cert
  namespace: rook-ceph
spec:
  commonName: s3-cert
  secretName: s3-secret
  dnsNames:
  - rook-ceph-rgw-s3-object-store.rook-ceph.svc
  privateKey:
    algorithm: ECDSA
    size: 256
  issuerRef:
    name: intermediate-ca-issuer
    kind: ClusterIssuer
    group: cert-manager.io
kubectl apply -f s3-cert.yaml
vi s3-object-store.yaml
apiVersion: ceph.rook.io/v1
kind: CephObjectStore
metadata:
  name: s3-object-store
  namespace: rook-ceph
spec:
  metadataPool:
    failureDomain: host
    replicated:
      size: 3
      requireSafeReplicaSize: true
    parameters:
      compression_mode: none
  dataPool:
    failureDomain: host
    replicated:
      size: 3
      requireSafeReplicaSize: true
    parameters:
      compression_mode: none
  preservePoolsOnDelete: false
  gateway:
    sslCertificateRef: s3-secret
    securePort: 443
    instances: 1
  healthCheck:
    startupProbe:
      disabled: false
    readinessProbe:
      disabled: false
kubectl apply -f s3-object-store.yaml
vi s3-storageclass.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
   name: s3-bucket
   namespace: rook-ceph
provisioner: rook-ceph.ceph.rook.io/bucket
reclaimPolicy: Delete
parameters:
  objectStoreName: s3-object-store
  objectStoreNamespace: rook-ceph
kubectl create -f s3-storageclass.yaml
vi s3-bucket-claim.yaml
apiVersion: objectbucket.io/v1alpha1
kind: ObjectBucketClaim
metadata:
  name: s3-bucket
  namespace: rook-ceph
spec:
  generateBucketName: s3-bucket
  storageClassName: s3-bucket
kubectl create -f s3-bucket-claim.yaml

Ingress

vi s3-example-com-cert.yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: s3-example-com-cert
  namespace: rook-ceph
spec:
  commonName: s3-example-com-cert
  secretName: s3-example-com-secret
  dnsNames:
  - s3.example.com
  privateKey:
    algorithm: ECDSA
    size: 256
  issuerRef:
    name: intermediate-ca-issuer
    kind: ClusterIssuer
    group: cert-manager.io
kubectl apply -f s3-example-com-cert.yaml
vi s3-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: s3-ingress
  namespace: rook-ceph
  annotations:
    kubernetes.io/ingress.class: haproxy
    ingress.kubernetes.io/secure-backends: "true"
    ingress.kubernetes.io/backend-protocol: "HTTPS"
spec:
  rules:
  - host: s3.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: rook-ceph-rgw-s3-object-store
            port:
              number: 443
  tls:
  -
    secretName: s3-example-com-secret
    hosts:
    - s3.example.com
kubectl create -f s3-ingress.yaml

S3 client

echo $(kubectl -n default get secret s3-bucket -n rook-ceph -o jsonpath='{.data.AWS_ACCESS_KEY_ID}' | base64 --decode)
echo $(kubectl -n default get cm s3-bucket -n rook-ceph -o jsonpath='{.data.BUCKET_NAME}')
echo $(kubectl -n default get secret s3-bucket -n rook-ceph -o jsonpath='{.data.AWS_SECRET_ACCESS_KEY}' | base64 --decode)

s3cmd

sudo apt install s3cmd
s3cmd --configure

.s3cfg

host_base = s3.example.com
host_bucket = s3://s3-bucket-xxxxxxxx-xxxx-xxx-xxxx-xxxxxxxxxxxx

Create S3 user

apiVersion: ceph.rook.io/v1
kind: CephObjectStoreUser
metadata:
  name: my-user
  namespace: rook-ceph
spec:
  store: my-store
  displayName: "my display name"