As covered in part one of this article series, it can be difficult to map application object locations in OpenShift Data Foundation (ODF) clusters. My goal is to make this process easier for you by demonstrating how to establish a troubleshooting container and then how to use it for both block and file storage mapping.
Be sure to read part one first to understand the environment and necessary toolkit. It's time to start by creating the demonstration project.
Create the project
Next, create two simple test applications, one that uses the block SC and the other that uses the file SC, to perform the tasks of mapping where the data of these applications are being stored in the ODF cluster.
First, create a project named ocs-block-app to host the application:
[alexon@bastion ~]$ oc new-project ocs-block-app
Now using project "ocs-block-app" on server "https://api.example.com:6443".
You can add applications to this project with the new-app
command. For example, to build a new example application in Ruby, try:
oc new-app rails-postgresql-example
Or use kubectl
to deploy a simple Kubernetes application:
kubectl create deployment hello-node --image=k8s.gcr.io/serve_hostname
Then, use one of the templates made available by OCP that makes use of block. It's a good idea is to use the template rails-pgsql-persistent:
[alexon@bastion ~]$ oc get templates -n openshift -o custom-columns=NAME:.metadata.name | grep ^rails | head -1
rails-pgsql-persistent
In the parameters available in the template, it's possible to see that the volume request size is customizable:
[alexon@bastion ~]$ oc process --parameters -n openshift rails-pgsql-persistent | grep -i volume
VOLUME_CAPACITY
Volume space available for data, e.g. 512Mi, 2Gi
1Gi
Run this new application and adjust the volume request size to 5GB:
[alexon@bastion ~]$ oc new-app rails-pgsql-persistent -p VOLUME_CAPACITY=5Gi
--> Deploying template "openshift/rails-pgsql-persistent" to project ocs-block-app
Rails + PostgreSQL
---------
An example Rails application with a PostgreSQL database. For more information about using this template, including OpenShift considerations, see https://github.com/sclorg/rails-ex/blob/master/README.md.
The following service(s) have been created in your project: rails-pgsql-persistent, postgresql.
For more information about using this template, including OpenShift considerations, see https://github.com/sclorg/rails-ex/blob/master/README.md.
* With parameters:
* Name=rails-pgsql-persistent
* Namespace=openshift
* Memory Limit=512Mi
* Memory Limit (PostgreSQL)=512Mi
* Volume Capacity=5Gi
* Git Repository URL=https://github.com/sclorg/rails-ex.git
* Git Reference=
* Context Directory=
* Application Hostname=
* GitHub Webhook Secret=ahNYBvvbrEFhRjFEX28XdXn04CvMgkbQuABBKruJ # generated
* Secret Key=m2aq81igaa74gh1shh8vawcywvsxjqjqubywwkcadymj0b1va0krkgsog000ksdusf7h6gyyhoxyh6dcfhw2swsen85o8sq43vod1hvlbtvu7n6x14sn7k4vcs0uwxr # generated
* Application Username=openshift
* Application Password=secret
* Rails Environment=production
* Database Service Name=postgresql
* Database Username=userWXH # generated
* Database Password=pOxlVrav # generated
* Database Name=root
* Maximum Database Connections=100
* Shared Buffer Amount=12MB
* Custom RubyGems Mirror URL=
--> Creating resources ...
secret "rails-pgsql-persistent" created
service "rails-pgsql-persistent" created
route.route.openshift.io "rails-pgsql-persistent" created
imagestream.image.openshift.io "rails-pgsql-persistent" created
buildconfig.build.openshift.io "rails-pgsql-persistent" created
deploymentconfig.apps.openshift.io "rails-pgsql-persistent" created
persistentvolumeclaim "postgresql" created
service "postgresql" created
deploymentconfig.apps.openshift.io "postgresql" created
--> Success
Access your application via route 'rails-pgsql-persistent-ocs-block-app.apps.example.com'
Build scheduled, use 'oc logs -f buildconfig/rails-pgsql-persistent' to track its progress.
Run' oc status' to view your app.
After a few moments, verify that the application is functional:
[alexon@bastion ~]$ oc status
In project ocs-block-app on server https://api.example.com:6443
svc/postgresql - 172.30.176.29:5432
dc/postgresql deploys openshift/postgresql:12-el8
deployment #1 deployed 4 minutes ago - 1 pod
http://rails-pgsql-persistent-ocs-block-app.apps.example.com (svc/rails-pgsql-persistent)
dc/rails-pgsql-persistent deploys istag/rails-pgsql-persistent:latest <-
bc/rails-pgsql-persistent source builds https://github.com/sclorg/rails-ex.git on openshift/ruby:2.6-ubi8
deployment #1 deployed 3 minutes ago - 1 pod
View details with 'oc describe <resource>/<name>' or list resources with 'oc get all'.
[alexon@bastion ~]$ oc get pods
NAME READY STATUS
RESTARTS AGE
postgresql-1-deploy 0/1 Completed
0 4m49s
postgresql-1-k6t47 1/1 Running
0 4m46s
rails-pgsql-persistent-1-build 0/1
Completed 0 4m50s
rails-pgsql-persistent-1-deploy 0/1
Completed 0 3m9s
rails-pgsql-persistent-1-dgfkq 1/1
Running 0 2m57s
rails-pgsql-persistent-1-hook-pre 0/1
Completed 0 3m6s
Check the PVC created by the application that it's using the ODF block SC, which in this case is Ceph RBD:
[alexon@bastion ~]$ oc get pvc
NAME STATUS
VOLUME
CAPACITY ACCESS MODES STORAGECLASS AGE
postgresql
Bound
pvc-371faec8-2017-43b4-8416-7003a0d539a9 5Gi
RWO
ocs-storagecluster-ceph-rbd
8m35s
In the PV specifications used by the PVC, within the CSI field, there's an attribute that provides the image name created for the application within the Ceph block pool. You can extract the name from this image as follows:
[alexon@bastion ~]$ oc get pv pvc-371faec8-2017-43b4-8416-7003a0d539a9 -o jsonpath="{.spec.csi.volumeAttributes.imageName}{'\n'}"
csi-vol-24624906-bccb-11eb-9cab-0a580a81023f
With the name of the image in hand, access the toolbox again and list the existing pools:
[alexon@bastion ~]$ oc rsh -n openshift-storage $toolbox
sh-4.4$ ceph df
RAW STORAGE:
CLASS SIZE
AVAIL USED RAW USED %RAW USED
ssd 1.5 TiB 1.3 TiB
252 GiB 255 GiB 16.63
TOTAL 1.5 TiB
1.3 TiB 252 GiB 255 GiB 16.63
POOLS:
POOL
ID STORED OBJECTS USED
%USED MAX AVAIL
ocs-storagecluster-cephblockpool 1 84 GiB 22.39k
252 GiB 19.37 350 GiB
ocs-storagecluster-cephfilesystem-metadata 2
1.4 MiB 25 4.2 MiB 0
350 GiB
ocs-storagecluster-cephfilesystem-data0 3 0 B 0 0 B 0
350 GiB
Remember that I mentioned that the ocs-storagecluster-cephblockpool pool is used for blocks? See if you can find your image inside:
sh-4.4$ rados -p ocs-storagecluster-cephblockpool ls | grep csi-vol-24624906-bccb-11eb-9cab-0a580a81023f
rbd_id.csi-vol-24624906-bccb-11eb-9cab-0a580a81023f
There's your image. Display some more information about it:
sh-4.4$ rbd -p ocs-storagecluster-cephblockpool info csi-vol-24624906-bccb-11eb-9cab-0a580a81023f
rbd image 'csi-vol-24624906-bccb-11eb-9cab-0a580a81023f':
size 5 GiB in 1280 objects
order 22 (4 MiB objects)
snapshot_count: 0
id: 926554e4aba49
block_name_prefix: rbd_data.926554e4aba49
format: 2
features: layering
op_features:
flags:
create_timestamp: Mon May 24 20:03:43 2021
access_timestamp: Mon May 24 20:03:43 2021
modify_timestamp: Mon May 24 20:03:43 2021
See that it has the same size previously defined for the creation of PVC. And what happens if you increase the capacity of PVC? Increase from 5GB to 10GB:
[alexon@bastion ~]$ oc get pvc
NAME
STATUS VOLUME
CAPACITY ACCESS MODES STORAGECLASS AGE
postgresql
Bound
pvc-371faec8-2017-43b4-8416-7003a0d539a9 5Gi
RWO
ocs-storagecluster-ceph-rbd 17m
[alexon@bastion ~]$ oc patch pvc postgresql -n ocs-block-app --type json --patch '[{ "op": "replace", "path": "/spec/resources/requests/storage", "value": "10Gi" }]'
persistentvolumeclaim/postgresql patched
[alexon@bastion ~]$ oc get pvc
NAME
STATUS VOLUME
CAPACITY ACCESS MODES STORAGECLASS AGE
postgresql
Bound
pvc-371faec8-2017-43b4-8416-7003a0d539a9 10Gi
RWO
ocs-storagecluster-ceph-rbd 19m
Access the toolbox pod again. The image size has also been modified, reflecting the resize of the PVC:
[alexon@bastion ~]$ oc rsh -n openshift-storage $toolbox
sh-4.4$ ceph df
RAW STORAGE:
CLASS SIZE
AVAIL USED RAW USED %RAW USED
ssd 1.5 TiB 1.3 TiB
253 GiB 256 GiB 16.64
TOTAL 1.5 TiB
1.3 TiB 253 GiB 256 GiB 16.64
POOLS:
POOL ID STORED
OBJECTS USED %USED MAX AVAIL
ocs-storagecluster-cephblockpool 1 84 GiB 22.41k
253 GiB 19.39 350 GiB
ocs-storagecluster-cephfilesystem-metadata 2
1.4 MiB 25 4.2 MiB 0
350 GiB
ocs-storagecluster-cephfilesystem-data0 3 0 B 0 0 B 0
350 GiB
sh-4.4$ rbd -p ocs-storagecluster-cephblockpool info csi-vol-24624906-bccb-11eb-9cab-0a580a81023f
rbd image 'csi-vol-24624906-bccb-11eb-9cab-0a580a81023f':
size 10 GiB in 2560 objects
order 22 (4 MiB objects)
snapshot_count: 0
id: 926554e4aba49
block_name_prefix: rbd_data.926554e4aba49
format: 2
features: layering
op_features:
flags:
create_timestamp: Mon May 24 20:03:43 2021
access_timestamp: Mon May 24 20:03:43 2021
modify_timestamp: Mon May 24 20:03:43 2021
What if you want to know which device and host the image is mapped on? The Ceph client retrieves the latest cluster map. The CRUSH algorithm calculates how to map the object to a placement group and then calculates how to assign the placement group to an OSD dynamically. To find the object location, all you need is the object name and the pool name:
sh-4.4$ ceph osd map ocs-storagecluster-cephblockpool csi-vol-24624906-bccb-11eb-9cab-0a580a81023f
osdmap e405 pool 'ocs-storagecluster-cephblockpool' (1) object 'csi-vol-24624906-bccb-11eb-9cab-0a580a81023f' -> pg 1.ecb58a2b (1.b) -> up ([1,0,2], p1) acting ([1,0,2], p1)
Now I know that my object is in a PG that has OSD ID 1 as its primary device, as well as replicas in OSDs ID 0 and 2. On which node in my cluster is the OSD 1 daemon? See below:
sh-4.4$ ceph osd status
+----+------------------------------+-------+-------+--------+---------+--------+---------+-----------+
| id |
host | used | avail | wr ops | wr data | rd ops | rd data | state |
+----+------------------------------+-------+-------+--------+---------+--------+---------+-----------+
| 0 | ip-10-0-171-63.ec2.internal | 86.7G | 425G | 50 | 517k
| 0 |
0 | exists,up |
| 1 | ip-10-0-143-192.ec2.internal | 86.7G | 425G | 109
| 1224k |
0 | 0
| exists,up |
| 2 | ip-10-0-154-20.ec2.internal | 86.7G | 425G | 78 | 1048k
| 2 |
106 | exists,up |
+----+------------------------------+-------+-------+--------+---------+--------+---------+-----------+
You can see above that it resides in the node ip-10-0-143-192.ec2.internal. And which device is being used on that node? See below:
sh-4.4$ ceph osd tree
ID CLASS WEIGHT TYPE NAME
STATUS REWEIGHT PRI-AFF
-1 1.50000 root default
-5 1.50000 region us-east-1
-4 0.50000 zone us-east-1a
-3 0.50000 host ocs-deviceset-gp2-csi-1-data-085b8h
1 ssd 0.50000 osd.1 up 1.00000 1.00000
-10
0.50000 zone us-east-1b
-9 0.50000 host ocs-deviceset-gp2-csi-2-data-0n9lkb
2 ssd 0.50000 osd.2 up 1.00000 1.00000
-14
0.50000 zone us-east-1c
-13
0.50000 host ocs-deviceset-gp2-csi-0-data-0gvt22
0 ssd 0.50000 osd.0 up 1.00000 1.00000
Now I know which node and device (host ocs-deviceset-gp2-csi-1-data-085b8h) my image is on. But I still don't know what path within that node it is. For this, you'll see another attribute of the PV that will give you this information:
[alexon@bastion ~]$ oc get pv pvc-371faec8-2017-43b4-8416-7003a0d539a9 -o jsonpath="{.spec.csi.volumeHandle}{'\n'}"
0001-0011-openshift-storage-0000000000000001-24624906-bccb-11eb-9cab-0a580a81023f
So, with the node name, device and volume handle information in hand, access the node and get your image. You can do this either by grepping for the image name on the node's current mount points or the name of the volume handle:
[alexon@bastion ~]$ oc debug node/ip-10-0-143-192.ec2.internal
Starting pod/ip-10-0-143-192ec2internal-debug ...
To use host binaries, run `chroot /host`
Pod IP: 10.0.143.192
If you don't see a command prompt, try pressing enter.
sh-4.4# mount | grep 24624906-bccb-11eb-9cab-0a580a81023f
/dev/rbd2 on /host/var/lib/kubelet/plugins/kubernetes.io/csi/pv/pvc-371faec8-2017-43b4-8416-7003a0d539a9/globalmount/0001-0011-openshift-storage-0000000000000001-24624906-bccb-11eb-9cab-0a580a81023f type ext4 (rw,relatime,seclabel,stripe=16)
You can see that the image is mounted on the following path with an EXT4 filesystem by the device/dev/rbd2
:
/host/var/lib/kubelet/plugins/kubernetes.io/csi/pv/pvc-371faec8-2017-43b4-8416-7003a0d539a9/globalmount/0001-0011-openshift-storage-0000000000000001-24624906-bccb-11eb-9cab-0a580a81023f
Look at the contents of this directory:
sh-4.4# ls /host/var/lib/kubelet/plugins/kubernetes.io/csi/pv/pvc-371faec8-2017-43b4-8416-7003a0d539a9/globalmount/0001-0011-openshift-storage-000000000000001-24624906-bccb-11eb-9cab-0a580a81023f
lost+found userdata
sh-4.4# ls /host/var/lib/kubelet/plugins/kubernetes.io/csi/pv/pvc-371faec8-2017-43b4-8416-7003a0d539a9/globalmount/0001-0011-openshift-storage-000000000000001-24624906-bccb-11eb-9cab-0a580a81023f/userdata/
PG_VERSION global pg_dynshmem pg_logical pg_replslot pg_stat pg_tblspc pg_xact postmaster.opts
base log pg_hba.conf pg_multixact pg_serial pg_stat_tmp pg_twophase postgresql.auto.conf postmaster.pid
current_logfiles
pg_commit_ts pg_ident.conf pg_notify
pg_snapshots pg_subtrans pg_wal postgresql.conf
And as you can see above, these are the contents of your database of the block application you created.
[ Learn the basics of using Kubernetes in this free cheat sheet. ]
Wrap up
At the start of this article (part two in the series), you created a demonstration project to work with. You also looked at block application mapping within an ODF cluster by using the Rook toolbox and OpenShift commands.
Be sure to read part three, as it contains additional mapping and troubleshooting ideas centered around file storage and mapping.
About the author
Alexon has been working as a Senior Technical Account Manager at Red Hat since 2018, working in the Customer Success organization focusing on Infrastructure and Management, Integration and Automation, Cloud Computing, and Storage Solutions. He is a part of the TAM Practices LATAM team based in São Paulo, Brazil, where his job is partnering with, advocating, trust-advising, and supporting customers in their success goals while making use of the complete portfolio. He also contributes to produce and enhance documentation, knowledge-base articles, blog posts, presentations, webinars, and workshops. He is a member of numerous communities in addition to the Sudoers, like Red Hat Academy and Red Hat Accelerators. When he’s not at work, he enjoys spending quality time with his family (wife, daughter, and cat) and participating in several volunteer jobs.
Browse by channel
Automation
The latest on IT automation for tech, teams, and environments
Artificial intelligence
Updates on the platforms that free customers to run AI workloads anywhere
Open hybrid cloud
Explore how we build a more flexible future with hybrid cloud
Security
The latest on how we reduce risks across environments and technologies
Edge computing
Updates on the platforms that simplify operations at the edge
Infrastructure
The latest on the world’s leading enterprise Linux platform
Applications
Inside our solutions to the toughest application challenges
Original shows
Entertaining stories from the makers and leaders in enterprise tech
Products
- Red Hat Enterprise Linux
- Red Hat OpenShift
- Red Hat Ansible Automation Platform
- Cloud services
- See all products
Tools
- Training and certification
- My account
- Customer support
- Developer resources
- Find a partner
- Red Hat Ecosystem Catalog
- Red Hat value calculator
- Documentation
Try, buy, & sell
Communicate
About Red Hat
We’re the world’s leading provider of enterprise open source solutions—including Linux, cloud, container, and Kubernetes. We deliver hardened solutions that make it easier for enterprises to work across platforms and environments, from the core datacenter to the network edge.
Select a language
Red Hat legal and privacy links
- About Red Hat
- Jobs
- Events
- Locations
- Contact Red Hat
- Red Hat Blog
- Diversity, equity, and inclusion
- Cool Stuff Store
- Red Hat Summit