<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>object storage on Digi Hunch</title><link>https://static.digihunch.com/tag/object-storage/</link><description>Recent content in object storage 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/object-storage/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>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><item><title>File storage vs object storage in the cloud</title><link>https://static.digihunch.com/2021/09/file-storage-vs-object-storage/</link><pubDate>Thu, 23 Sep 2021 22:54:00 -0400</pubDate><guid>https://static.digihunch.com/2021/09/file-storage-vs-object-storage/</guid><description>&lt;img src="https://static.digihunch.com/wp-content/uploads/2025/04/feature-file-obj-storage.webp" alt="Featured image of post File storage vs object storage in the cloud" /&gt;&lt;p class="wp-block-paragraph"&gt;File storage (e.g. NFS) used to be prevalent until object storage comes in for competition.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="h-the-competition"&gt;The competition&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Traditionally, enterprise storage product lines are built around three capabilities, as listed in this table below:&lt;/p&gt;&#10;&lt;figure class="wp-block-table is-style-stripes"&gt;&lt;table class="has-black-color has-white-background-color has-text-color has-background"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Capability&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Typical Implementation&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Data served&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;T1 &amp;#8211; &lt;br&gt;Block stroage&lt;/td&gt;&lt;td&gt;DAS (e.g. SAS cable) or SAN (Fibre Cable for FCP protocol, or Ethernet for iSCSI protocol)&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;Mission critical data that are extremely sensitive to latency (e.g. database). Client has block-level access.&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;T2 &amp;#8211; &lt;br&gt;File storage&lt;/td&gt;&lt;td&gt;NAS (connect via CIFS or NFS protocols). Storage arrays are typically a mix of HDD and SSD. Storage servers are usually deployed in the same location over low latency network. DR location is usually in the same region.&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;Hot data. Multiple client access at file level. The size of each data request varies from small to medium (e.g. text document)&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;T3 &amp;#8211; &lt;br&gt;Object storage&lt;/td&gt;&lt;td&gt;Hardware agnostic, connect via layer-7 protocol (e.g. S3). Storage backend can be either on premise, or in the cloud, over WAN connection.&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;Warm and code data. Multiple client access at object level. Traditionally for backup but use cases are expanding. The size of each data request varies significantly, from small to very large (e.g. media content).&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&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;In the last couple decades, leading players for T2 have been enterprise storage vendors. They each have developed their secret sauces to tackle the challenges. For example, EMC has OneFS, a parallel distributed file system as the foundation of &lt;a href="https://static.digihunch.com/2020/07/emc-productlines/"&gt;PowerScale&lt;/a&gt; (formerly Isilon) product line. NetApp develops ONTAP, featuring proprietary techniques for storage efficiency (deduplication, compaction and compression).&amp;nbsp;&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The leading players in T3 are mostly &lt;a href="https://static.digihunch.com/2020/08/cloud-storage-overview/"&gt;public cloud&lt;/a&gt; provider, such as Amazon&amp;#8217;s S3. They might work with enterprise storage vendor behind the scene. But the T3 services appear to the end users as provided by the public cloud. Originally, the use case for T3 was archive only for its virtually unlimited capacity. This is not entirely true today. With the drastic improvement in modern network infrastructure, T3 can also brings satisfactory performance to serve hot data. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;A competition between T2 and T3 arises. After all, both offer storage service over Ethernet, and both support multiple clients. Today when developers architect the storage layer of their applications, they need to weigh between supporting T2 and T3. Since &lt;a href="https://static.digihunch.com/2020/07/nfs-network-file-system-and-rpc-remote-procedure-call/"&gt;NFS&lt;/a&gt; is the typical protocol for T2 storage (sorry Windows guys) and S3 is typical T3 storage. This competition essentially boils down to NFS versus S3.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;For many, the fancy S3 is a no-brainer. While I have suffered from many NFS drawbacks, and there&amp;#8217;s even a whole &lt;a href="https://www.kernel.org/doc/ols/2006/ols2006v2-pages-59-72.pdf"&gt;article&lt;/a&gt; by Linux folks about why NFS sucks, is it sentenced to death today? Does it beat S3 in some cases? Do so many organizations still stick to NFS just out of inertia?&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;To answer these questions, I examine four aspects to explore the differences between file storage via NFS protocol, and object storage in S3. &lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-data-request-size"&gt;Data request size&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Storage client can make request by byte range of a file. Therefore, data request size, instead of file size, is what ultimately matters. I pick a few data request sizes (1K, 4K, 16K, 64K, 246K, 1024K and 4096K) in my experiment, and want to see how much network traffic a write operation produces using NFS and using S3.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;To emulate request size, I created files at each size (using dd command), and copy the entire file to each backend. In the mean time, I use tcpdump to write out traffic across the wire into capture files. The size of capture file gives me an idea of how much network traffic went through the network interface, which is closely related to latency. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;For NFS, I mounted the target with sync option. This requires NFS client to write out to server synchronously on file copy. I&amp;#8217;ve also set the wsize to be 1M. For S3, I simply use the following CLI command to copy file:&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 s3 cp 1kb.img s3://digihunch5ffafe32ab0fd40f&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;On the network interface, I use tcpdump to filter traffic through specific TCP port (443 for S3, or 2049 for NFS) and record the size of the capture file:&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;sudo tcpdump -s0 -pi eth0 dst port &lt;span style="color:#ae81ff"&gt;443&lt;/span&gt; or src port &lt;span style="color:#ae81ff"&gt;443&lt;/span&gt; -w /tmp/4096kb.cap&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;The key indicator is the payload size (file size) as a percentage of the capture size. I call it payload ratio. The closer it is to 1, the better. I have the following result from my experiment:&lt;/p&gt;&#10;&lt;figure class="wp-block-table is-style-stripes"&gt;&lt;table class="has-black-color has-white-background-color has-text-color has-background"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Request&lt;/td&gt;&lt;td&gt;Payload&lt;/td&gt;&lt;td&gt;S3 capture size (byte)&lt;/td&gt;&lt;td&gt;NFS capture size (byte)&lt;/td&gt;&lt;td&gt;S3 payload ratio&lt;/td&gt;&lt;td&gt;NFS payload ratio&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1K&lt;/td&gt;&lt;td&gt;1024&lt;/td&gt;&lt;td&gt;9352&lt;/td&gt;&lt;td&gt;4332&lt;/td&gt;&lt;td&gt;0.11&lt;/td&gt;&lt;td&gt;0.24&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;4K&lt;/td&gt;&lt;td&gt;4096&lt;/td&gt;&lt;td&gt;12640&lt;/td&gt;&lt;td&gt;7404&lt;/td&gt;&lt;td&gt;0.32&lt;/td&gt;&lt;td&gt;0.55&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;16K&lt;/td&gt;&lt;td&gt;16384&lt;/td&gt;&lt;td&gt;25969&lt;/td&gt;&lt;td&gt;20472&lt;/td&gt;&lt;td&gt;0.63&lt;/td&gt;&lt;td&gt;0.80&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;64K&lt;/td&gt;&lt;td&gt;65536&lt;/td&gt;&lt;td&gt;79183&lt;/td&gt;&lt;td&gt;69746&lt;/td&gt;&lt;td&gt;0.83&lt;/td&gt;&lt;td&gt;0.94&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;256K&lt;/td&gt;&lt;td&gt;262144&lt;/td&gt;&lt;td&gt;290035&lt;/td&gt;&lt;td&gt;271408&lt;/td&gt;&lt;td&gt;0.90&lt;/td&gt;&lt;td&gt;0.97&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1024K&lt;/td&gt;&lt;td&gt;1048576&lt;/td&gt;&lt;td&gt;1085366&lt;/td&gt;&lt;td&gt;1074076&lt;/td&gt;&lt;td&gt;0.97&lt;/td&gt;&lt;td&gt;0.98&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;4096K&lt;/td&gt;&lt;td&gt;4194304&lt;/td&gt;&lt;td&gt;4381547&lt;/td&gt;&lt;td&gt;4286910&lt;/td&gt;&lt;td&gt;0.96&lt;/td&gt;&lt;td&gt;0.98&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;This result indicates that NFS has a higher ratio in all groups. However, its advantage diminishes as the data request size grows. What it tells us is that if your applications workload issues most request in small chunks of data, such as 1K, 4K, then NFS will require much less traffic over the network, and thus less latency. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;This essentially explains the use case of NFS against S3: workload with small data requests.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-client-support"&gt;Client Support&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;NFS is natively supported by Linux operating system kernel. NFS client sits below the virtual file system (VFS) layer, which sits below the system call layer. The NFS client translate system calls into RPC (remote procedure calls). Communication between client and server is completed with RPC, on top of TCP. &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="554" height="314" src="https://static.digihunch.com/wp-content/uploads/2021/10/image.png" alt="" class="wp-image-2732"/&gt;&lt;figcaption class="wp-element-caption"&gt;NFS architecture&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;/div&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Because of the native support, in most cases, developer can treat NFS mounts as if they were local. For performance to be sustainable as file system grows, the directory structure on NFS should follow a certain naming conventions so that files are evenly distributed across directories. The client should also use list operation as sparse as it can because that operation is expensive across the network.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;From developer&amp;#8217;s perspective, NFS support is brought in by operating system and does not require much effort. On the other hand, S3 client support is not included by default in the operating system. S3 support requires special library, code changes, and integration effort to manage dependency and library version. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;NFS has an advantage on client supportability. However, as we move applications to containers, and as container storage options mature, we will need an intermediary layer (storage class, storage provisioner, CSI driver, etc), NFS, or in general file storage, does not have this advantage any more.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-client-side-cache"&gt;Client-side Cache&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The NFS support behind VFS layer also means it can leverage the I/O caching mechanism on the client side, that comes with operating system. Client operating system with sufficient memory can take advantage of this mechanism to give it a performance boost. Check out &lt;a href="https://www.ibm.com/docs/en/aix/7.2?topic=performance-nfs-tuning-client"&gt;this&lt;/a&gt; guide for NFS cache tuning.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In comparison, S3 does not have a cache mechanism by itself. Either the application needs to implement its own cache mechanism, or a cache architecture needs to be introduced, such as CloudFront. &lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-consistency-and-concurrency"&gt;Consistency and concurrency&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;A common consistency problem is whether client can read the changes immediately after it writes the file. S3 and NFS make a tie in this round.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;S3 &lt;a href="https://aws.amazon.com/blogs/aws/amazon-s3-update-strong-read-after-write-consistency/"&gt;originally&lt;/a&gt; came with eventual consistency model for read after write since 2006. As of &lt;a href="https://aws.amazon.com/about-aws/whats-new/2020/12/amazon-s3-now-delivers-strong-read-after-write-consistency-automatically-for-all-applications/"&gt;Dec 2020&lt;/a&gt; it introduced strong read-after-write consistency. For more information, refer to the guide &lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/Welcome.html#ConsistencyModel"&gt;here&lt;/a&gt;.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;NFS has a similar consistency guarantee called close-to-open cache coherency. Any changes made by client are flushed to the server on closing the file, and a cache revalidation occurs when you re-open it. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;There are more to consider in terms of consistency. For example, multiple clients tries to write the same file/object at the same time. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;On the S3 side, there is a locking mechanism called &lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-lock.html"&gt;S3 object lock&lt;/a&gt; at object level (no byte-range lock). Without an object lock, when two PUT requests are simultaneously made to an object, the request with the latest timestamp wins. Refer to the section &lt;em&gt;Concurrent application&lt;/em&gt; on &lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/Welcome.html#ConsistencyModel"&gt;this&lt;/a&gt; page.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;As far as NFS goes, managing this kind of consistency problem is not in the scope of the standard. Although there are some tinkers. For example, NFS v4 includes a file locking mechanism. Client can choose to lock the entire file, or a byte range within the file. Locking can be mandatory or advisory.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="h-the-convergence"&gt;The convergence&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;NFS and S3 each has their respective advantage. Enterprise NAS customers have been looking for ways to expand into the cloud for lower storage cost. To combine the advantages of the two, solution providers started to converge file storage and object storage. There are two types of solutions that reflects this trend of convergence. In the first trend, enterprise NAS deployed on premise now have the ability to scale out into the cloud. In the second trend, public cloud just brought enterprise NAS into their product offerings.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-scale-out-nas"&gt;Scale-out NAS&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;NAS is traditionally expensive to scale because it requires physical storage media. The idea of scale-out NAS allows NAS to connect to object storage in the public cloud, making it a hybrid architecture. This essentially makes T3 storage as a backend of T2 and it can be implemented with a virtual storage appliance (VSA). The VSA translate file system activities into API calls for object storage operations. One example is AWS &lt;a href="https://aws.amazon.com/storagegateway/?whats-new-cards.sort-by=item.additionalFields.postDateTime&amp;amp;whats-new-cards.sort-order=desc"&gt;storage gateway&lt;/a&gt;. EMC has a similar appliance called ECS and this white paper explains how it proxies file system calls and interact with object backends. NetApp, a vested enterprise NAS provider, also has a counterpart called Cloud Volumes ONTAP (CVO). It works well with NetApp on-premise deployment, but the architecture is similar. &lt;a href="https://cloud.netapp.com/blog/aws-cvo-blg-aws-storage-gateway-vs.-cloud-volumes-ontap"&gt;Here&lt;/a&gt;&amp;#8216;s NetApp&amp;#8217;s take on how CVO is different than AWS Storage Gateway.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In the scale-out NAS architecture, the public cloud acts merely as extension to on-premise storage solution, to provide capacity. The NAS on premise serves the storage workload primarily.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-cloud-hosted-nas"&gt;Cloud hosted NAS&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;For applications hosted in public cloud, it makes sense for public cloud provider to operate enterprise NAS storage as a service. The underlying storage technology is provided by storage vendor. It is just installed in the data centre managed by the public cloud vendor, instead of customer&amp;#8217;s own data centre. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;One example is &lt;a href="https://azure.microsoft.com/en-us/services/netapp/"&gt;Azure NetApp Files&lt;/a&gt; (ANF). ANF is fully managed services, presented to users as storage volumes. The underlying storage technology is NetApp ONTAP. Because it is offered as a fully managed service, the customers are not able to manage the fine details of the storage, as they could with an ONTAP cluster on premise. This takes a lot of flexibility away from the user.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://aws.amazon.com/fsx/netapp-ontap/"&gt;FSx ONTAP&lt;/a&gt; is a managed NetApp storage service by AWS, launched in September 2021. The NetApp arrays are installed in AWS data centre, ready for users to provision from AWS console, or using CLI. The Terraform provider support is not available as of yet. Unlike ANF, FSx ONTAP exposes the ONTAP CLI to users, allowing for advanced storage managed by storage gurus. They can use ONTAP CLI commands to configure custom policy for Snapshot, setup SnapMirror replication, and so forth.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Likewise, PowerScale landed on GCP as public cloud partner to launch &lt;a href="https://cloud.google.com/vmware-engine/docs/vmware-ecosystem/howto-cloud-dell-powerscale#:~:text=Dell%20PowerScale%20on%20Google%20Cloud,workload%20virtual%20machines%20(VMs)."&gt;Dell Cloud PowerScale for Google Cloud&lt;/a&gt; in 2020. However, it seems to require a purchase agreement before APIs are enabled.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="h-conclusion"&gt;Conclusion&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Object storage has a great momentum and some sees that as a replacement of file storage in the long run. However file storage has its advantages for small data requests, OS-level cache support, and built-in POSIX compatibility. It will continue to be an option for customers with specific workload. Customer stickiness to file storage is so firm, that public cloud providers now install them in their data centres. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;From competition to collaboration, it will be interesting to watch what happens next for enterprise storage.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Follow-up Reading&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Tom Lyon&amp;#8217;s presentation on &lt;a href="https://blocksandfiles.com/2024/06/17/eminent-sun-alumnus-says-nfs-must-die/"&gt;why NFS must die&lt;/a&gt;.&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/2021/09/single-node-kubernetes-cluster-minikube/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Local multi-node cluster – Minikube, MicroK8s and KinD&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2021/10/intro-to-plg-stack-prometheus-loki-and-grafana/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Intro to PLG stack -Prometheus, Loki and Grafana&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>Cloud storage overview</title><link>https://static.digihunch.com/2020/08/cloud-storage-overview/</link><pubDate>Wed, 12 Aug 2020 22:19:00 -0400</pubDate><guid>https://static.digihunch.com/2020/08/cloud-storage-overview/</guid><description>&lt;p class="wp-block-paragraph"&gt;In a narrow sense, cloud storage refers to object storage. In a broader sense, it refers to any storage service (block, file or object level) provided by cloud vendors, in a cloud business model. The underlying technology of storage, is the same be it in the cloud or on-premise. &lt;/p&gt;&#10;&lt;figure class="wp-block-table is-style-stripes"&gt;&lt;table class="has-background" style="background-color:#e9fbe5"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;Block storage&lt;/td&gt;&lt;td&gt;File storage&lt;/td&gt;&lt;td&gt;Object&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Interaction with OS&lt;/td&gt;&lt;td&gt;OS has direct byte-level access to disk blocks.&lt;/td&gt;&lt;td&gt;OS manages storage by file, or byte range of file. Files are organized in POSIX hierarchy.&lt;/td&gt;&lt;td&gt;OS reads and writes the entire object, or a byte range, via rest API calls.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Metadata&lt;/td&gt;&lt;td&gt;N/A&lt;/td&gt;&lt;td&gt;Stored in file system, for directory or file&lt;/td&gt;&lt;td&gt;customizable metadata&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Common protocol&lt;/td&gt;&lt;td&gt;N/A&lt;/td&gt;&lt;td&gt;NFS&lt;/td&gt;&lt;td&gt;S3&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Implementation&lt;/td&gt;&lt;td&gt;SAN (bock device is typically dedicated to a single VM) or DAS&lt;/td&gt;&lt;td&gt;NAS, file storage is usually shared amongst multiple VMs. Locking mechanism is usually in place to keep access in order.&lt;/td&gt;&lt;td&gt;S3&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Workload&lt;/td&gt;&lt;td&gt;database storage, scratch data, etc&lt;/td&gt;&lt;td&gt;persistent data, content management, etc&lt;/td&gt;&lt;td&gt;archive data, media streaming, data analytics, static asset serving, etc&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Below is a list of common storage services provided by public cloud vendors to day.&lt;/p&gt;&#10;&lt;figure class="wp-block-table is-style-stripes"&gt;&lt;table class="has-background" style="background-color:#e9fbe5"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Block Storage&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;File Storage&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Object Storage&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Other managed storage service&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;&lt;a href="https://aws.amazon.com/products/storage/"&gt;&lt;span class="has-inline-color has-black-color"&gt;AWS&lt;/span&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;a href="https://aws.amazon.com/ebs"&gt;&lt;span class="has-inline-color has-black-color"&gt;Elastic Block Store (EBS)&lt;/span&gt;&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href="https://aws.amazon.com/efs/"&gt;&lt;span class="has-inline-color has-black-color"&gt;Elastic File System (EFS)&lt;/span&gt;&lt;/a&gt;&lt;span class="has-inline-color has-black-color"&gt;&lt;br&gt;&lt;/span&gt;&lt;a href="https://aws.amazon.com/fsx/windows/"&gt;&lt;span class="has-inline-color has-black-color"&gt;FSx for Windows&lt;/span&gt;&lt;/a&gt;&lt;br&gt;FSx for Lustre&lt;/td&gt;&lt;td&gt;&lt;a href="https://aws.amazon.com/s3/"&gt;&lt;span class="has-inline-color has-black-color"&gt;Simple Storage Service (S3)&lt;/span&gt;&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href="https://aws.amazon.com/storagegateway"&gt;&lt;span class="has-inline-color has-black-color"&gt;Storage Gateway&lt;/span&gt;&lt;/a&gt; &lt;br&gt;Snow Family&lt;br&gt;DataSync&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-introduction"&gt;&lt;span class="has-inline-color has-black-color"&gt;Azure&lt;/span&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/virtual-machines/windows/managed-disks-overview"&gt;&lt;span class="has-inline-color has-black-color"&gt;Azure Managed Disks&lt;/span&gt;&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/storage/files/storage-files-introduction"&gt;&lt;span class="has-inline-color has-black-color"&gt;Azure Files&lt;/span&gt;&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/storage/blobs/storage-blobs-introduction"&gt;&lt;span class="has-inline-color has-black-color"&gt;Azure Blobs&lt;/span&gt;&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/storage/tables/table-storage-overview"&gt;&lt;span class="has-inline-color has-black-color"&gt;Azure Table&lt;/span&gt;&lt;/a&gt;&lt;span class="has-inline-color has-black-color"&gt; &lt;br&gt;&lt;/span&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/storage/queues/storage-queues-introduction"&gt;&lt;span class="has-inline-color has-black-color"&gt;Azure Queues&lt;/span&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;&lt;a href="https://cloud.google.com/products/storage"&gt;&lt;span class="has-inline-color has-black-color"&gt;GCP&lt;/span&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;a href="https://cloud.google.com/persistent-disk"&gt;&lt;span class="has-inline-color has-black-color"&gt;Persistent Disk&lt;/span&gt;&lt;/a&gt;&lt;span class="has-inline-color has-black-color"&gt;&lt;br&gt;&lt;/span&gt;&lt;a href="https://cloud.google.com/local-ssd"&gt;&lt;span class="has-inline-color has-black-color"&gt;local SSD&lt;/span&gt;&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href="https://cloud.google.com/filestore"&gt;&lt;span class="has-inline-color has-black-color"&gt;Filestore&lt;/span&gt;&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href="https://cloud.google.com/storage"&gt;&lt;span class="has-inline-color has-black-color"&gt;Cloud Storage&lt;/span&gt;&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a href="https://firebase.google.com/products/storage/"&gt;&lt;span class="has-inline-color has-black-color"&gt;Cloud Storage for Firebase&lt;/span&gt;&lt;/a&gt;&lt;br&gt;Data Transfer&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;&lt;a href="https://www.digitalocean.com/products/"&gt;&lt;span class="has-inline-color has-black-color"&gt;Digital Ocean&lt;/span&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;a href="https://www.digitalocean.com/products/block-storage/"&gt;&lt;span class="has-inline-color has-black-color"&gt;Volumes Block storage&lt;/span&gt;&lt;/a&gt;&lt;br&gt;local SSD&lt;/td&gt;&lt;td&gt;N/A&lt;/td&gt;&lt;td&gt;&lt;a href="https://www.digitalocean.com/products/spaces/"&gt;&lt;span class="has-inline-color has-black-color"&gt;Space object storage&lt;/span&gt;&lt;/a&gt; (S3 compatible)&lt;/td&gt;&lt;td&gt;Content Delivery Network&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;figcaption class="wp-element-caption"&gt;Storage Products from common public cloud vendor&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Since AWS is the first vendor that provides a full suite of storage service, this post will focus on the storage product lines, as a refresher of AWS cloud storage options: Simple Storage Service, Elastic File Storage and Elastic Block Storage). There will be some overlap with the AWS storage service &lt;a href="https://d0.awsstatic.com/whitepapers/AWS%20Storage%20Services%20Whitepaper-v9.pdf"&gt;whitepaper&lt;/a&gt;.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Before getting further to details, here&amp;#8217;s a reminder of two types of policies in AWS:&lt;/p&gt;&#10;&lt;figure class="wp-block-table is-style-stripes"&gt;&lt;table class="has-background" style="background-color:#e9fbe5"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;IAM policy&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Resource-based policy&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Principal&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Must be attached to individual user, group, or role to take effect&lt;/td&gt;&lt;td&gt;Needs to be explicitly specified, can be ARN under other AWS account&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Element&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Action/NotAction&lt;br&gt;Resource/NotResource&lt;br&gt;Effect (Allow/Deny)&lt;br&gt;Condition&lt;/td&gt;&lt;td&gt;Principal/NotPrincipal&lt;br&gt;Action/NotAction&lt;br&gt;Resource/NotResource&lt;br&gt;Effect (Allow/Deny)&lt;br&gt;Condition&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Example&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Managed policy, custom policy&lt;/td&gt;&lt;td&gt;File system policy, S3 bucket policy, access point policy, etc&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;figcaption class="wp-element-caption"&gt;Two types of policies&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Although the resource is usually assumed in a resource-based policy, the policy usually target a sub-section of a resource (e.g. object with certain prefix), so resource section is still required in resource-based policy. In storage services, we may use S3 bucket policy, access point policy, or file system policy for EFS.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Below we go over the three families of storage service in AWS.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-ebs-elastic-block-storage"&gt;EBS (Elastic Block Storage)&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;EBS is a distributed system. Each volume is a logical volume, made up of multiple physical devices. EBS data is persistent, and access is dedicated to a single EC2 instance at a time. If EC2 instance failed, the attached EBS volume can be detached, and then re-attached to other instance, in the same Availability Zone. There are two types of EBS:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;EC2 Instance store: ephemeral, block-level storage for EC2 instance, no replication by default, no snapshot support. Used as buffers, caches, scratch data, temporary content.&lt;/li&gt;&#10;&lt;li&gt;EBS volume (persistent) : used for database, dev/test, enterprise application, etc. There are two sub-categories:&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;SSD-backed volumes:&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;Optimized for transnational workloads that requires very low latency&lt;/li&gt;&#10;&lt;li&gt;Dominant performance attribute is IOPS&lt;/li&gt;&#10;&lt;li&gt;For frequent, read/write with small size and &lt;a href="https://static.digihunch.com/2019/04/application-i-o-characteristics/"&gt;random&lt;/a&gt; I/O&lt;/li&gt;&#10;&lt;li&gt;Typical use case include relational database (PostgresQL, MySQL) and NoSQL (Cassandra, Mongo)&lt;/li&gt;&#10;&lt;li&gt;gp2 (general purpose) and io1 (provisioned IOPS)&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;HDD-backed volumes:&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;Optimized for large streaming workloads demanding throughput&lt;/li&gt;&#10;&lt;li&gt;Dominant performance attribute is &lt;span style="text-decoration: underline;"&gt;throughput&lt;/span&gt;&lt;/li&gt;&#10;&lt;li&gt;For workloads with lots of &lt;a href="https://static.digihunch.com/2019/04/application-i-o-characteristics/"&gt;sequential&lt;/a&gt; I/O&lt;/li&gt;&#10;&lt;li&gt;Typical use case icnlude big data, analytics (Kafka, Splunk, Hadoop, data warehousing), file/media server&lt;/li&gt;&#10;&lt;li&gt;st1 (throughput optimized0 and sc1 (cold HDD)&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The four types of EBS are compared here:&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-large"&gt;&lt;img loading="lazy" decoding="async" width="865" height="770" src="https://static.digihunch.com/wp-content/uploads/2020/08/image-10.png" alt="" class="wp-image-1307"/&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Note that the volume can be modified (change type, increase size) after creation. However, you cannot decrease size. If you increase the size, the file system must be extended after the increase.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Another way to deliver better performance is to use &lt;a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ebs-optimized.html"&gt;EBS-optimized instances&lt;/a&gt;. These instances have dedicated network bandwidth for its I/O traffic to and from EBS. Without EBS-optimized instance, the traffic between EBS volume and EC2 instance uses shared network link with EC2, which is subject to latency during heavy traffic. This distinction is similiar to the difference between iSCSI SAN and FC SAN. Also, you may increase read-ahead buffer in OS for better EBS performance.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;On EBS, users can create snapshot, a point-in-time incremental backup. When snapshot is restored to a volume, data is loaded lazily in the background, so that volume is available immediately. This also means that initial read of data that is not yet loaded will be subject to latency, known as first read penalty. To achieve target performance, user may run an initialization on the volume, by reading all blocks with data upfront.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In a newly created snapshot, only the data blocks modified since the previous snapshot are stored as is. The rest are pointers to unchanged data blocks in the original snapshot. When a previous snapshot is deleted, AWS ensures changes are reconciled into the newer snapshot so there is no loss of data. Creation of snapshots on many volumes can be automated with Data Lifecycle Manager (DLM).&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;As far as encryption goes, the best practice is to create your own master key. KMS uses envelop encryption, where the data key encrypts the data, and the master key encrypts the data key. The encryption key is stored in EC2 instance memory only and never written to disk, for security and performance considerations.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-efs-elastic-file-storage"&gt;EFS (Elastic File Storage)&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;EFS is a managed implementation of file storage that supports NFS 4.0 and 4.1, with strong data consistency and file locking. An EFS includes a single mount target in (one subnet of) each availability zone. EC2 instance, or on-premise client via Direct Connect, can mount EFS volumes using amazon-efs-utils yum package. EC2 instance can also be configured to automatic mount EFS volume in launch wizard. EFS also has a lifecycle management policy, and a storage class for infrequent access.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://docs.aws.amazon.com/efs/latest/ug/performance.html"&gt;Performance &lt;/a&gt;wise, EFS has two performance modes and two throughput modes. The two performance modes are:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;&lt;strong&gt;General Purpose&lt;/strong&gt;: for latency-sensitive applications and general-purpose workloads. limit of 7k ops/sec, best choice for most workloads&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Max I/O&lt;/strong&gt;: for large-scale and data-heavy applications, with virtually unlimited ability to scale out throughput/IOPS, but with slightly higher latencies. consider this for large scale-out workloads&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The two throughput modes are:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;&lt;strong&gt;Bursting throughput&lt;/strong&gt;: recommended for the majority of workload. Since file system workload is typically spiky, aws use credit system to determine when the file system throughput can burst. credit accumates idle time, and consumed in retrieval&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Provisioned throughput&lt;/strong&gt;: recommended for higher throughput to storage ratio workload, can increase the provisioned throughput afterwards. but it incurs separate throughput charge&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Other ways to achieve higher performance, include parallelization of file operation (e.g. multiple threads, more instances); and increase I/O size for better throughput.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In terms of security, EFS encryption at rest must be selected at the time of file system creation. There is an TLS mount option to encrypt traffic in transit. EFS involves its own resource-based policy called file system policy to manage file-level POSIX permissions. IAM policy is used to manage NFS administration access and client access. EFS &lt;a href="https://docs.aws.amazon.com/efs/latest/ug/efs-access-points.html"&gt;access points&lt;/a&gt; is also a means to enforce the use of a specific operating system user, and group to access EFS.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-s3-simple-storage-service"&gt;S3 (Simple Storage Service)&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;S3 is one of the earliest and maturest AWS services for object storage. It is very cheap and easy to use, and supports user-defined metadata on objects as well as many peripheral features. There is no limit to the number of objects in a bucket. As the object in bucket increases, S3 scales to request rate by automatically creating more partitions to meet the target number of request per partition. There used to be a performance trick, that requires client to make object key naming pattern distribute across multiple prefixes. It is &lt;a href="https://aws.amazon.com/about-aws/whats-new/2018/07/amazon-s3-announces-increased-request-rate-performance/"&gt;not required&lt;/a&gt; any more as of July 2018.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Versioning can be enabled at bucket level, and suspended afterwards. New version of object is created on every upload, without performance penalty. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;S3 integrate well with other event-driven AWS services, such as SNS, SQS, Lambda, etc. Event can fire on request such as PUT, POST, COPY. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Object &lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/dev/object-tagging.html"&gt;tags &lt;/a&gt;(not to be confused with object metadata) can help categorize storage. It also facilitates access control (i.e. by being referenced in bucket policy or IAM policy), lifecycle policy, analysis and CloudWatch configurations.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://aws.amazon.com/s3/features/#s3-select"&gt;S3 select&lt;/a&gt; is a way to retrieve only a subset of data from an object based on a SQL expression, to reduce amount of data and help with performance. The &lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/API/API_SelectObjectContent.html"&gt;input &lt;/a&gt;can be json or CSV and output will be in CSV.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/dev/storage-inventory.html"&gt;S3 Inventory&lt;/a&gt; is a tool to audit object replication status and encryption status. It generates CSV report with all objects in the given bucket name, including: key name, version id, islatest, size, last modified date, etag, storage class, multipart upload flag, delete marker, replication status, encryption status. For storage-class analysis, S3 inventory is much faster than list-object API call which parses through all objects.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;S3 also has &lt;a href="https://aws.amazon.com/s3/features/access-points/"&gt;access point&lt;/a&gt;, similar to EFS, with unique hostnames that customers create to enforce distinct permissions and network controls for any request made through the access point.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;S3 &lt;a href="https://aws.amazon.com/s3/transfer-acceleration/"&gt;transfer acceleration&lt;/a&gt; take advantage of edge locations (at additional charge) to speed up transfer of large object over long distance, by providing a separate end point. It is also helpful for faster uploads over long distances. Apart from transfer acceleration, for faster uploads for large object, user may also consider multi-part upload API when the object reaches 100MB. Orphaned uploaded parts can be cleaned up in lifecycle configuration. For better download performance, take advantage of CloudFront and byte range request.&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/2020/08/java-garbage-collection/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Java Garbage Collection&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2020/08/virtualization-3-of-3-containers/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Virtualization 3 of 4 – Containers&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>Storage Nitty-Gritty 3 of 5 – NAS and Object Storage</title><link>https://static.digihunch.com/2019/07/storage-nitty-gritty-3-of-5-nas-and-object-storage/</link><pubDate>Sat, 13 Jul 2019 23:31:00 -0400</pubDate><guid>https://static.digihunch.com/2019/07/storage-nitty-gritty-3-of-5-nas-and-object-storage/</guid><description>&lt;h4 class="wp-block-heading" id="h-nas-network-attached-storage"&gt;&lt;strong&gt;NAS (network attached storage)&lt;/strong&gt;&lt;/h4&gt;&#10;&lt;p class="wp-block-paragraph"&gt;NAS server is dedicated to file-serving. NAS device runs its own specialized operating system that is optimized for file I/O, integrated hardware and software component that meets specific file-service needs, and performs file I/O better than a general-purpose server. NAS device can serve more clients than general-purpose servers and provide the benefit of server consolidation (centralized storage).&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;NAS uses network and file-sharing protocols to provide access to the file data. These protocols include TCP/IP for data transfer, and Common Internet File System (CIFS) and Network File System (NFS) for network file service.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Network File Sharing&lt;/strong&gt; &amp;#8211; user who creates a file determines the type of access to be given to other user. When multiple users try to access a shared file at the same time, a locking scheme is required to maintain data integrity and, at the same time, make this sharing possible. Examples of file sharing method (FTP, DFS, NFS, CIFS, P2P)&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Components of NAS&lt;/strong&gt; &amp;#8211; NAS head (CPU, memory, NIC, optimized OS, ports, applications that supports CIFS/NFS) and Storage Array&lt;/p&gt;&#10;&lt;div class="wp-block-image"&gt;&#10;&lt;figure class="aligncenter size-large is-resized"&gt;&lt;img loading="lazy" decoding="async" src="https://static.digihunch.com/wp-content/uploads/2019/11/image-42.png" alt="" class="wp-image-379" width="502" height="279"/&gt;&lt;figcaption class="wp-element-caption"&gt;Typical NAS components&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;/div&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;NAS I/O operation&lt;/strong&gt;:&lt;/p&gt;&#10;&lt;ol class="wp-block-list"&gt;&#10;&lt;li&gt;Client packages an I/O request into TCP/IP and forwards it through network stack. NAS head receives this request from network;&lt;/li&gt;&#10;&lt;li&gt;NAS head converts the I/O request into an appropriate physical storage request, which is a block-level I/O, and then performs the operation on the physical storage;&lt;/li&gt;&#10;&lt;li&gt;When NAS head receives data from the storage array, it processes and repackages the data into an appropriate NFS/CIFS response;&lt;/li&gt;&#10;&lt;li&gt;NAS head packages this response into TCP/IP again and forwards it to the client through the network&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;div class="wp-block-image"&gt;&#10;&lt;figure class="aligncenter size-large"&gt;&lt;img loading="lazy" decoding="async" width="1128" height="452" src="https://static.digihunch.com/wp-content/uploads/2019/11/image-43.png" alt="" class="wp-image-380"/&gt;&lt;figcaption class="wp-element-caption"&gt;NAS I/O operation&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;/div&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;NAS implementation&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Unified NAS&lt;/strong&gt; &amp;#8211;&amp;nbsp; consolidate NAS-based and SAN-based data access within a unified storage platform and provides a unified management interface for managing both the environments. &lt;/p&gt;&#10;&lt;div class="wp-block-image"&gt;&#10;&lt;figure class="aligncenter size-large is-resized"&gt;&lt;img loading="lazy" decoding="async" src="https://static.digihunch.com/wp-content/uploads/2019/11/image-44.png" alt="" class="wp-image-381" width="464" height="456"/&gt;&lt;figcaption class="wp-element-caption"&gt;Unified NAS connectivity&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;/div&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Gateway implementation&lt;/strong&gt; &amp;#8211; similar to unified NAS, the storage is shared with other applications that use block-level I/O. The gateway NAS is more scalable compared to unified NAS because NAS heads and storage arrays can be independently scaled up when required. For example, NAS heads can be added to scale up the NAS device performance.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;When the storage limit is reached, it can scale up, adding capacity on the SAN, independent of NAS heads. Similar to a unified NAS, a gateway NAS also enables high utilization of storage capacity by sharing it with the SAN environment.&lt;/p&gt;&#10;&lt;div class="wp-block-image"&gt;&#10;&lt;figure class="aligncenter size-large is-resized"&gt;&lt;img loading="lazy" decoding="async" src="https://static.digihunch.com/wp-content/uploads/2019/11/image-45.png" alt="" class="wp-image-382" width="547" height="366"/&gt;&lt;figcaption class="wp-element-caption"&gt;Gateway NAS connectivity&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;/div&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Scale-out NAS&lt;/strong&gt; &amp;#8211; enables grouping multiple nodes together to construct a clustered NAS system. A scaled-out NAS provides the capability to scale its resources by simply adding nodes to a clustered NAS architecture. The cluster works as a single NAS device and is managed centrally. Scaled-out NAS creates a single file system that runs on all nodes in the cluster. All information is shared among nodes, so the entire file system is accessible by clients connecting to any node in the cluster. Scale-out NAS stripes data across all nodes in a cluster along with mirror or parity protection. As data is sent from clients to the cluster, the data is divided and allocated to different nodes in parallel. When a client sends a request to read a file, the scale-out NAS retrieves the appropriate blocks from multiple nodes, recombines the blocks into a file, and presents the file to the client. As nodes are added, the file system grows dynamically and data is evenly distributed to every node. Each node added to the cluster increases the aggregate storage, memory, CPU, and network capacity. Hence, cluster performance also increases.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Scale-out NAS use separate internal and external networks for back-end and front-end connectivity, respectively. The internal network offers high throughput and low-latency and uses high-speed networking technology, such as InfiniBand or Gigabit Ethernet.&lt;/p&gt;&#10;&lt;div class="wp-block-image"&gt;&#10;&lt;figure class="aligncenter size-large is-resized"&gt;&lt;img loading="lazy" decoding="async" src="https://static.digihunch.com/wp-content/uploads/2019/11/image-46.png" alt="" class="wp-image-383" width="475" height="247"/&gt;&lt;figcaption class="wp-element-caption"&gt;Scale-out NAS with dual internal and single external networks&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;/div&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;NFS protocol &lt;/strong&gt;&amp;#8211; originally based on UDP, uses RPC as a method of inter-process communication between two computers. NFS provides a set of RPCS to access remote file system for the following operations:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;Searching files and directories&lt;/li&gt;&#10;&lt;li&gt;Opening, reading, writing to and closing a file&lt;/li&gt;&#10;&lt;li&gt;Changing file attributes&lt;/li&gt;&#10;&lt;li&gt;Modifying file links and directories&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;NFSv3&lt;/strong&gt; and earlier is stateless protocol. Each call provides a full set of arguments to access files on the server. NFSv3 is most commonly used version, based on UDP or TCP.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;NFSv4&lt;/strong&gt; uses TCP and is based on stateful protocol design.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;CIFS&lt;/strong&gt; &amp;#8211; a public, or open variation of SMB protocol. Filenames in CIFS are encoded using unicode characters. It is stateful protocol because the server maintain connection information regarding every connected client. If a network failure or CIFS server failure occurs, the client receives a disconnection notification. If application has embedded intelligence to restore the connection, then the storage solution is fault tolerant. If the embedded intelligence is missing, the user must take steps to reestablish the CIFS connection.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;NAS Performance&lt;/strong&gt; &amp;#8211; network congestion is one of the most significant sources of latency in NAS environment. Other factors&lt;/p&gt;&#10;&lt;ol class="wp-block-list"&gt;&#10;&lt;li&gt;number of hops&lt;/li&gt;&#10;&lt;li&gt;authentication with AD&lt;/li&gt;&#10;&lt;li&gt;Retransmission &amp;#8211; speed and duplex settings on the network devices and NAS heads must match&lt;/li&gt;&#10;&lt;li&gt;Over-utilized routers and switches&lt;/li&gt;&#10;&lt;li&gt;File system lookup and metadata request &amp;#8211; deep directory structure could cause delay.&lt;/li&gt;&#10;&lt;li&gt;&lt;span style="text-decoration: underline;"&gt;Over-utilized NAS devices&lt;/span&gt; &amp;#8211; client accessing multiple files can cause high utilization levels on a NAS device&lt;/li&gt;&#10;&lt;li&gt;&lt;span style="text-decoration: underline;"&gt;Over-utilized clients&lt;/span&gt; &amp;#8211; if a client is busy itself, it requires a longer time to process the request and responses.&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;div class="wp-block-image"&gt;&#10;&lt;figure class="aligncenter size-large"&gt;&lt;img loading="lazy" decoding="async" width="988" height="664" src="https://static.digihunch.com/wp-content/uploads/2019/11/image-47.png" alt="" class="wp-image-385"/&gt;&lt;figcaption class="wp-element-caption"&gt;NAS latency&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;/div&gt;&#10;&lt;p class="wp-block-paragraph"&gt;NFS server manages privilege and does not require username and password from the client at the time of mounting. CIFS share does require username and password.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Common network optimization practices&lt;/strong&gt; for network contestion:&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;A &lt;span style="text-decoration: underline;"&gt;VLAN&lt;/span&gt; is a logical segment of a switched network or logical grouping of end devices connected to different physical networks. The segmentation or grouping can be done based on business functions, project teams, or applications. VLAN is a Layer 2 (data link layer) construct and works similar to a physical LAN. A network switch can be logically divided among multiple VLANs, enabling better utilization of the switch and reducing overall cost of deploying a network infrastructure.&amp;nbsp;&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The broadcast traffic on one VLAN is not transmitted outside that VLAN, which substantially reduces the broadcast overhead, makes bandwidth available for applications, and reduces the network&amp;#8217;s vulnerability to broadcast storms.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;span style="text-decoration: underline;"&gt;MTU&lt;/span&gt; setting determines the size of the largest packet that can be transmitted without data fragmentation. &lt;span style="text-decoration: underline;"&gt;Path maximum transmission&lt;/span&gt; unit discovery is the process of discovering the maximum size of a packet that can be sent across a network without fragmentation. The default MTU setting for an Ethernet interface card is 1,500 bytes. A feature called &lt;span style="text-decoration: underline;"&gt;jumbo frames&lt;/span&gt; sends, receives or transports Ethernet frames with an MTU of more than 1,500 bytes. The most common deployments of jumbo frames have an MTU of 9,000 bytes. However, not all vendors use the same MTU size for jumbo frames. Servers send and receive larger frames more efficiently than smaller ones in heavy network traffic conditions. Jumbo frames ensure increased efficiency because it takes fewer, larger frames to transfer the same amount of data. Larger packets also reduce the amount of raw network bandwidth being consumed for the same amount of payload. Larger frames also help to smooth sudden I/O burst.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The &lt;span style="text-decoration: underline;"&gt;TCP window size&lt;/span&gt; is the maximum amount of data that can be sent at any time for a connection. For example, if a pair of hosts is talking over a TCP connection that has a TCP windows size of 64KB, the sender can send only 64KB of data and must then wait for an acknowledgement from the receiver. If the receiver acknowledges that all the data has been received, then the sender is free to send another 64 KB of data. If the sender receives an acknowledgment from the receiver that only the first 32 KB of data has been received, which can happen only if another 32 KB of data is in transit or was lost, the sender can send only another 32 KB of data because the transmission cannot have more than 64 KB of unacknowledged data outstanding.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In theory, the TCP window size should be set to the product of the available bandwidth of the network and the round-trip time of data sent over the network. For example, if a network has a bandwidth of 100 Mbps and the round-trip time is 5 milliseconds, the TCP window should be as follows:&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;100 Mb/s x .005 seconds = 524,288 bits or 65,536 bytes&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The size of the TCP window fi eld that controls the fl ow of data is between 2 bytes and 65,535 bytes&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;span style="text-decoration: underline;"&gt;Link aggregation&lt;/span&gt; is the process of combining two or more network interfaces into a logical network interface, enabling higher throughput, load sharing or load balancing, transparent path failover, and scalability. Due to link aggregation, multiple active Ethernet connections to the same switch appear as one link. If a connection or a port in the aggregation is lost, then all the network traffic on that link is redistributed across the remaining active connections.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;File-level virtualization&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;File-level virtualization eliminates the dependencies between the data accessed at the file level and the location where the files are physically stored. Implementation of file-level virtualization is common in NAS or file-server environments. It provides non-disruptive file mobility to optimize storage utilization.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;It provides user or application independence from the location where the files are stored. File-level virtualization creates a logical pool of storage, enabling users to use a logical path, rather than a physical path, to access files. While the files are being moved, clients can access their files non-disruptively. Clients can also read their files from the old location and write them back to the new location without realizing that the physical location has changed. A global namespace is used to map the logical path of a file to the physical path names.&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-large"&gt;&lt;img loading="lazy" decoding="async" width="1114" height="682" src="https://static.digihunch.com/wp-content/uploads/2019/11/image-48.png" alt="" class="wp-image-386"/&gt;&lt;figcaption class="wp-element-caption"&gt;File-serving environment before and after file-level virtualization&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;h4 class="wp-block-heading" id="h-object-based-storage"&gt;&lt;strong&gt;Object-based storage&lt;/strong&gt;&lt;/h4&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In NAS, metadata are stored as part of the file distributed throughout the environment, which adds to the complexity and latency in searching and retrieving files. Object-based storage, on the other hand, stores file data in the form of objects based on its content and other attributes, rather than the name and location.&lt;/p&gt;&#10;&lt;div class="wp-block-image"&gt;&#10;&lt;figure class="aligncenter size-large is-resized"&gt;&lt;img loading="lazy" decoding="async" src="https://static.digihunch.com/wp-content/uploads/2019/11/image-49.png" alt="" class="wp-image-387" width="402" height="240"/&gt;&lt;figcaption class="wp-element-caption"&gt;Hierarchical File System and Flat Address Space&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;/div&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;OSD &amp;#8211; object-based storage devices&lt;/strong&gt;, stores data in the form of objects using flat address space. There is no hierarchy of directories and file. Object is identified by objectID, which is usually generated using hash function.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In block storage, when file system receives the IO from an application, the file system maps the incoming I/O to the disk blocks. The block interface is used for sending the I/O over the channel or network to the storage device. The I/O is then written to the block allocated on the disk drive. When an application accesses data stored in OSD, the request is sent to the file system user component. The file system user component communicates to the OSD interface, which in turn sends the request to the storage device. The storage device has the OSD storage component responsible for managing the access to the object on a storage device.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Benefit of object storage&lt;/strong&gt;&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;security and reliability: OSD can use special algorithm for strong encryption capacity. Request authentication is performed at the storage device rather than with an external authentication mechanism&lt;/li&gt;&#10;&lt;li&gt;platform independence: standard web access via REST or SOAP&lt;/li&gt;&#10;&lt;li&gt;scalability: Both storage and OSD nodes can be scaled independently in terms of performance and capacity&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="wp-block-image"&gt;&#10;&lt;figure class="aligncenter size-large is-resized"&gt;&lt;img loading="lazy" decoding="async" src="https://static.digihunch.com/wp-content/uploads/2019/11/image-50.png" alt="" class="wp-image-388" width="401" height="445"/&gt;&lt;figcaption class="wp-element-caption"&gt;Block-level access vs object-level access&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;/div&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;OSD components&lt;/strong&gt;:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;nodes: a server with OSD operating environment to provide services to store, retrieve and manage data. Two key services are metadata service (generating objectID and maintaining the mapping between objectID and file) and storage service (manage a set of disks where data are stored).&lt;/li&gt;&#10;&lt;li&gt;private network: provides node-to-node connectivity and node-to-storage connectivity.&lt;/li&gt;&#10;&lt;li&gt;storage device&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="wp-block-image"&gt;&#10;&lt;figure class="aligncenter size-large is-resized"&gt;&lt;img loading="lazy" decoding="async" src="https://static.digihunch.com/wp-content/uploads/2019/11/image-51.png" alt="" class="wp-image-389" width="518" height="166"/&gt;&lt;figcaption class="wp-element-caption"&gt;OSD system components&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;/div&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Storage mechanism&lt;/strong&gt;&lt;/p&gt;&#10;&lt;ol class="wp-block-list"&gt;&#10;&lt;li&gt;The application server presents the file to be stored to the OSD node.&lt;/li&gt;&#10;&lt;li&gt;The OSD node divides the file into two parts: user data and metadata.&lt;/li&gt;&#10;&lt;li&gt;The OSD node generates the object ID using a specialized algorithm. The algorithm is executed against the contents of the user data to derive an ID unique to this data.&lt;/li&gt;&#10;&lt;li&gt;For future access, the OSD node stores the metadata and object ID using the metadata service.&lt;/li&gt;&#10;&lt;li&gt;The OSD node stores the user data (objects) in the storage device using the storage service.&lt;/li&gt;&#10;&lt;li&gt;An acknowledgment is sent to the application server stating that the object is stored.&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;div class="wp-block-image"&gt;&#10;&lt;figure class="aligncenter size-large is-resized"&gt;&lt;img loading="lazy" decoding="async" src="https://static.digihunch.com/wp-content/uploads/2019/11/image-52.png" alt="" class="wp-image-390" width="512" height="334"/&gt;&lt;figcaption class="wp-element-caption"&gt;OSD: object storage&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;/div&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Retrieval mechanism&lt;/strong&gt;&lt;/p&gt;&#10;&lt;ol class="wp-block-list"&gt;&#10;&lt;li&gt;The application server sends a read request to the OSD system.&lt;/li&gt;&#10;&lt;li&gt;The metadata service retrieves the object ID for the requested file.&lt;/li&gt;&#10;&lt;li&gt;The metadata service sends the object ID to the application server.&lt;/li&gt;&#10;&lt;li&gt;The application server sends the object ID to the OSD storage service for object retrieval.&lt;/li&gt;&#10;&lt;li&gt;The OSD storage service retrieves the object from the storage device.&lt;/li&gt;&#10;&lt;li&gt;The OSD storage service sends the file to the application server.&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;div class="wp-block-image"&gt;&#10;&lt;figure class="aligncenter size-large is-resized"&gt;&lt;img loading="lazy" decoding="async" src="https://static.digihunch.com/wp-content/uploads/2019/11/image-53.png" alt="" class="wp-image-391" width="525" height="291"/&gt;&lt;figcaption class="wp-element-caption"&gt;OSD object retrieval&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;/div&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;OSD usage&lt;/strong&gt;: data archival, especially long-term; and cloud storage, storage as service&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;CAS &amp;#8211; content addressed storage&lt;/strong&gt;, a special type of OSD designed for secure online storage and retrieval of fixed content. Data access in CAS differs from other OSD devices. &lt;span style="text-decoration: underline;"&gt;In CAS, the application server access the CAS device only via the CAS API running on the application server&lt;/span&gt;. However, the way CAS stores data is similar to the other OSD systems.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;CAS&lt;/strong&gt; &lt;strong&gt;Use case &lt;/strong&gt;&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;Healthcare: storing patient studies &amp;#8211; size of radiology study ranges from 15MB to more than 1GB. Newly acquired studies are retained for 60 days and moved to long term storage.&lt;/li&gt;&#10;&lt;li&gt;Finance: storing financial records &amp;#8211; bank stores images of cheques (~25KB each) for about 90 millions a month. Images are processed in transaction system for 5 days. For the next 60 days images are requested for verifications. After 60 days access requirements drop drastically. Retention policy manages life-cycle of the images.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Unified storage&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Components&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;storage controller: The storage controller provides block-level access to application servers through iSCSI, FC, or FCoE protocols.&lt;/li&gt;&#10;&lt;li&gt;NAS head: a dedicated file server that provides file access to NAS clients&lt;/li&gt;&#10;&lt;li&gt;OSD node: accesses the storage through the storage controller using a FC or FCoE connection.&lt;/li&gt;&#10;&lt;li&gt;Storage&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div class="wp-block-image"&gt;&#10;&lt;figure class="aligncenter size-large is-resized"&gt;&lt;img loading="lazy" decoding="async" src="https://static.digihunch.com/wp-content/uploads/2019/11/image-54.png" alt="" class="wp-image-392" width="459" height="533"/&gt;&lt;figcaption class="wp-element-caption"&gt;Unified storage platform&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;/div&gt;&#10;&lt;h4 class="wp-block-heading" id="h-related-postings"&gt;Related Postings&lt;/h4&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;&lt;a href="https://static.digihunch.com/2019/03/storage-nitty-gritty-1-5/"&gt;Disk and RAID&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://static.digihunch.com/2019/05/storage-nitty-gritty-2-5/"&gt;SAN&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://static.digihunch.com/2019/07/storage-nitty-gritty-3-of-5-nas-and-object-storage/"&gt;Backup and Archive Solutions&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://static.digihunch.com/2019/11/storage-nitty-gritty-5-of-5-replication/"&gt;Replication&lt;/a&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;nav class="wp-post-navigation" aria-label="Post navigation"&gt;&#10;&lt;a rel="prev" href="https://static.digihunch.com/2019/07/practical-cryptography-for-it-professional/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Cryptography Basics 1 of 2&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2019/08/aws-certified-devops-engineer-exam-tips/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;AWS Certified DevOps Engineer Exam Tips&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item></channel></rss>