Friday, April 20, 2018

Dynamic Provisioning in K8S using FlexVolume Plug-in

                           

                           Dynamic Provisioning in K8S using FlexVolume Plug-in

Unlike Static provisioning example there can be use cases where Dynamic provisioning is useful in cases where you do not want MapR and Kubernetes administrators to create storage manually to store the Pod storage state/data. The PersistentVolume is created automatically based on the parameters specified in the referenced StorageClass.

The following Blog uses a PersistentVolumeClaim that references a Storage Class. In this example, a Kubernetes Administrator has created a storage class called secure-maprfs for Pod creators to use when they want to create persistent storage for their Pods. The created Pod storage will survive the deletion of a Pod hence the reclaim policy is set to retain.
1) Below is sample yaml file to statically provision MapR Flex volume to K8S .

[root@tssperf09 abizerwork]# cat DynamicProvisioner.yaml 
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
   name: secure-maprfs
   namespace: mapr-system
provisioner: mapr.com/maprfs
parameters:
    restServers: "10.10.70.113:8443"
    cldbHosts: "10.10.70.113 10.10.70.114 10.10.70.115"
    cluster: "ObjectPool"
    securityType: "unsecure"
    ticketSecretNamespace: "mapr-system"
    maprSecretName: "mapr-provisioner-secrets"
    maprSecretNamespace: "mapr-system"
    namePrefix: "pv"
    mountPrefix: "/pv"
    readOnly: “true”
    reclaimPolicy: “Retain”
    advisoryquota: "100M"

---

kind: Pod
apiVersion: v1
metadata:
  name: test-secure-provisioner
  namespace: mapr-system
spec:
  containers:
  - name: busybox
    image: docker.io/maprtech/kdf-plugin:1.0.0_029_centos7 
    args:
    - sleep
    - "1000000"
    imagePullPolicy: Always
    volumeMounts:
      - name: maprfs-pvc
        mountPath: "/dynvolume"
  restartPolicy: "Never"
  volumes:
    - name: maprfs-pvc
      persistentVolumeClaim:
        claimName: maprfs-secure-pvc

---

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: maprfs-secure-pvc
  namespace: mapr-system
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: secure-maprfs
  resources:
    requests:
      storage: 300M
---

apiVersion: v1
kind: Secret
metadata:
  name: mapr-provisioner-secrets
  namespace: mapr-system
type: Opaque
data:
  MAPR_CLUSTER_USER: cm9vdA==                       <--- Username in base64 format
  MAPR_CLUSTER_PASSWORD: YWJpemVy                   <--- Password in base64 format

[root@tssperf09 abizerwork]# 

Note :- Convert username and password to base64 format.

https://www.base64encode.org/

2)  Use the kubectl create command with the -f option to install Dynamic provisioner on  Kubernetes cluster .

[root@tssperf09 abizerwork]# kubectl create -f DynamicProvisioner.yaml 
storageclass "secure-maprfs" created
pod "test-secure-provisioner" created
persistentvolumeclaim "maprfs-secure-pvc" created
secret "mapr-provisioner-secrets" created

[root@tssperf09 abizerwork]# 

3) Now we can see "test-secure-provisioner" pod is up and running. This would give all the steps 

[root@tssperf09 abizerwork]# kubectl get pods -n mapr-system -o wide
NAME                                   READY     STATUS    RESTARTS   AGE       IP                NODE
mapr-kdfplugin-6l5n7                   1/1       Running   0          23d       192.168.61.65     tssperf10.lab
mapr-kdfplugin-crzhk                   1/1       Running   0          23d       192.168.217.129   tssperf11.lab
mapr-kdfplugin-srcln                   1/1       Running   0          23d       192.168.196.223   tssperf09.lab
mapr-kdfprovisioner-79b86f459d-hjkcn   1/1       Running   0          23d       192.168.217.130   tssperf11.lab
test-secure                            1/1       Running   0          2d        192.168.61.67     tssperf10.lab
test-secure-provisioner                1/1       Running   0          1m        192.168.217.135   tssperf11.lab
[root@tssperf09 abizerwork]# 


4) To review the status of the Pod being spun up review the "Events" para for the command output.

[root@tssperf09 abizerwork]# kubectl describe pod test-secure-provisioner  -n mapr-system
Name:         test-secure-provisioner
Namespace:    mapr-system
Node:         tssperf11.lab/10.10.72.251
Start Time:   Fri, 20 Apr 2018 14:57:41 -0600
Labels:       <none>
Annotations:  <none>
Status:       Running
IP:           192.168.217.135
Containers:
  busybox:
    Container ID:  docker://dce62da9f665d8362fa62af528fb2c2b005a3b23c505da3764e33d8cf7f2fa37
    Image:         docker.io/maprtech/kdf-plugin:1.0.0_029_centos7
    Image ID:      docker-pullable://docker.io/maprtech/kdf-plugin@sha256:eecb2d64ede9b9232b6eebf5d0cc59fe769d16aeb56467d0a00489ce7224278d
    Port:          <none>
    Args:
      sleep
      1000000
    State:          Running
      Started:      Fri, 20 Apr 2018 14:57:51 -0600
    Ready:          True
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /dynvolume from maprfs-pvc (rw)
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-9g8tq (ro)
Conditions:
  Type           Status
  Initialized    True 
  Ready          True 
  PodScheduled   True 
Volumes:
  maprfs-pvc:
    Type:       PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)
    ClaimName:  maprfs-secure-pvc
    ReadOnly:   false
  default-token-9g8tq:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-9g8tq
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  <none>
Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                 node.kubernetes.io/unreachable:NoExecute for 300s
Events:
  Type    Reason                 Age   From                    Message
  ----    ------                 ----  ----                    -------
  Normal  Scheduled              30s   default-scheduler       Successfully assigned test-secure-provisioner to tssperf11.lab
  Normal  SuccessfulMountVolume  30s   kubelet, tssperf11.lab  MountVolume.SetUp succeeded for volume "default-token-9g8tq"
  Normal  SuccessfulMountVolume  22s   kubelet, tssperf11.lab  MountVolume.SetUp succeeded for volume "pv-xplttvibrl"
  Normal  Pulling                21s   kubelet, tssperf11.lab  pulling image "docker.io/maprtech/kdf-plugin:1.0.0_029_centos7"
  Normal  Pulled                 20s   kubelet, tssperf11.lab  Successfully pulled image "docker.io/maprtech/kdf-plugin:1.0.0_029_centos7"
  Normal  Created                20s   kubelet, tssperf11.lab  Created container
  Normal  Started                20s   kubelet, tssperf11.lab  Started container
[root@tssperf09 abizerwork]# 

As seen above the POD is assigned to be spun up on node tssperf11 . Incase if there are any issues while provisioner is trying to Provision the POD we can review the logs where Provisioner is running in this case node tssperf11 and tail the logs to review the logs and errors they are running into to figure out the RC and fix the issue accordingly.


[root@tssperf11 logs]# tail -12 provisioner-k8s.log 
2018/04/19 19:18:33 main.go:443: INFO  === Starting volume provisioning ===
2018/04/19 19:18:33 main.go:444: INFO  options={Delete pvc-be766816-4438-11e8-b9b1-84b80208e1f2 &PersistentVolumeClaim{ObjectMeta:k8s_io_apimachinery_pkg_apis_meta_v1.ObjectMeta{Name:maprfs-secure-pvc,GenerateName:,Namespace:mapr-system,SelfLink:/api/v1/namespaces/mapr-system/persistentvolumeclaims/maprfs-secure-pvc,UID:be766816-4438-11e8-b9b1-84b80208e1f2,ResourceVersion:3036847,Generation:0,CreationTimestamp:2018-04-19 19:18:33 -0600 MDT,DeletionTimestamp:<nil>,DeletionGracePeriodSeconds:nil,Labels:map[string]string{},Annotations:map[string]string{},OwnerReferences:[],Finalizers:[],ClusterName:,Initializers:nil,},Spec:PersistentVolumeClaimSpec{AccessModes:[ReadWriteOnce],Resources:ResourceRequirements{Limits:ResourceList{},Requests:ResourceList{storage: {{300 6} {<nil>} 300M DecimalSI},},},VolumeName:,Selector:nil,StorageClassName:*secure-maprfs,},Status:PersistentVolumeClaimStatus{Phase:Pending,AccessModes:[],Capacity:ResourceList{},},} map[maprSecretName:mapr-provisioner-secrets mountPrefix:/pv namePrefix:pv readOnly:“true” restServers:10.10.70.113:8443 advisoryquota:100M cldbHosts:10.10.70.113 10.10.70.114 10.10.70.115 cluster:ObjectPool maprSecretNamespace:mapr-system reclaimPolicy:“Retain” securityType:unsecure ticketSecretNamespace:mapr-system]}
2018/04/19 19:18:33 main.go:445: INFO  Cleaning parameters...
2018/04/19 19:18:33 main.go:449: INFO  Parsing parameters...
2018/04/19 19:18:33 main.go:135: INFO  Getting admin secret: mapr-provisioner-secrets from namespace: mapr-system
2018/04/19 19:18:33 main.go:165: INFO  Got admin secret
2018/04/19 19:18:33 main.go:452: INFO  Constructed server info: (rest: 10.10.70.113:8443, cldb: 10.10.70.113 10.10.70.114 10.10.70.115, cluster: ObjectPool, securitytype: unsecure)
2018/04/19 19:18:33 main.go:105: INFO  Convert Kubernetes capacity: %!s(int64=300000000)
2018/04/19 19:18:33 main.go:108: INFO  Converted MapR capacity: 300M
2018/04/19 19:18:33 main.go:458: INFO  Generated Mapr volumename: pv.uclcmsgkxq mountpoint: /pv/pv-uclcmsgkxq
2018/04/19 19:18:33 main.go:319: INFO  Creating MapR query...
2018/04/19 19:18:33 main.go:326: INFO  Calling executeQuery with query string: /rest/volume/create?createparent=1&name=pv.uclcmsgkxq&advisoryquota=100M&path=%2Fpv%2Fpv-uclcmsgkxq&quota=300M&mount=1
2018/04/19 19:18:36 main.go:346: INFO  Response: {"timestamp":1524186116264,"timeofday":"2018-04-19 06:01:56.264 GMT-0700","status":"OK","total":0,"data":[],"messages":["Successfully created volume: 'pv.uclcmsgkxq'"]}
2018/04/19 19:18:36 main.go:467: INFO  Creating Kubernetes PersistentVolume: pv-uclcmsgkxq
2018/04/19 19:18:36 main.go:472: INFO  Reclaim Policy: Delete
2018/04/19 19:18:36 main.go:511: INFO  === Finished volume provisioning ===
[root@tssperf11 logs]# 


As seen in screenshot below Volume did get created with prefix pv-<RandomString>




Wednesday, April 18, 2018

Statically Provisioning a MapR Volume Using the FlexVolume Plug-in (Non-Secure cluster)

                             

        Statically Provisioning in K8S using FlexVolume Plug-In (Non-Secure cluster)

You can designate a pre-created MapR volume for use with Kubernetes by specifying the MapR FlexVolume parameters directly inside the Pod spec. In the Pod spec, you define a Kubernetes volume and add the MapR FlexVolume information to it. You can supply path information by using the volumePath parameter.

For static provisioning, configuring a PersistentVolume has some advantages over Kubernetes volume in a Pod:
  • The configuration file can be shared for use by multiple Pod specs.
  • The configuration file enables the PersistentVolume to be mounted and available even when the Pod spec that references it is removed.

1) Below is sample yaml file to statically provision MapR Flex volume to K8S .

[root@tssperf09 abizerwork]# cat staticProvisioning.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: test-secure
  namespace: mapr-system
spec:
  containers:
  - name: mycontainer
      imagePullPolicy: Always
      image: docker.artifactory/maprtech/base:5.2.2_3.0.1_centos7    args:
    - sleep
    - "1000000"
    imagePullPolicy: Always
    resources:
      requests:
        memory: "2Gi"
        cpu: "500m"
    volumeMounts:
    - mountPath: /maprvolume1                                     # mount name in K8S POD 
      name: maprvolume                                        # Volume name pre-created in cluster
  volumes:
    - name: maprvolume
      flexVolume:
        driver: "mapr.com/maprfs"
        readOnly: true
        options:
          volumePath: "/maprvolume"                           # Volume mount point
          cluster: "ObjectPool"
          cldbHosts: "10.10.70.113 10.10.70.114 10.10.70.115"
          securityType: "unsecure"

[root@tssperf09 abizerwork]#

Note : -  On the cluster side its assumed "maprvolume" is already created and mounted on /maprvolume.


[root@node113rhel67 ~]# maprcli volume info -name maprvolume -json
{
"timestamp":1524095640124,
"timeofday":"2018-04-18 04:54:00.124 GMT-0700",
"status":"OK",
"total":1,
"data":[
{
"acl":{
"Principal":"User root",
"Allowed actions":[
"dump",
"restore",
"m",
"d",
"fc"
]
},
"creator":"root",
"aename":"root",
"aetype":0,
"numreplicas":"3",
"minreplicas":"2",
"nsNumReplicas":"3",
"nsMinReplicas":"2",
"allowGrant":"false",
"reReplTimeOutSec":"0",
"replicationtype":"high_throughput",
"rackpath":"/data",
"mirrorthrottle":"1",
"accesstime":"April 18, 2018",
"readonly":"0",
"mountdir":"/maprvolume",
"volumename":"maprvolume",
"mounted":1,
"quota":"0",
"advisoryquota":"0",
"snapshotcount":"0",
"logicalUsed":"0",
"used":"0",
"snapshotused":"0",
"totalused":"0",
"scheduleid":0,
"schedulename":"",
"mirrorscheduleid":0,
"volumetype":0,
"mirrortype":3,
"creatorcontainerid":2181,
"creatorvolumeuuid":"-9169018513486905817:7826340903402007859",
"volumeid":45178265,
"actualreplication":[
0,
0,
0,
100,
0,
0,
0,
0,
0,
0,
0
],
"nameContainerSizeMB":0,
"nameContainerId":2181,
"needsGfsck":false,
"maxinodesalarmthreshold":"0",
"dbrepllagsecalarmthresh":"0",
"limitspread":"true",
"partlyOutOfTopology":0,
"auditVolume":0,
"audited":0,
"coalesceInterval":60,
"enableddataauditoperations":"getattr,setattr,chown,chperm,chgrp,getxattr,listxattr,setxattr,removexattr,read,write,create,delete,mkdir,readdir,rmdir,createsym,lookup,rename,createdev,truncate,tablecfcreate,tablecfdelete,tablecfmodify,tablecfScan,tableget,tableput,tablescan,tablecreate,tableinfo,tablemodify,getperm,getpathforfid,hardlink",
"disableddataauditoperations":"",
"volumeAces":{
"readAce":"p",
"writeAce":"p"
},
"fixCreatorId":"false",
"ReplTypeConversionInProgress":"0",
"tier":{
"enable":"false"
}
}
]
}

[root@node113rhel67 ~]# 



2)  Use the kubectl create command with the -f option to install static provisioner on  Kubernetes cluster

 kubectl create -f staticProvisioning.yaml

3) Once the pod starts and is in running state you should see a new pod "test-secure" .

[root@tssperf09 abizerwork]#  kubectl get pods --all-namespaces -o wide --sort-by=.status.hostIP 
NAMESPACE     NAME                                      READY     STATUS    RESTARTS   AGE       IP                NODE
kube-system   kube-scheduler-tssperf09.lab              1/1       Running   0          25d       10.10.72.249      tssperf09.lab
kube-system   calico-kube-controllers-d554689d5-mv6lz   1/1       Running   0          25d       10.10.72.249      tssperf09.lab
kube-system   kube-dns-6f4fd4bdf-x2g82                  3/3       Running   0          25d       192.168.196.222   tssperf09.lab
mapr-system   mapr-kdfplugin-srcln                      1/1       Running   0          21d       192.168.196.223   tssperf09.lab
kube-system   calico-node-z6tqw                         2/2       Running   0          25d       10.10.72.249      tssperf09.lab
kube-system   etcd-tssperf09.lab                        1/1       Running   0          25d       10.10.72.249      tssperf09.lab
kube-system   kube-apiserver-tssperf09.lab              1/1       Running   0          25d       10.10.72.249      tssperf09.lab
kube-system   kube-controller-manager-tssperf09.lab     1/1       Running   0          25d       10.10.72.249      tssperf09.lab
kube-system   calico-etcd-8s8mf                         1/1       Running   0          25d       10.10.72.249      tssperf09.lab
kube-system   kube-proxy-kln5q                          1/1       Running   0          25d       10.10.72.249      tssperf09.lab
kube-system   calico-node-rcxzm                         2/2       Running   0          25d       10.10.72.250      tssperf10.lab
mapr-system   mapr-kdfplugin-6l5n7                      1/1       Running   0          21d       192.168.61.65     tssperf10.lab
kube-system   kube-proxy-68tv4                          1/1       Running   0          25d       10.10.72.250      tssperf10.lab
mapr-system   test-secure                               1/1       Running   0          3m        192.168.61.67     tssperf10.lab
kube-system   kube-proxy-cknz7                          1/1       Running   0          25d       10.10.72.251      tssperf11.lab
mapr-system   mapr-kdfplugin-crzhk                      1/1       Running   0          21d       192.168.217.129   tssperf11.lab
kube-system   calico-node-x5qds                         2/2       Running   0          25d       10.10.72.251      tssperf11.lab
mapr-system   mapr-kdfprovisioner-79b86f459d-hjkcn      1/1       Running   0          21d       192.168.217.130   tssperf11.lab
[root@tssperf09 abizerwork]# 

To check the status and step the pod is currently executing while coming up below command can be executed.


[root@tssperf09 abizerwork]# kubectl describe pod test-secure  -n mapr-system
Name:         test-secure
Namespace:    mapr-system
Node:         tssperf10.lab/10.10.72.250
Start Time:   Tue, 17 Apr 2018 19:32:57 -0600
Labels:       <none>
Annotations:  <none>
Status:       Running
IP:           192.168.61.67
Containers:
  mycontainer:
    Container ID:  docker://588093ea68361532a56b82bedeb78a4c22c1b501b83df50f76664438ffad236f
    Image:         docker.io/maprtech/kdf-plugin:1.0.0_029_centos7
    Image ID:      docker-pullable://docker.io/maprtech/kdf-plugin@sha256:eecb2d64ede9b9232b6eebf5d0cc59fe769d16aeb56467d0a00489ce7224278d
    Port:          <none>
    Args:
      sleep
      1000000
    State:          Running
      Started:      Tue, 17 Apr 2018 19:33:05 -0600
    Ready:          True
    Restart Count:  0
    Requests:
      cpu:        500m
      memory:     2Gi
    Environment:  <none>
    Mounts:
      /maprvolume1 from maprvolume (rw)
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-9g8tq (ro)
Conditions:
  Type           Status
  Initialized    True 
  Ready          True 
  PodScheduled   True 
Volumes:
  maprvolume:
    Type:    FlexVolume (a generic volume resource that is provisioned/attached using an exec based plugin)
    Driver:      Options:  %v

    FSType:     mapr.com/maprfs
    SecretRef:  
    ReadOnly:   <nil>
%!(EXTRA bool=true, map[string]string=map[cluster:ObjectPool securityType:unsecure volumePath:/maprvolume cldbHosts:10.10.70.113 10.10.70.114 10.10.70.115])  default-token-9g8tq:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-9g8tq
    Optional:    false
QoS Class:       Burstable
Node-Selectors:  <none>
Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                 node.kubernetes.io/unreachable:NoExecute for 300s
Events:
  Type    Reason                 Age   From                    Message
  ----    ------                 ----  ----                    -------
  Normal  Scheduled              3m    default-scheduler       Successfully assigned test-secure to tssperf10.lab
  Normal  SuccessfulMountVolume  3m    kubelet, tssperf10.lab  MountVolume.SetUp succeeded for volume "default-token-9g8tq"
  Normal  SuccessfulMountVolume  3m    kubelet, tssperf10.lab  MountVolume.SetUp succeeded for volume "maprvolume"
  Normal  Pulling                3m    kubelet, tssperf10.lab  pulling image "docker.io/maprtech/kdf-plugin:1.0.0_029_centos7"
  Normal  Pulled                 3m    kubelet, tssperf10.lab  Successfully pulled image "docker.io/maprtech/kdf-plugin:1.0.0_029_centos7"
  Normal  Created                3m    kubelet, tssperf10.lab  Created container
  Normal  Started                3m    kubelet, tssperf10.lab  Started container


4) Once the POD is up you can login into the POD via below command.

[root@tssperf09 abizerwork]# kubectl exec -it test-secure -n mapr-system -- bash
bash-4.4# df -hP
Filesystem                Size      Used Available Capacity Mounted on
/dev/mapper/docker-253:0-393780-e7ea6408663cf79cf844e6f1f44915099168752e33c258a51ff64bb54dcc8149                                                                                 10.0G    306.1M      9.7G   3% /
tmpfs                    62.8G         0     62.8G   0% /dev
tmpfs                    62.8G         0     62.8G   0% /sys/fs/cgroup
posix-client-basic      415.1G      1.8G    413.3G   0% /maprvolume1   <--- This is the mount path via fuse
/dev/mapper/VolGroup-lv_root             49.1G     15.1G     31.4G  32% /dev/termination-log
/dev/mapper/VolGroup-lv_root             49.1G     15.1G     31.4G  32% /etc/resolv.conf
/dev/mapper/VolGroup-lv_root             49.1G     15.1G     31.4G  32% /etc/hostname
/dev/mapper/VolGroup-lv_root             49.1G     15.1G     31.4G  32% /etc/hosts
shm                      64.0M         0     64.0M   0% /dev/shm
/dev/mapper/VolGroup-lv_root             49.1G     15.1G     31.4G  32% /run/secrets
tmpfs                    62.8G     12.0K     62.8G   0% /run/secrets/kubernetes.io/serviceaccount
tmpfs                    62.8G         0     62.8G   0% /proc/kcore
tmpfs                    62.8G         0     62.8G   0% /proc/timer_list
tmpfs                    62.8G         0     62.8G   0% /proc/timer_stats
tmpfs                    62.8G         0     62.8G   0% /proc/sched_debug
tmpfs                    62.8G         0     62.8G   0% /proc/scsi
bash-4.4# 

Note : To get more details on the logs journals has collected for the Kubelet service, run below command.

journalctl -u kubelet