I am new to Kubernetes but familiar with docker.
Docker Use Case
Usually, when I want to persist data I just create a volume with a name then attach it to the container, and even when I stop it then start another one with the same image I can see the data persisting.
So this is what i used to do in docker
docker volume create nginx-storage
run -it --rm -v nginx-storage:/usr/share/nginx/html -p 80:80 nginx:1.14.2
then I:
- Create a new html file in /usr/share/nginx/html
- Stop container
- Run the same docker run command again (will create another container with same volume)
- html file exists (which means data persisted in that volume)
Kubernetes Use Case
Usually, when I work with Kubernetes volumes I specify a PVC (PersistentVolumeClaim) and PV (PersistentVolume) using hostPath which will bind mount directory or a file from the host machine to the container.
what I want to do is reproduce the same behavior specified in the previous example (Docker Use Case) so how can I do that? Is Kubernetes creating volumes process is different from Docker? and if possible providing a YAML file would help me understand.
2
Answers
I managed to do that by creating a PVC only this is how I did it (with an Nginx image):
nginx-pvc.yaml
nginx-deployment.yaml
Once I run kubectl apply on the PVC then on the deployment going to
localhost:30080
will show 404 not found page means that all data in the/usr/share/nginx/html
was deleted once the container gets started and that's because it's bind mounting a dir from the k8s cluster node to that container as a volume:I tried adding a new file into that container in the html dir as a new index.html file, then deleted the container, a new container was created by the pod and checking localhost:30080 worked with the newly created home page
I tried deleting the deployment and reapplying it (without deleting the PVC) checked localhost:30080 and everything still persists.
To a first approximation, you can’t (portably) do this. Build your content into the image instead.
There are two big practical problems, especially if you’re running a production-oriented system on a cloud-hosted Kubernetes:
If you look at the list of PersistentVolume types, very few of them can be used in ReadWriteMany mode. It’s very easy to get, say, an AWSElasticBlockStore volume that can only be used on one node at a time, and something like this will probably be the default cluster setup. That means you’ll have trouble running multiple pod replicas serving the same (static) data.
Once you do get a volume, it’s very hard to edit its contents. Consider the aforementioned EBS volume: you can’t edit it without being logged into the node on which it’s mounted, which means finding the node, convincing your security team that you can have root access over your entire cluster, enabling remote logins, and then editing the file. That’s not something that’s actually possible in most non-developer Kubernetes setups.
The thing you should do instead is build your static content into a custom image. An image registry of some sort is all but required to run Kubernetes and you can push this static content server into the same registry as your application code.
Then in your deployment spec, set
image: registry.example.com/nginx-frontend:20220209
or whatever you’ve chosen to name this build of this image, and do not use volumes at all. You’d deploy this the same way you deploy other parts of your application; you could use Helm or Kustomize to simplify the update process.Correspondingly, in the plain-Docker case, I’d avoid volumes here. You don’t discuss how files get into the
nginx-storage
named volume; if you’re using imperative commands likedocker cp
or debugging tools likedocker exec
, those approaches are hard to script and are intrinsically local to the system they’re running on. It’s not easy to copy a Docker volume from one place to another. Images, though, can be pushed and pulled through a registry.