Showing posts with label rook. Show all posts
Showing posts with label rook. Show all posts

Wednesday, October 5, 2022

Using S3 storage on Open Data Framework provided by Ceph-RGW

My previous posts demonstrated how to use CephFS and Ceph RBD backed storage classes as deployed by Open Data Framework on OpenShift. 

This blog post I will demonstrate how to use the Ceph RGW backed storage class from within a pod running on the OpenShift cluster. I will extract the S3 authentication credentials, create a name space, start a pod and demonstrate how to securely interact with the S3 service. 

Background

As stated in the previous blog posts ODF deploys a Ceph cluster within the OCP cluster. The cluster master nodes are used as the Ceph monitor processes, workers are utilized as OSD and the remaining related pods are scheduled on the cluster. 

This post as been verified against OCP and ODF versions 4.11. 

Storage Class Listing

Let's start by verifying the availability of ODF storage classes. The following command will display the available storage classes.

$ oc get sc
NAME                          PROVISIONER                             RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
localblock                    kubernetes.io/no-provisioner            Delete          WaitForFirstConsumer   false                  6d
ocs-storagecluster-ceph-nfs   openshift-storage.nfs.csi.ceph.com      Delete          Immediate              false                  6d
ocs-storagecluster-ceph-rbd   openshift-storage.rbd.csi.ceph.com      Delete          Immediate              true                   6d
ocs-storagecluster-ceph-rgw   openshift-storage.ceph.rook.io/bucket   Delete          Immediate              false                  6d
ocs-storagecluster-cephfs     openshift-storage.cephfs.csi.ceph.com   Delete          Immediate              true                   6d
openshift-storage.noobaa.io   openshift-storage.noobaa.io/obc         Delete          Immediate              false                  6d

Verify S3 Access

To verify S3 access we will create an object bucket claim, extract the needed authentication and connection information, create a namespace with a configured POD and verify access.

Create ObjectBucketClaim

An ObjectBucketClaim is created against the CephRGW backed storage class.

$ cat objectbucketclaim.yaml 
apiVersion: objectbucket.io/v1alpha1
kind: ObjectBucketClaim
metadata:
  name: ceph-bucket
  namespace: openshift-storage
spec:
  generateBucketName: ceph-bkt
  storageClassName: ocs-storagecluster-ceph-rgw
$ oc apply -f objectbucketclaim.yaml 
objectbucketclaim.objectbucket.io/ceph-bucket created
$ oc get objectbucketclaim -n openshift-storage ceph-bucket -o jsonpath='{.status.phase}{"\n"}'
Bound

Extract Secrets and Connection Information

Once the ObjectBucketClaim is phase is Bound, the S3 secrets and connection information can be extract from the OCP cluster. The following commands will extract the needed information for later usage and print the resulting information to the screen. 

$ export AWS_ACCESS_KEY_ID=`oc get secret -n openshift-storage rook-ceph-object-user-ocs-storagecluster-cephobjectstore-ocs-storagecluster-cephobjectstoreuser -o jsonpath='{.data.AccessKey}'  | base64 -d`
$ export AWS_SECRET_ACCESS_KEY=`oc get secret -n openshift-storage rook-ceph-object-user-ocs-storagecluster-cephobjectstore-ocs-storagecluster-cephobjectstoreuser -o jsonpath='{.data.SecretKey}'  | base64 -d`
$ export AWS_BUCKET=`oc get cm ceph-bucket -n openshift-storage -o jsonpath='{.data.BUCKET_NAME}'`
$ export AWS_HOST=`oc get cm ceph-bucket -n openshift-storage -o jsonpath='{.data.BUCKET_HOST}'`
$ export AWS_PORT=`oc get cm ceph-bucket -n openshift-storage -o jsonpath='{.data.BUCKET_PORT}'`
$ echo ${AWS_ACCESS_KEY_ID}
$ echo ${AWS_SECRET_ACCESS_KEY}
$ echo ${AWS_BUCKET}
$ echo ${AWS_BUCKET}
$ echo ${AWS_HOST}
$ echo ${AWS_PORT}

Update S3 pod yaml

The pod yaml file will be updated to pass the S3 parameters and applied to the cluster
$ cat 74-consume-s3.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: s3-test
---
apiVersion: v1
kind: Pod
metadata:
  name: test-pod
  namespace: s3-test
  labels:
    app: rook-s3
spec:
  containers:
  - name: run-pod1
    image: registry.access.redhat.com/ubi8/ubi
    imagePullPolicy: IfNotPresent
    command: ['sh', '-c', 'yum install -y wget python3 && cd /tmp && wget https://downloads.sourceforge.net/project/s3tools/s3cmd/2.2.0/s3cmd-2.2.0.tar.gz && tar -zxf /tmp/s3cmd-2.2.0.tar.gz && ls /tmp && tail -f /dev/null' ]
    env:
    - name: AWS_ACCESS_KEY_ID
      value: VALUE_FROM_ECHO_AWS_ACCESS_KEY_ID
    - name: AWS_SECRET_ACCESS_KEY
      value: VALUE_FROM_ECHO_AWS_SECRET_ACCESS_KEY
    - name: AWS_HOST
      value: VALUE_FROM_ECHO_AWS_HOST
    - name: AWS_PORT
      value: VALUE_FROM_ECHO_AWS_PORT
    - name: AWS_BUCKET
      value: VALUE_FROM_ECHO_AWS_BUCKET
$ sed -e "s/VALUE_FROM_ECHO_AWS_ACCESS_KEY_ID/${AWS_ACCESS_KEY_ID}/g" \
-e "s/VALUE_FROM_ECHO_AWS_SECRET_ACCESS_KEY/${AWS_SECRET_ACCESS_KEY}/" \
-e "s/VALUE_FROM_ECHO_AWS_HOST/${AWS_HOST}/" \
-e "s/VALUE_FROM_ECHO_AWS_PORT/\"${AWS_PORT}\"/" \
-e "s/VALUE_FROM_ECHO_AWS_BUCKET/${AWS_BUCKET}/" \
-i consume-s3.yaml
$ oc apply -f consume-s3.yaml 
namespace/s3-test created
pod/test-pod created

Wait for the pod to be ready

The pod command line includes the installation commands needed to update the UBI image as needed for this demonstration. A customized image should be used in a production environment. Checking for the python3 command will be a sufficient check to ensure this demonstration pod is configured.

$ oc exec -n s3-test test-pod -- python3 -V
Python 3.6.8

NOTE: This demonstration is using the s3cmd to interface with the bucket. A customized configuration file using the needed S3 parameters and the service CA certificate is copied into to the pod for easier testing. This updating and copying of this file is left out of this blog post.

Verify S3 Environment

We can use the printenv command to verify the setting of the necessary environment credentials. These parameters can be used with a custom image to access the internal Ceph RGW storage
$ oc exec -n s3-test test-pod -- printenv | grep AWS
AWS_BUCKET=ceph-bkt-...ac49
AWS_ACCESS_KEY_ID=FAJ...1HR
AWS_SECRET_ACCESS_KEY=3z3...Vtd
AWS_HOST=rook-ceph-rgw-ocs-storagecluster-cephobjectstore.openshift-storage.svc
AWS_PORT=443

Verify S3 Access

To verify S3 access, we will simply create and list a new bucket.

$ oc exec -n s3-test test-pod -- python3 /tmp/s3cmd-2.2.0/s3cmd mb s3://validate.${RANDOM}
Bucket 's3://validate.18454/' created
$ oc exec -n s3-test test-pod -- python3 /tmp/s3cmd-2.2.0/s3cmd ls
2022-10-05 20:54  s3://validate.18454

Conclusion

With this blog post we have demonstrated how to consume the internal S3 storage service by creating an ObjectBucketClaim, extracting needed authentication information, deploying a customized pod and running commands. This information can be extended to support the deployment and operation of customized S3 enabled applications. 

Monday, October 3, 2022

Verifying Openshift Data Foundation data access with RBD

This post is similar to my previous post where a CephFS backed storage class was verified with Openshift Data Foundation on Openshift Container Platform. 

 This blog post will demonstrate how to use the ODF provisioned RBD backed storage class by binding a persistent volume claim (PVC), binding to a pod and verifying data access.

Background

ODF deploys a Ceph cluster on top of an existing OCP cluster. Ceph features are provided to the cluster via a variety of storage classes.

This post as been verified against OCP and ODF versions 4.8 through 4.11. 

Storage Class Listing

Let's start by verifying the availability of ODF storage classes. The following command will display the available storage classes.

$ oc get sc
NAME                          PROVISIONER                             RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
localblock                    kubernetes.io/no-provisioner            Delete          WaitForFirstConsumer   false                  40h
ocs-storagecluster-ceph-nfs   openshift-storage.nfs.csi.ceph.com      Delete          Immediate              false                  40h
ocs-storagecluster-ceph-rbd   openshift-storage.rbd.csi.ceph.com      Delete          Immediate              true                   40h
ocs-storagecluster-ceph-rgw   openshift-storage.ceph.rook.io/bucket   Delete          Immediate              false                  40h
ocs-storagecluster-cephfs     openshift-storage.cephfs.csi.ceph.com   Delete          Immediate              true                   40h
openshift-storage.noobaa.io   openshift-storage.noobaa.io/obc         Delete          Immediate              false                  40h

Verify RBD Storage Class

To verify RBD, we will create a namespace, bind a PVC and create a POD with the PVC attached. Once the POD is running we will copy content into the mount point and verify access.

Create RBD Verification Namespace

 The namespace is created via the following yaml and command

$ cat rbd-ns.yaml
apiVersion: v1                                                                                                                                                                                                     
kind: Namespace                                                                                                                                                                                                    
metadata:                                                                                                                                                                                                          
  labels:                                                                                                                                                                                                          
    openshift.io/cluster-monitoring: "true"                                                                                                                                                                        
  name: rbd-ns                                                                                                                                                                                                     
spec: {}
$ oc apply -f rbd-ns.yaml 
namespace/rbd-ns created

Create RBD Verification PVC

The PVC is created against the RBD backed storage class.

$ cat rbd-pvc.yaml 
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: rbd-pvc
  namespace: rbd-ns
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
  storageClassName: ocs-storagecluster-ceph-rbd
$ oc apply -f rbd-pvc.yaml 
persistentvolumeclaim/rbd-pvc created

Create RBD Verification POD

A pod is created in the RBD verification namespace. This pod uses the Red Hat's Apache 2.4 image based on their UBI image. This image was chosen as a convenience and to permit verification of network access to copied data. The image can be replaced with any other suitable image and related tests.

NOTE: This pod description includes setting the fsGroup in the securityContext. This will ensure the mounted volume will be accessible by the internal process. In this pod, httpd runs as UID 1001. 

$ cat rbd-pod.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: test-pod
  namespace: rbd-ns
  labels:
    app: rook-ceph-block
spec:
  securityContext:
    fsGroup: 1001
  containers:
  - name: sample-pod1
    image: registry.access.redhat.com/ubi8/httpd-24
    imagePullPolicy: IfNotPresent
    volumeMounts:
    - name: repo-vol
      mountPath: "/var/www/html/"
  volumes:
  - name: repo-vol
    persistentVolumeClaim:
      claimName: rbd-pvc
$ oc apply -f rbd-pod.yaml 
pod/test-pod created

Copy Static Content Into RBD Verification Pod

A simple HTML file is copied into the pod's document root. This will ensure the attached PVC can be written to and read from bia the web service.

$ $ cat index-block.html 
Here be block dragons
$ oc cp index-rbd.html rbd-ns/test-pod:/var/www/html/index.html

Create and Expose Service from Verification Pod

The RBD pod is exposed via the standard OCP service and route commands.

$ cat rbd-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: block-httpd
  namespace: rbd-ns
spec:
  ports:
  - name: http
    port: 8080
    target: 8080
    protocol: TCP
  selector:
    app: rook-ceph-block
---
apiVersion: route.openshift.io/v1
kind: Route
metadata:
  name: block-httpd
  namespace: rbd-ns
spec:
  port:
    targetPort: http
  to:
    kind: Service
    name: block-httpd
$ oc apply -f rbd-service.yaml 
service/block-httpd created
route.route.openshift.io/block-httpd created

Verify RBD Service and Data Access

A simple curl command is used to validate access to the data written to the RBD backed PVC.

$ RBD_HOST=`oc get route -n rbd-ns block-httpd block-httpd -o jsonpath='{.items[0].spec.host}'`
$ curl ${RBD_HOST}
Here be block dragons

RBD Verification Conclusion

As with the CephFS post, this post has demonstrated how to bind a PVC to a RBD backed storage class, attach the PVC to a pod, copy data into the pod and verify access to the data via a network service. Other than setting a securityContext, no major changes are needed from the previous demo.


Friday, September 16, 2022

Verifying Openshift Data Foundation data access with CephFS

This post serves as a follow up to my previous post about deploying Openshift Data Foundation on Openshift Container Platform. 

This blog post will demonstrate how to use the ODF provisioned CepfFS backed storage class by binding a persistent volume claim (PVC), binding to a pod and verifying data access. 

Background

ODF deploys a Ceph cluster on top of an existing OCP cluster. Ceph features are provided to the cluster via a variety of storage classes.

This post as been verified against OCP and ODF versions 4.8 through 4.11. 

Storage Class Listing

Lets start by verifying the availability of ODF storage classes. The following command will display the available storage classes.

$ oc get sc
NAME                          PROVISIONER                             RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
localblock                    kubernetes.io/no-provisioner            Delete          WaitForFirstConsumer   false                  40h
ocs-storagecluster-ceph-nfs   openshift-storage.nfs.csi.ceph.com      Delete          Immediate              false                  40h
ocs-storagecluster-ceph-rbd   openshift-storage.rbd.csi.ceph.com      Delete          Immediate              true                   40h
ocs-storagecluster-ceph-rgw   openshift-storage.ceph.rook.io/bucket   Delete          Immediate              false                  40h
ocs-storagecluster-cephfs     openshift-storage.cephfs.csi.ceph.com   Delete          Immediate              true                   40h
openshift-storage.noobaa.io   openshift-storage.noobaa.io/obc         Delete          Immediate              false                  40h

Verify CepfFS Storage Class

To verify CephFS, we will create a namespace, bind a PVC and create a POD with the PVC attached. Once the POD is running we will copy content into the mount point and verify access.

Create CephFS Verification Namespace

 The namespace is created via the following yaml and command

$ cat cephfs-ns.yaml
apiVersion: v1
kind: Namespace
metadata:
  labels:
    openshift.io/cluster-monitoring: "true"
  name: cephfs-ns
spec: {}
$ oc apply -f cephfs-ns.yaml 
namespace/cephfs-ns created

Create CephFS Verification PVC

The PVC is created against the CephFS backed storage class.

$ cat cephfs-pvc.yaml 
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: cephfs-pvc
  namespace: cephfs-ns
spec:
  accessModes:
  - ReadWriteMany
  resources:
    requests:
      storage: 1Gi
  storageClassName: ocs-storagecluster-cephfs
$ oc apply -f cephfs-pvc.yaml 
persistentvolumeclaim/cephfs-pvc created

Create CephFS Verification POD

A pod is created in the CephFS verification namespace. This pod uses the Red Hat's Apache 2.4 image based on their UBI image. This image was chosen as a convenience and to permit verification of network access to copied data. The image can be replaced with any other suitable image and related tests. 

$ cat cephfs-pod.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: cephfs-pod
  namespace: cephfs-ns
  labels:
    app: rook-ceph-cephfs
spec:
  containers:
  - name: cephfs-pod1
    image: registry.access.redhat.com/ubi8/httpd-24
    imagePullPolicy: IfNotPresent
    volumeMounts:
    - name: repo-vol
      mountPath: "/var/www/html/"
  volumes:
  - name: repo-vol
    persistentVolumeClaim:
      claimName: cephfs-pvc
$ oc apply -f cephfs-pod.yaml 
pod/cephfs-pod created

Copy Static Content Into CephFS Verification Pod

A simple HTML file is copied into the pod's document root. This will ensure the attached PVC can be written to and read from bia the web service.

$ cat index-cephfs.html 
Here be cephfs dragons
$ oc cp index-cephfs.html cephfs-ns/test-pod:/var/www/html/index.html

Create and Expose Service from Verification Pod

The CephFS pod is exposed via the standard OCP service and route commands.

 $ cat cephfs-service.yaml 
apiVersion: v1
kind: Service
metadata:
  name: cephfs-httpd
  namespace: cephfs-ns
spec:
  ports:
  - name: http
    port: 8080
    target: 8080
    protocol: TCP
  selector:
    app: rook-ceph-cephfs
---
apiVersion: route.openshift.io/v1
kind: Route
metadata:
  name: cephfs-httpd
  namespace: cephfs-ns
spec:
  port:
    targetPort: http
  to:
    kind: Service
    name: cephfs-httpd
$ oc apply -f cephfs-service.yaml 
service/cephfs-httpd created
route.route.openshift.io/cephfs-httpd created

Verify CephFS Service and Data Access

A simple curl command is used to validate access to the data written to the CephFS backed PVC

$ CEPHFS_HOST=`oc get route -n cephfs-ns cephfs-httpd cephfs-httpd -o jsonpath='{.items[0].spec.host}'`
$ curl ${CEPHFS_HOST} Here be cephfs dragons

CephFS Verification Conclusion

This post has demonstrated how to bind a PVC to a CephFS backed storage class, attach the PVC to a pod, copy data into the pod and verify access to the data via a network service. 


Wednesday, September 14, 2022

Installing Red Hat Openshift Data Foundation via the command line

Red Hat Openshift Data Foundation (ODF) is an Openshift Container Platform (OCP) add-on for providing Ceph storage to pods running within a deployed cluster. This Red Hat product is based on the upstream Rook project. When deployed, ODF will provide CephFS, RBD and RGW backed storage classes. The Ceph cluster monitors will be installed on the OCP master nodes with the Ceph ODS processes running on the designated OCP worker nodes.

The processes in this post have been validated against OCP and ODF versions 4.8 through 4.11.

A basic understanding of Openshift, Openshift Data Foundation and Ceph are needed to understand this post. This post is not intended to replace official product documentation.

Lab Description

Hardware

This post is developed utilizing a virtual lab consisting of 7 virtual machines. These consist of the following types of hosts:

  • Provision: 2 CPU, 16G RAM, >70G system disk, RHEL 8
  • Master (x3): 6 CPU, 16G RAM, 60G system disk
  • Worker (x3): 14 CPU, 48G RAM, 60G system disk, 10G data disk (x3)

Network

The virtual lab consists of two networks.

  • Provision: Isolated, managed by the Openshift Installer
  • Baremetal: Bridged, managed by an DNS/DHCP server out of scope for this document

Additional Lab Infrastructure

  • A virtual BMC service is used to provide IMPI management of the virtual machines. This service runs on the hypervisor and is reachable from the provision host.
  • A DNS/DHCP virtual server. This service provides DHCP and DNS services to the OCP cluster. The OS provided dhcp and bind servers are used to provide IP address assignment and name resolution.

Cluster Installation

The OCP cluster is deployed using the Openshift Installer Provisioned Infrastructure (IPI) install method. This method uses of a series of Ansible playbooks executed from the provision node to deploy an OCP cluster. The details of the installation is beyond the scope of this post.

Installation Environment
The ODF installation process is performed from the provision host by a user with access to the admin level kubeconfig. This is automatically configured for the user who runs the IPI installer.

ODF Installation Process

Node Verification

Verify availability of nodes. Ensure three master and three worker nodes are available.
$ oc get nodes
NAME       STATUS   ROLES    AGE    VERSION
master-0   Ready    master   110m   v1.24.0+b62823b
master-1   Ready    master   110m   v1.24.0+b62823b
master-2   Ready    master   110m   v1.24.0+b62823b
worker-0   Ready    worker   91m    v1.24.0+b62823b
worker-1   Ready    worker   91m    v1.24.0+b62823b
worker-2   Ready    worker   90m    v1.24.0+b62823b

Verify availability of storage on the worker nodes. At least one disk needs to be available per host but three disks are used in this example. worker-0 is used as an example with worker-1 and worker-2 being similar.
$ oc debug node/worker-0

Pod IP: 192.168.122.35
If you don't see a command prompt, try pressing enter.
sh-4.4# chroot /host
sh-4.4# lsblk
NAME   MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
sda      8:0    0   60G  0 disk 
|-sda1   8:1    0    1M  0 part 
|-sda2   8:2    0  127M  0 part 
|-sda3   8:3    0  384M  0 part /boot
`-sda4   8:4    0 59.5G  0 part /sysroot
vda    252:0    0   10G  0 disk 
vdb    252:16   0   10G  0 disk 
vdc    252:32   0   10G  0 disk

ODF Subscription Installation and Verification

The ODF subscription needs to be added to the OCP cluster. This subscription is available via the Openshift Marketplace and is added to the cluster with the following yaml file.
$ cat odf-subscription.yaml
apiVersion: v1
kind: Namespace
metadata:
  labels:
    openshift.io/cluster-monitoring: "true"
  name: openshift-storage
spec: {}
---
apiVersion: operators.coreos.com/v1
kind: OperatorGroup
metadata:
  annotations:
  generateName: openshift-storage-
  name: openshift-storage-24mhn
  namespace: openshift-storage
spec:
  targetNamespaces:
  - openshift-storage
---
apiVersion: operators.coreos.com/v1alpha1
kind: Subscription
metadata:
  labels:
    operators.coreos.com/odf-operator.openshift-storage: ""
  name: odf-operator
  namespace: openshift-storage
spec:
  channel: stable-4.11
  installPlanApproval: Automatic
  name: odf-operator
  source: redhat-operators
  sourceNamespace: openshift-marketplace
  startingCSV: odf-operator.v4.11.0
  
$ oc apply -f 22-ocs-sub.yaml
namespace/openshift-storage created
operatorgroup.operators.coreos.com/openshift-storage-24mhn created
subscription.operators.coreos.com/odf-operator created
The installation can be monitored with the following command. The operator is fully installed when "Succeed" is returned as the phase.
$ watch -d "oc get csv -n openshift-storage -l operators.coreos.com/ocs-operator.openshift-storage='' -o jsonpath='{.items[0].status.phase}'"

The openshift-storage pods can be listed with the following command. All pods should be in "Running" or "Completed" state. No pods should in a "Pending" or "Error" state.
$ oc get pods -n openshift-storage

Next we will enable the ODF console in the OCP web console. This will allow the modification and monitoring of the ODF cluster via the OCP web console.
$ oc patch console.operator cluster -n openshift-storage --type json -p '[{"op": "add", "path": "/spec/plugins", "value": ["odf-console"]}]'

Local Storage Subscription Installation and Verification

The Local Storage subscription needs to be installed. This is to support the worker nodes service as Ceph OSD servers. This subscription is available via the Openshift Marketplace and is added to the cluster with the following yaml file.

$ cat local-subscription.yaml
apiVersion: v1
kind: Namespace
metadata:
  labels:
    kubernetes.io/metadata.name: openshift-local-storage
    olm.operatorgroup.uid/1b9690c6-f7d4-47f4-8046-b389b44b0612: ""
  name: openshift-local-storage
spec:
  finalizers:
  - kubernetes
---
apiVersion: operators.coreos.com/v1
kind: OperatorGroup
metadata:
  annotations:
    olm.providedAPIs: LocalVolume.v1.local.storage.openshift.io,LocalVolumeDiscovery.v1alpha1.local.storage.openshift.io,LocalVolumeDiscoveryResult.v1alpha1.local.storage.openshift.io,LocalVolumeSet.v1alpha1.local.storage.openshift.io
  name: openshift-local-storage-operator
  namespace: openshift-local-storage
spec:
  targetNamespaces:
  - openshift-local-storage
---
apiVersion: operators.coreos.com/v1alpha1
kind: Subscription
metadata:
  labels:
    operators.coreos.com/local-storage-operator.openshift-local-storage: ""
  name: local-storage-operator
  namespace: openshift-local-storage
spec:
  channel: stable
  installPlanApproval: Automatic
  name: local-storage-operator
  source: redhat-operators
  sourceNamespace: openshift-marketplace

The installation of the local storage operator can be monitored with a command similar to the ODF operator installation. The operator is fully installed when "Succeed" is returned as the phase.

$ watch -d "`oc get csv -n openshift-local-storage -l operators.coreos.com/local-storage-operator.openshift-local-storage="" -o=jsonpath='{.items[0].status.phase}'"

Again, the status of the pods can be checked. All pods in the openshift-local-storage namespace should be in either the "Running" or "Completed" state.

Configure Local Storage Disks

Once the ODF and local storage operators are configured, the local disks can be configured and make ready for the storage cluster deployment. This consists of two elements:
  1. Labeling nodes which are used for OSD storage
  2. Configuring the disks for usage.
Each worker node will need to be labeled with the "cluster.ocs.openshift.io/openshift-storage=" tag. The command for worker-0 is given as an example below. worker-1 and worker-2 are labeled with a similar command.

$ oc label nodes worker-0 cluster.ocs.openshift.io/openshift-storage=''

The local storage disks are provisioned with following yaml file

$ cat label-disks.yaml
apiVersion: local.storage.openshift.io/v1alpha1
kind: LocalVolumeSet
metadata:
  name: localpv
  namespace: openshift-local-storage
spec:
  deviceInclusionSpec:
    deviceTypes: #Unused disks and partitions meeting these requirements are used
    - disk
    - part
    minSize: 1Gi
  nodeSelector:
    nodeSelectorTerms:
    - matchExpressions: #Nodes with this label are used
      - key: cluster.ocs.openshift.io/openshift-storage
        operator: Exists
  storageClassName: localblock
  tolerations:
  - effect: NoSchedule
    key: node.ocs.openshift.io/storage
    operator: Equal
    value: "true"
  volumeMode: Block
$ oc apply -f label-disks.yaml
localvolumeset.local.storage.openshift.io/localpv created

The apply command will start the configuration process of the local volume disks and their related persistent volumes (PV). The progress of this process can be monitored with the following command. The process is complete when the status returns "True"

$ watch -d "oc get localvolumeset -n openshift-local-storage localpv -o jsonpath='{.status.conditions[0].status}'"

This command will provide more information while monitoring the configuration of the local disks.
$ watch -d "oc get LocalVolumeSet -A;echo; oc get pods -n openshift-local-storage; echo ; oc get pv"

There should be one PV for each disk which matches the "deviceInclusionSpec". In this lab, a total of 9 PVs should be available.

$ oc get pv | wc -l

Configure ODF Storage Cluster

The ODF storage cluster can be deployed with the following yaml file. The storageDeviceSets count should be a OSD sets configured. In this lab, 9 disks are configure for OSD usage and the storageDeviceSet count is set to 3. This value will need to be adjusted for the local environment.

$ cat deploy-storagecluster.yamlapiVersion: ocs.openshift.io/v1
kind: StorageCluster
metadata:
  name: ocs-storagecluster
  namespace: openshift-storage
spec:
  arbiter: {}
  encryption:
    kms: {}
  externalStorage: {}
  flexibleScaling: true
  resources:
    mds:
      limits:
        cpu: "3"
        memory: "8Gi"
      requests:
        cpu: "3"
        memory: "8Gi"
  monDataDirHostPath: /var/lib/rook
  managedResources:
    cephBlockPools:
      reconcileStrategy: manage   # <-- Default value is manage
    cephConfig: {}
    cephFilesystems: {}
    cephObjectStoreUsers: {}
    cephObjectStores: {}
  multiCloudGateway:
    reconcileStrategy: manage   # <-- Default value is manage
  storageDeviceSets:
  - count: 3  # <-- Modify count to desired value. For each set of 3 disks increment the count by 1.
    dataPVCTemplate:
      spec:
        accessModes:
        - ReadWriteOnce
        resources:
          requests:
            storage: "100Mi"
        storageClassName: localblock
        volumeMode: Block
    name: ocs-deviceset
    placement: {}
    portable: false
    replica: 3
    resources:
      limits:
        cpu: "2"
        memory: "5Gi"
      requests:
        cpu: "2"
        memory: "5Gi"
$ oc apply -f deploy-storagecluster.yaml
storagecluster.ocs.openshift.io/ocs-storagecluster created

The storage cluster deployment start the configuration process of the Ceph monitors and OSD processes on the node. A simple monitoring of this process can be monitored with the below command. The storage cluster is deployed and ready for usage once the phase returns "Ready".

$ watch -d "oc get storagecluster -n openshift-storage ocs-storagecluster -o jsonpath={'.status.phase'}"

A more through monitoring of the configuration process can be accomplished with this command

$ watch -d "oc get storagecluster -n openshift-storage; echo ; oc get cephcluster -n openshift-storage; echo; oc get noobaa -n openshift-storage ; echo; oc get pods -n openshift-storage|tail -n 20"

Checking Available Storage Classes

Multiple Ceph storage classes are available at the completion of the storage cluster deployment. This can be viewed with the following command

$ oc get sc
NAME                          PROVISIONER                             RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
localblock                    kubernetes.io/no-provisioner            Delete          WaitForFirstConsumer   false                  5m54s
ocs-storagecluster-ceph-rbd   openshift-storage.rbd.csi.ceph.com      Delete          Immediate              true                   2m4s
ocs-storagecluster-ceph-rgw   openshift-storage.ceph.rook.io/bucket   Delete          Immediate              false                  5m36s
ocs-storagecluster-cephfs     openshift-storage.cephfs.csi.ceph.com   Delete          Immediate              true                   2m4s
openshift-storage.noobaa.io   openshift-storage.noobaa.io/obc         Delete          Immediate              false                  14s

PVs can now be created against this storage classes with their eventual consumption by PVCs and pods.

Deploying Ceph Toolbox Pod

A pod containing the Ceph command line tools can be added to the deploy cluster with the below command.
$ oc patch OCSInitialization ocsinit -n openshift-storage --type json --patch  '[{ "op": "replace", "path": "/spec/enableCephTools", "value": true }]'
ocsinitialization.ocs.openshift.io/ocsinit patched

The Ceph tool box can be used with the following command
$ $ oc rsh -n openshift-storage `oc get pods -n openshift-storage -l app=rook-ceph-tools -o jsonpath='{.items[0].metadata.name}'`
sh-4.4$ ceph status
  cluster:
    id:     c680a945-60bb-4da3-b419-64f017884b8f
    health: HEALTH_OK
 
  services:
    mon: 3 daemons, quorum a,b,c (age 17m)
    mgr: a(active, since 17m)
    mds: 1/1 daemons up, 1 hot standby
    osd: 9 osds: 9 up (since 16m), 9 in (since 17m)
    rgw: 1 daemon active (1 hosts, 1 zones)
 
  data:
    volumes: 1/1 healthy
    pools:   12 pools, 449 pgs
    objects: 362 objects, 134 MiB
    usage:   437 MiB used, 90 GiB / 90 GiB avail
    pgs:     449 active+clean
 
  io:
    client:   3.4 KiB/s rd, 80 KiB/s wr, 4 op/s rd, 9 op/s wr

sh-4.4$ ceph osd tree
ID  CLASS  WEIGHT   TYPE NAME                          STATUS  REWEIGHT  PRI-AFF
-1         0.08817  root default                                                
-7         0.02939      host worker-0-osp-example-com                           
 0    hdd  0.00980          osd.0                          up   1.00000  1.00000
 5    hdd  0.00980          osd.5                          up   1.00000  1.00000
 8    hdd  0.00980          osd.8                          up   1.00000  1.00000
-3         0.02939      host worker-1-osp-example-com                           
 1    hdd  0.00980          osd.1                          up   1.00000  1.00000
 3    hdd  0.00980          osd.3                          up   1.00000  1.00000
 7    hdd  0.00980          osd.7                          up   1.00000  1.00000
-5         0.02939      host worker-2-osp-example-com                           
 2    hdd  0.00980          osd.2                          up   1.00000  1.00000
 4    hdd  0.00980          osd.4                          up   1.00000  1.00000
 6    hdd  0.00980          osd.6                          up   1.00000  1.00000

Conclusion and Followup

This post has detailed the operations needed to configure OCP for ODF, configuration of the local disks and the deployment of the storage cluster. Additional posts will be made providing examples of how to consume the storage provide by ODF.

References:

Friday, April 5, 2019

Developing and testing patches for Rook

Backgroud


The purpose of this posting is to detail the steps needed to develop and test Rook code using the provided CI scripts. My previous blog posting did not use the CI scripting provided by rook and may not provide sufficient testing coverage to pass the upstream CI.

Pre-built infrastructure


Test Hosts Configuration
This CI development environment uses four (4) libvirt virtual machines as test hosts. The hardware configurations of the virtual machines remains the same as in the previous blog posts. These machines are built from the same clone image and configured with as follows
  • Ubuntu 16 (some commands may change for Ubuntu 18)
  • Local user with admin rights, updated to use sudo with no password
  • Pre-populated SSH host keys and StrictHostchecking set to no in the .ssh/config file
  • /etc/hosts file pre-populated with the host name and IP of each test host. 
  • Statically defined IP address as per this blog post

Hostnames and IPs

The virtual machines in this environment will be configured with the following hostnames and IPs
192.168.122.31 kube-ub-master
192.168.122.32 kube-ub-node1
192.168.122.33 kube-ub-node2
192.168.122.34 kube-ub-node3

Configuring the master server

The Rook CI scripts are designed to run from the kubernetes master host. These configuration steps are ran as the configured admin user on that host.

Update DNS resolver and hostname

On Ubuntu 16, the resolv.conf file is managed by systemd. This configuration can result in the coredns container not starting due to a lookup loop.
sudo sed -i -e 's/dns=.*/dns=default/' /etc/NetworkManager/NetworkManager.conf
sudo systemctl disable systemd-resolved.service
sudo systemctl stop  systemd-resolved.service
sudo rm /etc/resolv.conf
echo nameserver 8.8.8.8 | sudo tee /etc/resolv.conf
echo kube-ub-master | sudo tee /etc/hostname

Install go 1.11

The CI requires go version 1.11 to be available on the system in order to build the local images and to run the go based test infrastructure.
wget https://dl.google.com/go/go1.11.6.linux-amd64.tar.gz
cd /usr/local
sudo tar -zxf ~kschinck/go1.11.6.linux-amd64.tar.gz
cd ~
echo export PATH=/usr/local/go/bin:\$PATH | tee -a ~/.bashrc
source .bashrc

Install and configure docker

Configure docker to use the registry on the master node
sudo apt-get install -y docker.io git ansible curl
cat <<EOF | sudo tee /etc/docker/daemon.json
{
  "insecure-registries" : ["192.168.122.31:5000"]
}
EOF
sudo systemctl start docker
sudo systemctl enable docker

Add user to the docker group

To run the CI scripts, the docker user needs to able to run docker commands without using sudo.
sudo usermod -a -G docker myuser
The new group assignment can be picked up by either logging out and back in or running the newgrp command.

Start the docker registry container

The docker registry container needs to be running in order to host the locally build versions of the Rook images.
docker run -d -p 5000:5000 --restart=always --name registry registry:2

Verify Registry Access

The curl command can be used to verify access to the local registry.

curl http://192.168.122.31:5000/v2/_catalog
{"repositories":[]}

Configure Worker Nodes

The worker nodes need to be configure similar to the master node with the exception of needing golang support added.
for HOST in kube-ub-node1 kube-ub-node2 kube-ub-node3
do
  cat<<EOF | ssh $HOST
sudo sed -i -e 's/dns=.*/dns=default/' /etc/NetworkManager/NetworkManager.conf
sudo systemctl disable systemd-resolved.service
sudo systemctl stop  systemd-resolved.service
sudo rm /etc/resolv.conf
echo nameserver 8.8.8.8 | sudo tee /etc/resolv.conf
echo $HOST | sudo tee /etc/hostname
sudo apt-get install -y docker.io 
cat <<EOG | sudo tee /etc/docker/daemon.json
{
  "insecure-registries" : ["192.168.122.31:5000"]
}
EOG
sudo systemctl start docker
sudo systemctl enable docker
echo ‘export GOPATH=${HOME}/go’ | tee -a ~/.bashrc
source .bashrc
echo $PATH
echo $GOPATH
mkdir -p ${GOPATH}/src/github.com/rook
cd ${GOPATH}/src/github.com/rook
git clone http://github.com/myuser/rook.git
cd rook
git checkout mypatch
EOF
done

Download Source Code

At this point we are ready to prepare for and download the forked git repository.The repository is configured according to the Rook development guidelines
These commands will prepare the needed directory path, clone the git repo, switch to the development branch and build the images.
cat <<EOF>>~/.bashrc
export GOPATH=${HOME}/go
EOF
export GOPATH=${HOME}/go
mkdir -p ${GOPATH}/src/github.com/rook
cd ${GOPATH}/src/github.com/rook
git clone http://github.com/myuser/rook.git
cd rook
git checkout mypatch
make

Tag and push built image

The make command will build and upload a rook/ceph image. In order to use this image, this image will need to be tagged and pushed back to the local registry.
docker tag `docker images | grep "rook/ceph" | awk '{print $1":"$2}'` 192.168.122.31:5000/rook/ceph:latest
docker push 192.168.122.31:5000/rook/ceph:latest
The local test framework files need to be update to use the new image. The following command will update the image reference to the local registry.
sed -i -e 's/image: rook.*$/image: 192.168.122.31:5000\/rook\/ceph:latest/' ./tests/framework/installer/ceph_manifests.go

Deploy master  node using CI script

cd tests/scripts
./kubeadm.sh up
The end of this command will display the kubectl command used to configure additional worker nodes. This needs to be copied and used in below worker node configuration setp

Deploy worker nodes using CI script

This command will add each worker host to the kubernetes cluster.
for HOST in kube-ub-node1 kube-ub-node2 kube-ub-node3
do
  cat<<EOF | ssh $HOST
  cd cd ${GOPATH}/src/github.com/rook/rook/tests/scripts
  ./kubeadm.sh install node TEXT_TAKEN_FROM_THE_MASTER_INSTALL_OUTPUT
EOF


Setup the kubectl command for debugging


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

At this point, the admin will be able to use the kubectl command to interact with the deployed kubernetes cluster.

Run CI Test

Rook uses the provide test framework of go to run the validation commands. The test command is ran from the top of the rook repository directory. It will deploy a variety of configurations and validate the operation of the cluster. Output is saved under the _output directory.
This command will run the standard tests called SmokeSuite and save the output to a file in the /tmp directory.


time go test -v -timeout 1800s -run SmokeSuite github.com/rook/rook/tests/integration 2>&1 | tee /tmp/integration.log

The results can be reviewed from /tmp/integration.log file.

The kubernetes cluster should be in a clean state if the tests finish successfully.

Repeating the CI Execution


If an operator is to be update updated, the previous uploaded images should be deleted from the local repository prior to making updates, rebuilding the image, tagging and pushing.

If the CI configuration is updated, it is sufficient to rerun the go test command line.



Friday, March 8, 2019

Configuring a Rook Test and Development System

Reason

All patches should be tested locally prior to submitting a PR to the Rook project. This posting will detail the steps needed to configure an environment for developing and testing patches for the Rook project.

Environment

This post was developed on virtual machines running Fedora Core 29 but should work on other recent Fedora/CentOS/RHEL OS releases.

Pre-reqs

  • Four (4) virtual machines with the following specifications
    • 1 node: 2 CPU, =>2G, 20Gb storage
    • 3 nodes: 1 CPU, =>2G, 20Gb storage
  • A non-root user with sudo access with the ability install packages locally and on the other test nodes.

Description

This posting will extend the previous blog posting about deploying Ceph storage using Rook on a kubernetes cluster. This posting will detail how to deploy a local docker registry, configure the environment to Rook development, build Rook and, finally, how to test the locally built code.

Procedure


Deploy Local Docker Registry
The docker registry needs to be added to the kube-master host. This can be performed after the base OS configuration but prior to running "kubeadm --init"

The following command will pull down the docker registry image, start the container, make it always restart with the base OS and expose TCP port 5000. Note: the docker command is not normally ran as a non-root user as per this blog posting. For my local config, I have updated the group ownership of the docker UNIX socket from root to wheel.

 $ docker run -d --restart=always -p 5000:5000 --name registry registry
Unable to find image 'registry:latest' locally
Trying to pull repository docker.io/library/registry ... 
sha256:3b00e5438ebd8835bcfa7bf5246445a6b57b9a50473e89c02ecc8e575be3ebb5: Pulling from docker.io/library/registry
c87736221ed0: Pull complete 
1cc8e0bb44df: Pull complete 
54d33bcb37f5: Pull complete 
e8afc091c171: Pull complete 
b4541f6d3db6: Pull complete 
Digest: sha256:3b00e5438ebd8835bcfa7bf5246445a6b57b9a50473e89c02ecc8e575be3ebb5
Status: Downloaded newer image for docker.io/registry:latest
4d56fadeadbff76b14de2093b655af44b7cd08484df5f366fe3c83b4942c7306
$ sudo netstat -tulpn | grep 5000
tcp6       0      0 :::5000                 :::*                    LISTEN      11227/docker-proxy- 

Next, all nodes need docker to be configured to use the local insecure registry. This is done by updating /etc/containers/registries.conf and adding the new registry to the registries.insecure list.
 [registries.insecure]  
 registries = ['192.168.122.3:5000']  

And restart docker.
 $ sudo systemctl restart docker  

Configure Rook Development Environment

Configuring the rook development environment is fairly direct. The only build requirements are the git, go and perl-Digest-SHA packages. The rest of the golang libraries are retrieved during the build process
$ sudo yum install -y git go perl-Digest-SHA  
$ export GOPATH=/home/user/go  
$ mkdir -p ${GOPATH}/github.com/rook  
$ cd ${GOPATH}/github.com/rook  
$ git clone http://github.com/myrepo/rook.git  
$ cd rook  

Note: You should fork the upstream repository, if you are going to develop code for an eventual pull request.

Build Rook

 $ make  
 === helm package rook-ceph  
 ==> Linting /home/kschinck/go/src/github.com/rook/rook/cluster/charts/rook-ceph  
 Lint OK  
 1 chart(s) linted, no failures  
 Successfully packaged chart and saved it to: /home/kschinck/go/src/github.com/rook/rook/_output/charts/rook-ceph-v0.9.0-162.g2ed99b1c.dirty.tgz  
 === helm index  
 === go vet  
 === go build linux_amd64  
 .  
 .  
 . skipped text   
 .  
 .  
 === docker build build-7ad1f371/ceph-amd64  
 sha256:91a2f03ae0bb99a8f65b225b4160402927350618cd2a9592068503c24cb5d701  
 === docker build build-7ad1f371/cockroachdb-amd64  
 sha256:2d6f04f76d22de950fcf7df9e7205608c9baca627dbe4df81448419a4aff2b68  
 === docker build build-7ad1f371/minio-amd64  
 sha256:c1a4b7e09dc5069a6de809bbe2db6f963420038e243080c61bc61ea13bceff14  
 === docker build build-7ad1f371/nfs-amd64  
 sha256:e80fd66429923a0114210b8c254226d11e5ffb0a68cfc56377b8a3eccd3b663f  
 === saving image build-7ad1f371/nfs-amd64  
 === docker build build-7ad1f371/cassandra-amd64  
 sha256:492b314ef2123328c84702c66b0c9589f342b5f644ac5cff1de2263356446701  
 === docker build build-7ad1f371/edgefs-amd64  
 sha256:0d0ab8dd81261d0f325f83a690c7997707582126ab01e5f7e7a55fe964143c5d  
 === saving image build-7ad1f371/edgefs-amd64  
 $ docker images  
 REPOSITORY                         TAG              IMAGE ID      CREATED       SIZE  
 build-7ad1f371/edgefs-amd64        latest             0d0ab8dd8126    13 minutes ago   411 MB  
 build-7ad1f371/cassandra-amd64     latest             492b314ef212    13 minutes ago   141 MB  
 build-7ad1f371/nfs-amd64           latest             e80fd6642992    13 minutes ago   391 MB  
 build-7ad1f371/minio-amd64         latest             c1a4b7e09dc5    18 minutes ago   81.9 MB  
 build-7ad1f371/cockroachdb-amd64   latest             2d6f04f76d22    18 minutes ago   243 MB  
 build-7ad1f371/ceph-amd64          latest             91a2f03ae0bb    18 minutes ago   610 MB  
 docker.io/rook/ceph                master             b924a5979c14    4 days ago     610 MB  

Testing Locally Built Code

The built Ceph image needs to be tagged and the Ceph operator.yaml CRD file updated to use the new image from the local registry.
 $ IMG=`docker images | grep -Eo '^build-[a-z0-9]{8}/ceph-[a-z0-9]+\s'`  
 $ echo $IMG  
 build-7ad1f371/ceph-amd64  
 $ docker tag $IMG 192.168.122.3:5000/rook/ceph:latest  
 $ docker push 192.168.122.3:5000/rook/ceph:latest  
 The push refers to a repository [192.168.122.3:5000/rook/ceph]  
 5111818ce34e: Pushed   
 1d339a1e5398: Pushed   
 88c1eb656680: Pushed   
 f972d139738d: Pushed   
 latest: digest: sha256:80d3ec16e4e6206530756a5a7ce76b51f336a1438af5de77488917f5d1f7b602 size: 1163  
 $ docker images | grep "rook/ceph"  
 192.168.122.3:5000/rook/ceph     latest             91a2f03ae0bb    2 hours ago     610 MB  
 docker.io/rook/ceph         master             b924a5979c14    4 days ago     610 MB 
$ curl -X GET http://192.168.122.3:5000/v2/_catalog
{"repositories":["rook/ceph"]}
 $ sed -i 's|image: .*$|image: 192.168.122.3:5000/rook/ceph:latest|' cluster/examples/kubernetes/ceph/operator.yaml  

Once the operator.yaml CRD file has been updated, the ceph cluster can be deployed using the normal workflow.
$ cd cluster/examples/kubernetes/ceph/
$ kubectl -n rook-ceph-system describe pod rook-ceph-operator-9d496c54b-gmnrw | grep Image  
   Image:     192.168.122.3:5000/rook/ceph:latest  
   Image ID:   docker-pullable://192.168.122.3:5000/rook/ceph@sha256:80d3ec16e4e6206530756a5a7ce76b51f336a1438af5de77488917f5d1f7b602  


References:

https://schmaustech.blogspot.com/2019/01/rook-ceph-on-kubernetes.html
https://www.projectatomic.io/blog/2015/08/why-we-dont-let-non-root-users-run-docker-in-centos-fedora-or-rhel/
https://rook.io/docs/rook/v0.9/development-flow.html
https://github.com/rook/rook


Monday, February 18, 2019

Using Rook deployed Object Store in Kubernetes

Using Rook Deployed Object Store in Kubernetes 


This posting will explore Rook deployed object store using Ceph radosgw within a kubernetes cluster. A radosgw pod will be deployed and a user created. This will be followed by an exploration of the stored credential information and using this information with a custom deployed pod.

Background


Previously, we have deployed a Ceph storage cluster using Rook and demonstrated how to customize the cluster configuration.

Current deployments

$ kubectl -n rook-ceph get pods
NAME                                     READY   STATUS      RESTARTS   AGE
rook-ceph-mgr-a-569d76f456-sddpg         1/1     Running     0          3d21h
rook-ceph-mon-a-6bc4689f9d-r8jcm         1/1     Running     0          3d21h
rook-ceph-mon-b-566cdf9d6-mhf8w          1/1     Running     0          3d21h
rook-ceph-mon-c-74c6779667-svktr         1/1     Running     0          3d21h
rook-ceph-osd-0-6766d4f547-6qlvv         1/1     Running     0          3d21h
rook-ceph-osd-1-c5c7ddf67-xrm2k          1/1     Running     0          3d21h
rook-ceph-osd-2-f7b75cf4d-bm5sc          1/1     Running     0          3d21h
rook-ceph-osd-prepare-kube-node1-ddgkk   0/2     Completed   0          3d21h
rook-ceph-osd-prepare-kube-node2-nmgqj   0/2     Completed   0          3d21h
rook-ceph-osd-prepare-kube-node3-xzwnr   0/2     Completed   0          3d21h
rook-ceph-tools-76c7d559b6-tnmrf         1/1     Running     0          3d21h

Ceph cluster status

$ kubectl -n rook-ceph exec `kubectl -n rook-ceph get pods --selector=app=rook-ceph-tools -o jsonpath='{.items[0].metadata.name}'` -- ceph status
  cluster:
    id:     eff29897-252c-4e65-93e7-6f4975c0d83a
    health: HEALTH_OK
 
  services:
    mon: 3 daemons, quorum a,c,b
    mgr: a(active)
    osd: 3 osds: 3 up, 3 in
 
 data:
    pools:   0 pools, 0 pgs
    objects: 0  objects, 0 B
    usage:   3.1 GiB used, 57 GiB / 60 GiB avail
    pgs:     

Deploying Object Store Pod and User

Rook has CephObjectStore and CephObjectStoreUser CRD which permit the creation of a Ceph RadosGW service and related users. 
The default configurations are deployed with the below commands
RGW Pod

$ kubectl create -f object.yaml 
cephobjectstore.ceph.rook.io/my-store created
$ kubectl -n rook-ceph get pods
NAME                                      READY   STATUS      RESTARTS   AGE
rook-ceph-mgr-a-569d76f456-sddpg          1/1     Running     0          3d21h
rook-ceph-mon-a-6bc4689f9d-r8jcm          1/1     Running     0          3d21h
rook-ceph-mon-b-566cdf9d6-mhf8w           1/1     Running     0          3d21h
rook-ceph-mon-c-74c6779667-svktr          1/1     Running     0          3d21h
rook-ceph-osd-0-6766d4f547-6qlvv          1/1     Running     0          3d21h
rook-ceph-osd-1-c5c7ddf67-xrm2k           1/1     Running     0          3d21h
rook-ceph-osd-2-f7b75cf4d-bm5sc           1/1     Running     0          3d21h
rook-ceph-osd-prepare-kube-node1-ddgkk    0/2     Completed   0          3d21h
rook-ceph-osd-prepare-kube-node2-nmgqj    0/2     Completed   0          3d21h
rook-ceph-osd-prepare-kube-node3-xzwnr    0/2     Completed   0          3d21h
rook-ceph-rgw-my-store-57556c8479-vkjvn   1/1     Running     0          5m58s
rook-ceph-tools-76c7d559b6-tnmrf          1/1     Running     0          3d21h

RGW User

$ kubectl create -f object-user.yaml 
cephobjectstoreuser.ceph.rook.io/my-user created
$ kubectl -n rook-ceph exec `kubectl -n rook-ceph get pods --selector=app=rook-ceph-tools -o jsonpath='{.items[0].metadata.name}'` -- radosgw-admin user list
[
    "my-user"
]

The RGW user information can be explored with the radosgw-admin command below. Notice the access_key and secret_key are available. 

$ kubectl -n rook-ceph exec `kubectl -n rook-ceph get pods --selector=app=rook-ceph-tools -o jsonpath='{.items[0].metadata.name}'` -- radosgw-admin user info --uid my-user
{
    "user_id": "my-user",
    "display_name": "my display name",
    "email": "",
    "suspended": 0,
    "max_buckets": 1000,
    "auid": 0,
    "subusers": [],
    "keys": [
        {
            "user": "my-user",
            "access_key": "C6FIZTCAAEH1LBWNY84X",
            "secret_key": "i8Pw44ViKt3DVAQTSWIEJcazUHrYRCj0u6Xw9jPE"
        }
    ],
    "swift_keys": [],
    "caps": [],
    "op_mask": "read, write, delete",
    "default_placement": "",
    "placement_tags": [],
    "bucket_quota": {
        "enabled": false,
        "check_on_raw": false,
        "max_size": -1,
        "max_size_kb": 0,
        "max_objects": -1
    },
    "user_quota": {
        "enabled": false,
        "check_on_raw": false,
        "max_size": -1,
        "max_size_kb": 0,
        "max_objects": -1
    },
    "temp_url_keys": [],
    "type": "rgw",
    "mfa_ids": []
}

Rook adds the access_key and secret_key to a stored secret for usage by other pods.

$ kubectl -n rook-ceph get secrets
NAME                                     TYPE                                  DATA   AGE
default-token-67jhm                      kubernetes.io/service-account-token   3      3d21h
rook-ceph-admin-keyring                  kubernetes.io/rook                    1      3d21h
rook-ceph-config                         kubernetes.io/rook                    2      3d21h
rook-ceph-dashboard-password             kubernetes.io/rook                    1      3d21h
rook-ceph-mgr-a-keyring                  kubernetes.io/rook                    1      3d21h
rook-ceph-mgr-token-sbk8f                kubernetes.io/service-account-token   3      3d21h
rook-ceph-mon                            kubernetes.io/rook                    4      3d21h
rook-ceph-mons-keyring                   kubernetes.io/rook                    1      3d21h
rook-ceph-object-user-my-store-my-user   kubernetes.io/rook                    2      7m31s
rook-ceph-osd-token-qlsst                kubernetes.io/service-account-token   3      3d21h
rook-ceph-rgw-my-store                   kubernetes.io/rook                    1      14m

$ kubectl -n rook-ceph get secret rook-ceph-object-user-my-store-my-user
NAME                                     TYPE                 DATA   AGE
rook-ceph-object-user-my-store-my-user   kubernetes.io/rook   2      7m49s

$ kubectl -n rook-ceph get secret rook-ceph-object-user-my-store-my-user -o yaml
apiVersion: v1
data:
  AccessKey: QzZGSVpUQ0FBRUgxTEJXTlk4NFg=
  SecretKey: aThQdzQ0VmlLdDNEVkFRVFNXSUVKY2F6VUhyWVJDajB1Nlh3OWpQRQ==
kind: Secret
metadata:
  creationTimestamp: "2019-02-18T14:37:40Z"
  labels:
    app: rook-ceph-rgw
    rook_cluster: rook-ceph
    rook_object_store: my-store
    user: my-user
  name: rook-ceph-object-user-my-store-my-user
  namespace: rook-ceph
  ownerReferences:
  - apiVersion: v1
    blockOwnerDeletion: true
    kind: CephCluster
    name: rook-ceph
    uid: 200d59ce-307a-11e9-bc12-52540087c4d1
  resourceVersion: "1175482"
  selfLink: /api/v1/namespaces/rook-ceph/secrets/rook-ceph-object-user-my-store-my-user
  uid: be847f63-338a-11e9-bc12-52540087c4d1
type: kubernetes.io/rook

The AccessKey and SecretKey values are base64 encoded stores of the access_key and secret_key seen in the radosgw-admin command.

$ base64 -d -
QzZGSVpUQ0FBRUgxTEJXTlk4NFg=
C6FIZTCAAEH1LBWNY84X
$ base64 -d -
aThQdzQ0VmlLdDNEVkFRVFNXSUVKY2F6VUhyWVJDajB1Nlh3OWpQRQ==
i8Pw44ViKt3DVAQTSWIEJcazUHrYRCj0u6Xw9jPE

The RGW service can be queried to display currently available S3 buckets. No buckets are initially created by Rook.

$ kubectl -n rook-ceph exec `kubectl -n rook-ceph get pods --selector=app=rook-ceph-tools -o jsonpath='{.items[0].metadata.name}'` -- radosgw-admin bucket list
[]

Consume Object Store

Some information must be gathered so they can be provided to the custom pod. 
Object Store name: 
$ kubectl -n rook-ceph get pods --selector='app=rook-ceph-rgw' -o jsonpath='{.items[0].metadata.labels.rook_object_store}'
my-store

Object Store Service Hostname
$ kubectl -n rook-ceph get services
NAME                      TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
rook-ceph-mgr             ClusterIP   10.108.38.115            9283/TCP   3d23h
rook-ceph-mgr-dashboard   ClusterIP   10.107.5.72              8443/TCP   3d23h
rook-ceph-mon-a           ClusterIP   10.99.36.158             6789/TCP   3d23h
rook-ceph-mon-b           ClusterIP   10.103.132.39            6789/TCP   3d23h
rook-ceph-mon-c           ClusterIP   10.101.117.131           6789/TCP   3d23h
rook-ceph-rgw-my-store    ClusterIP   10.107.251.22            80/TCP     147m
 

Create Custom Deployment
A custom deployment file to deploy a basic CentOS7 and install the python-bono package. The environment is populated with the needed parameters to access the S3 store and create a bucket. 

$ cat ~/my-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mydemo
  namespace: rook-ceph
  labels:
    app: mydemo
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mydemo
  template:
    metadata:
      labels:
        app: mydemo
    spec:
      dnsPolicy: ClusterFirstWithHostNet
      hostNetwork: true
      containers:
      - name: mydemo
        image: docker.io/jdeathe/centos-ssh
        imagePullPolicy: IfNotPresent
        command: ["/usr/bin/supervisord"]
        securityContext:
          privileged: true
          capabilities:
            add:
              - SYS_ADMIN
        lifecycle:
          postStart:
            exec:
              command: ["/usr/bin/yum", "install", "-y", "python-boto"]
        env:
          - name: AWSACCESSKEYID
            valueFrom:
              secretKeyRef:
                name: rook-ceph-object-user-my-store-my-user
                key: AccessKey
          - name: AWSSECRETACCESSKEY
            valueFrom:
              secretKeyRef:
                name: rook-ceph-object-user-my-store-my-user
                key: SecretKey
          - name: BUCKETNAME
            value: my-store
          - name: RGWHOST
            # the value is {service-name}.{name-space}
            value: rook-ceph-rgw-my-store.rook-ceph


$ kubectl create -f ~/my-deployment.yaml
 deployment.apps/mydemo created

Once the pod is running, open a shell and examine the environment

$ kubectl -n rook-ceph exec `kubectl -n rook-ceph get pods --selector=app=mydemo -o jsonpath='{.items[0].metadata.name}'` -it /bin/bash
# printenv | sort | grep -E "AWSACCESS|AWSSECRET|BUCKETNAME|RGWHOST"
AWSACCESSKEYID=C6FIZTCAAEH1LBWNY84X
AWSSECRETACCESSKEY=i8Pw44ViKt3DVAQTSWIEJcazUHrYRCj0u6Xw9jPE
BUCKETNAME=my-store
RGWHOST=rook-ceph-rgw-my-store.rook-ceph
Create and run a simple test script. This script will connect to the RGW and create a bucket. No output will be printed on a success.

# cat ~/test-s3.py
import boto
import os
import boto.s3.connection
access_key = os.environ['AWSACCESSKEYID']
secret_key = os.environ['AWSSECRETACCESSKEY']
bucket = os.environ['BUCKETNAME']
myhost = os.environ['RGWHOST']
conn = boto.connect_s3(
        aws_access_key_id = access_key,
        aws_secret_access_key = secret_key,
        host = myhost,
        is_secure=False,
        calling_format = boto.s3.connection.OrdinaryCallingFormat(),
        )
bucket = conn.create_bucket(bucket)

# python ~/test-s3.py 

The RGW service can be queried to display the created bucket

$ kubectl -n rook-ceph exec `kubectl -n rook-ceph get pods --selector=app=rook-ceph-tools -o jsonpath='{.items[0].metadata.name}'` -- radosgw-admin bucket list
[
    "my-store"
]

Issues and Going Forward

  • Deleting the CephObjectStoreUser does not delete the stored secret.
  • The ceph.conf section name is hard coded for the radosgw service
  • Dynamically query the environment variables used for the application deployment

Wednesday, February 13, 2019

Customizing Ceph.conf deployed with Rook

Customizing a Ceph.conf deployed with Rook on Kubernetes


Two options for customizing the parameters of a ceph.conf file deployed by Rook. These customizations could be needed for performance or troubleshooting reasons. In this post, the debug output level of various Ceph services will be modified. Other parameters can be updated using the same process

The override settings are saved in a ConfigMap called rook-config-override within the rook-ceph namespace and applied to the pods during creation. The contents of this map are empty in a default deployment.

To list the available ConfigMaps in the rook-ceph namespace:

$ kubectl -n rook-ceph get ConfigMaps
NAME                      DATA   AGE
rook-ceph-config          1      106m
rook-ceph-mon-endpoints   3      106m
rook-config-override      1      106m
rook-crush-config         1      105m
rook-test-ownerref        0      106m

To list the contents of the rook-config-override ConfigMap and display the contents in YAML format.

$ kubectl -n rook-ceph get ConfigMap rook-config-override -o yaml
apiVersion: v1
data:
  config: ""
kind: ConfigMap
metadata:
  creationTimestamp: "2019-02-13T21:53:51Z"
  name: rook-config-override
  namespace: rook-ceph
  ownerReferences:
  - apiVersion: v1
    blockOwnerDeletion: true
    kind: CephCluster
    name: rook-ceph
    uid: cfcb486e-2fd9-11e9-bc12-52540087c4d1
  resourceVersion: "164993"
  selfLink: /api/v1/namespaces/rook-ceph/configmaps/rook-config-override
  uid: d9b48916-2fd9-11e9-bc12-52540087c4d1


Option 1: Setting parameters via live editing


Edit config map using EDITOR. YAML is the default format for editing

$ kubectl -n rook-ceph edit ConfigMap rook-config-override -o yaml

In this example, we will update the config from "" to setting needed to enable debugging of the OSD service.  More information on available configuration settings can be found in the references below.

Display updated config map

$ kubectl -n rook-ceph get configmaps rook-config-override -o yaml
apiVersion: v1
data:
  config: |
    [global]
    debug osd = 5
kind: ConfigMap
metadata:
  creationTimestamp: "2019-02-13T21:53:51Z"
  name: rook-config-override
  namespace: rook-ceph
  ownerReferences:
  - apiVersion: v1
    blockOwnerDeletion: true
    kind: CephCluster
    name: rook-ceph
    uid: cfcb486e-2fd9-11e9-bc12-52540087c4d1
  resourceVersion: "182611"
  selfLink: /api/v1/namespaces/rook-ceph/configmaps/rook-config-override
  uid: d9b48916-2fd9-11e9-bc12-52540087c4d1

Restart impacted pod

Once the updated settings are saved, the impacted pods will need to be restarted. In this case, the OSD pods will need to be restarted. Care must be taken to restart the OSD pods only with the cluster is healthy and all data protected.

List running OSD pods:

$ kubectl -n rook-ceph get pods --selector=app=rook-ceph-osd
NAME                               READY   STATUS    RESTARTS   AGE
rook-ceph-osd-0-6669bdbf6d-vvsjn   1/1     Running   0          127m
rook-ceph-osd-1-556bff7694-8mhq2   1/1     Running   0          127m
rook-ceph-osd-2-7db64c88bc-d7sp5   1/1     Running   0          127m

Restart each pod while waiting for the cluster to recover

$ kubectl -n rook-ceph delete pod rook-ceph-osd-0-6669bdbf6d-vvsjn
pod "rook-ceph-osd-0-6669bdbf6d-vvsjn" deleted

The cluster will go into a HEALTH_WARN while the OSD pod is being restarted and any data re-syncing occurs. Restart the remaining OSD pods once the ceph cluster has returned to HEALTH_OK

Verify setting

$ kubectl -n rook-ceph exec rook-ceph-osd-0-6669bdbf6d-p5msf -- cat /etc/ceph/ceph.conf | grep "debug osd"
debug osd                 = 5


Option 2: Setting parameters during deployment


Customized ceph.conf parameters can be deployed during cluster deployment by adding a ConfigMap to the cluster.yaml file. These values will be applied to the nodes during initial and follow pod startups. In this example, we are going to set the debug level for the Ceph mon service.

Edit cluster.yaml file

Using your favorite editor, add the following lines to the cluster.yaml file:

---
apiVersion: v1
kind: ConfigMap
data:
  config: |
    [global]
    debug mon = 5
metadata:
  name: rook-config-override
  namespace: rook-ceph

Deploy cluster

Deploy the ceph cluster as per previous blog posts listed below.

Verify setting

$ kubectl -n rook-ceph get pods --selector=app=rook-ceph-mon
NAME                               READY   STATUS    RESTARTS   AGE
rook-ceph-mon-a-79b6c85f89-6rzrw   1/1     Running   0          2m50s
rook-ceph-mon-b-57bc4756c9-bmg9n   1/1     Running   0          2m39s
rook-ceph-mon-c-6f8bb9598d-9mlcb   1/1     Running   0          2m25s
$ kubectl -n rook-ceph exec rook-ceph-mon-a-79b6c85f89-6rzrw -- cat /etc/ceph/ceph.conf | grep "debug mon"
debug mon                 = 5

Notes

  • The OSD and Mon pods should be restarted one at a time with the Ceph cluster returning to a HEALTH_OK between pod restarts
  • No validation is performed on the override parameters. "mon debug" or a config option which could render the Ceph cluster inoperable can be added to the config override and applied on the next pod restart
References:

Thursday, January 31, 2019

Deploying Rook with Ceph using Bluestore

Deploying Rook using Ceph/Bluestore on Kubernetes


This article will describe how to deploy Rook using Ceph storage and Bluestore as the backend storage. This is deployed within a kurbernetes infrastructure

System Design

Four hosts are used for this deployment: 1 master node and 3 worker nodes. In this example, these nodes are hosted within a libvirt environment and deployed using Ben Schmaus' write up and configuration changes detailed below.


The kube-master host is configured with 2vCPU, 2G of ram and 20Gb of virtio disk local storage. Each work is configured with 1vCPU, 2G of ram, and two 20G virtio disks. one for local storage and for OSD storage disk.

Additional Configuration Changes


After the Rook git repository is mirrored, the cluster.yaml file needs to be updated prior to being deployed with the following changes.
  • set storeType to bluestore
  • set useAllNodes to false 
  • each node needs to listed with the designated OSD device

Configuration Excerpt:



  storage:
    useAllNodes: false
    useAllDevices: false
    deviceFilter:
    location:
    nodes:
    - name: "kube-node1"
      devices:
      - name: "vdb"
    - name: "kube-node2"
      devices:
      - name: "vdb"
    - name: "kube-node3"
      devices:
      - name: "vdb"
    config:
      storeType: bluestore

Deployment and Verification


Rook deployment follows the same steps as detailed in Ben's link above. Verification can be performed with a few simple commands. 

Ceph Status


$  kubectl -n rook-ceph exec \
$(kubectl -n rook-ceph get pod -l "app=rook-ceph-tools" \
-o jsonpath='{.items[0].metadata.name}') -- ceph -s
  cluster:
    id:     9467587e-7d45-4b81-9c68-c216964e7d79
    health: HEALTH_OK
  services:
    mon: 3 daemons, quorum b,a,c
    mgr: a(active)
    osd: 3 osds: 3 up, 3 in
  data:
    pools:   0 pools, 0 pgs
    objects: 0  objects, 0 B
    usage:   3.0 GiB used, 57 GiB / 60 GiB avail
    pgs:     


OSD Tree


$ kubectl -n rook-ceph exec $(kubectl -n rook-ceph get pod -l "app=rook-ceph-tools" \
-o jsonpath='{.items[0].metadata.name}') -- ceph osd tree
ID CLASS WEIGHT  TYPE NAME           STATUS REWEIGHT PRI-AFF 
-1       0.05846 root default                                
-3       0.01949     host kube-node1                         
 0   hdd 0.01949         osd.0           up  1.00000 1.00000 
-7       0.01949     host kube-node2                         
 1   hdd 0.01949         osd.1           up  1.00000 1.00000 
-5       0.01949     host kube-node3                         
 2   hdd 0.01949         osd.2           up  1.00000 1.00000 

OSD Store Location


$ kubectl -n rook-ceph exec rook-ceph-osd-0-d848c6b74-rncp4 -- ls -laF /var/lib/ceph/osd/ceph-0
total 24
drwxrwxrwt  2 ceph ceph 180 Feb  1 05:00 ./
drwxr-x---. 1 ceph ceph  20 Feb  1 05:00 ../
lrwxrwxrwx  1 ceph ceph  92 Feb  1 05:00 block -> /dev/ceph-651a13f3-dc9f-465c-8cef-7c6618958f0b/osd-data-2e004e5d-8210-4e20-9e28-d431f468a977
-rw-------  1 ceph ceph  37 Feb  1 05:00 ceph_fsid
-rw-------  1 ceph ceph  37 Feb  1 05:00 fsid
-rw-------  1 ceph ceph  55 Feb  1 05:00 keyring
-rw-------  1 ceph ceph   6 Feb  1 05:00 ready
-rw-------  1 ceph ceph  10 Feb  1 05:00 type
-rw-------  1 ceph ceph   2 Feb  1 05:00 whoami