Kubernetes equivalent of env-file in Docker
Solution 1
You can populate a container's environment variables through the use of Secrets or ConfigMaps. Use Secrets when the data you are working with is sensitive (e.g. passwords), and ConfigMaps when it is not.
In your Pod definition specify that the container should pull values from a Secret:
apiVersion: v1
kind: Pod
metadata:
labels:
context: docker-k8s-lab
name: mysql-pod
name: mysql-pod
spec:
containers:
- image: "mysql:latest"
name: mysql
ports:
- containerPort: 3306
envFrom:
- secretRef:
name: mysql-secret
Note that this syntax is only available in Kubernetes 1.6 or later. On an earlier version of Kubernetes you will have to specify each value manually, e.g.:
env:
- name: MYSQL_USER
valueFrom:
secretKeyRef:
name: mysql-secret
key: MYSQL_USER
(Note that env
take an array as value)
And repeating for every value.
Whichever approach you use, you can now define two different Secrets, one for production and one for dev.
dev-secret.yaml:
apiVersion: v1
kind: Secret
metadata:
name: mysql-secret
type: Opaque
data:
MYSQL_USER: bXlzcWwK
MYSQL_PASSWORD: bXlzcWwK
MYSQL_DATABASE: c2FtcGxlCg==
MYSQL_ROOT_PASSWORD: c3VwZXJzZWNyZXQK
prod-secret.yaml:
apiVersion: v1
kind: Secret
metadata:
name: mysql-secret
type: Opaque
data:
MYSQL_USER: am9obgo=
MYSQL_PASSWORD: c2VjdXJlCg==
MYSQL_DATABASE: cHJvZC1kYgo=
MYSQL_ROOT_PASSWORD: cm9vdHkK
And deploy the correct secret to the correct Kubernetes cluster:
kubectl config use-context dev
kubectl create -f dev-secret.yaml
kubectl config use-context prod
kubectl create -f prod-secret.yaml
Now whenever a Pod starts it will populate its environment variables from the values specified in the Secret.
Solution 2
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:
-
Secrets docs, search for
--from-file
- shows that this option is available. -
The equivalent
ConfigMap
docs shows an example on how to use it.
Note: there's a difference between --from-file
and --from-env-file
when creating secret as described in the comments below.
Solution 3
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 4
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 5
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
Related videos on Youtube
Johan
Architecture, domain driven design, large-scale systems, devops, simplicity. Strives to find pragmatic solutions to hard problems. Active open source contributor and founder of several popular open source projects such as PowerMock, REST Assured and Awaitility. Frequent speaker at user groups, companies and conferences such as Öredev, Jazoon, Devoxx and JFokus. Blogs at https://code.haleby.se
Updated on March 08, 2022Comments
-
Johan about 2 years
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
ortest.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:
- 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
- If this is not possible, what is the suggested approach?
-
alltej about 4 yearsI am also looking for something like this. I don't want to create a
Secret
orConfigMap
resource because this is just temporary and use for testing. I have limited permissions in the k8s cluster. I maybe be able to create aSecret
resource but I won't be able to delete them once it is already created.
-
Tim Hockin over 8 yearsIdeally you should be able to define a Secret (or the eventual config objects we will have) and have that injected as env vars. Unfortunately that work is not done yet, so I am voting for this.
-
ant31 over 8 yearsIf you're using ansible, we have a common role to deploy on kubernetes: github.com/ansibl8s/k8s-common. Then it's very easy to prepare new applications, see exemples how to use it in other repo: github.com/ansibl8s
-
Paul Morie over 8 yearsI am hoping that we will do secrets in env vars for 1.2
-
luebken about 8 yearsNote that there is a proposal for templates: github.com/kubernetes/kubernetes/blob/master/docs/proposals/…
-
jävi almost 8 yearsThis is my current approach, however I have 3 different pods using the same list of secrets exposed as EnvVars. Is it possible to define them once and expose them to the 3 pods?
-
Pixel Elephant almost 8 yearsNot that I know of.
-
holms over 7 yearswhat should I do if i want to use
kubectl-run
to pass 20 env variables??? why then don't do 12factor easier?? -
AndrewMcLagan over 7 yearsthat would be so great... seems like allot of boilerplate to get the env vars into containers. @PixelElephant
-
Bruce Zu over 7 yearsCan this work. At least in my case it does not work. Please see my issue github.com/kubernetes/kubernetes/issues/38858 . Will you please have a look to see if I am wrong at some part. Thank you!
-
aronchick over 7 yearsThis is no longer correct. The higher voted answer (below) is the correct answer.
-
aronchick over 7 years@jävi Do you mean replication controllers? Regardless, there's nothing binding a secret/config map to a single pod/RC/Deployment. It's just defined in the manifest as above, and can be mounted to as many things as you would like.
-
Pixel Elephant over 7 years@aronchick I believe they are looking for this feature: github.com/kubernetes/kubernetes/issues/26299 which looks like it will be landing soon. I'll update the answer once the feature is in a released version of Kubernetes.
-
Artem Dolobanko almost 7 yearsCan you share Kubernetes documentation on this?
-
Or Duan almost 7 years@ArtemDolobanko Edited, keep in mind this is still new and lakes of docs, you can find many discussions on Github's issues tracker if you want more details.
-
linuxbandit about 5 yearsI think it's important to mention that the values MUST be base64 encoded, in the definition of the Secret. I just tried this with my learning cluster and I get error unless the values are all base64 encoded
-
Alex about 5 yearsCorrect syntax is in the answer below, please fix in your answer, otherwise it generates error. You need a dash before secretRef and two spaces before name.
-
Muzi Jack over 4 years@Or Duan how would i pass a version number to docker image using env
-
Muzi Jack over 4 years@Pixel Elephant, how would i use env for docker image so i don't have to update deployment.yaml every time i need to increment a version
-
Muzi Jack over 4 yearshow would i use env for docker image so i don't have to update deployment.yaml every time i need to increment a version
-
Muzi Jack over 4 yearshow would i use env for docker image so i don't have to update deployment.yaml every time i need to increment a version
-
Tara Prasad Gurung over 4 yearswhat if we have to mount that text file to some location and the app will create the env automatically from there
-
David almost 4 yearsShould this be
--from-env-file
? Using--from-file
results in one key (named after the input file) with the content of the file. Using--from-env-file
expands the keys inside the file into the secret. See this Google documentation for more. -
srth12 about 2 yearsReferencing '/var/www/html/.env' is creating a
.env
folder instead of the filename for me. -
Cyril I almost 2 yearsstackoverflow.com/questions/72343649/… my question also is related to env variable . Please help me to sort this out
-
Cyril I almost 2 yearsstackoverflow.com/questions/72343649/… … my question also is related to env variable . Please help me to sort this out