Kubernetes
November 4, 2022

Создать PV в S3 для кластера k8s

В этой статье опишем процесс подключения персистентного хранилища на базе S3 к поду кластера Kubernetes.

Хранилище S3 медленне аналогичного устройства на базе диска, но дешевле по стоимсости и потенциально не ограничено. Есть квоты, но их легко можно увеличить в большую сторону.

Для подключения бакета необходимо:

1. Установить и настроить утилиты yc, jq, git, kubectl.
2. Создать бакет. У меня это будет cam-kuber-s3.
3. Иметь SA с соответствующими правами для записи в данный бакет (например, editor) и сгенерированным авторизованным ключом.

Создадим Secret, в котором укажем ключи SA для доступа к бакету.

cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Secret
metadata:
  namespace: kube-system
  name: csi-s3-secret
stringData:
  accessKeyID: YCAJ11kn7y11112g111111hMv
  secretAccessKey: YCO1111GH8114It111116RP01111EY11117Zi11P
  endpoint: https://storage.yandexcloud.net
EOF
kubectl get secret -A | grep csi-s3-secret
kube-system       csi-s3-secret                                    Opaque                                3      55s

Создадим StorageClass, который будет хранить информацию о типе хранилища.

cat <<EOF | kubectl apply -f -
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: csi-s3
provisioner: ru.yandex.s3.csi
parameters:
  mounter: geesefs
  options: "--memory-limit=1000 --dir-mode=0777 --file-mode=0666"
  bucket: cam-kuber-s3
  csi.storage.k8s.io/provisioner-secret-name: csi-s3-secret
  csi.storage.k8s.io/provisioner-secret-namespace: kube-system
  csi.storage.k8s.io/controller-publish-secret-name: csi-s3-secret
  csi.storage.k8s.io/controller-publish-secret-namespace: kube-system
  csi.storage.k8s.io/node-stage-secret-name: csi-s3-secret
  csi.storage.k8s.io/node-stage-secret-namespace: kube-system
  csi.storage.k8s.io/node-publish-secret-name: csi-s3-secret
  csi.storage.k8s.io/node-publish-secret-namespace: kube-system
EOF
kubectl get sc
NAME                           PROVISIONER                     RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
csi-s3                         ru.yandex.s3.csi                Delete          Immediate              false                  9s
yc-network-hdd (default)       disk-csi-driver.mks.ycloud.io   Delete          WaitForFirstConsumer   true                   4d1h
yc-network-nvme                disk-csi-driver.mks.ycloud.io   Delete          WaitForFirstConsumer   true                   4d1h
yc-network-ssd                 disk-csi-driver.mks.ycloud.io   Delete          WaitForFirstConsumer   true                   4d1h
yc-network-ssd-nonreplicated   disk-csi-driver.mks.ycloud.io   Delete          WaitForFirstConsumer   true                   4d1h

В предыдущем пункте мы указали информацию о том какой драйвер использовать (ru.yandex.s3.csi) и программу, которая будет использоваться для монтирования бакета (geesefs).
Теперь нам надо скачать сам драйвер, программу и установить их.

git clone https://github.com/yandex-cloud/k8s-csi-s3.git

Установим драйвер и программу.

kubectl create -f k8s-csi-s3/deploy/kubernetes/provisioner.yaml && \
kubectl create -f k8s-csi-s3/deploy/kubernetes/attacher.yaml && \
kubectl create -f k8s-csi-s3/deploy/kubernetes/csi-s3.yaml

Создадим PVC.

cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: csi-s3-pvc-dynamic
  namespace: default
spec:
  accessModes:
  - ReadWriteMany
  resources:
    requests:
      storage: 5Gi
  storageClassName: csi-s3
EOF
kubectl get pvc
NAME                 STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
csi-s3-pvc-dynamic   Bound    pvc-afd588b3-b10d-490f-8cc2-07d9457bb3e0   5Gi      RWX            csi-s3         7s

Создадим Deployment c PV.

cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: cam-nginx
  labels: 
    app: nginx-prod 
    environment: prod
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  strategy: 
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 1
    type: RollingUpdate
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        imagePullPolicy: IfNotPresent
        ports: 
        - name: http
          containerPort: 80
        resources: 
          requests: 
            cpu: 300m
            memory: 300Mi 
          limits: 
            cpu: 400m 
            memory: 400Mi
        volumeMounts: 
        - mountPath: /mnt/s3 
          name: cameda-volume
      restartPolicy: Always
      volumes: 
      - name: cameda-volume 
        persistentVolumeClaim: 
          claimName: csi-s3-pvc-dynamic
EOF
kubectl get po
NAME                         READY   STATUS    RESTARTS   AGE
cam-nginx-59798c8884-f9shd   1/1     Running   0          3m54s
cam-nginx-59798c8884-psbvt   1/1     Running   0          3m54s
kubectl exec --stdin --tty cam-nginx-59798c8884-f9shd -- /bin/bash
cd /mnt/s3
touch fule
echo -n "Hello, World!" > fule
cat fule
Hello, World!
kubectl exec --stdin --tty cam-nginx-59798c8884-psbvt -- /bin/bash
cd /mnt/s3
cat fule
Hello, World!

echo -n "Hello, Alex!!!" >> fule
cat fule
Hello, World!
Hello, Alex!!!
kubectl exec --stdin --tty cam-nginx-59798c8884-f9shd -- /bin/bash
cd /mnt/s3
cat fule
Hello, World!
Hello, Alex!!!

Итого.

Читать и писать в хранилище можно из обоих подов.