kubernetes deployment mounts secret as a folder instead of a file

Viewed 5376

I am having a config file as a secret in kubernetes and I want to mount it into a specific location inside the container. The problem is that the volume that is created inside the container is a folder instead of a file with the content of the secrets in it. Any way to fix it? My deployment looks like this:

kind: Deployment
apiVersion: apps/v1
metadata:
  name: jetty
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: jetty
  template:
    metadata:
      labels:
        app: jetty
    spec:
      containers:
        - name: jetty
          image: quay.io/user/jetty
          ports:
            - containerPort: 8080
          volumeMounts:
          - name: config-properties
            mountPath: "/opt/jetty/config.properties"
            subPath: config.properties
          - name: secrets-properties
            mountPath: "/opt/jetty/secrets.properties"
          - name: doc-path
            mountPath: /mnt/storage/
          resources:
            limits:
              cpu: '1000m'
              memory: '3000Mi'
            requests:
              cpu: '750m'
              memory: '2500Mi'
      volumes:
      - name: config-properties
        configMap:
          name: jetty-config-properties
      - name: secrets-properties
        secret: 
          secretName: jetty-secrets
      - name: doc-path
        persistentVolumeClaim:
          claimName: jetty-docs-pvc
      imagePullSecrets:
      - name: rcc-quay
1 Answers

Secrets vs ConfigMaps

Secrets let you store and manage sensitive information (e.g. passwords, private keys) and ConfigMaps are used for non-sensitive configuration data.
As you can see in the Secrets and ConfigMaps documentation:

A Secret is an object that contains a small amount of sensitive data such as a password, a token, or a key.

A ConfigMap allows you to decouple environment-specific configuration from your container images, so that your applications are easily portable.

Mounting Secret as a file

It is possible to create Secret and pass it as a file or multiple files to Pods.
I've create simple example for you to illustrate how it works. Below you can see sample Secret manifest file and Deployment that uses this Secret:
NOTE: I used subPath with Secrets and it works as expected.

---
apiVersion: v1
kind: Secret
metadata:
  name: my-secret
data:
  secret.file1: |
    c2VjcmV0RmlsZTEK
  secret.file2: |
    c2VjcmV0RmlsZTIK
---
apiVersion: apps/v1
kind: Deployment
metadata:
...
    spec:
      containers:
      - image: nginx
        name: nginx
        volumeMounts:
        - name: secrets-files
          mountPath: "/mnt/secret.file1"  # "secret.file1" file will be created in "/mnt" directory
          subPath: secret.file1
        - name: secrets-files
          mountPath: "/mnt/secret.file2"  # "secret.file2" file will be created in "/mnt" directory
          subPath: secret.file2
      volumes:
        - name: secrets-files
          secret:
            secretName: my-secret # name of the Secret
            

Note: Secret should be created before Deployment.

After creating Secret and Deployment, we can see how it works:

$ kubectl get secret,deploy,pod
NAME                         TYPE                                  DATA   AGE
secret/my-secret             Opaque                                2      76s

NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/nginx   1/1     1            1           76s

NAME                         READY   STATUS    RESTARTS   AGE
pod/nginx-7c67965687-ph7b8   1/1     Running   0          76s

$ kubectl exec nginx-7c67965687-ph7b8 -- ls /mnt
secret.file1
secret.file2
$ kubectl exec nginx-7c67965687-ph7b8 -- cat /mnt/secret.file1
secretFile1
$ kubectl exec nginx-7c67965687-ph7b8 -- cat /mnt/secret.file2
secretFile2

Projected Volume

I think a better way to achieve your goal is to use projected volume.

A projected volume maps several existing volume sources into the same directory.

In the Projected Volume documentation you can find detailed explanation but additionally I created an example that might help you understand how it works. Using projected volume I mounted secret.file1, secret.file2 from Secret and config.file1 from ConfigMap as files into the Pod.

---
apiVersion: v1
kind: Secret
metadata:
  name: my-secret
data:
  secret.file1: |
    c2VjcmV0RmlsZTEK
  secret.file2: |
    c2VjcmV0RmlsZTIK
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: my-config
data:
  config.file1: |
    configFile1  
---
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: nginx
    volumeMounts:
    - name: all-in-one
      mountPath: "/config-volume"
      readOnly: true
  volumes:
  - name: all-in-one
    projected:
      sources:
      - secret:
          name: my-secret
          items:
            - key: secret.file1
              path: secret-dir1/secret.file1
            - key: secret.file2
              path: secret-dir2/secret.file2
      - configMap:
          name: my-config
          items:
            - key: config.file1
              path: config-dir1/config.file1

We can check how it works:

$ kubectl exec nginx -- ls /config-volume
config-dir1
secret-dir1
secret-dir2    
$ kubectl exec nginx -- cat /config-volume/config-dir1/config.file1
configFile1
$ kubectl exec nginx -- cat /config-volume/secret-dir1/secret.file1
secretFile1
$ kubectl exec nginx -- cat /config-volume/secret-dir2/secret.file2
secretFile2

If this response doesn't answer your question, please provide more details about your Secret and what exactly you want to achieve.

Related