środa, 6 czerwca 2018

Kubernetes z GlusterFS jako miejsce składowania danych

Gdy już mamy GlusterFS (jako przewodnik możesz wykorzystać ten link) to musimy usunąć restrykcję mówiącą, że masz wolumen może być montowany tylko z localhost:
root@kubernetes-master1:~# gluster volume reset gvol0 auth.allow
volume reset: success: reset volume successful
Stworzyliśmy również klaster Kubernetes (np. dzięki temu). Najpierw tworzymy punkt końcowy dla usługi aby określić szczegóły dostępu do GlusterFS. Tworzymy plik "glusterfs-endpoints.yml" o poniższej zawartości:
apiVersion: v1
kind: Endpoints
metadata:
  name: glusterfs-cluster
subsets:
  - addresses:
      - ip: 192.168.33.30
    ports:
      - port: 1
  - addresses:
      - ip: 192.168.33.31
    ports:
      - port: 1
  - addresses:
      - ip: 192.168.33.32
    ports:
      - port: 1
  - addresses:
      - ip: 192.168.33.33
    ports:
      - port: 1
Podajemy adresy naszych węzłów w GlusterFS (numer portu jest pomijany) i wdrażamy:
root@kubernetes-master1:~# kubectl create -f glusterfs-endpoints.yml
endpoints "glusterfs-cluster" created
Warto sprawdzić czy nam się udało:
root@kubernetes-master1:~# kubectl get endpoints
NAME                ENDPOINTS                                                     AGE
glusterfs-cluster   192.168.33.30:1,192.168.33.31:1,192.168.33.32:1 + 1 more...   11s
kubernetes          192.168.33.30:6443                                            6d 
Kolejnym krokiem jest definicja usługi:
apiVersion: v1
kind: Service
metadata:
  name: glusterfs-cluster
spec:
  ports:
  - port: 1
Pole "name" musi odpowiadać nazwie w definicji punktów końcowych. Wdrażamy i sprawdzamy jak nam poszło:
root@kubernetes-master1:~# kubectl create -f glusterfs-service.yml
service "glusterfs-cluster" created
root@kubernetes-master1:~# kubectl get services
NAME                TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
glusterfs-cluster   ClusterIP   10.109.25.207   <none>        1/TCP     4s
kubernetes          ClusterIP   10.96.0.1       <none>        443/TCP   6d
Przechodzimy do definicji obiektu PersistentVolume czyli niskopoziomowej reprezentacji wolumenu przechowywania danych. Odwołujemy się do punktu końcowego aby poinformować Kubernetes gdzie klaster GlusterFS jest dosępny oraz jaka jest nazwa wolumenu, który utworzono. Tworzymy plik "glusterfs-persistent-volume.yml":
apiVersion: v1
kind: PersistentVolume
metadata:
  name: fileupload-vol
  labels:
    dev: dev
spec:
  accessModes:
  - ReadWriteMany
  capacity:
    storage: 500M
  glusterfs:
    endpoints: glusterfs-cluster
    path: gvol0
  persistentVolumeReclaimPolicy: Recycle
W polu "path" podajemy nazwę naszego wolumenu i uruchamiamy:
root@kubernetes-master1:~# kubectl create -f glusterfs-persistent-volume.yml
persistentvolume "fileupload-vol" created
root@kubernetes-master1:~# kubectl get pv
NAME             CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM     STORAGECLASS   REASON    AGE
fileupload-vol   500M       RWX            Recycle          Available                                      6s 
Kolejno musimy utworzyć obiekt PersistentVolumeClaim, który wiąże "strąk" ("pod") z obiektem PersistentVolume. Definicja w pliku "glusterfs-persistent-volume-claim.yml":
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: file-upload-claim
spec:
  accessModes:
  - ReadWriteMany
  resources:
     requests:
       storage: 100M
Sprawdźmy jak nam poszło:
root@kubernetes-master1:~# kubectl create -f glusterfs-persistent-volume-claim.yml
persistentvolumeclaim "file-upload-claim" created
root@kubernetes-master1:~# kubectl get pvc
NAME                STATUS    VOLUME           CAPACITY   ACCESS MODES   STORAGECLASS   AGE
file-upload-claim   Bound     fileupload-vol   500M       RWX                           4s
Ostatecznie w pliku "nginx.yml" piszemy definicję usługi. W naszym przypadku będzie to serwer Nginx:
apiVersion: v1
kind: List
items:
- apiVersion: extensions/v1beta1
  kind: Deployment
  metadata:
    name: nginx
  spec:
    replicas: 1
    template:
      metadata:
        labels:
          app: nginx
      spec:
        containers:
        - name: nginx
          image: nginx
          volumeMounts:
          - mountPath: /usr/share/nginx/html/
            name: dir-1
        volumes:
          - name: dir-1
            persistentVolumeClaim:
              claimName: file-upload-claim
 
Pole "claimName" musi odpowiadać definicji obiektu PersistentVolumeClaim zaś w polu "mountPath" określamy jaki katalog w kontenerach chcemy współdzielić. Wdrażamy, sprawdzamy jakie mamy usługi, "strąki" oraz wchodzimy do kontenera z Nginksem:
root@kubernetes-master1:~# kubectl create -f nginx.yml
deployment.extensions "nginx" created
root@kubernetes-master1:~# kubectl get services
NAME                TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
glusterfs-cluster   ClusterIP   10.109.25.207   <none>        1/TCP     22m
kubernetes          ClusterIP   10.96.0.1       <none>        443/TCP   6d
root@kubernetes-master1:~# kubectl get pods
NAME                    READY     STATUS    RESTARTS   AGE
nginx-944f45fb8-ztv92   1/1       Running   0          59s
root@kubernetes-master1:~# kubectl exec -it nginx-944f45fb8-ztv92 -- /bin/bash
root@nginx-944f45fb8-ztv92:/#
Tak przygotowane rozwiązanie pozwala nam na współdzielenie plików w kontenerach Nginx (katalog "/usr/share/nginx/html") i na komputerach gdzie jest GlusterFS.