DEV Community

Cover image for Configuration and Storage in Kubernetes
Arsh Sharma for Okteto

Posted on • Originally published at

Configuration and Storage in Kubernetes

Hello fellow developers! By this point in the series, I hope you’re now much less scared of Kubernetes. So far we’ve explored its architecture, some essential K8s objects, and even deployed an app on a Kubernetes cluster using Okteto! Pat yourselves on the back for making it till here :)

In this article, we’ll first look at two somewhat similar Kubernetes objects which help with providing configuration to our application running in the cluster - ConfigMaps and Secrets. Then we’ll move on to look at how storage is handled in Kubernetes using Volumes and Persistent Volumes. So strap on and let’s get started!

ConfigMaps and Secrets

To inject configuration data into a container, Kubernetes provides us with two objects: ConfigMaps and Secrets. It is highly recommended to separate configuration data from your application code so you’ll see these two objects being used in almost all Kubernetes clusters.

If you see the YAML for a ConfigMap or a Secret you’ll notice that both of them are almost similar. They both have a data key under which the configuration data is provided in key-value pairs. For example,

  key1: value1
  key2: value2
Enter fullscreen mode Exit fullscreen mode

The difference is in the fact that secrets are meant for holding sensitive data. When writing the YAML for a secret we wouldn’t specify value1 and value2 directly like we would for ConfigMaps. Instead, we would specify the base64 encoded versions of these values.

Pods can refer to a particular ConfigMap and/or Secret and specify a key and then they would have an environment variable in their container with the corresponding value. This would enable you to refer to these environment variables in your application code.

For the movies app which we deployed, our api pod needed the credentials for the MongoDB database in order to connect to it. We provided these using a secret. If you see the YAML for the api deployment you’ll see that we’re getting an environment variable called MONGODB_PASSWORD for our container from a secret called mongodb.

Secret being used in pod

If you want to see how the YAML for this secret looks, head over to the terminal and run:

kubectl get secret mongodb -o yaml
Enter fullscreen mode Exit fullscreen mode

The -o yaml flag gets the YAML for a particular Kubernetes object. You’ll see that under the data key for the returned object, we have the mongodb-password key which we were referring to in our api deployment. To see the actual value for this key you’ll have to decode the base64 encoded value shown.

Now that you have an idea of how configuration data is handled in Kubernetes clusters, let’s move on and take a look at how data is shared between K8s objects using Volumes and Persistent Volumes.

Storage in Kubernetes

If you recall, in the second article I mentioned that Pods are meant to be ephemeral. This means that any data generated by containers running in the Pod also gets destroyed when the pod is destroyed. In Kubernetes, Volumes and Persistent Volumes help us solve this problem of data loss. Apart from this they also solve another problem - sharing of data between different containers.


There are a lot of volume types offered by Kubernetes. But thankfully as developers we mostly never have to worry about all this stuff. In this section, we’ll just cover a common volume type which you might run into - emptyDir.

The emptyDir type has two important use cases. The first is that it allows us to share data between two containers running in the same pod. The second is that if our container ever crashes, it enables us to still retain all the data created previously. Do note that this volume only exists as long as the Pod is running. So if your pod is destroyed for any reason, you WILL lose all the data. Let’s look at how volumes are configured for Pods:

apiVersion: v1
kind: Pod
  name: my-pod
  - name: cache-volume
    emptyDir: {}
  - image: nginx
    name: my-container
    - mountPath: /cache
      name: cache-volume
Enter fullscreen mode Exit fullscreen mode

Under the Pod spec we first define our volumes in a list - in the above example we have one volume called cache-volume which is of type emptyDir. Then while specifying our containers we refer to this volume under volumeMounts. mountPath is where in the filesystem of the container the data from the volume should be loaded into.

Persistent Volumes

We just learned that emptyDir volumes won’t save our data if our Pod goes down. So you must be wondering how does one store data which persists regardless of any changes to the Pod. This is where Persistent Volumes come to save the day.

A Persistent Volume (PV) is a cluster level storage object. What this means is that just like nodes, it too is a resource present in the cluster. It is an administrator’s job to provision this so don’t worry too much about how it’s created. However, what we as developers should be familiar with is how to use this provisioned storage.

To use a Persistent Volume, we create a Persistent Volume Claim (PVC) object and then refer to this claim under the volumes key of the Pod YAML like we saw above. A PVC is nothing but a request for storage. This is how a basic PVC object would look like:

apiVersion: v1
kind: PersistentVolumeClaim
  name: pv-claim
    - ReadWriteOnce
      storage: 3Gi
Enter fullscreen mode Exit fullscreen mode

Once you create this PVC, the Kubernetes control plane will bind this claim to a suitable persistent volume for you. The above YAML should be pretty simple to understand, we’re requesting 3 Gigabyte of storage with the access mode of ReadWriteOnce. What this means is that the volume can be mounted as a read-write storage but only by a single node.

After you create the PVC, all that you need to do is refer to it in your Pod’s YAML as we did for emptyDir above.

    - name: pv-storage
        claimName: pv-claim
Enter fullscreen mode Exit fullscreen mode

And voilà! You now have a persistent storage solution for your application. Okteto gives you the ability to do a lot more with volumes including creating a data clone of your application's database and using it with your development environment. You can read up more on how to do that here.

This concludes our discussion on configuration and storage in Kubernetes. We started by taking a look at ConfigMaps and Secrets and saw how they help provide us configuration data to our application. Then we looked at how we can leverage Volumes to safeguard our application data in case our container restarts. Finally, we looked at Persistent Volumes which provide us a way to persist data in a separate resource present in the cluster - thus ensuring that even Pod deletion doesn't lead to a loss of data.

All of this does look intimidating at first but remember that you don’t have to fight these battles alone as a developer. If you’re using a managed Kubernetes environment like Okteto, most of this is already taken care of for you. If not, even then, you should be receiving support from the infra team. But like I said earlier, even as a developer it is good to have an idea of things so you’re not totally lost! In the final article of this series, we’ll be taking a look at how networking works in Kubernetes so make sure to keep an eye out for that one! :D

The "Kubernetes for Developers" blog series has now concluded, and you can find all the posts in this series here.

Discussion (0)