Can I share a single file between containers in a pod? - kubernetes

My pod has two containers - a primary container, and a sidecar container that monitors the /var/run/utmp file in the primary container and takes action when it changes. I'm trying to figure out how to make this file visible in the sidecar container.
This page describes how to use an emptyDir volume to share directories between containers in a pod. However, this only seems to work for directories, not single files. I also can't use this strategy to share the entire /var/run/ directory in the primary container, since mounting a volume there erases the contents of the directory, which the container needs to run.
I tried to work around this by creating a symlink to utmp in another directory and mounting that directory, but it doesn't look like symlinks in volumes are resolved in the way they would need to be for this to work.
Is there any way I can make one file in a container visible to other containers in the same pod? The manifest I'm experimenting with looks like this:
apiVersion: v1
kind: Pod
metadata:
name: utmp-demo
spec:
restartPolicy: Never
containers:
- name: main
image: debian
command: ["/bin/bash"]
args: ["-c", "sleep infinity"]
volumeMounts:
- name: main-run
mountPath: /var/run # or /var/run/utmp, which crashes
- name: helper
image: debian
command: ["/bin/bash"]
args: ["-c", "sleep infinity"]
volumeMounts:
- name: main-run
mountPath: /tmp/main-run
volumes:
- name: main-run
emptyDir: {}

If you can move the file to be shared in an empty subfolder this could be a simple solution.
For example, move your file to /var/run/utmp/utmp and share /var/run/utmp folder with an emptydir.

Related

There's any way, in K8S, to source an env file, dynamically generated during an initcontainer?

I'm planning to have an initcontainer that will handle some crypto stuff and then generate a source file to be sourced by a container.
The source file will be dynamically generated, the VARS will be dynamic, this means I will never know the VAR names or it's contents. This also means I cannot use k8s env.
The file name will always be the same.
I know I can change the Dockerfile from my applications and include an entrypoint to execute a script before running the workload to source the file, but, still, is this the only option?
There's no way to achieve this in k8s?
My container can mount the dir where the file was created by the initcontainer. But it can't, somehow, source the file?
apiVersion: v1
kind: Pod
metadata:
name: pod-init
namespace: default
spec:
nodeSelector:
env: sm
initContainers:
name: genenvfile
image: busybox
imagePullPolicy: Always
command: ["/bin/sh"]
# just an example, there will be a software here that will translate some encrypted stuff into VARS and then append'em to a file
args: ["-c", "echo MYVAR=func > /tmp/sm/filetobesourced"]
volumeMounts:
- mountPath: /tmp/sm
name: tmpdir
containers:
image: gcr.io/google.com/cloudsdktool/cloud-sdk:slim
imagePullPolicy: IfNotPresent
name: mypod-cm
tty: true
volumeMounts:
- mountPath: /tmp/sm
readOnly: true
name: tmpdir
volumes:
name: tmpdir
emptyDir:
medium: Memory
The step-by-step that I'm thinking would be:
initcontainer mounts /tmp/sm and generates a file called /tmp/sm/filetobesourced
container mounts the /tmp/sm
container source the /tmp/sm/filetobesourced
workload runs using all the vars sourced by the last step
Am I missing something to get the third step done?
Change the command and/or args on the main container to be more like bash -c 'source /tmp/sm/filetobesourced && exec whatevertheoriginalcommandwas'.

Mounting /etc/default directory problem with SOLR image

I'm deploying a basic "solr:8.9.0" image to local Kubernetes env.
If I'm trying to mount pod's "/var/solr" directory, it works well.
I can see the files inside /var/solr in the mounted directory.
spec:
containers:
- image: solr:8.6.0
imagePullPolicy: IfNotPresent
name: solr
ports:
- name: solrport
containerPort: 8983
volumeMounts:
- mountPath: /var/solr/
name: solr-volume
volumes:
- name: solr-volume
persistentVolumeClaim:
claimName: solr-pvc
But somehow I can't mount "/etc/default/" directory. That doesn't work.
I knew there are files inside that directory but they are disappearing.
Any idea why?
Thanks!
this is because of how volumeMounts work.
A standard volumeMount mounts the volume in the suplied directory overwriting everything that is inside that directory.
You want to specify a subpath for the data you actually want to mount. By doing this the original contents of the directory won't get overridden.
see here for more information regarding the usage of subpaths.

Unable to access volume content using initContainers

I have a simple image (mdw:1.0.0) with some content in it:
FROM alpine:3.9
COPY /role /mdw
WORKDIR /mdw
I was expecting that my container 'nginx' would see the content of /mdw folder, but there is no file.
apiVersion: v1
kind: Pod
metadata:
name: init-demo
spec:
initContainers:
- name: install
image: mdw:1.0.0
imagePullPolicy: Never
volumeMounts:
- name: workdir
mountPath: "/mdw"
containers:
- name: nginx
image: nginx
volumeMounts:
- name: workdir
mountPath: /mdw
command: ["ls", "-l", "/mdw"]
volumes:
- name: workdir
emptyDir: {}
Do you know what is the reason and how to fix it ?
Thank you very much
When mounting volume if directory already exists will get wiped. It's intentional and no fix really.
Only way would be to populate the directory after mounting is done.
Your init container doesn't do anything: the Dockerfile doesn't have a CMD and the Kubernetes deployment spec doesn't set a command: either. It starts and immediately exits. (The base Linux distribution images generally have a default command to launch an interactive shell, but absent a tty this will also immediately exit.)
Meanwhile, your Kubernetes setup is also mounting an empty directory over the only content you've put into the image, which prevents the init container from having an effect.
You can build a custom nginx image that directly copies the content in:
FROM nginx
COPY /role /usr/share/nginx/html
Don't use initContainers:, and use that image as the main containers: image.
There is a Docker-specific feature, using Docker named volumes, that can populate a named volume on first use, and you're probably thinking of this feature. This comes with a couple of important caveats (it only takes effect the very first time you run a container, and ignores updates to the image; it doesn't work with bind mounts). This is a plain-Docker-specific feature: Kubernetes will never auto-populate a volume for you.

stop k8s initContainers volume overwriting container folder

I need to download files into a specific folder of a container on a pod, at startup. The image for this container already has an existing folder with other files in it. (example is adding plugin jars to an application)
I've attempted the below example, however k8s volumeMounts overwrites the folder on container.
In the example below '/existing-folder-on-my-app-image/' is a folder on the my-app image which already contains files. When using the below I only get the downloaded plugin.jar in folder '/existing-folder-on-my-app-image/' and existing files are removed.
I want to add other files to this folder, but still keep those files which where there to start with.
How can I stop k8s from overwriting '/existing-folder-on-my-app-image/' to only have the files from initContainer?
apiVersion: v1
kind: Pod
metadata:
name: my-app
spec:
initContainers:
- name: config-data
image: joosthofman/wget:1.0
command: ["sh","-c","wget https://url.to.plugins/plugin.jar --no-check-certificate"]
volumeMounts:
- name: config-data
mountPath: /config
containers:
- name: my-app
image: my-app:latest
volumeMounts:
- name: config-data
mountPath: /existing-folder-on-my-app-image/
volumes:
- name: config-data
emptyDir: {}
volume mounts always shadow the directory they are mounted to. a volume mount is the only way for an init container to manage files that are also visible to another container in the pod. if you want to copy files into a directory that already contains files in the main container image, you'll need to perform that copy as part of the container startup

What is the best way to exec into another container and access its directory?

I have a container running inside a pod and I want to be able to monitor its content every week. I want to write a Kube cronjob for it. Is there a best way to do this?
At the moment I am doing this by running a script in my local machine that does kubectl exec my-container and monitors the content of the directory in that container.
kubectl exec my-container sounds perfectly fine to me. You might want to look at this if you want to run kubectl in a pod (Kubernetes CronJob).
There are other ways but depending on what you are trying to do in the long term it might be an overkill. For example:
You can set up a Fluentd or tail/grep sidecar (or ls, if you are using a binary file?) to send the content or part of the content of that file to an Elasticsearch cluster.
You can set up Prometheus in Kubernetes to scrape metrics on the pod mounted filesystems. You will probably have to use a custom exporter in the pod or something else that exports files in mount points in the pod. This is a similar example.
You can run your script in another sidecar of your pod.
Define a empty directory volume
Mount this volume as your content directory
Also mount this directory to sidecar, so that it can access and able to monitor.
Example:
apiVersion: v1
kind: Pod
metadata:
name: monitor-by-sidecar
spec:
restartPolicy: Never
volumes: # empty directory volume
- name: shared-data
emptyDir: {}
containers:
- name: container-which-produce-content # This container is main application which generate contect. Suppose in /usr/share/nginx/html directory
image: debian
volumeMounts:
- name: shared-data
mountPath: /usr/share/nginx/html
command: ["/bin/bash", "-c"]
args:
- while true;
do
echo "hello world";
echo "----------------" > /usr/share/nginx/html/index.html;
cat /usr/share/nginx/html/index.html;
done
- name: container-which-run-script-to-monitor # this container will run your monitor scripts. this container mount main application's volume in /pod-data directory and run required scripts.
image: debian
volumeMounts:
- name: shared-data
mountPath: /pod-data
command: ["/bin/sh", "-c"]
args:
- while true;
do
echo "hello";
sleep 10;
ls -la /pod-data/;
cat /pod-data/index.html;
done
Example Description
First container(named container-which-produce-content) is main application, which mount a emptyDir volume in /usr/share/nginx/html. In this directory main application will generate data.
Second container(named container-which-run-script-to-monitor) will mount same emptyDir volume (named shared-data which also mounted by main application in /usr/share/nginx/html dir) in /pod-data directory. This /pod-data contains whole data which main application generated in /usr/share/nginx/html directory. You can then run your scripts on this directory.