'Kubernetes equivalent of env-file in Docker

Background:

Currently we're using Docker and Docker Compose for our services. We have externalized the configuration for different environments into files that define environment variables read by the application. For example a prod.env file:

ENV_VAR_ONE=Something Prod
ENV_VAR_TWO=Something else Prod

and a test.env file:

ENV_VAR_ONE=Something Test
ENV_VAR_TWO=Something else Test

Thus we can simply use the prod.env or test.env file when starting the container:

docker run --env-file prod.env <image>

Our application then picks up its configuration based on the environment variables defined in prod.env.

Questions:

  1. Is there a way to provide environment variables from a file in Kubernetes (for example when defining a pod) instead of hardcoding them like this:
apiVersion: v1
kind: Pod
metadata: 
  labels: 
    context: docker-k8s-lab
    name: mysql-pod
  name: mysql-pod
spec: 
  containers: 
    - 
      env: 
        - 
          name: MYSQL_USER
          value: mysql
        - 
          name: MYSQL_PASSWORD
          value: mysql
        - 
          name: MYSQL_DATABASE
          value: sample
        - 
          name: MYSQL_ROOT_PASSWORD
          value: supersecret
      image: "mysql:latest"
      name: mysql
      ports: 
        - 
          containerPort: 3306
  1. If this is not possible, what is the suggested approach?


Solution 1:[1]

A new update for Kubernetes(v1.6) allows what you asked for(years ago).

You can now use the envFrom like this in your yaml file:

  containers:
  - name: django
    image: image/name
    envFrom:
      - secretRef:
         name: prod-secrets

Where development-secrets is your secret, you can create it by:

kubectl create secret generic prod-secrets --from-env-file=prod/env.txt`

Where the txt file content is a key-value:

DB_USER=username_here
DB_PASSWORD=password_here

The docs are still lakes of examples, I had to search really hard on those places:

Note: there's a difference between --from-file and --from-env-file when creating secret as described in the comments below.

Solution 2:[2]

When defining a pod for Kubernetes using a YAML file, there's no direct way to specify a different file containing environment variables for a container. The Kubernetes project says they will improve this area in the future (see Kubernetes docs).

In the meantime, I suggest using a provisioning tool and making the pod YAML a template. For example, using Ansible your pod YAML file would look like:

file my-pod.yaml.template:

apiVersion: v1
kind: Pod
...
spec:
  containers:
  ...
    env:
    - name: MYSQL_ROOT_PASSWORD
      value: {{ mysql_root_pasword }}
    ...

Then your Ansible playbook can specify the variable mysql_root_password somewhere convenient, and substitute it when creating the resource, for example:

file my-playbook.yaml:

- hosts: my_hosts
  vars_files: 
  - my-env-vars-{{ deploy_to }}.yaml
  tasks:
  - name: create pod YAML from template
    template: src=my-pod.yaml.template dst=my-pod.yaml
  - name: create pod in Kubernetes
    command: kubectl create -f my-pod.yaml

file my-env-vars-prod.yaml:

mysql_root_password: supersecret

file my-env-vars-test.yaml:

mysql_root_password: notsosecret

Now you create the pod resource by running, for example:

ansible-playbook -e deploy=test my-playbook.yaml

Solution 3:[3]

This works for me:

file env-secret.yaml

apiVersion: v1
kind: Secret
metadata:
  name: env-secret
type: Opaque
stringData:
  .env: |-
    APP_NAME=Laravel
    APP_ENV=local

and into the deployment.yaml or pod.yaml

spec:
  ...
        volumeMounts:
        - name: foo
          mountPath: "/var/www/html/.env"
          subPath: .env
      volumes:
      - name: foo
        secret:
          secretName: env-secret
````

Solution 4:[4]

I smashed my head aupon tyhis for 2 hours now. I found in the docs a very simple solution to minimize my (and hopefully your) pain.

  • Keep env.prod, env.dev as you have them.

  • Use a oneliner script to import those into yaml:

    kubectl create configmap my-dev-config --from-env-file=env.dev

    kubectl create configmap my-prod-config --from-env-file=env.prod

You can see the result (for instant gratification):

# You can also save this to disk
kubectl get configmap my-dev-config -o yaml

As a rubyist, I personally find this solution the DRYest as you have a single point to maintain (the ENV bash file, which is compatible with Python/Ruby libraries, ..) and then you YAMLize it in a single execution.

Note that you need to keep your ENV file clean (I have a lot of comments which prevented this to work so had to prepend a cat config.original | egrep -v "^#" | tee config.cleaned) but this doen't change the complexity substantially.

It's all documented here

Solution 5:[5]

This is an old question but it has a lot of viewers so I add my answer. The best way to separate the configuration from K8s implementation is using Helm. Each Helm package can have a values.yaml file and we can easily use those values in the Helm chart. If we have a multi-component topology we can create an umbrella Helm package and the parent values package also can overwrite the children values files.

Solution 6:[6]

This is an old question but let me describe my answer for future beginner.

You can use kustomize configMapGenerator.

configMapGenerator:
  - name: example
    env: dev.env

and refer this configMap/example in pod definition

Solution 7:[7]

You can reference K8S values by specifying them in your container as environment variables.

let your deployment be mongo.yml as follows:

--
kind: Deployment
   --
      --
      containers:
        --
        env:
        - name: DB_URL
          valueFrom:
            configMapKeyRef:
              name: mongo-config
              key: mongo-url
        - name: MONGO_INITDB_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mongo-secret
              key: mongo-password  

Where mongo-secret is used for senective data, e.g.: passwords or certificates

apiVersion: v1
kind: Secret
metadata:
  name: mongo-secret
type: Opaque
data:
  mongo-user: bW9uZ291c2Vy
  mongo-password: bW9uZ29wYXNzd29yZA==

and mongo-config is used for non-sensitive data

apiVersion: v1
kind: ConfigMap
metadata:
  name: mongo-config
data:
  mongo-url: mongo-service

Solution 8:[8]

You could try this steps:

This command will put your file prod.env in the secrets.

kubectl create secret generic env-prod --from-file=prod.env=prod.env

Then, you could reference this file in your deployment.yaml like

apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-identity
  labels:
    app.kubernetes.io/name: api-identity
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: api-identity
  template:
    metadata:
      labels:
        app.kubernetes.io/name: api-identity
    spec:
      imagePullSecrets:
        - name: docker-registry-credential
      containers:
        - name: api-identity
          image: "api-identity:test"
          imagePullPolicy: IfNotPresent
          ports:
            - name: http
              containerPort: 8005
              protocol: TCP
          volumeMounts:
          - name: env-file-vol
            mountPath: "/var/www/html/.env"
            subPath: .env
      volumes:
      - name: env-file-vol
        secret:
          secretName: env-prod

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Gowtham
Solution 2 mmoya
Solution 3 madwyatt
Solution 4 Riccardo
Solution 5 AVarf
Solution 6
Solution 7 Mostafa Wael
Solution 8 srth12