Создаем самую простую конфигурацию Kubernetes

1) Обновить файл hosts, прописать в них айпишник с доменным именем

192.168.1.190   k8smaster.example.com k8smaster 
192.168.1.191   k8sworker.example.com k8sworker

Отключаем swap 

sudo swapoff -a 
sudo sed -i '/swap/d' /etc/fstab
sudo tee  /etc/modules-load.d/containerd.conf <<EOF 
overlay
br_netfilter
EOF

Сохраним и закроем файл

sudo modprobe overlay 
sudo modprobe br_netfilter

Создадим следующий файл и сохраним его с таким содержимым:

sudo cat > /etc/sysctl.d/kubernetes.conf <<EOF 
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
EOF

Перезапустим ядро с параметрами выше

sudo sysctl --system

2) Установим Containerd и включим Kubernetes репозиторий.

sudo apt install -y curl gnupg2 software-properties-common apt-transport-https ca-certificates

Включаем Docker репозиторий

sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmour -o /etc/apt/trusted.gpg.d/docker.gpg 
sudo add-apt-repository -y "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

Установим containerd

sudo apt update && sudo apt install -y containerd.io

Настроим containerd чтобы он стартовал с использованием systemd как cgroup.

containerd config default | sudo tee /etc/containerd/config.toml 
sudo sed -i 's/SystemdCgroup \= false/SystemdCgroup \= true/g' /etc/containerd/config.toml

sudo systemctl restart containerd && sudo systemctl enable containerd

3) Установим kubeadm, kubectl и kubelet.

curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.29/deb/Release.key | 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.29/deb/ /' | tee /etc/apt/sources.list.d/kubernetes.list
apt update && apt -y install kubelet kubeadm kubectl && apt-mark hold kubelet kubeadm kubectl

4) Инициализация Kubernetes кластера

sudo kubeadm init --control-plane-endpoint=<DNS имя мастер ноды из 1го пункта>

Выполняем команду с экрана (пример)

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

Run kubectl command, Запустим команды и проверим что данные возвращаются и кластер работает

kubectl cluster-info 
kubectl get nodes

5) Добавьте worker ноду в кластер и установите calico cni

sudo kubeadm join k8smaster.kbashlaev.local k8smasterkb:6443  (Копируем вывод готовой команды из 4го пункта)

Далее все ставится только на мастер-ноде
Установка Calico CNI

kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.25.0/manifests/calico.yaml

verify calico pods

kubectl get pods -n kube-system

Сейчас все ноды должны быть в статусе Ready State

kubectl get nodes

6) Тестируем k8s кластер

To test Kubernetes installation, let’s try to deploy nginx based application and try to access it.

kubectl create deployment nginx-app --image=nginx --replicas=2

Проверим Deployment и pods статусы

kubectl get deployment nginx-app 
kubectl get pods
kubectl get deployment nginx-app & kubectl get pods


Expose the deployment,

kubectl expose deployment nginx-app --type=NodePort --port=80


Проверим статус сервиса

kubectl get svc nginx-app && kubectl describe svc nginx-app


Access nginx application using worker IP and nodeport

curl http://worker-ip-address:nodeport

7) Установка Rook + Ceph 

https://rook.io/docs/rook/latest/Getting-Started/quickstart/#create-a-ceph-cluster

A simple Rook cluster is created for Kubernetes with the following kubectl commands and example manifests.

$ git clone --single-branch --branch master https://github.com/rook/rook.git 
cd rook/deploy/examples
kubectl create -f crds.yaml -f common.yaml -f operator.yaml

Verify the rook-ceph-operator is in the `Running` state before proceeding

kubectl -n rook-ceph get pod

Create the cluster

kubectl create -f cluster.yaml
$ kubectl -n rook-ceph get pod 
NAME READY STATUS RESTARTS AGE
csi-cephfsplugin-provisioner-d77bb49c6-n5tgs 5/5 Running 0 140s
csi-cephfsplugin-provisioner-d77bb49c6-v9rvn 5/5 Running 0 140s
csi-cephfsplugin-rthrp 3/3 Running 0 140s
csi-rbdplugin-hbsm7 3/3 Running 0 140s
csi-rbdplugin-provisioner-5b5cd64fd-nvk6c 6/6 Running 0 140s
csi-rbdplugin-provisioner-5b5cd64fd-q7bxl 6/6 Running 0 140s
rook-ceph-crashcollector-minikube-5b57b7c5d4-hfldl 1/1 Running 0 105s
rook-ceph-mgr-a-64cd7cdf54-j8b5p 2/2 Running 0 77s
rook-ceph-mgr-b-657d54fc89-2xxw7 2/2 Running 0 56s
rook-ceph-mon-a-694bb7987d-fp9w7 1/1 Running 0 105s
rook-ceph-mon-b-856fdd5cb9-5h2qk 1/1 Running 0 94s
rook-ceph-mon-c-57545897fc-j576h 1/1 Running 0 85s
rook-ceph-operator-85f5b946bd-s8grz 1/1 Running 0 92m
rook-ceph-osd-0-6bb747b6c5-lnvb6 1/1 Running 0 23s
rook-ceph-osd-1-7f67f9646d-44p7v 1/1 Running 0 24s
rook-ceph-osd-2-6cd4b776ff-v4d68 1/1 Running 0 25s
rook-ceph-osd-prepare-node1-vx2rz 0/2 Completed 0 60s
rook-ceph-osd-prepare-node2-ab3fd 0/2 Completed 0 60s
rook-ceph-osd-prepare-node3-w4xyz 0/2 Completed 0 60s

8) Настройка сторадж класса для Ceph

https://rook.io/docs/rook/latest/Storage-Configuration/Block-Storage-RBD/block-storage/

kubectl create -f csi/rbd/storageclass.yaml

9) Установка снапшотера

# Change to the latest supported snapshotter version

SNAPSHOTTER_VERSION=v4.2.1

# Apply VolumeSnapshot CRDs

kubectl apply -f https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/${SNAPSHOTTER_VERSION}/client/config/crd/snapshot.storage.k8s.io_volumesnapshotclasses.yaml 
kubectl apply -f https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/${SNAPSHOTTER_VERSION}/client/config/crd/snapshot.storage.k8s.io_volumesnapshotcontents.yaml
kubectl apply -f https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/${SNAPSHOTTER_VERSION}/client/config/crd/snapshot.storage.k8s.io_volumesnapshots.yaml

# Create snapshot controller

kubectl apply -f https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/${SNAPSHOTTER_VERSION}/deploy/kubernetes/snapshot-controller/rbac-snapshot-controller.yaml 
kubectl apply -f https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/${SNAPSHOTTER_VERSION}/deploy/kubernetes/snapshot-controller/setup-snapshot-controller.yaml

10) Создание VolumeSnapshotClass (для Ceph)

https://rook.io/docs/rook/latest/Storage-Configuration/NFS/nfs-csi-driver/#connecting-to-an-export-directly

Создаем и применяем VolumeSnapshotClass

---
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshotClass
metadata:
  name: csi-rbdplugin-snapclass
driver: rook-ceph.rbd.csi.ceph.com # driver:namespace:operator
parameters:
  # Specify a string that identifies your cluster. Ceph CSI supports any
  # unique string. When Ceph CSI is deployed by Rook use the Rook namespace,
  # for example "rook-ceph".
  clusterID: rook-ceph # namespace:cluster
  csi.storage.k8s.io/snapshotter-secret-name: rook-csi-rbd-provisioner
  csi.storage.k8s.io/snapshotter-secret-namespace: rook-ceph # namespace:cluster
deletionPolicy: Delete

11) Установка и настройка мониторинга

curl https://baltocdn.com/helm/signing.asc | gpg --dearmor | 
sudo tee /usr/share/keyrings/helm.gpg > /dev/null
sudo apt-get install apt-transport-https --yes
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/helm.gpg] https://baltocdn.com/helm/stable/debian/ all main" | sudo tee /etc/apt/sources.list.d/helm-stable-debian.list
sudo apt-get update
sudo apt-get install helm
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts 
helm repo update
helm search repo prometheus-community
kubectl create namespace monitoring 
helm install kube-prom-stack prometheus-community/kube-prometheus-stack -n monitoring
kubectl --namespace monitoring get pods -l "release=kube-prom-stack"

12) Настройка LVM и Linstor PVC

На каждой ноде должен быть добавлен второй диск (1 системный + 1 под LVM).

Сначала установим заголовки ядра, потому что репликация DRBD основана на модуле ядра, который должен быть создан на всех нодах:

apt-get install linux-headers-$(uname -r)

Потом добавим репозиторий ppa:

add-apt-repository ppa:linbit/linbit-drbd9-stack 
apt-get update

На всех нодах установим эти пакеты:

apt install drbd-utils drbd-dkms lvm2

Загрузим модуль ядра DRBD:

modprobe drbd

Проверим, что он точно загрузился:

lsmod | grep -i drbd

Убедимся, что он автоматически загружается при запуске:

echo drbd > /etc/modules-load.d/drbd.conf

Кластер Linstor состоит из одного активного контроллера, который управляет всей информацией о кластере, и спутников — нод, которые предоставляют хранилище. На ноде, которая будет контроллером, выполним команду:

apt install linstor-controller linstor-satellite linstor-client

Эта команда делает контроллер еще и спутником. В моем случае контроллером был linstor-master1. Чтобы сразу запустить контроллер и включить его автоматический запуск при загрузке, выполним команду:

systemctl enable --now linstor-controller 
systemctl start linstor-controller

На оставшихся нодах-спутниках установим следующие пакеты:

apt install linstor-satellite linstor-client

Запустим спутник и сделаем так, чтобы он запускался при загрузке:

systemctl enable --now linstor-satellite 
systemctl start linstor-satellite

Теперь можно добавить к контролеру спутники, включая саму эту ноду:

linstor node create <node_name1> <node_ip> 
linstor node create <node_name2> <node_ip>
linstor node create <node_name3> <node_ip>

Подождем пять секунд и убедимся, что ноды онлайн:

linstor node list

Теперь нужно настроить хранилище. Linstor работает с LVM или ZFS, чтобы управлять хранилищем. Не знаю, в чем разница, но я больше знаком с LVM, его и возьму.

Сначала подготовим физический диск или диски на каждом узле. В моем случае это /dev/sdb:

pvcreate /dev/sdb

Создадим группу томов:

vgcreate vg /dev/sdb

Я назову группу «vg», а вы — как хотите.

Теперь создадим «тонкий» пул для thin provisioning (то есть возможности создавать тома больше доступного места, чтобы потом расширять хранилище по необходимости) и снапшотов:

lvcreate -l 100%FREE --thinpool vg/lvmthinpool

Эта команда создает логический том, который занимает весь диск.

Пора создать пул хранилища на каждой ноде, так что на контроллере выполняем команду:

linstor storage-pool create lvmthin <node_name1> linstor-pool vg/lvmthinpool 
linstor storage-pool create lvmthin <node_name2> linstor-pool vg/lvmthinpool
linstor storage-pool create lvmthin <node_name3> linstor-pool vg/lvmthinpool

Я назову пул «linstor-pool». Убедимся, что пул создан:

linstor storage-pool list

На этом настройка LVM закончена, далее настраиваем Linstor плагин

Создаем файл с описанием linstor-csi-controller и остальных компонентов для работы плагина Linstor

Обратите внимание что нужно подменить свой ip адрес контроллера в значениях LINSTOR_IP (несколько мест)

---
kind: StatefulSet
apiVersion: apps/v1
metadata:
  name: linstor-csi-controller
  namespace: kube-system
spec:
  serviceName: "linstor-csi"
  replicas: 1
  selector:
    matchLabels:
      app: linstor-csi-controller
      role: linstor-csi
  template:
    metadata:
      labels:
        app: linstor-csi-controller
        role: linstor-csi
    spec:
      priorityClassName: system-cluster-critical
      serviceAccountName: linstor-csi-controller-sa
      containers:
        - name: csi-provisioner
          image: quay.io/k8scsi/csi-provisioner:v2.0.2
          args:
            - "--csi-address=$(ADDRESS)"
            - "--v=5"
            - "--feature-gates=Topology=true"
            - "--timeout=120s"
          env:
            - name: ADDRESS
              value: /var/lib/csi/sockets/pluginproxy/csi.sock
          imagePullPolicy: "Always"
          volumeMounts:
            - name: socket-dir
              mountPath: /var/lib/csi/sockets/pluginproxy/
        - name: csi-attacher
          image: quay.io/k8scsi/csi-attacher:v3.0.0
          args:
            - "--v=5"
            - "--csi-address=$(ADDRESS)"
            - "--timeout=120s"
          env:
            - name: ADDRESS
              value: /var/lib/csi/sockets/pluginproxy/csi.sock
          imagePullPolicy: "Always"
          volumeMounts:
            - name: socket-dir
              mountPath: /var/lib/csi/sockets/pluginproxy/
        - name: csi-resizer
          image: quay.io/k8scsi/csi-resizer:v1.0.0
          args:
          - "--v=5"
          - "--csi-address=$(ADDRESS)"
          env:
          - name: ADDRESS
            value: /var/lib/csi/sockets/pluginproxy/csi.sock
          imagePullPolicy: "Always"
          volumeMounts:
          - mountPath: /var/lib/csi/sockets/pluginproxy/
            name: socket-dir
        - name: csi-snapshotter
          image: quay.io/k8scsi/csi-snapshotter:v3.0.0
          args:
            - "-csi-address=$(ADDRESS)"
            - "-timeout=120s"
          env:
            - name: ADDRESS
              value: /var/lib/csi/sockets/pluginproxy/csi.sock
          imagePullPolicy: Always
          volumeMounts:
            - name: socket-dir
              mountPath: /var/lib/csi/sockets/pluginproxy/
        - name: linstor-csi-plugin
          image: quay.io/piraeusdatastore/piraeus-csi:v1.4.0
          args:
            - "--csi-endpoint=$(CSI_ENDPOINT)"
            - "--node=$(KUBE_NODE_NAME)"
            - "--linstor-endpoint=$(LINSTOR_IP)"
            - "--log-level=debug"
          env:
            - name: CSI_ENDPOINT
              value: unix:///var/lib/csi/sockets/pluginproxy/csi.sock
            - name: KUBE_NODE_NAME
              valueFrom:
                fieldRef:
                  fieldPath: spec.nodeName
            - name: LINSTOR_IP
              value: "http://10.77.243.10:3370"
          imagePullPolicy: "Always"
          volumeMounts:
            - name: socket-dir
              mountPath: /var/lib/csi/sockets/pluginproxy/
      volumes:
        - name: socket-dir
          emptyDir: {}
---

kind: ServiceAccount
apiVersion: v1
metadata:
  name: linstor-csi-controller-sa
  namespace: kube-system

---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: linstor-csi-provisioner-role
rules:
  - apiGroups: [""]
    resources: ["persistentvolumes"]
    verbs: ["get", "list", "watch", "create", "delete"]
  - apiGroups: [""]
    resources: ["persistentvolumeclaims"]
    verbs: ["get", "list", "watch", "update"]
  - apiGroups: ["storage.k8s.io"]
    resources: ["storageclasses"]
    verbs: ["get", "list", "watch"]
  - apiGroups: [""]
    resources: ["events"]
    verbs: ["list", "watch", "create", "update", "patch"]
  - apiGroups: ["snapshot.storage.k8s.io"]
    resources: ["volumesnapshots"]
    verbs: ["get", "list"]
  - apiGroups: ["snapshot.storage.k8s.io"]
    resources: ["volumesnapshotcontents"]
    verbs: ["get", "list"]
  - apiGroups: ["storage.k8s.io"]
    resources: ["volumeattachments"]
    verbs: ["get", "list", "watch"]

---

kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: linstor-csi-provisioner-binding
subjects:
  - kind: ServiceAccount
    name: linstor-csi-controller-sa
    namespace: kube-system
roleRef:
  kind: ClusterRole
  name: linstor-csi-provisioner-role
  apiGroup: rbac.authorization.k8s.io

---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: linstor-csi-attacher-role
rules:
  - apiGroups: [""]
    resources: ["persistentvolumes"]
    verbs: ["get", "list", "watch", "update", "patch"]
  - apiGroups: [""]
    resources: ["nodes"]
    verbs: ["get", "list", "watch"]
  - apiGroups: ["storage.k8s.io"]
    resources: ["csinodes"]
    verbs: ["get", "list", "watch"]
  - apiGroups: ["storage.k8s.io"]
    resources: ["volumeattachments"]
    verbs: ["get", "list", "watch", "update", "patch"]
  - apiGroups: ["storage.k8s.io"]
    resources: ["volumeattachments/status"]
    verbs: ["patch"]

---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: linstor-csi-attacher-binding
subjects:
  - kind: ServiceAccount
    name: linstor-csi-controller-sa
    namespace: kube-system
roleRef:
  kind: ClusterRole
  name: linstor-csi-attacher-role
  apiGroup: rbac.authorization.k8s.io

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: linstor-csi-resizer-role
rules:
  - apiGroups: [""]
    resources: ["persistentvolumes"]
    verbs: ["get", "list", "watch", "patch"]
  - apiGroups: [""]
    resources: ["persistentvolumeclaims"]
    verbs: ["get", "list", "watch"]
  - apiGroups: [""]
    resources: ["persistentvolumeclaims/status"]
    verbs: ["patch"]
  - apiGroups: [""]
    resources: ["events"]
    verbs: ["list", "watch", "create", "update", "patch"]

---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: linstor-csi-resizer-binding
subjects:
  - kind: ServiceAccount
    name: linstor-csi-controller-sa
    namespace: kube-system
roleRef:
  kind: ClusterRole
  name: linstor-csi-resizer-role
  apiGroup: rbac.authorization.k8s.io

---

kind: DaemonSet
apiVersion: apps/v1
metadata:
  name: linstor-csi-node
  namespace: kube-system
spec:
  selector:
    matchLabels:
      app: linstor-csi-node
      role: linstor-csi
  template:
    metadata:
      labels:
        app: linstor-csi-node
        role: linstor-csi
    spec:
      priorityClassName: system-node-critical
      serviceAccountName: linstor-csi-node-sa
      containers:
        - name: csi-node-driver-registrar
          image: quay.io/k8scsi/csi-node-driver-registrar:v2.0.1
          args:
            - "--v=5"
            - "--csi-address=$(ADDRESS)"
            - "--kubelet-registration-path=$(DRIVER_REG_SOCK_PATH)"
          lifecycle:
            preStop:
              exec:
                command: ["/bin/sh", "-c", "rm -rf /registration/linstor.csi.linbit.com /registration/linstor.csi.linbit.com-reg.sock"]
          env:
            - name: ADDRESS
              value: /csi/csi.sock
            - name: DRIVER_REG_SOCK_PATH
              value: /var/lib/kubelet/plugins/linstor.csi.linbit.com/csi.sock
            - name: KUBE_NODE_NAME
              valueFrom:
                fieldRef:
                  fieldPath: spec.nodeName
          volumeMounts:
            - name: plugin-dir
              mountPath: /csi/
            - name: registration-dir
              mountPath: /registration/
        - name: linstor-csi-plugin
          image: quay.io/piraeusdatastore/piraeus-csi:v1.4.0
          args:
            - "--csi-endpoint=$(CSI_ENDPOINT)"
            - "--node=$(KUBE_NODE_NAME)"
            - "--linstor-endpoint=$(LINSTOR_IP)"
            - "--log-level=debug"
          env:
            - name: CSI_ENDPOINT
              value: unix:///csi/csi.sock
            - name: KUBE_NODE_NAME
              valueFrom:
                fieldRef:
                  fieldPath: spec.nodeName
            - name: LINSTOR_IP
              value: "http://10.77.243.10:3370"
          imagePullPolicy: "Always"
          securityContext:
            privileged: true
            capabilities:
              add: ["SYS_ADMIN"]
            allowPrivilegeEscalation: true
          volumeMounts:
            - name: plugin-dir
              mountPath: /csi
            - name: pods-mount-dir
              mountPath: /var/lib/kubelet
              mountPropagation: "Bidirectional"
            - name: device-dir
              mountPath: /dev
      volumes:
        - name: registration-dir
          hostPath:
            path: /var/lib/kubelet/plugins_registry/
            type: DirectoryOrCreate
        - name: plugin-dir
          hostPath:
            path: /var/lib/kubelet/plugins/linstor.csi.linbit.com/
            type: DirectoryOrCreate
        - name: pods-mount-dir
          hostPath:
            path: /var/lib/kubelet
            type: Directory
        - name: device-dir
          hostPath:
            path: /dev
---

apiVersion: v1
kind: ServiceAccount
metadata:
  name: linstor-csi-node-sa
  namespace: kube-system

---

kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: linstor-csi-driver-registrar-role
  namespace: kube-system
rules:
  - apiGroups: [""]
    resources: ["events"]
    verbs: ["get", "list", "watch", "create", "update", "patch"]

---

apiVersion: storage.k8s.io/v1
kind: CSIDriver
metadata:
  name: linstor.csi.linbit.com
spec:
  attachRequired: true
  podInfoOnMount: true

---

kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: linstor-csi-driver-registrar-binding
subjects:
  - kind: ServiceAccount
    name: linstor-csi-node-sa
    namespace: kube-system
roleRef:
  kind: ClusterRole
  name: linstor-csi-driver-registrar-role
  apiGroup: rbac.authorization.k8s.io

---

kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: linstor-csi-snapshotter-role
rules:
  - apiGroups: [""]
    resources: ["persistentvolumes"]
    verbs: ["get", "list", "watch"]
  - apiGroups: [""]
    resources: ["persistentvolumeclaims"]
    verbs: ["get", "list", "watch", "update"]
  - apiGroups: ["storage.k8s.io"]
    resources: ["storageclasses"]
    verbs: ["get", "list", "watch"]
  - apiGroups: [""]
    resources: ["events"]
    verbs: ["list", "watch", "create", "update", "patch"]
  - apiGroups: ["snapshot.storage.k8s.io"]
    resources: ["volumesnapshotclasses"]
    verbs: ["get", "list", "watch"]
  - apiGroups: ["snapshot.storage.k8s.io"]
    resources: ["volumesnapshotcontents"]
    verbs: ["create", "get", "list", "watch", "update", "delete"]
  - apiGroups: ["snapshot.storage.k8s.io"]
    resources: ["volumesnapshotcontents/status"]
    verbs: ["update"]
  - apiGroups: ["snapshot.storage.k8s.io"]
    resources: ["volumesnapshots"]
    verbs: ["get", "list", "watch", "update"]
  - apiGroups: ["apiextensions.k8s.io"]
    resources: ["customresourcedefinitions"]
    verbs: ["create", "list", "watch", "delete"]
  - apiGroups: ["snapshot.storage.k8s.io"]
    resources: ["volumesnapshots/status"]
    verbs: ["update"]

---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: linstor-csi-snapshotter-binding
subjects:
  - kind: ServiceAccount
    name: linstor-csi-controller-sa
    namespace: kube-system
roleRef:
  kind: ClusterRole
  name: linstor-csi-snapshotter-role
  apiGroup: rbac.authorization.k8s.io

Применяем его командой

kubectl apply -f linstor-csi.yaml

Ждем, пока все поды поднимутся

Далее создаем StorageClass

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: linstor-basic-storage
provisioner: linstor.csi.linbit.com
allowVolumeExpansion: true
parameters:
  linstor.csi.linbit.com/placementCount: "2"
  linstor.csi.linbit.com/storagePool: linstor-pool
  linstor.csi.linbit.com/resourceGroup: linstor-basic-storage

Применяем его

kubectl apply -f StorageClass.yaml

и сам PersistentVolumeClaim

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
     name: test-pvc
spec:
     storageClassName: linstor-basic-storage
     accessModes:
         -  ReadWriteOnce
     resources:
         requests:
            storage: 1Gi

Применяем

kubectl apply -f PersistentVolumeClaim.yaml

Готово

root@k8s4-node1kb:/home/kbashlaev# kubectl get pvc
NAME              STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS            AGE
test-pvc          Bound    pvc-15608c29-5696-42f7-84d6-5d2c5a2a05f5   1Gi        RWO            linstor-basic-storage   134m
root@k8s4-node1kb:/home/kbashlaev# kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                     STORAGECLASS            REASON   AGE
pvc-15608c29-5696-42f7-84d6-5d2c5a2a05f5   1Gi        RWO            Delete           Bound    default/test-pvc          linstor-basic-storage            134m

13) Создание VolumeSnapshotClass (для linstor)

Создаем класс ниже и применяем его

apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshotClass
metadata:
  name:  linstor-csi-snapshot-class-in-cluster
driver: linstor.csi.linbit.com
deletionPolicy: Delete

Разное

Как повторно сгенерировать токен для добавления ноды в кластер?

под рутом выполняем следующие команды:

kubeadm token generate 

kubeadm token create <token_from_prev_step> --print-join-command --ttl=0

и далее уже вставляем сгенерированную команду на добавляемой ноде

Рубрика: Конфигурации | Метки: , | Оставить комментарий

Алгоритм быстрой сортировки на Java

package org.example;
import java.util.Arrays;

public class QuickSort {

    public static void quickSort(int[] array, int low, int high) {
        if (array.length == 0)
            return;//завершить выполнение, если длина массива равна 0

        if (low >= high)
            return;//завершить выполнение если уже нечего делить

        // выбрать опорный элемент
        int middle = low + (high - low) / 2;
        int opora = array[middle];

        // разделить на подмассивы, который больше и меньше опорного элемента
        int i = low, j = high;
        while (i <= j) {
            while (array[i] < opora) {
                i++;
            }

            while (array[j] > opora) {
                j--;
            }

            if (i <= j) {//меняем местами
                int temp = array[i];
                array[i] = array[j];
                array[j] = temp;
                i++;
                j--;
            }
        }

        // вызов рекурсии для сортировки левой и правой части
        if (low < j)
            quickSort(array, low, j);

        if (high > i)
            quickSort(array, i, high);
    }
    public static void main(String[] args) {
        int[] x = { 8, 0, 4, 7, 3, 7, 10, 12, -3 };
        System.out.println("Было");
        System.out.println(Arrays.toString(x));

        int low = 0;
        int high = x.length - 1;

        quickSort(x, low, high);
        System.out.println("Стало");
        System.out.println(Arrays.toString(x));
    }
}
Рубрика: Программирование | Метки: , | Комментарии к записи Алгоритм быстрой сортировки на Java отключены

Рекурсивная функция подсчета элементов в списке на Java

Пример рекурсивной функции для подсчета элементов в списке

import java.util.List;

public class RecursiveListCount {

    public static void main(String[] args) {
        // Пример использования функции
        List<Integer> myList = List.of(1, 2, 3, 4, 5);
        int count = countElements(myList);
        System.out.println("Количество элементов в списке: " + count);
    }

    // Рекурсивная функция для подсчета элементов в списке
    private static <T> int countElements(List<T> list) {
        // Базовый случай: если список пуст, возвращаем 0
        if (list.isEmpty()) {
            return 0;
        } else {
            // Рекурсивный случай: суммируем 1 (текущий элемент) с результатом вызова функции для оставшейся части списка
            return 1 + countElements(list.subList(1, list.size()));
        }
    }
}
Рубрика: Программирование | Метки: , | Комментарии к записи Рекурсивная функция подсчета элементов в списке на Java отключены

Реализация бинарного поиска на Java

public class BinSearch {

    public static Object binSearch(ArrayList<Integer> list, int item) {
        int low = 0; // нижняя граница списка
        int high = list.size() - 1; // верхняя граница списка

        while (low <= high) { // пока эта част не сократится до одного элемента
            int mid = (low + high) / 2; // проверяем средний элемент
            int guess = list.get(mid);
            if (guess == item) { // если значение найдено
                return mid;
            }
            if (guess > item) { // много
                high = mid - 1;
            }
            else { // мало
                low = mid + 1;
            }
        }
        return null; // значение не существует
    }

    public static void binSearchStart() {
        ArrayList<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(3);
        list.add(5);
        list.add(7);
        list.add(9);

        System.out.println(binSearch(list, 3));
        System.out.println(binSearch(list, -1));
    }

С бинарным поиском каждый раз берется число в середине диапазона и исключает половину оставшихся чисел. Работает только в отсортированном списке.

Рубрика: Без рубрики, Программирование | Метки: , | Оставить комментарий