<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>ceph on Digi Hunch</title><link>https://static.digihunch.com/tag/ceph/</link><description>Recent content in ceph on Digi Hunch</description><generator>Hugo -- gohugo.io</generator><language>en-US</language><lastBuildDate>Thu, 17 Apr 2025 14:04:59 -0400</lastBuildDate><atom:link href="https://static.digihunch.com/tag/ceph/index.xml" rel="self" type="application/rss+xml"/><item><title>MinIO for S3-compatible Object Storage</title><link>https://static.digihunch.com/2022/09/minio-object-storage/</link><pubDate>Fri, 09 Sep 2022 09:00:00 -0400</pubDate><guid>https://static.digihunch.com/2022/09/minio-object-storage/</guid><description>&lt;img src="https://static.digihunch.com/wp-content/uploads/2025/04/feature-minio.webp" alt="Featured image of post MinIO for S3-compatible Object Storage" /&gt;&lt;p class="wp-block-paragraph"&gt;I reviewed some storage technologies on Kubernetes but they are all for block and file storage. In this post, I will discuss the current available options for container workload to use object storage. I will also touch on MinIO as an object storage solution.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="h-object-storage"&gt;Object storage&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Block and file system are more native to operating system because they present themselves to the OS as a block device or file system attached to the OS. In other words, application processes running on the OS will be able to access the storage by address expressed as a POSIX-compatible path. On the contrary, object storage is a REST API service, operating at the application layer in the TCP/IP stack. Therefore, we can think of object storage as &amp;#8220;storage as a web service&amp;#8221;.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Object storage can be made very cheap. However, the application protocol may vary depending on the object storage provider. Amazon S3 is a forerunner in object storage market and its protocol has emerged as the de-facto standard for object storage. When building an application and if there is one object storage protocol to support, it should be S3. For non-S3 object storage services, we can front them with an S3 interface, if the provider itself does not have one. For example Ceph storage has its &lt;a href="https://docs.ceph.com/en/latest/radosgw/s3/"&gt;Gateway S3 API&lt;/a&gt;. &lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Container Object Storage Interface&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;If we use S3 as the universal object storage protocol, does that also address object storage access with container workload on Kubernetes? Absolutely. Nonetheless, for a number of reasons using REST API from containers are not the best option. From platform&amp;#8217;s perspective, it is the platform that should define how to access object storage, instead of leaving it with an application-layer protocol. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;When a pattern (for storage, or networking, etc) turns out very common, the platform layer should incorporate it as an infrastructure service, manage it with its own standard, and provide it to application so that developer can focus on business features. With that vision, the community brought up the &lt;a href="https://github.com/kubernetes-sigs/container-object-storage-interface"&gt;Container Object Storage Interface&lt;/a&gt; (COSI) initiative. It is currently in very early stage, but the idea is to commoditize object storage in Kubernetes platform with a unified interface. For more background about this initiative, refer to the post &amp;#8220;&lt;a href="https://thenewstack.io/beyond-block-and-file-cosi-enables-object-storage-in-kubernetes/"&gt;Beyond block and file &amp;#8211; COSI enables object storage in Kubernetes&lt;/a&gt;&amp;#8220;.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;COSI is the ultimate cloud native solution but it is still in pre-alpha phase as of mid 2022. Unfortunately, it is not a recommended solution to any real-life project in 2022, and we are stuck with the unified API approach until COSI matures.. The unified API approach is by no means cloud native, but has come to maturity for adoption. S3 Rest API is our friend, regardless of whether the client process is in a container or not.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Update: on Sept 2, 2022, Kubernetes &lt;a href="https://kubernetes.io/blog/2022/09/02/cosi-kubernetes-object-storage-management/"&gt;introduced COSI&lt;/a&gt; as alpha feature.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;MinIO Introduction&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In order to use S3 protocol without using Amazon S3 storage, we can use MinIO to build our own object storage service serve client via a S3-compatible REST API interface. The main developer of the &lt;a href="https://min.io/"&gt;MinIO&lt;/a&gt; project is MinIO Inc, a startup from 2014. Having learned the lessons from GlusterFS, the founders and developers make MinIO very simple. MinIO operates in two modes: gateway mode (soon to be legacy) and server mode.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In the Gateway mode, MinIO as a gateway between client and destination storage, and does not persist data to itself. In the past, the destination storage can be Azure Blob and Google Cloud Storage (GCS) and HDFS as backend. However, these supports are &lt;a href="https://github.com/minio/minio/pull/14418"&gt;deprecated&lt;/a&gt; now. The current release (July 2022) only supports S3 and NAS backend. According to MinIO&amp;#8217;s blog &lt;a href="https://blog.min.io/deprecation-of-the-minio-gateway/"&gt;post&lt;/a&gt; from February 2022, the entire MinIO Gateway feature will be removed in August, leaving server mode the only option for MinIO.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In the Server mode, the MinIO service will persist data to itself in a file system (or volume). You can specify that file system (or volume) as you launch the server. As one of the &lt;a href="https://docs.min.io/docs/minio-quickstart-guide.html"&gt;quick-start guides&lt;/a&gt; shows, we can host MinIO server using a single executable. For administrative tasks, MinIO has a web console and a client utility called mc.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;MinIO Deployment Options&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;For storage service, there are a number of &lt;a href="https://docs.min.io/minio/baremetal/installation/deployment-and-management.html"&gt;deployment options&lt;/a&gt;: &lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;SNSD (single-node, single-drive): single MinIO server with a single storage volume or folder. &lt;/li&gt;&#10;&lt;li&gt;SNMD (signle-node, multi-drive): single MinIO server with four or more storage volumes.&lt;/li&gt;&#10;&lt;li&gt;MNMD (multi-node, multi-drive, aka distributed): multiple MinIO servers with at least four drives across all servers. This should be considered for production grade configuration.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The deployment options above describes the node and volume topology. No matter which topology option, there are also a number of ways to host the MinIO service process: on &lt;a href="https://min.io/docs/minio/linux/index.html"&gt;Linux OS&lt;/a&gt;, &lt;a href="https://min.io/docs/minio/windows/index.html"&gt;Windows OS&lt;/a&gt;, &lt;a href="https://min.io/docs/minio/macos/index.html"&gt;MacOS&lt;/a&gt;, &lt;a href="https://min.io/docs/minio/container/index.html"&gt;Docker Container&lt;/a&gt;, and on &lt;a href="https://min.io/docs/minio/kubernetes/upstream/index.html"&gt;Kubernetes&lt;/a&gt; platform. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In addition, MinIO Inc ships the software under different business models. For example, there are fully managed applications in &lt;a href="https://web.archive.org/web/20220927211802/https://azuremarketplace.microsoft.com/en-us/marketplace/apps/minio.minio-object-storage_v1dot1"&gt;Azure Marketplace&lt;/a&gt;, &lt;a href="https://aws.amazon.com/marketplace/pp/prodview-smchi7bcs4nn4"&gt;AWS Marketplace&lt;/a&gt;, and &lt;a href="https://console.cloud.google.com/marketplace/product/minio-inc-public/minio-enterprise"&gt;GCP Marketplace&lt;/a&gt; all hosted on virtual machines with extra charges. Clients not willing to pay can host MinIO storage all on their own, either on virtual machines, or on managed Kubernetes environment provided by each cloud provider. &lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;MinIO Hosting solutions&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;MinIO lists these hosting solutions under multi-cloud products. These hosting solutions (or &amp;#8220;products&amp;#8221; in MinIO&amp;#8217;s term) vary in terms of where peripheral services and data tiers are hosted. Here is the list of the supported platforms:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;&lt;a href="https://min.io/product/kubernetes"&gt;(generic) Kubernetes&lt;/a&gt;;&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://min.io/product/private-cloud-vmware-tanzu"&gt;VMWare Tanzu&lt;/a&gt;;&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://min.io/product/private-cloud-red-hat-openshift"&gt;OpenShift&lt;/a&gt;;&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://min.io/product/multicloud-suse-rancher"&gt;SUSE Rancher&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://min.io/product/multicloud-elastic-kubernetes-service"&gt;EKS&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://min.io/product/multicloud-azure-kubernetes-service"&gt;AKS&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://min.io/product/multicloud-google-kubernetes-service"&gt;GKE&lt;/a&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;To illustrate how these solutions are different, I put some details on a few options together for an incomplete comparison below:&lt;/p&gt;&#10;&lt;figure class="wp-block-table is-style-regular"&gt;&lt;table class="has-very-light-gray-to-cyan-bluish-gray-gradient-background has-background"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Kubernetes&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;EKS&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;AKS&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;GKE&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Hot Storage&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Direct PV (NVMe)&lt;/td&gt;&lt;td&gt;EKS EBS CSI&lt;/td&gt;&lt;td&gt;Azure CSI &lt;/td&gt;&lt;td&gt;GKE Standard SSD&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Warm Storage&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Direct PV (HDD)&lt;/td&gt;&lt;td&gt;S3 IA&lt;/td&gt;&lt;td&gt;Azure BlobStore&lt;/td&gt;&lt;td&gt;GCS&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Cold Storage&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Public Cloud storage&lt;/td&gt;&lt;td&gt;Glacier&lt;/td&gt;&lt;td&gt;Azure Cool Blob&lt;/td&gt;&lt;td&gt;GCS for Data Archiving&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Encryption&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;HashiCorp Vault&lt;/td&gt;&lt;td&gt;KMS&lt;/td&gt;&lt;td&gt;Azure Key Vault&lt;/td&gt;&lt;td&gt;Cloud Key Management&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Observability&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Elastic Stack and Grafana&lt;/td&gt;&lt;td&gt;Managed ElasticSearch Prometheus&lt;/td&gt;&lt;td&gt;Azure Monitor&lt;/td&gt;&lt;td&gt;Stack Driver&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Identity Provider&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;KeyCloak&lt;/td&gt;&lt;td&gt;LDAP, SSO&lt;/td&gt;&lt;td&gt;Azure Active Directory&lt;/td&gt;&lt;td&gt;GCP Cloud Identity&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;LB and Cert Mgmt&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Nginx, Let&amp;#8217;s Entrypt&lt;/td&gt;&lt;td&gt;AWS Cert Mgr, ELB&lt;/td&gt;&lt;td&gt;Azure Load Balancer, JetStack, Let&amp;#8217;s Encrypt&lt;/td&gt;&lt;td&gt;GCP Cloud LB and Managed Cert&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Note that all of these hosting solutions are based on some flavour of Kubernetes. The hot tier is usually based on storage options available to the platform. MinIO service access this hot tier via Kubernetes persistent volume. The warm and cold tiers are backed by different object storage service. Between MinIO and storage client, it always use the same S3 compatible Rest API.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;MinIO also has tiering capability. While the hot storage destination has to be either a file system or Kubernetes persistent volume, remote tiers can be S3 , Azure Blob, or GCS. MinIO supports encryption at rest (SSE-KMS, SSE-S3, SSE-C) and in transit (TLS) for security, as well as many other useful features such as object &lt;a href="https://docs.min.io/minio/baremetal/replication/replication-overview.html"&gt;replication&lt;/a&gt;, &lt;a href="https://docs.min.io/minio/baremetal/object-retention/bucket-versioning.html"&gt;versioning&lt;/a&gt;, &lt;a href="https://docs.min.io/minio/baremetal/object-retention/minio-object-locking.html"&gt;locking&lt;/a&gt;, &lt;a href="https://docs.min.io/minio/baremetal/monitoring/bucket-notifications/bucket-notifications.html"&gt;events&lt;/a&gt;, Prometheus &lt;a href="https://docs.min.io/minio/baremetal/monitoring/metrics-alerts/minio-metrics-and-alerts.html"&gt;metrics&lt;/a&gt;, &lt;a href="https://docs.min.io/minio/baremetal/lifecycle-management/lifecycle-management-overview.html"&gt;lifecycle management&lt;/a&gt; etc. &lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Connect to MinIO server with S3 client&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;To validate that the client is compatible, we use MinIO&amp;#8217;s client utility (mc) to connect to an AWS S3 bucket. Then we use AWS CLI to connect to a MinIO server, similar to this &lt;a href="https://docs.min.io/docs/aws-cli-with-minio"&gt;instruction&lt;/a&gt;. To do so, we first install client and server utilities:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;brew install minio/stable/minio&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;brew install minio/stable/mc&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;minio --version&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mc --version&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Then, we start MinIO server and store an object using AWS CLI&amp;#8217;s S3 tool. In our working directory, we create a new directory called minio_data and launch MinIO server with it:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mkdir minio_data&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;minio server minio_data --console-address :9090&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Once the server is up, the screen should display the details, including the portal URL and the default username and password will be used as Access Key ID and Secret Key:&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-large"&gt;&lt;img loading="lazy" decoding="async" width="1307" height="649" src="https://static.digihunch.com/wp-content/uploads/2022/07/image-2.png" alt="" class="wp-image-6276"/&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Note that the MinIO service does NOT have &lt;a href="https://docs.min.io/docs/how-to-secure-access-to-minio-server-with-tls.html"&gt;TLS enabled&lt;/a&gt; by default, on the console or API service. At this point, we can browse to the console web page using the given credential. Then, we can configure AWS CLI with a new profile just to act as a client to communicate with the MinIO server:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ aws configure --profile minio-cli&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;AWS Access Key ID &lt;span style="color:#f92672"&gt;[&lt;/span&gt;None&lt;span style="color:#f92672"&gt;]&lt;/span&gt;: minioadmin&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;AWS Secret Access Key &lt;span style="color:#f92672"&gt;[&lt;/span&gt;None&lt;span style="color:#f92672"&gt;]&lt;/span&gt;: minioadmin&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Default region name &lt;span style="color:#f92672"&gt;[&lt;/span&gt;None&lt;span style="color:#f92672"&gt;]&lt;/span&gt;: us-east-1&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Default output format &lt;span style="color:#f92672"&gt;[&lt;/span&gt;None&lt;span style="color:#f92672"&gt;]&lt;/span&gt;: json&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ aws configure set default.s3.signature_version s3v4 --profile minio-cli&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;At this point, the AWS CLI is configured to communicate with MinIO server. Then, we can create bucket, list object in the bucket, copy an object to the bucket, etc&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ aws --endpoint-url http://127.0.0.1:9000 s3 ls --profile minio-cli &lt;span style="color:#75715e"&gt;# list all bucket, should return empty&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ aws --endpoint-url http://127.0.0.1:9000 s3 mb s3://hehebucket --profile minio-cli &lt;span style="color:#75715e"&gt;# create new bucket&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;make_bucket: hehebucket&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ aws --endpoint-url http://127.0.0.1:9000 s3 cp README.md s3://hehebucket --profile minio-cli &lt;span style="color:#75715e"&gt;# copy a file to bucket as a new object&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;upload: ./README.md to s3://hehebucket/README.md&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ aws --endpoint-url http://127.0.0.1:9000 s3 ls s3://hehebucket --profile minio-cli &lt;span style="color:#75715e"&gt;# list objects in the bucket&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2022-07-09 00:30:23 &lt;span style="color:#ae81ff"&gt;631&lt;/span&gt; README.md&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;The created bucket and object are also visible in MinIO web console, under &amp;#8220;Bucket&amp;#8221;:&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-full"&gt;&lt;img loading="lazy" decoding="async" width="947" height="235" src="https://static.digihunch.com/wp-content/uploads/2022/07/image-3.png" alt="" class="wp-image-6287"/&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The steps above validate that AWS CLI can talk to MinIO server. Because of that, MinIO server can emulate an S3 service in any development environment so users do not always have to use S3 from AWS. This makes sense for both cost and security reasons for the organization. &lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Connect to S3 with MinIO client&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In this lab, we create an S3 bucket and use mc utility to store an object to it. In order to consistently create S3 bucket and associated permissions, I use the CloudFormation template in &lt;a href="https://github.com/digihunch/cloudformation/blob/master/obj-store-helper/aws-s3-stack.yaml"&gt;this&lt;/a&gt; repo. The output of the CloudFormation stack returns the Access Key ID and Secret Key required for the client to access the bucket. Once we cloned the repo, let&amp;#8217;s enter the &lt;a href="https://github.com/digihunch/cloudformation/tree/master/obj-store-helper"&gt;obj-store-helper&lt;/a&gt; directory, and run aws cli command to launch the CloudFormation template, assuming it has been configured:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;BUCKET_NAME&lt;span style="color:#f92672"&gt;=&lt;/span&gt;c0sas2dsadigihunch&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;S3_STACK_NAME&lt;span style="color:#f92672"&gt;=&lt;/span&gt;$BUCKET_NAME-stack&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;aws cloudformation create-stack --template-body file://aws-s3-stack.yaml --stack-name $S3_STACK_NAME --parameters ParameterKey&lt;span style="color:#f92672"&gt;=&lt;/span&gt;S3BucketName,ParameterValue&lt;span style="color:#f92672"&gt;=&lt;/span&gt;$BUCKET_NAME --capabilities CAPABILITY_IAM&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# to delete stack after test, run: aws cloudformation delete-stack --stack-name $S3_STACK_NAME&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;In the AWS console, we should see the configuration information as below:&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-full"&gt;&lt;img loading="lazy" decoding="async" width="925" height="708" src="https://static.digihunch.com/wp-content/uploads/2022/07/image-1.png" alt="" class="wp-image-6266"/&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Supposed the bucket name is vna-tst-c0sas2dsadigihunch as shown above, this allows us to configure the client utility MC as below:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mc alias set awss3 https://s3.amazonaws.com &lt;span style="color:#75715e"&gt;# Fill in access key ID and Secret key at the prompt&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mc ls awss3/vna-tst-c0sas2dsadigihunch &lt;span style="color:#75715e"&gt;# list objects in the bucket, should return empty&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mc cp README.md awss3/vna-tst-c0sas2dsadigihunch/README.md &lt;span style="color:#75715e"&gt;# upload and object to bucket&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mc ls awss3/vna-tst-c0sas2dsadigihunch &lt;span style="color:#75715e"&gt;# list objects in the bucket, the uploaded object should be there&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mc rm awss3/vna-tst-c0sas2dsadigihunch/README.md &lt;span style="color:#75715e"&gt;# delete the object&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mc alias remove awss3 &lt;span style="color:#75715e"&gt;# remove awss3 alias&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Once we emptied the bucket, we can delete the CloudFormation stack. This test only needs client utility mc to verify that MinIO client is able to talk to AWS S3 server.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Erasure Coding&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;For scalable production use, we should deploy MinIO in distributed mode. When MinIO is configured in &lt;a href="https://docs.min.io/minio/baremetal/installation/deploy-minio-distributed.html"&gt;distributed deployment&lt;/a&gt; (MNMD, or multi-node, multi-drive), it implicitly enables an important feature called &lt;a href="https://docs.min.io/minio/baremetal/concepts/erasure-coding.html#minio-erasure-coding"&gt;erasure coding&lt;/a&gt;. This erasure coding feature further unlocks a number of other MinIO features:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;&lt;a href="https://docs.min.io/minio/baremetal/object-retention/bucket-versioning.html#minio-bucket-versioning"&gt;Object Versioning&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://docs.min.io/minio/baremetal/replication/bucket-replication-overview.html#minio-bucket-replication-serverside"&gt;Server-Side Replication&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://docs.min.io/minio/baremetal/reference/minio-mc/mc-retention-set.html#minio-bucket-locking"&gt;Write-Once Read-Many (WORM) Locking&lt;/a&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Erasure coding is MinIO&amp;#8217;s data redundancy and availability feature that allows MinIO deployments to automatically reconstruct objects on-the-fly despite the loss of multiple drives or nodes in the cluster. Erasure coding provides object-level handling with less overhead than adjacent technologies such as RAID. The key concept is &lt;a href="https://docs.min.io/minio/baremetal/concepts/erasure-coding.html#erasure-sets"&gt;Erasure Set&lt;/a&gt;, a set of drives in a MinIO deployment that supports Erasure Coding. MinIO evenly distributes object data and parity blocks among the drives in the Erasure Set. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Two important variables are M and N: for a given erasure set of size M, MinIO splits objects into N parity blocks, and M-N data blocks. MinIO uses the &lt;a href="https://docs.min.io/minio/baremetal/concepts/erasure-coding.html#erasure-code-parity-ec-n"&gt;EC:N&lt;/a&gt; notation to refer to the number of parity blocks (N) in the deployment. To determine optimal erasure set size for the cluster, use MinIO&amp;#8217;s &lt;a href="https://min.io/product/erasure-code-calculator"&gt;Erasure Coding Calculator&lt;/a&gt; tool.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;To help client to specify per-object parity with Erasure Coding, MinIO uses storage classes. Note that the storage class concept in MinIO is distinct from AWS &lt;a href="https://aws.amazon.com/s3/storage-classes/"&gt;S3 storage class&lt;/a&gt; or Kubernetes &lt;a href="https://kubernetes.io/docs/concepts/storage/storage-classes/"&gt;storage class&lt;/a&gt;. In MinIO, a &lt;a href="https://github.com/minio/minio/tree/master/docs/erasure/storage-class"&gt;storage class&lt;/a&gt; defines parity settings per object. The STANDARD &lt;a href="https://docs.min.io/minio/baremetal/concepts/erasure-coding.html#storage-classes"&gt;storage class&lt;/a&gt; (default) defines EC:N based on M, which can be overridden. In addition, there is REDUCED_REDUNDANCY storage class, whose parity must be less than or equal to that of STANDARD storage class. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The &lt;a href="https://docs.min.io/minio/baremetal/concepts/erasure-coding.html#bitrot-protection"&gt;erasure coded backend&lt;/a&gt; also protects the storage against &lt;a href="https://github.com/minio/minio/blob/master/docs/erasure/README.md#what-is-bit-rot-protection"&gt;Bit Rot&lt;/a&gt; with HighwayHash algorithm. &lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;More Features&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Authentication and authorization between MinIO client and MinIO server have a number of options. MinIO client may use the built-in standalone identity management in MinIO server. This is the default mode. In addition, one may delegate IAM to external service. To Active Directory via LDAP, or any Identity provider that supports OIDC (JWT with Authorization Code Flow). &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;As to &lt;a href="https://docs.min.io/minio/baremetal/lifecycle-management/lifecycle-management-overview.html"&gt;Object Lifecycle Management&lt;/a&gt; (OLM), MinIO allows you to define a remote tier storage for each local target (bucket). The remote tier can be Amazon S3, Google Cloud Storage or Azure Blob storage. We can use mc utility to administer the remote tier and OLM. Configuration steps (e.g. &lt;a href="https://docs.min.io/minio/baremetal/lifecycle-management/transition-objects-to-azure.html"&gt;Azure&lt;/a&gt; Blob, &lt;a href="https://docs.min.io/minio/baremetal/lifecycle-management/transition-objects-to-s3.html"&gt;AWS S3&lt;/a&gt;) usually include:&lt;/p&gt;&#10;&lt;ol class="wp-block-list"&gt;&#10;&lt;li&gt;Configure required permissions on the MinIO bucket, create user account for OLM activities. &lt;/li&gt;&#10;&lt;li&gt;Configure the Remote Storage Tier&lt;/li&gt;&#10;&lt;li&gt;Create and Apply an ILM Transition Rule. The rule can be expressed in a json document.&lt;/li&gt;&#10;&lt;li&gt;Validate the creation of ILM transition rule&lt;/li&gt;&#10;&lt;li&gt;Validate the effect of transition rule. &lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p class="wp-block-paragraph"&gt;As for encryption, MinIO can support encryption at rest. It can also work with &lt;a href="https://static.digihunch.com/2022/06/etcd-the-key-value-store-for-kubernetes/"&gt;etcd&lt;/a&gt; store to store encrypted IAM assets if KMS is configured. &lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Conclusion&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Even though we watch for the progress of COSI initiative, we still use Rest API to access object storage from container, which is no different than from a virtual machine. If we develop an application, then we should make it support S3 protocol, a de-facto standard protocol for object storage. As for the storage backend, if we want to be vendor neutral, the feature-rich MinIO is the best bet. We can use MinIO to build our own Object storage as a service compatible with S3. We can also lifecycle our object to remote object storage tier backed by Azure, GCP or S3. In this post we validated the S3 compatibility, and discussed some advanced MinIO features.&lt;/p&gt;&#10;&lt;nav class="wp-post-navigation" aria-label="Post navigation"&gt;&#10;&lt;a rel="prev" href="https://static.digihunch.com/2022/08/storage-solution-on-aks-2-of-3-ceph-by-rook/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Kubernetes Storage on Azure 3 of 3 – Ceph by Rook&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2022/09/build-a-kubernetes-cluster/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Build and Manage Kubernetes Clusters&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>Kubernetes Storage on Azure 3 of 3 – Ceph by Rook</title><link>https://static.digihunch.com/2022/08/storage-solution-on-aks-2-of-3-ceph-by-rook/</link><pubDate>Fri, 26 Aug 2022 19:43:00 -0400</pubDate><guid>https://static.digihunch.com/2022/08/storage-solution-on-aks-2-of-3-ceph-by-rook/</guid><description>&lt;img src="https://static.digihunch.com/wp-content/uploads/2025/04/feature-k8s-storage-3.webp" alt="Featured image of post Kubernetes Storage on Azure 3 of 3 – Ceph by Rook" /&gt;&lt;p class="wp-block-paragraph"&gt;In the last two posts, I covered the native storage options on Azure Kubernetes Service, as well as Portworx as an example of a proprietary Software Defined Storage (SDS) solution. There are also a number of open-source alternative SDS solutions. Ceph has nearly a decade of history from prior to containerization, and is the most widely adopted storage platform. In this post, we continue to explore Ceph as an open-source storage solution on Azure Kubernetes. &lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="h-ceph-by-rook"&gt;Ceph by Rook&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Ceph is an open-source SDS platform for distributed storage on a cluster and provides object, block and file storage. Installation of Ceph SDS can be complex, especially on Kubernetes platform. &lt;a href="https://rook.io/"&gt;Rook&lt;/a&gt; is a graduated CNCF project to orchestrate storage platform. Rook by itself is not SDS and it supports:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;&lt;a href="https://rook.io/docs/rook/v1.9/Getting-Started/intro/"&gt;Ceph&lt;/a&gt;: configure a Ceph cluster. Think of this as the equivalent of &lt;a href="https://docs.ceph.com/en/quincy/cephadm/"&gt;cephadm&lt;/a&gt; on Kubernetes platform.&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://rook.io/docs/nfs/v1.7/"&gt;NFS&lt;/a&gt;: configure an NFS server. Think of this as the equivalent of nfsd daemon on Kubernetes platform.&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://rook.io/docs/cassandra/v1.7/"&gt;Cassandra&lt;/a&gt;: an operator to configure a Cassandra database cluster. It is now &lt;strong&gt;deprecated&lt;/strong&gt;.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;We play with Rook Ceph. I also refer to it as Ceph by Rook. The contribution of Rook project is it simplifies the installation as a matter of declaring custom resources using CRDs. Here are some high-level CRDs to know:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;&lt;a href="https://rook.io/docs/rook/v1.9/CRDs/ceph-cluster-crd/"&gt;CephCluster&lt;/a&gt;: creates a Ceph storage cluster&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://rook.io/docs/rook/v1.9/CRDs/Block-Storage/ceph-block-pool-crd/"&gt;CephBlockPool&lt;/a&gt;: represents a block pool&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://rook.io/docs/rook/v1.9/CRDs/Shared-Filesystem/ceph-filesystem-crd/"&gt;CephFilesystem&lt;/a&gt;: represents a file system&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://rook.io/docs/rook/v1.9/CRDs/Object-Storage/ceph-object-store-crd/#example"&gt;CephObjectStore&lt;/a&gt;: represents an object store&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://rook.io/docs/rook/v1.9/CRDs/ceph-nfs-crd/"&gt;CephNFS&lt;/a&gt;: spins up a NFS Ganesha server to export NFS shares of a CephFilesystem or CephObjectStore.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;As with typical Kubernetes resources in controller pattern, Ceph by Rook needs an operator along with custom resources. We can use YAML manifest for both of them, and the manifests are usually very tediously long. We can also use Helm to install both of them, by providing a value file. Now we will install Ceph on AKS.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Install Ceph Operator on AKS&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The steps are influenced by two relevant posts (&lt;a href="https://carlos.mendible.com/2021/10/23/aks-high-available-storage-with-rook-and-ceph/"&gt;here&lt;/a&gt; and &lt;a href="https://github.com/evillgenius75/rook-aks"&gt;here&lt;/a&gt;). However, I&amp;#8217;ve incorporated the cluster configuration in the &lt;a href="https://github.com/digihunch/cloudkube/tree/main/azure"&gt;Azure directory of the cloudkube project&lt;/a&gt;, a modular Terraform template to configure AKS cluster and facilitate storage configuration. The node group and instance sizes are selected to be just enough to run a ceph POC cluster with minimum cost. One of the node groups is tainted with storage-node, as if the following command were run:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kubectl taint nodes my-node-pool-node-name storage-node&lt;span style="color:#f92672"&gt;=&lt;/span&gt;true:NoSchedule&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;You will only need to taint the nodes with the command above if you choose not to use the cloudkube template. The taint ensures that only Pods with corresponding toleration and effect can be scheduled to those nodes.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;We use Helm to install Rook Operator. We need a value file (e.g. rook-ceph-operator-values.yaml) with content as below:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;#&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;https&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#75715e"&gt;//github.com/rook/rook/blob/master/Documentation/Helm-Charts/operator-chart.md&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;crds&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;enabled&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;csi&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;provisionerTolerations&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;effect&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;NoSchedule&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;key&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;storage&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;node&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;operator&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Exists&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;pluginTolerations&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;effect&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;NoSchedule&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;key&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;storage&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;node&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;operator&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Exists&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;agent&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;#&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;AKS&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;https&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#75715e"&gt;//rook.github.io/docs/rook/v1.7/flexvolume.html#azure-aks&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;flexVolumeDirPath&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;/etc/kubernetes/volumeplugins&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Then we install the operator with Helm:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;helm install rook-ceph-operator rook-ceph --namespace rook-ceph --create-namespace --version v1.9.6 --repo https://charts.rook.io/release/ --values rook-ceph-operator-values.yaml&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kubectl -n rook-ceph get po -l app&lt;span style="color:#f92672"&gt;=&lt;/span&gt;rook-ceph-operator&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;After installing the operator, we check the Pod status to make sure it is running. Then we can install the actual Ceph Cluster in one of the two ways. We can declare a CephClusterCRD ourself, or we can use Helm again to declare the CRD. Helm Chart gives us a lot of useful default values and saves us from editing a large body of YAML manifest.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Install Ceph CR on AKS&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;We use Helm to install CephCluster CRD. We create a value file (e.g. rook-ceph-cluster-values.yaml) with content as below:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;#&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;https&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#75715e"&gt;//github.com/rook/rook/blob/master/Documentation/Helm-Charts/ceph-cluster-chart.md&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;operatorNamespace&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;rook&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;ceph&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;toolbox&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;enabled&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;cephObjectStores&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; [] &lt;span style="color:#960050;background-color:#1e0010"&gt;#&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;by&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;default&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;cephObjectStore&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;will&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;be&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;created&lt;/span&gt;. &lt;span style="color:#a6e22e"&gt;Setting&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;to&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;disables&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;it&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;#&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;cephBlockPools&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;#&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;by&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;default&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;cephBlockPool&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;will&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;also&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;be&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;created&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;with&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;default&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;values&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;#&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;cephFileSystems&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;#&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;by&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;default&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;cephFileSystem&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;will&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;also&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;be&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;created&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;with&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;default&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;values&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;cephClusterSpec&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;mon&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;count&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;volumeClaimTemplate&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;spec&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;storageClassName&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;managed&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;premium&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;resources&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;requests&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;storage&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;Gi&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;resources&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;limits&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;cpu&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;500m&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;memory&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;1Gi&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;requests&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;cpu&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;100m&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;memory&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;500Mi&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;dashboard&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;enabled&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;storage&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;storageClassDeviceSets&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;set1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;#&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;The&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;number&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;of&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;OSDs&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;to&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;create&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;device&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;set&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;count&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;#&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;IMPORTANT&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;If&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;volumes&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;specified&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;by&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;the&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;storageClassName&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;are&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;not&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;portable&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;across&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;nodes&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;needs&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;to&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;be&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;set&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;to&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;. &lt;span style="color:#a6e22e"&gt;For&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;example&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;using&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;the&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;local&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;storage&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;provisioner&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;#&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;should&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;be&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;portable&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;#&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Since&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;the&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;OSDs&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;could&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;end&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;up&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;on&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;any&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;node&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;an&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;effort&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;needs&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;to&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;be&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;made&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;to&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;spread&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;the&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;OSDs&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;#&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;across&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;nodes&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;as&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;much&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;as&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;possible&lt;/span&gt;. &lt;span style="color:#a6e22e"&gt;Unfortunately&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;the&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;pod&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;anti&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;affinity&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;breaks&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;down&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;#&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;as&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;soon&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;as&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;you&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;have&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;more&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;than&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;one&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;OSD&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;per&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;node&lt;/span&gt;. &lt;span style="color:#a6e22e"&gt;The&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;topology&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;spread&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;constraints&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;will&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;#&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;give&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;us&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;an&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;even&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;spread&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;on&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;K8s&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1.18&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;or&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;newer&lt;/span&gt;.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;placement&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;topologySpreadConstraints&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;maxSkew&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;topologyKey&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;kubernetes&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;io&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;hostname&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;whenUnsatisfiable&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ScheduleAnyway&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;labelSelector&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;matchExpressions&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;key&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;app&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;operator&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;In&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;values&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;rook&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;ceph&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;osd&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;tolerations&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;key&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;storage&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;node&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;operator&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Exists&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;preparePlacement&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;tolerations&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;key&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;storage&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;node&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;operator&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Exists&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;nodeAffinity&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;requiredDuringSchedulingIgnoredDuringExecution&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;nodeSelectorTerms&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;matchExpressions&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;key&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;agentpool&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;operator&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;In&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;values&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;storagenp&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;topologySpreadConstraints&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;maxSkew&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;#&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;IMPORTANT&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;If&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;you&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;don&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;t&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;have&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;zone&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;labels&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;change&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;to&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;another&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;key&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;such&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;as&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;kubernetes&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;io&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;hostname&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;topologyKey&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;topology&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;kubernetes&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;io&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;zone&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;whenUnsatisfiable&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;DoNotSchedule&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;labelSelector&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;matchExpressions&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;key&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;app&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;operator&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;In&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;values&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;rook&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;ceph&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;osd&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;prepare&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;resources&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;limits&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;cpu&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;500m&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;memory&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;4Gi&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;requests&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;cpu&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;500m&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;memory&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;2Gi&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;volumeClaimTemplates&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;metadata&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;data&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;spec&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;resources&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;requests&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;storage&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;Gi&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;storageClassName&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;managed&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;premium&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;volumeMode&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Block&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;accessModes&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ReadWriteOnce&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;During the cluster provisioning, there will be a number of preparing Pods. We want those Pods to run on nodes with label agentpool=storagenp. In real life, we need to orchestrate where to run each workload, by restricting the nodes to schedule certain types of workload.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Then we can install the cluster using Helm:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;helm install rook-ceph-cluster rook-ceph-cluster --namespace rook-ceph --create-namespace --version v1.9.6 --repo https://charts.rook.io/release/ --values rook-ceph-cluster-values.yaml&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;After running the Helm install, it may take as long as 15 minutes for all resources to settle. Watch the Pod status in rook-ceph namespace. At the end, make sure that the cluster is created successfully:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kubeadmin@pro-sturgeon-bastion-host:~$ kubectl -n rook-ceph get CephCluster&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;NAME DATADIRHOSTPATH MONCOUNT AGE PHASE MESSAGE HEALTH EXTERNAL&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rook-ceph /var/lib/rook &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; 15m Ready Cluster created successfully HEALTH_OK&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kubeadmin@pro-sturgeon-bastion-host:~$ kubectl -n rook-ceph get cephBlockPools&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;NAME PHASE&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ceph-blockpool Ready&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kubeadmin@pro-sturgeon-bastion-host:~$ kubectl -n rook-ceph get cephFileSystems&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;NAME ACTIVEMDS AGE PHASE&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ceph-filesystem &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; 20m Ready&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;In my case it took 15 minutes before the cluster comes up as created successfully. You should notice that two storage classes were also created as a part of the install. It however did not create a storage class or CRD for object storage, because we explicitly disabled it in the Helm value file by setting cephObjectStores value to null.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Dashboard&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;We enabled dashboard. To configure the dashboard view properly, we would need an ingress. For a quick view here, we can play port forwarding tricks. First we fetch the admin password for use in the next step. Then expose the dashboard to the bastion host:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ kubectl -n rook-ceph get secret rook-ceph-dashboard-password -o jsonpath&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;{.data.password}&amp;#39;&lt;/span&gt; | base64 -d&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ kubectl -n rook-ceph port-forward svc/rook-ceph-mgr-dashboard 8443:8443&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Since I don&amp;#8217;t have UI on the bastion host, I use the port forwarding trick again from my own MacBook. Start a new terminal and SSH to the bastion host with port-forwarding switch:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ ssh -L 8443:localhost:8443 kubeadmin@20.116.132.8&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;The command above suppose the public IP of the bastion host is 20.116.132.8. Then from my MacBook I can browse to localhost:8443 (with Safari browser which gives me the option to bypass certificate error). At the web portal, provide username (admin) and password (as retrieved above):&lt;/p&gt;&#10;&lt;div class="wp-block-image"&gt;&#10;&lt;figure class="aligncenter size-full"&gt;&lt;img loading="lazy" decoding="async" width="1795" height="1026" src="https://static.digihunch.com/wp-content/uploads/2022/06/image-16.png" alt="" class="wp-image-6037"/&gt;&lt;figcaption class="wp-element-caption"&gt;Ceph console for Kubernetes&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;/div&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Apart from the dashboard, we can also use &lt;a href="https://docs.ceph.com/en/quincy/man/8/ceph/"&gt;ceph admin tool&lt;/a&gt; from a &lt;a href="https://github.com/rook/rook/blob/master/deploy/examples/toolbox.yaml"&gt;toolbox&lt;/a&gt; pod, following &lt;a href="https://rook.io/docs/rook/v1.9/ceph-toolbox.html"&gt;this&lt;/a&gt; instruction. For monitoring, Ceph by Rook can expose metrics for &lt;a href="https://www.rook.io/docs/rook/v1.9/Storage-Configuration/Monitoring/ceph-monitoring/"&gt;Prometheus&lt;/a&gt; to scrape.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Performance&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;With default ceph configuration on AKS, I ran quick performance test using kube-str . The result is as follows:&lt;/p&gt;&#10;&lt;figure class="wp-block-table is-style-regular"&gt;&lt;table class="has-very-light-gray-to-cyan-bluish-gray-gradient-background has-background"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;read_iops&lt;/td&gt;&lt;td&gt;write_iops&lt;/td&gt;&lt;td&gt;read_bw&lt;/td&gt;&lt;td&gt;write_bw&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;ceph-block&lt;/td&gt;&lt;td&gt;IOPS=464.507294 BW(KiB/s)=1874&lt;/td&gt;&lt;td&gt;IOPS=243.296143 BW(KiB/s)=989&lt;/td&gt;&lt;td&gt;IOPS=509.928162 BW(KiB/s)=65797&lt;/td&gt;&lt;td&gt;IOPS=248.530762 BW(KiB/s)=32338&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;ceph-filesystem&lt;/td&gt;&lt;td&gt;IOPS=438.701324 BW(KiB/s)=1770&lt;/td&gt;&lt;td&gt;IOPS=226.270660 BW(KiB/s)=920&lt;/td&gt;&lt;td&gt;IOPS=405.936340 BW(KiB/s)=52456&lt;/td&gt;&lt;td&gt;IOPS=208.869293 BW(KiB/s)=27229&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The metrics reflects performance under default configuration. It should not be considered as the best performance that Ceph can deliver on Azure Kubernetes.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Summary&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;I discussed three storage options for Azure Kubernetes but the idea applies to other Kubernetes platform hosted on a CSP. The &lt;a href="https://static.digihunch.com/2022/07/kubernetes-storage-on-azure-1-of-3-built-in-storage-and-nfs/"&gt;native storage&lt;/a&gt; has significant limitation. NFS has latency. Block storage does not address high availability at the storage layer. Portworx and LINSTOR fill that gap as a commercial solution. Ceph is based on Object storage.&lt;/p&gt;&#10;&lt;nav class="wp-post-navigation" aria-label="Post navigation"&gt;&#10;&lt;a rel="prev" href="https://static.digihunch.com/2022/08/kubernetes-storage-on-azure-2-of-3-portworx/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Kubernetes Storage on Azure 2 of 3 – Portworx&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2022/09/minio-object-storage/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;MinIO for S3-compatible Object Storage&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>Kubernetes Storage on Azure 2 of 3 – Portworx</title><link>https://static.digihunch.com/2022/08/kubernetes-storage-on-azure-2-of-3-portworx/</link><pubDate>Fri, 12 Aug 2022 15:23:00 -0400</pubDate><guid>https://static.digihunch.com/2022/08/kubernetes-storage-on-azure-2-of-3-portworx/</guid><description>&lt;img src="https://static.digihunch.com/wp-content/uploads/2025/04/feature-k8s-azstorage.webp" alt="Featured image of post Kubernetes Storage on Azure 2 of 3 – Portworx" /&gt;&lt;p class="wp-block-paragraph"&gt;In the previous &lt;a href="https://static.digihunch.com/2022/07/kubernetes-storage-on-azure-1-of-3-built-in-storage-and-nfs/"&gt;post&lt;/a&gt;, we have discussed built-in storage classes on Azure Kubernetes. Further to that, we will examine some third-party software defined storage (SDS) options that are compatible with Azure Kubernetes Service in this post. Then we take Portworx on Azure as an example. Although, these options are specific to Azure, most of the players also have solutions for other managed Kubernetes platforms. Also, the methodology to study storage options remain the same regardless of cloud service provider.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In fact, I touched on software defined storage (SDS) in the context of general non-containerized workload in a separate &lt;a href="https://static.digihunch.com/2022/07/intro-to-ceph-storage/"&gt;post&lt;/a&gt;. In short, storage providers decouple the SDS appliance from the full storage solution in order to lower the cost and increase flexibility. To the storage consumer (e.g. a process running on Linux OS), SDS can present a block disk or file system. There are also SDS solution that can host your own object storage and we will discuss that later. In fact, SDS has gained significant popularity in recent years. For example, the report &amp;#8220;&lt;a href="https://www.architecting.it/product/brksw0140-ebook/"&gt;Validating Software-Defined Storage Operating Models for the Enterprise&lt;/a&gt;&amp;#8221; by &lt;em&gt;&lt;a href="https://www.architecting.it/"&gt;archiectingit&lt;/a&gt;&lt;/em&gt; divided the evolution into four phases and cited that Gartner predicts the SDS revolution to reach 50% of the storage market by 2024, from 15% in 2020.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;This post discusses SDS in the context of container storage. Then we will install Portworx on Azure Kubernetes.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="h-sds-for-kubernetes"&gt;SDS for Kubernetes&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Many SDS appliances also developed the capability to present storage volumes to containerized workload. I put together a list of SDS products that works on Azure with their supported access modes: &lt;/p&gt;&#10;&lt;figure class="wp-block-table is-style-regular"&gt;&lt;table class="has-cyan-bluish-gray-background-color has-background"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Solution&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Licence&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Development and Support&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Access Mode&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="https://portworx.com/products/portworx-enterprise/features/"&gt;Portworx&lt;/a&gt;&lt;/td&gt;&lt;td&gt;Closed source. Free Essential tier. Enterprise features on License. &lt;/td&gt;&lt;td&gt;Commercially supported by PureStorage&lt;/td&gt;&lt;td&gt;RWO, RWX&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="https://docs.ceph.com/en/quincy/"&gt;Ceph&lt;/a&gt; by &lt;a href="https://rook.io/"&gt;Rook&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href="https://github.com/rook/rook"&gt;Open source&lt;/a&gt;. Rook is a graduated &lt;a href="https://www.cncf.io/projects/rook/"&gt;CNCF project&lt;/a&gt;.&lt;/td&gt;&lt;td&gt;Developed and commercially supported by &lt;a href="https://access.redhat.com/documentation/en-us/red_hat_openshift_container_storage/4.8/html-single/red_hat_openshift_container_storage_architecture/index"&gt;Red Hat&lt;/a&gt;, &lt;a href="https://ubuntu.com/ceph"&gt;Canonical&lt;/a&gt; and &lt;a href="https://softiron.com/"&gt;SoftIron&lt;/a&gt;&lt;/td&gt;&lt;td&gt;RWO, ROX, RWX&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="https://openebs.io/"&gt;OpenEBS&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href="https://github.com/openebs/openebs"&gt;Open source&lt;/a&gt;. Sandbox &lt;a href="https://www.cncf.io/projects/openebs/"&gt;CNCF project&lt;/a&gt;.&lt;/td&gt;&lt;td&gt;Developed and &lt;a href="https://openebs.io/commercial-support"&gt;commercially supported&lt;/a&gt; by &lt;a href="https://openebs.io/"&gt;MayaData&lt;/a&gt; et al.&lt;/td&gt;&lt;td&gt;RWO&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="https://longhorn.io/"&gt;Longhorn&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href="https://github.com/longhorn/longhorn"&gt;Open source&lt;/a&gt;. Incubating &lt;a href="https://www.cncf.io/projects/longhorn/"&gt;CNCF project&lt;/a&gt;.&lt;/td&gt;&lt;td&gt;Originally developed by &lt;a href="https://rancher.com/products/longhorn"&gt;Rancher&lt;/a&gt;, and commercially supported by &lt;a href="https://www.suse.com/products/longhorn/"&gt;SUSE&lt;/a&gt;&lt;/td&gt;&lt;td&gt;RWO&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="https://docs.ondat.io/docs/install/microsoft-azure-aks/"&gt;StorageOS&lt;/a&gt;&lt;/td&gt;&lt;td&gt;Closed source. License required.&lt;/td&gt;&lt;td&gt;Commercial support by &lt;a href="https://www.ondat.io/"&gt;Ondat&lt;/a&gt;.&lt;/td&gt;&lt;td&gt;RWO&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="https://linbit.com/kubernetes/"&gt;LINBIT&lt;/a&gt;&lt;/td&gt;&lt;td&gt;Open-source with enterprise plans&lt;/td&gt;&lt;td&gt;Enterprise support&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;RWO is the most commonly supported mode. The report &amp;#8220;&lt;a href="https://www.architecting.it/product/performance-benchmarking-cloud-native-storage-solutions-for-kubernetes-ebook/"&gt;Performance Benchmarking Cloud Native Storage Solutions for Kubernetes&lt;/a&gt;&amp;#8221; makes a comparison of performance among some of the options in early 2021. Another potentially opinionated &lt;a href="https://linbit.com/cloud-native-sds-platform-comparsion/"&gt;comparison list&lt;/a&gt; is by LINBIT.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Portworx is a leading player with commercial SDS solution and I will test its free &lt;a href="https://portworx.com/blog/portworx-essentials-vs-portworx-enterprise/"&gt;Essential&lt;/a&gt; tier in the rest of this post. Ceph is one of the most mature leading open-source offering and I will test it in the next post.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;For Portworx, we can use the terraform template &lt;a href="https://github.com/digihunch/cloudkube/tree/main/azure"&gt;cloudkube for Azure&lt;/a&gt;. The template assigns the kubelet&amp;#8217;s managed identity as contributor of the node resource group. The template also creates a bastion host with direct SSH access to the nodes.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="h-portworx-operator-on-azure"&gt;Portworx Operator on Azure&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;We use Portworx Operator to configure storage cluster. Portworx has an &lt;a href="https://docs.portworx.com/portworx-enterprise/platform/kubernetes/azure-aks/install"&gt;instruction&lt;/a&gt; for AKS but it is not tailored to specific identity model. For simplicity, use my cloudkube &lt;a href="https://github.com/digihunch/cloudkube/tree/main/azure"&gt;Terraform template&lt;/a&gt; to create the AKS cluster, and skip the &amp;#8220;&lt;a href="https://docs.portworx.com/portworx-enterprise/platform/kubernetes/azure-aks/install/install-using-operator"&gt;Prepare Your AKS Platform&lt;/a&gt;&amp;#8221; page. Instead, follow the &amp;#8220;&lt;a href="https://docs.portworx.com/portworx-enterprise/platform/kubernetes/azure-aks/install/azure-managed-identity-on-aks"&gt;Deploy Portworx using Azure managed identity on new AKS cluster&lt;/a&gt;&amp;#8221; page starting at step 7. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;At that step, we need to create a secret with the client ID of the managed identity for node agent. The terraform template outputs the BYO identity&amp;#8217;s client ID. After cluster creation, we simply SSH to the bastion host and create the secret using the output.&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-large"&gt;&lt;img loading="lazy" decoding="async" width="1953" height="755" src="https://static.digihunch.com/wp-content/uploads/2022/06/image-15.png" alt="" class="wp-image-5810"/&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;To install Porworx using operator, we can follow a wizard in &lt;a href="https://central.portworx.com/"&gt;PX-central&lt;/a&gt;. If this is the first time, we need to create an account and log in to the portal. If this is not the first time and you have previously created a cluster, you need to detach that cluster by going to Profile from bottom left corner on the portal page. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Follow the guide in &amp;#8220;&lt;a href="https://docs.portworx.com/portworx-enterprise/platform/kubernetes/azure-aks/install/install-using-operator"&gt;Install Portworx on AKS using the Operator&lt;/a&gt;&amp;#8220;. In the wizard, click on &amp;#8220;Portworx Essentials&amp;#8221; for free tier, or &amp;#8220;Portworx Enterprise&amp;#8221; for the 30-day trial. Then select operator with latest version. In the rest of the wizard steps, select options applicable to Azure environment. The last step will present two kubectl commands to install operator and install the CR. Run the command to install operator and verify result:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kubectl apply -f &lt;span style="color:#e6db74"&gt;&amp;#39;https://install.portworx.com/2.9?comp=pxoperator&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kubectl -n kube-system get deployment portworx-operator&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 class="wp-block-heading"&gt;Portworx Custom Resource&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;To install the CR, we need to customize the given manifest in order to use our managed identity. We can download the YAML manifest (portworx_essentials.yml) and modify it in text editor. As the page &amp;#8220;&lt;a href="https://docs.portworx.com/portworx-enterprise/platform/kubernetes/azure-aks/install/azure-managed-identity-on-aks"&gt;Deploy Portworx using Azure managed identity on new AKS cluster&lt;/a&gt;&amp;#8221; suggest at step 9: in the&amp;nbsp;env&amp;nbsp;section, remove the AZURE_CLIENT_SECRET and AZURE_TENANT_ID sections but keep the AZURE_CLIENT_ID section. My CRD declaration looks like this:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;#&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;SOURCE&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;https&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#75715e"&gt;//install.portworx.com/?operator=true&amp;amp;mc=false&amp;amp;kbver=&amp;amp;oem=esse&amp;amp;user=myuserid&amp;amp;b=true&amp;amp;kd=type%3DPremium_LRS%2Csize%3D150&amp;amp;s=%22type%3DPremium_LRS%2Csize%3D150%22&amp;amp;c=my-very-long-px-cluster-id&amp;amp;aks=true&amp;amp;stork=true&amp;amp;csi=true&amp;amp;mon=true&amp;amp;tel=false&amp;amp;st=k8s&amp;amp;promop=true&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;kind&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;StorageCluster&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;apiVersion&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;core&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;libopenstorage&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;org&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;v1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;metadata&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;my&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;very&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;long&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;px&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;cluster&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;namespace&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;kube&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;system&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;annotations&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;portworx&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;io&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;install&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;source&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;https://install.portworx.com/?operator=true&amp;amp;mc=false&amp;amp;kbver=&amp;amp;oem=esse&amp;amp;user=myuserid&amp;amp;b=true&amp;amp;kd=type%3DPremium_LRS%2Csize%3D150&amp;amp;s=%22type%3DPremium_LRS%2Csize%3D150%22&amp;amp;c=my-very-long-px-cluster-id&amp;amp;aks=true&amp;amp;stork=true&amp;amp;csi=true&amp;amp;mon=true&amp;amp;tel=false&amp;amp;st=k8s&amp;amp;promop=true&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;portworx&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;io&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;is&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;aks&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;true&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;portworx&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;io&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;misc&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;args&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;--oem esse&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;spec&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;image&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;portworx&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;oci&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;monitor&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;2.10&lt;/span&gt;.&lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;imagePullPolicy&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Always&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;kvdb&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;internal&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;cloudStorage&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;deviceSpecs&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;type&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;Premium_LRS&lt;/span&gt;,&lt;span style="color:#a6e22e"&gt;size&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;150&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;kvdbDeviceSpec&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;type&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;Premium_LRS&lt;/span&gt;,&lt;span style="color:#a6e22e"&gt;size&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;150&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;secretsProvider&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;k8s&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;stork&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;enabled&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;args&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;webhook&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;controller&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;true&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;autopilot&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;enabled&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;monitoring&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;prometheus&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;enabled&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;exportMetrics&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;featureGates&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;CSI&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;true&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;env&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;AZURE_CLIENT_ID&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;valueFrom&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;secretKeyRef&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;px&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;azure&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;key&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;AZURE_CLIENT_ID&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;---&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;apiVersion&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;v1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;kind&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Secret&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;metadata&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;px&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;essential&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;namespace&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;kube&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;system&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;data&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;px&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;essen&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;user&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;aaaabbbbccccddddmyverylongpxessenuserid&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;px&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;osb&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;endpoint&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ssssssyyyyyyyzzzzzzmyverylongpxosbendpoint&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;In this custom resource manifest, I specify to get the cluster to create disk from Azure, even though it has the capability of using an existing disk. Then apply the CRD manifest:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; kubectl apply -f portworx_essentials.yml&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;This will take up to 10 minutes to create several related resources. There are several check points to ensure the cluster is created successfully. Here are some useful commands:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kubectl -n kube-system get po &lt;span style="color:#75715e"&gt;# all Pods related to portworx should be ready and running, especially the portworx-api ones&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kubectl -n kube-system get storagecluster &lt;span style="color:#75715e"&gt;# the status should report online&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;PX_POD&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;$(&lt;/span&gt;kubectl get pods -l name&lt;span style="color:#f92672"&gt;=&lt;/span&gt;portworx -n kube-system -o jsonpath&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;{.items[0].metadata.name}&amp;#39;&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;)&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# get the name of one of the portworx Pod for storage cluster&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kubectl -n kube-system exec -c portworx -it $PX_POD --tty --stdin -- /opt/pwx/bin/pxctl status &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# should report &amp;#34;Status: PX is operational&amp;#34; with valid license loaded&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kubectl get sc &lt;span style="color:#75715e"&gt;# portworx related storage classes are available&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;The pre-built storage classes are not CSI based. However, CSI should be automatically enabled in recent operator versions. We should create our own &lt;a href="https://docs.portworx.com/portworx-install-with-kubernetes/storage-operations/csi/volumelifecycle/"&gt;CSI storage classes&lt;/a&gt; and &lt;a href="https://docs.portworx.com/portworx-install-with-kubernetes/storage-operations/create-pvcs/dynamic-provisioning/"&gt;PVCs&lt;/a&gt; using our own storage classes. Here are two examples:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;kind&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;StorageClass&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;apiVersion&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;storage&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;k8s&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;io&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;v1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;metadata&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;px&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;csi&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;database&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;provisioner&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;pxd&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;portworx&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;com&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;parameters&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;repl&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;2&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;priority_io&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;high&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;io_profile&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;db&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;---&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;kind&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;StorageClass&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;apiVersion&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;storage&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;k8s&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;io&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;v1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;metadata&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;px&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;csi&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;artifact&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;provisioner&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;pxd&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;portworx&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;com&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;parameters&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;repl&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;2&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;priority_io&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;medium&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;io_profile&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;sequential&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;That is a bare minimum Portworx installation. Check out their &lt;a href="https://docs.portworx.com/portworx-install-with-kubernetes/"&gt;documentation&lt;/a&gt; for the full features. With this minimum install we can go to the section &amp;#8220;Validate Persistent Storage&amp;#8221; from the previous post to validate the persistent volume.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;For troubleshooting purpose, &lt;a href="https://docs.portworx.com/reference/cli/basics/"&gt;pxctl&lt;/a&gt; is the utility and it is available on Portworx Pods.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Performance&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;We care not only the functionality, but also the performance. So I ran a quick performance test using kube-str, using all default configuration. The result is as follows:&lt;/p&gt;&#10;&lt;figure class="wp-block-table is-style-regular"&gt;&lt;table class="has-cyan-bluish-gray-background-color has-background"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;read_iops&lt;/td&gt;&lt;td&gt;write_iops&lt;/td&gt;&lt;td&gt;read_bw&lt;/td&gt;&lt;td&gt;write_bw&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;px-csi-database&lt;/td&gt;&lt;td&gt;IOPS=969.614136 BW(KiB/s)=3894&lt;/td&gt;&lt;td&gt;IOPS=729.698059 BW(KiB/s)=2935&lt;/td&gt;&lt;td&gt;IOPS=1172.772827 BW(KiB/s)=150639&lt;/td&gt;&lt;td&gt;IOPS=691.626526 BW(KiB/s)=89053&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;px-csi-artifact&lt;/td&gt;&lt;td&gt;IOPS=780.681946 BW(KiB/s)=3139&lt;/td&gt;&lt;td&gt;IOPS=682.522766 BW(KiB/s)=2746&lt;/td&gt;&lt;td&gt;IOPS=773.548584 BW(KiB/s)=99549&lt;/td&gt;&lt;td&gt;IOPS=659.015320 BW(KiB/s)=84890&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Note that those numbers reflect performance under default configuration, and they should not be considered as the best performance that Portworx can deliver on Azure Kubernetes. Before moving to production, it is important to establish your own test parameters that best represents the container workload, and then iterate through different parameters for the storage class based on the requirement and performance output.&lt;/p&gt;&#10;&lt;nav class="wp-post-navigation" aria-label="Post navigation"&gt;&#10;&lt;a rel="prev" href="https://static.digihunch.com/2022/07/kubernetes-storage-on-azure-1-of-3-built-in-storage-and-nfs/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Kubernetes Storage on Azure 1 of 3 – built-in storage and NFS&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2022/08/storage-solution-on-aks-2-of-3-ceph-by-rook/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Kubernetes Storage on Azure 3 of 3 – Ceph by Rook&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>Intro to Ceph storage</title><link>https://static.digihunch.com/2022/07/intro-to-ceph-storage/</link><pubDate>Thu, 21 Jul 2022 18:55:00 -0400</pubDate><guid>https://static.digihunch.com/2022/07/intro-to-ceph-storage/</guid><description>&lt;img src="https://static.digihunch.com/wp-content/uploads/2025/04/feature-ceph.webp" alt="Featured image of post Intro to Ceph storage" /&gt;&lt;p class="wp-block-paragraph"&gt;Ceph is a unified, distributed storage system designed for excellent performance, reliability and scalability. In this post, I will introduce Ceph and explain how it stands out from traditional enterprise storage technology. &lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="h-software-defined-storage"&gt;Software defined storage&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In the realm of enterprise storage, I discussed &lt;a href="https://static.digihunch.com/2020/07/emc-productlines/"&gt;PowerScale (Isilon)&lt;/a&gt; from Dell EMC, and touched on &lt;a href="https://static.digihunch.com/2021/09/file-storage-vs-object-storage/"&gt;ONTAP&lt;/a&gt; by NetApp as an alternative. These solutions usually include both enterprise grade hardware, and the software layer that manages those expensive hardware. As the competition with cloud storage arises, those vendors start to decouple the software layer from the hardware to sell them separately. As a result, clients have the options to use commodity hardware. On the other hand, the software layer is built to be more accommodative to different hardware options. Eventually, the software layer evolves into Software Defined Storage (SDS) with the purpose of supporting cheaper storage hardware.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;This table shows the full solution offering and SDS offering from NetApp and Dell EMC:&lt;/p&gt;&#10;&lt;figure class="wp-block-table is-style-regular"&gt;&lt;table class="has-black-color has-cyan-bluish-gray-background-color has-text-color has-background has-fixed-layout"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Full solution offering&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;SDS offering&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;NetApp&lt;/td&gt;&lt;td&gt;&lt;a href="https://docs.netapp.com/ontap-9/index.jsp"&gt;ONTAP&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href="https://docs.netapp.com/us-en/ontap-select/index.html"&gt;ONTAP Select&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;EMC&lt;/td&gt;&lt;td&gt;PowerScale&lt;/td&gt;&lt;td&gt;PowerFlex&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;It is not easy to make a proprietary SDS appliance support commodity hardware. For example, PowerFlex currently supports (and bundles with) DELL&amp;#8217;s commodity hardware only. It is most likely an involuntary move. Then, why would these commercial providers even be motivated to support a broader range of hardware by moving to SDS? It is because they face fierce competition from open-source SDS technologies, which were born to support commodity hardware. In this family of technologies, Ceph is a rising star. This family also includes other technologies such as Gluster and HDFS.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Note that the performance of a storage based on SDS still has to do with the underlying hardware. Therefore, comparing Ceph storage with PowerScale is apple to orange, without identical storage hardware. Now that we decoupled SDS and hardware, let&amp;#8217;s take a look at two important aspects of SDS: the distributed technology to manage hardware, and the interface it provides to storage clients.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Distributed storage&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The reason to use an SDS layer to manage hardware in a distributed architecture is for better scalability and high availability. The soul of this SDS layer is the ability to manage distributed system. However, a distributed storage introduces problems of its own, such as coordinating consistency. Different storage technologies have their own way to tackle these problems. For example, with PowerScale, OneFS has its own Group Management Protocol. Ceph uses CRUSH for data distribution. GlusterFS uses DHT(Distributed Hash Table) Translator. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Storage architects usually do not need to know these technologies in detail. It is not the intention of this post to cover the details of any distributed technology in any of the storage options above. However, storage architects needs to know supported API very well.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Access API&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The supported access API of a storage system determines its compatibility with client systems. One good example is NFS for file storage, which defines the protocol for file share without defining the underlying implementation. Most GNU/Linux distributions come with nfsd (NFS server) which exports directories on XFS or ext4 FS as a file share with NFS protocol. In order to transfer data over network, NFS uses RPC, a request-response protocol. With object storage, S3 is a widespread protocol. Below is a list of storage implementations and their supported access API:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;Ceph supports librados, S3, Swift and FUSE&lt;/li&gt;&#10;&lt;li&gt;GlusterFS supports SMB, NFS, FUSE,&lt;/li&gt;&#10;&lt;li&gt;PowerScale supports NFS, SMB/CIFS, HDFS, Object, POSIX&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;CephFS is distributed file system built on top of Ceph RADOS. It is also a client-server architecture. A Ceph Client, via &lt;a href="https://docs.ceph.com/en/latest/rados/api/librados/"&gt;librados&lt;/a&gt;, interacts directly with OSDs to store and retrieve data. In order to interact with OSDs, the client app must invoke librados and connect to a Ceph Monitor. For compatibility, CephFS namespaces can be export over NFS protocol using &lt;a href="https://docs.ceph.com/en/latest/rados/api/librados-intro/"&gt;NFS-Ganesha&lt;/a&gt; NFS server.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Ceph Architecture&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Ceph is a high-performance, distributed storage platform. It provides object storage, block storage and distributed file system, all backed by a single, reliable storage cluster running on commodity server hardware. A Ceph Storage Cluster consists of Ceph Nodes on a network. A Ceph Storage cluster requires at least one Ceph monitor (ceph-mon), Ceph Manager (ceph-mgr) and Ceph OSDs (ceph-osd). For file system clients, it also requires Ceph Metadata Server (MDS, ceph-mds) to allow user to execute basic commands on POSIX file system (e.g. ls, find)&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Under the hood, Ceph stores data as objects within logical storage pools. Using the&amp;nbsp;&lt;a href="https://docs.ceph.com/en/latest/glossary/#term-CRUSH"&gt;CRUSH&lt;/a&gt;&amp;nbsp;algorithm, Ceph calculates which placement group (PG) should contain the object, and which OSD should store the placement group. The CRUSH algorithm enables the Ceph Storage Cluster to scale, rebalance, and recover dynamically.&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-full"&gt;&lt;img loading="lazy" decoding="async" width="689" height="483" src="https://static.digihunch.com/wp-content/uploads/2022/06/image-11.png" alt="" class="wp-image-5585"/&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Ceph is based on RADOS (reliable autonomic distributed object store), a self-healing system that distributes and replicates data across nodes. It then layers CephFS (a distributed file system), block storage service (RADOS Block Device or RBD), and s3-compatible object storage (RADOS Gateway or RGW) on top of RADOS. For a better description, refer to &lt;a href="https://ubuntu.com/ceph/what-is-ceph"&gt;this&lt;/a&gt; page. The chart above shows how Ceph interacts with different kinds of client. For CephFS, the client can interact with the file system via metadata daemon, as illustrated below. This diagram looks similar to the diagram for &lt;a href="https://static.digihunch.com/2020/07/nfs-network-file-system-and-rpc-remote-procedure-call/"&gt;NFS&lt;/a&gt;.&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-full"&gt;&lt;img loading="lazy" decoding="async" width="883" height="706" src="https://static.digihunch.com/wp-content/uploads/2022/06/image-12.png" alt="" class="wp-image-5586"/&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In a RADOS cluster, each server runs some daemons (i.e. OSD, MON or MDS). &lt;/p&gt;&#10;&lt;div class="wp-block-image"&gt;&#10;&lt;figure class="aligncenter size-full"&gt;&lt;img loading="lazy" decoding="async" width="736" height="317" src="https://static.digihunch.com/wp-content/uploads/2022/09/ceph.png" alt="" class="wp-image-7275"/&gt;&lt;/figure&gt;&#10;&lt;/div&gt;&#10;&lt;p class="wp-block-paragraph"&gt;When an I/O request occurs, it needs to be mapped to the specific OSD that keeps the storage units. Here is an illustration of the mapping:&lt;/p&gt;&#10;&lt;div class="wp-block-image"&gt;&#10;&lt;figure class="aligncenter size-full"&gt;&lt;img loading="lazy" decoding="async" width="603" height="338" src="https://static.digihunch.com/wp-content/uploads/2022/09/io-path.png" alt="" class="wp-image-7277"/&gt;&lt;/figure&gt;&#10;&lt;/div&gt;&#10;&lt;p class="wp-block-paragraph"&gt;As typically observed in distributed system, there is quite some communication overhead to serve a file.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Ceph Cluster Installation&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Installing a VM-based Ceph cluster is no trivial effort and there are several methods. The recommended method is &lt;a href="https://docs.ceph.com/en/latest/cephadm/#cephadm"&gt;Cephadm&lt;/a&gt;. &lt;a href="https://kifarunix.com/install-and-setup-ceph-storage-cluster-on-ubuntu/"&gt;Here&lt;/a&gt; is a good instruction, where you will notice a lot of steps on each nodes, such as configuring NTP, installing docker, configuring hostname, Linux user and SSH, etc. You may also check &lt;a href="https://www.youtube.com/watch?v=LxDQyFWDNHI"&gt;this&lt;/a&gt; video for how involving it is. Red Hat adopts &lt;a href="https://www.redhat.com/en/technologies/storage/ceph"&gt;Ceph&lt;/a&gt; project as a product and has an &lt;a href="https://access.redhat.com/documentation/en-us/red_hat_ceph_storage/5/html/installation_guide/red-hat-ceph-storage_install"&gt;installation guide&lt;/a&gt; on its documentation.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Previously, there was a legacy tool &lt;a href="https://docs.ceph.com/projects/ceph-ansible/en/latest/"&gt;ceph-ansible&lt;/a&gt; to help administrators with server configuration. It is similar to the way kubespray helps administrators configure Kubernetes cluster. However, the &lt;a href="https://docs.ceph.com/en/quincy/install/#other-methods"&gt;document&lt;/a&gt; suggests that ceph-ansible is not integrated with new orchestrator APIs and therefore is not a viable option anymore. Also I did not find a way to install a single-node ceph cluster just for a quick demo. It involves tweaking the &lt;a href="https://docs.ceph.com/en/quincy/rados/operations/crush-map/"&gt;CRUSH&lt;/a&gt; map configuration. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;If we deploy Ceph on Kubernetes for Kubernetes workload, we use &lt;a href="https://rook.io/docs/rook/v1.9/Getting-Started/intro/"&gt;Rook&lt;/a&gt;, an orchestrator running on Kubernetes, to integrate storage to a cluster.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Cloud Native Storage&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Moving to cloud native storage, instead of presenting storage to operating system, we need to configure storage classes for Pods to use persistent volumes dynamically, using storage provisioners. Ceph also shows good presence in cloud native storage ecosystem. In a self-managed Kubernetes cluster, Ceph gives us the capability to configure storage classes to access connected storage. In public cloud, Ceph allows us to configure storage classes connecting to disks attached to the Nodes, an alternative to the cloud vendor provided native storage classes with high availability across availability zones. This layer enables the organization to normalize how their application connects to persistent volumes, a capability particularly helpful in the multi-cloud strategy of the cluster.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Rook is a CNCF project to orchestrate storage system on Kubernetes. It automates storage administrative tasks such as deployment, bootstrapping, configuring, provisioning and monitoring, using declarative templates. It supports Ceph and a number of other storage backends such as Cassandra, NFS, MinIO. &lt;/p&gt;&#10;&lt;nav class="wp-post-navigation" aria-label="Post navigation"&gt;&#10;&lt;a rel="prev" href="https://static.digihunch.com/2022/07/kick-the-tires-on-argocd/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Kick the tires on ArgoCD&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2022/07/kubernetes-storage-on-azure-1-of-3-built-in-storage-and-nfs/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Kubernetes Storage on Azure 1 of 3 – built-in storage and NFS&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item></channel></rss>