206

I was considering using secrets to mount a single file but it seems that you can only mount directory that will overwrites all the other content. How can I share a single config file without mounting a directory?

mkobit
  • 43,979
  • 12
  • 156
  • 150
Smana
  • 2,331
  • 2
  • 14
  • 10

6 Answers6

279

For example you have a configmap which contain 2 config files:

kubectl create configmap config --from-file <file1> --from-file <file2>

You could use subPath like this to mount single file into existing directory:

---
        volumeMounts:
        - name: "config"
          mountPath: "/<existing folder>/<file1>"
          subPath: "<file1>"
        - name: "config"
          mountPath: "/<existing folder>/<file2>"
          subPath: "<file2>"
      restartPolicy: Always
      volumes:
        - name: "config"
          configMap:
            name: "config"
---

Full example here

Tommy Nguyen
  • 3,403
  • 1
  • 15
  • 14
  • 7
    confused why this shows example for 2 files when OP only needs 1, I assume the same applies though for the case of a single file. – Randy L Oct 18 '18 at 18:14
  • 17
    @the0ther yea just to make it clear how it works with multiple files – Tommy Nguyen Nov 11 '18 at 12:08
  • @TommyNguyen, is there any way if i only want to mount my main path and not sub path like ./abc.txt where abc.txt is located inside the container at main folder and not sub folder. – PrinceT Jul 05 '19 at 12:00
  • 5
    What if the file is not a ConfigMap, or not in a ConfigMap? Is it possible to mount an arbitrary file from your local disk? – LondonRob Feb 14 '20 at 14:40
  • 5
    @LondonRob in your case you should use hostPath, see https://kubernetes.io/docs/concepts/storage/volumes/#hostpath – Masupilami Apr 17 '20 at 06:13
  • 6
    **Note**: A container using a ConfigMap as a subPath volume will not receive ConfigMap updates. https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/ – Michael Dec 31 '20 at 19:05
  • 3
    Please note that this approach most probably will not work if we are dealing with "big" files, there is a limitation on the ConfigMap side (1MiB) – mau Jun 03 '21 at 15:08
  • 1
    The direct link to the information about the ConfigMap updates when using subPath is https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/#mounted-configmaps-are-updated-automatically – chronicc Oct 20 '21 at 15:15
74

I'd start with this working example from here. Make sure you're using at least Kubernetes 1.3.

Simply create a ConfigMap like this:

apiVersion: v1
kind: ConfigMap
metadata:
  name: test-pd-plus-cfgmap
data:
  file-from-cfgmap: file data

And then create a pod like this:

apiVersion: v1
kind: Pod
metadata:
  name: test-pd-plus-cfgmap
spec:
  containers:
  - image: ubuntu
    name: bash
    stdin: true
    stdinOnce: true
    tty: true
    volumeMounts:
    - mountPath: /mnt
      name: pd
    - mountPath: /mnt/file-from-cfgmap
      name: cfgmap
      subPath: file-from-cfgmap
  volumes:
  - name: pd
    gcePersistentDisk:
      pdName: testdisk
  - name: cfgmap
    configMap:
      name: test-pd-plus-cfgmap
Joel B
  • 12,082
  • 10
  • 61
  • 69
  • 4
    This will undesirably overwrite the entire directory like the OP mentioned already. – davegallant Jan 02 '17 at 18:38
  • 11
    I don't agree. Tested the approach including "subPath" and only the files were mounted not the entire directory. Tested with Kubernetes 1.5. – dmorlock Jan 11 '17 at 14:14
  • @dmorlock The question was ambiguously worded. This will as the title states "share/mount one file into a pod" and like the question asks "share a config file without mounting a directory" – Joel B Jan 12 '17 at 10:22
  • 4
    I've had to come to this question three times now because the word "subpath" is not mentioned anywhere in the docs at https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/#add-configmap-data-to-a-specific-path-in-the-volume . I guess that's a friendly documentation PR that needs to be created and submitted. – Todd Lyons Feb 01 '18 at 17:17
  • @JoelB, is there any way if i only want to mount my main path and not sub path like ./abc.txt where abc.txt is located inside the container at main folder and not sub folder. – PrinceT Jul 05 '19 at 12:00
16

An useful additional information to the accepted answer:

Let's say your origin file is called environment.js, and you want the destination file to be called destination_environment.js, then, your yaml file should look like this:

---
        volumeMounts:
        - name: "config"
          mountPath: "/<existing folder>/destination_environment.js"
          subPath: "environment.js"
      volumes:
        - name: "config"
          configMap:
            name: "config"
---
nolwww
  • 1,355
  • 1
  • 15
  • 33
  • 1
    Works great on Linux Docker containers! I get this error message when attempted on a Windows Docker container: `invalid mount config for type "bind": source path must be a directory`. – jrbe228 May 29 '22 at 23:56
  • @JeremyBeale if you interact with Docker (Desktop) from WSL with a WSL path, it should work. From the windows side won't work by itself. – MatsLindh Apr 01 '23 at 19:16
9

There is currently (v1.0, v1.1) no way to volume mount a single config file. The Secret structure is naturally capable of representing multiple secrets, which means it must be a directory.

When we get config objects, single files should be supported.

In the mean time you can mount a directory and symlink to it from your image, maybe?

Tim Hockin
  • 3,567
  • 13
  • 18
8

I don't have a reputation to vote or reply to threads, so I'll post here. The most up-voted answer does not work as it is stated (at least in k8s 1.21.1):

          volumeMounts:
            - mountPath: /opt/project/config.override.json
              name: config-override
              subPath: config.override.json
          command:
            - ls
            - -l
            - /opt/project/config.override.json

produces an empty dir /opt/project/config.override.json. I'm digging through docs and google for several hours already and I am still not able to mount this single json file as json file.

I've also tried this:

          volumeMounts:
            - mountPath: /opt/project/
              name: config-override
              subPath: config.override.json
          command:
            - ls
            - -l
            - /opt/project

Quite obviously it lists /opt/project as empty dir as it tries to mount a json file to it. File with name config.override.json is not created in this case.

PS: the only way to mount to file at all is this:

          volumeMounts:
            - mountPath: /opt/project/override
              name: config-override
          command:
            - ls
            - -l
            - /opt/project/override

It creates a directory /opt/project/override and symlinks an original filename used in configMap creation to the needed content:

lrwxrwxrwx 1 root root 27 Jun 27 14:37 config.override.json -> ..data/config.override.json
Alexey Bursan
  • 91
  • 1
  • 3
  • exact same is happening to me today. This is on 1.18. It works if the volume is a configmap but somehow if it's a secret it does not. Did you find a solution ? – Moulick Dec 02 '21 at 12:03
  • 2
    Pretty sure there's a typo in your penultimate code-block - `ls` should be `ln`. – scubbo May 21 '22 at 19:12
0

Lets say you want to mount a new log4j2.xml into a running deployment to enhance logging

# Variables
k8s_namespace=xcs
deployment_name=orders-service
container_name=orders-service
container_working_dir=/opt/orders-service

# Create config map and patch deployment
kubectl -n ${k8s_namespace} create cm log4j \
 --from-file=log4j2.xml=./log4j2.xml

kubectl -n ${k8s_namespace} patch deployment ${deployment_name} \
 -p '{"spec":{"template":{"spec":{"volumes":[{"configMap":{"defaultMode": 420,"name": "log4j"},"name": "log4j"}]}}}}'

kubectl -n ${k8s_namespace} patch deployment ${deployment_name} \
 -p '{"spec":{"template":{"spec":{"containers":[{"name": "'${container_name}'","volumeMounts": [{  "mountPath": "'${container_working_dir}'/log4j2.xml","name": "log4j","subPath": "log4j2.xml"}]}]}}}}'

Ajar
  • 1