Expose folder from a container as a volume in a Kubernetes Pod - docker

I have a pod which contains two containers. One container is a web application and another store some static data for this web application.
The data here is a set of files which are stored in the folder of this container with name /data and that's only function of the container to store this data and expose them to the web application.
I'm looking for the way to share the content of this folder with web application container in this pod.
If I'm using the YAML spec below the folder in both containers is empty. Is there a way to share the data from container folder without cleaning it up?
apiVersion: v1
kind: Pod
metadata:
name: my-pod
labels:
app: my-app
version: 1.2.3
spec:
volumes:
- name: my-app-data-volume
containers:
- name: my-app-server
image: my-app-server-container-name
volumeMounts:
- name: my-app-data-volume
mountPath: /data
ports:
- containerPort: 8080
- name: my-app-data
image: my-app-data-container-name
volumeMounts:
- name: my-app-data-volume
mountPath: /data

You can use an EmptyDir volume for this. Specify the container that contains the files as an initContainer, then copy the files into the EmptyDir volume. Finally, mount that volume in the web app container.

Related

mountPath property in the Volume Kubernetes

I am learning about Volumes in the Kubernetes.
I understood the concept of Volume and types of volume.
But, I am confused about the mouthPath property. Following my YAML file:
apiVersion: v1
kind: Pod
metadata:
name: nginx-alpine-volume
spec:
containers:
- name: nginx
image: nginx:alpine
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html
readOnly: true
resources:
- name: html-updater
image: alpine
command: ["/bin/sh", "-c"]
args:
- while true; do date >> /mohit/index.html;sleep 10; done
resources:
volumeMounts:
- name: html
mountPath: /mohit
volumes:
- name: html
emptyDir: {}
Question: What is the use of the mountPath property. Here, I am using one pod with two containers. Both containers have different mounPath values.
Update:
Consider the mount path as the directory where you are attaching or mounting the files or system
While your actual volume is emptyDir
What basically the idea is there to both container have different mount path
as both containers need to use different folders
While as your volume is single name html so locally from volume both container pointing or using the different folders
both containers manage the different files at their mounting point (or folder)
so mount path is a point or directly where your container will be managing files.
Empty dir : https://kubernetes.io/docs/concepts/storage/volumes/#emptydir
Read more at : https://kubernetes.io/docs/tasks/access-application-cluster/communicate-containers-same-pod-shared-volume/
if you see this example: https://github.com/harsh4870/Kubernetes-wordpress-php-fpm-nginx/blob/master/wordpress-deployment.yaml
it has the same two containers with mount path and emptydir volume
what i am doing is attaching the Nginx configuration file, to the container so Nginx will use that configuration file which i am mounting from outside to the container.
My config file stored inside configmap or secret.

K8s doesn't mount files on Persistent Volume

I have a Docker image and I'd like to share an entire directory on a volume (a Persistent Volume) on Kubernetes.
Dockerfile
FROM node:carbon
WORKDIR /node-test
COPY hello.md /node-test/hello.md
VOLUME /node-test
CMD ["tail", "-f", "/dev/null"]
Basically it copies a file hello.md and makes it part of the image (lets call it my-image).
On the Kubernetes deployment config I create a container from my-image and I share a specific directory to a volume.
Kubernetes deployment
# ...
spec:
containers:
- image: my-user/my-image:v0.0.1
name: node
volumeMounts:
- name: node-volume
mountPath: /node-test
volumes:
- name: node-volume
persistentVolumeClaim:
claimName: node-volume-claim
I'd expect to see the hello.md file in the directory of the persistent volume, but nothing shows up.
If I don't bind the container to a volume I can see the hello.md file (with kubectl exec -it my-container bash).
I'm not doing anything different from what this official Kubernetes example does. As matter of fact I can change mountPath and switch to the official Wordpress image and it works as expected.
How can Wordpress image copy all files into the volume directory?
What's in the Wordpress Dockerfile that is missing on mine?
In order not to overwrite the existing files/content, you can use subpath to mount the testdir directory (In the example below) in the existing Container file system.
volumeMounts:
- name: node-volume
mountPath: /node-test/testdir
subPath: testdir
volumes:
- name: node-volume
persistentVolumeClaim:
claimName: node-volume-claim
you can find for more information here using-subpath

How to copy home directory file into new persistent volume with Kubernetes?

I've got a JupyterHub Kubernetes deployment.
When I create and attach a persistent volume (PV) it wipes out the home directory that is part of my image. It replaces it with an empty home directory where anything is written will be persisted as expected (that is fine).
How can I get the files from my image's home folder into the PV home folder?
Here is an example from the docs that unfortunately seems to only copy from the new PV (not the image):
singleuser:
lifecycleHooks:
postStart:
exec:
command: ["cp", "-a", "src", "target"]
Here is my singleuser configuration:
singleuser:
image:
name: myimage
tag: latest
pullPolicy: Always
storage:
capacity: 10Gi
dynamic:
storageClass: standard
The above should work fine.
You are probably mounting the PV on your home directory that is the same home directory of the container. You can either mount the PV on a different directory and do the copy or create a new image where your data is not stored in your home directory. This is an example of how to use mountPath:
apiVersion: v1
kind: Pod
metadata:
name: jypyterhuyb
namespace: default
spec:
volumes:
- name: myvol
...
containers:
- name: jypyter
image: "jypytercontainer"
volumeMounts:
- name: myvol
mountPath: /mnt/mypath

kubernetes: how to write pod yaml file for mapping volumn from host to container

I have a command to run docker,
docker run --name pre-core -itdp 8086:80 -v /opt/docker/datalook-pre-core:/usr/application app
In above command, /opt/docker/datalook-pre-core is host directory, /usr/application is container directory. The purpose is that container directory maps to host directory. So when container crashes, the directory functions as storage and data on it would be saved.
When I am going to use kubernetes to create a pod for this containter, how to write pod.yaml file?
I guess it is something like following:
apiVersion: v1
kind: Pod
metadata:
name: app-ykt
labels:
app: app-ykt
purpose: ykt_production
spec:
containers:
- name: app-ykt
image: app
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
volumnMounts:
- name: volumn-app-ykt
mountPath: /usr/application
volumns:
- name: volumn-app-ykt
????
I do not know what's the exact properties in yaml I shall write in my case?
This would be a hostPath volume: https://kubernetes.io/docs/concepts/storage/volumes/
volumes:
- name: volumn-app-ykt
hostPath:
# directory location on host
path: /opt/docker/datalook-pre-core
# this field is optional
type: Directory
However remember that while a container crash won't move things, other events can cause a pod to move to a different host so you need to be prepared to both deal with cold caches and to clean up orphaned caches.

How to mimic '--volumes-from' in Kubernetes

I'm looking for a pattern that allows to share volumes between two containers running on the same pod in Kubernetes.
My use case is:
I have a Ruby on Rails application running inside a docker container.
The docker image contains static assets in /app/<app-name>/public directory, and I need to access those assets from the nginx container running alongside in the same pod.
In 'vanilla' docker I would have used --volumes-from flag to share this directory:
docker run --name app -v /app/<app-dir>/public <app-image>
docker run --volumes-from app nginx
After reading this doc: https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/volumes.md
I tried this (only relevant entries presented):
spec:
containers:
- image: <app-image>
name: <app-name>
volumeMounts:
- mountPath: /app/<app-name>/public
name: assets
- image: nginx
name: nginx
volumeMounts:
- mountPath: /var/www/html
name: assets
readOnly: true
volumes:
- name: assets
hostPath:
path: /tmp/assets
But:
Even though /tmp/assets on the node exists, it's empty
/app/<app-name>/public inside the app container is also empty
As a workaround I'm gonna try to populate the shared directory when the application container is up (simply cp /app/<app-name>/public/* to shared directory), but I really dislike this idea.
Question: how to mimic --volumes-from in Kubernetes, or if there is no direct counterpart, how can I share files from one container to other running in the same pod ?
apiVersion: v1beta3
Client Version: version.Info{Major:"0", Minor:"17", GitVersion:"v0.17.0", GitCommit:"82f8bdac06ddfacf493a9ed0fedc85f5ea62ebd5", GitTreeState:"clean"}
Server Version: version.Info{Major:"0", Minor:"17", GitVersion:"v0.17.0", GitCommit:"82f8bdac06ddfacf493a9ed0fedc85f5ea62ebd5", GitTreeState:"clean"}
[update-2016-8] In latest Kubernetes release, you can use a very nice feature named init-container to replace the postStart part in my answer below, which will make sure the container order.
apiVersion: v1
kind: Pod
metadata:
name: javaweb-2
spec:
initContainers:
- name: war
image: resouer/sample:v2
command: ["cp", "/sample.war", "/app"]
volumeMounts:
- mountPath: /app
name: app-volume
containers:
- name: tomcat
image: resouer/mytomcat:7.0
command: ["sh","-c","/root/apache-tomcat-7.0.42-v2/bin/start.sh"]
volumeMounts:
- mountPath: /root/apache-tomcat-7.0.42-v2/webapps
name: app-volume
ports:
- containerPort: 8080
hostPort: 8001
volumes:
- name: app-volume
emptyDir: {}
NOTE: initContainer is still a beta feature so the work version of this yaml is actually like: http://kubernetes.io/docs/user-guide/production-pods/#handling-initialization, please notice the pod.beta.kubernetes.io/init-containers part.
---original answer begin---
Actually, you can. You need to use container life cycle handler to control what files/dirs you want to share with other containers. Like:
---
apiVersion: v1
kind: Pod
metadata:
name: server
spec:
restartPolicy: OnFailure
containers:
- image: resouer/sample:v2
name: war
lifecycle:
postStart:
exec:
command:
- "cp"
- "/sample.war"
- "/app"
volumeMounts:
- mountPath: /app
name: hostv1
- name: peer
image: busybox
command: ["tail", "-f", "/dev/null"]
volumeMounts:
- name: hostv2
mountPath: /app/sample.war
volumes:
- name: hostv1
hostPath:
path: /tmp
- name: hostv2
hostPath:
path: /tmp/sample.war
Please check my gist for more details:
https://gist.github.com/resouer/378bcdaef1d9601ed6aa
And of course you can use emptyDir. Thus, war container can share its /sample.war to peer container without mess peer's /app directory.
If we can tolerate /app been overridden, it will be much simpler:
---
apiVersion: v1
kind: Pod
metadata:
name: javaweb-2
spec:
restartPolicy: OnFailure
containers:
- image: resouer/sample:v2
name: war
lifecycle:
postStart:
exec:
command:
- "cp"
- "/sample.war"
- "/app"
volumeMounts:
- mountPath: /app
name: app-volume
- image: resouer/mytomcat:7.0
name: tomcat
command: ["sh","-c","/root/apache-tomcat-7.0.42-v2/bin/start.sh"]
volumeMounts:
- mountPath: /root/apache-tomcat-7.0.42-v2/webapps
name: app-volume
ports:
- containerPort: 8080
hostPort: 8001
volumes:
- name: app-volume
emptyDir: {}
The answer is - for now - you can't. Here's a couple of discussion threads from the Kubernetes issues:
https://github.com/GoogleCloudPlatform/kubernetes/issues/6120
https://github.com/GoogleCloudPlatform/kubernetes/issues/831
However, may I suggest that you have an alternate design that might work better?
If your assets are locked at the point of the container going live,
you could use something like gitRepo
volume which would copy it to an emptyDir at the point of going live, and would mean you wouldn't have to move the content around at
all, just download it directly to the shared directory.
If your assets are locked at the point of the container
being built, it's probably best to copy them in at that point, using
the Docker COPY command.
If you really want to stick with the way you're doing it, you would have to copy the content to the emptyDir volume, which is designed for exactly what you're looking for (minus the lack of having to copy it in).
NFS[1] volumes also could solve your problem, but may be overly complex.
Additionally, I'd recommend that these two services exist in different pods, so you can scale each separately. You can create a service endpoint to communicate between them if you need to.
[1] https://github.com/GoogleCloudPlatform/kubernetes/blob/master/examples/nfs/nfs-web-pod.yaml
Further update from the future:
There is now a FlexVol plugin for Docker volumes: https://github.com/dims/docker-flexvol
At the time of writing, FlexVol is still an alpha feature though, so caveat emptor.
Kubernetes has its own volume types and these are most used volume type:
emptyDir
secret
gitRepo
hostPath (similar to --volumes-from)
config Maps
persistent storage (storage disks provided by cloud platforms)
You can find more about kubernets volumes here -https://kubernetes.io/docs/concepts/storage/volumes/
an example of hostpath volume :
apiVersion: v1
kind: Pod
metadata:
name: test-pd
spec:
containers:
- image: k8s.gcr.io/test-webserver
name: test-container
volumeMounts:
- mountPath: /test-pd
name: test-volume
volumes:
- name: test-volume
hostPath:
# directory location on host
path: /data
# this field is optional
type: Directory
hostpath will mount host/node directory to container directory.Multiple containers inside a pod can use different or same volumes.You need to mention it in each container.
hostPath volumes are independent of pod lifecycle but it create tight coupling between node and pod , you should avoid using hostPath.
If you are using Docker v17.0.5 or greater you can use a multi-stage build to copy files from one of your containers to the other during build time. This is a great primer on the advanced features at https://medium.com/#tonistiigi/advanced-multi-stage-build-patterns-6f741b852fae
The way I used it to copy static assets from my backend container into Nginx proxy is
ARG API_BACKEND_CONTAINER="api:backend"
FROM $API_BACKEND_CONTAINER as source
FROM nginx:mainline-alpine
ARG NGINX_ROOT=/usr/share/nginx/html/
COPY --from=source /var/share/api/static/ ${NGINX_ROOT}
The great thing is that because the API_BACKEND_CONTAINER is a build arg I'm able to pass in the tag of the latest API build.

Resources