Source From Here
Preface
When working with Docker, you’ll stumble over lots of confusing details. I struggled with understanding how to pass variables to Docker images, and how to configure dockerized applications properly. Do these sound familiar to you?
In this article, I’d like to share a focused view of what I learned in the process. Let’s do a deep dive into Docker environment and build-time variables, and how they can be used to build images and running Docker containers. Both with the Docker CLI, as well as with docker-compose.
Before We Do
This is a long, in-depth article. I understand that you might be busy and not looking to learn all there is to know, but fix your current problem. Here are shorter articles, which will help you make progress as quickly as possible:
Docker Image Build-time Variables
You can define variables inside of a Dockerfile, to help you not to repeat yourself:
As you see, we tell the Dockerfile to let Docker know, that it expects a variable named some_variable_name to be passed to it during the build. Subsequent lines can reference that variable with a dollar notation. This might look like we’re passing something to the bash environment where the
echo command is being executed, but you can use ARG-defined values in other directives (like USER) as well. Docker is taking care of the substitution.
When building a Docker image from the commandline, you can set those values using –build-arg:
Running that command, with the above Dockerfile, will result in the following line being printed in the process:
When you try to set a variable which is not ARG mentioned in the Dockerfile, you’ll get a warning.
Notive how we use ARG? ARG are build-time variables, which are not available to future running containers anymore. ENV can be used to define default environment variables. More on this later. Here is an overview of the ARG and ENV availability:
Building the Image with Docker Compose
So, how does this translate to using docker-compose? In docker-compose, you can specify values to pass on for ARG, in an args block:
Here’s what happens above: You set variables to be passed to docker when building a new image from “Dockerfile” in directory “./app” If the Dockerfile contains an ARG entry as above, a_value will be passed into it and available as $some_variable_name.
When building an image, no other variables apart from those listed in “args” are used. Environment stuff only applies to containers, not images. Just a heads-up to prevent confusion. Read on for more info on that. Those ARG variables will not be available in containers started based on the built image without further work.
If you want ARG entries to change and take effect, you need to build a new image. Probably you’ll need to manually delete any old ones.
Setting Environment Variables in Your Dockerfiles
So, how do you set stuff so it’s available to future running containers? ENV. Take a look at this Dockerfile snippet:
You see, we can reference an environment variable with the same notation, as build-arg before. If
ENV is specified after an ARG entry with the same variable name, the ENV value is used. Unlike ARG, ENV variables will still be available in containers. You can inspect images, and see which ENV entries are set by default:
Setting Dynamic Default ENV Values During The Image Build
Let’s combine ARG and ENV. Assuming we want to set default ENV values for future containers on build, here’s how you would do that:
Once you build a container, specifying
–build-arg, the ENV line makes sure, that the value can be accessed in future containers (unless manually overridden).
Setting Environment Variables When Running a Container
So, are we bound to setting ENV values only when building images? Nope. You can override ENV entries in images when starting containers, by specifying your own values. When using the Docker commandline, this looks this way:
the -e flag sets a variable with name “env_var_name”. Maybe your value is secret and you don’t want to type it out? Well, read on. Do variables from the host automatically get passed to the container? Nope again. Only those environment variables will be set when starting a container. Your host environment does not get passed through. Unless…
Passing Environment Variables From the Host Into a Container
Unless, you don’t specify the value of the environmant variable in the command line, but just the name:
In this case, the local value of the host environment variable env_var_name will be passed through to the container. Just don’t specify the value. To be honest, this feels kinda dangerous as it’s not explicit enough for my taste. Luckily, there’s another way.
Using an ‘env_file’ to Set Environment Variables When Running a Container
Instead of writing the variables out or hard-coding them (not in good taste according to the 12-factor folks), we can specify a file to read values from. The contents of such a file look something like this:
The file above is called
env_file_name and it’s located in the current directory. You can reference the filename, which is parsed to extract the environment variables to set:
So much for plain-docker-CLI. On to docker-compose.
Environment Variables using Docker Compose
As above, you can either spell the values out, or reference an env_file to read from. In both cases, the values will be passed into the container which is being started.
As before, we have another option to writing the variables out. Once again, this will keep the values out of the docker-compose file, as is in
good taste. We just reference a *env_file”, and parse it for the variables to set.
But wait, there’s more
When working with docker-compose, you have one more way to use variables. You can do string substitution inside of the docker-compose file. Neat-o, but also a bit confusing, when you don’t have an overview. This one has nothing to do with ENV, ARG, or anything Docker-specifig explained above. It’s exclusively a docker-compose thing.
It’s also known as the .env file.
An .env file resides in the same folder as your docker-compose.yml file. It’s the same folder from which you run the docker-compose commands. It contains values like:
which is exactly the same format as an env_file.
Those values don’t get injected into container environments. They are however available inside the docker-compose.yml file. They are used to substitute strings in the format of ${some_name} or $some_name. That’s it.
Of course, we can use this to pass values into args, or environments, to name your images, and many more. Basically, you can think of your docker-compose.yml file as a template, from which a temporary docker-compose.yml file is created and used with the values from the .env file.
Llet’s look at an example! In the case below, we simply set an environment variable of the future container, based on the value we got from the .env file. Just putting it directly into the docker-compose.yml file. Think string replacement.
Hint: When working with an .env file, you can debug your docker-compose.yml files quite easily. Just type docker-compose config. This way you’ll see if everything looks after the substitution step.
Supplement
* Dockerfile - ENV 與 ARG 參數
Preface
When working with Docker, you’ll stumble over lots of confusing details. I struggled with understanding how to pass variables to Docker images, and how to configure dockerized applications properly. Do these sound familiar to you?
In this article, I’d like to share a focused view of what I learned in the process. Let’s do a deep dive into Docker environment and build-time variables, and how they can be used to build images and running Docker containers. Both with the Docker CLI, as well as with docker-compose.
Before We Do
This is a long, in-depth article. I understand that you might be busy and not looking to learn all there is to know, but fix your current problem. Here are shorter articles, which will help you make progress as quickly as possible:
Docker Image Build-time Variables
You can define variables inside of a Dockerfile, to help you not to repeat yourself:
- ARG some_variable_name
- # or with a default:
- #ARG some_variable_name=default_value
- RUN echo "Oh dang look at that $some_variable_name"
- # or with ${some_variable_name}
When building a Docker image from the commandline, you can set those values using –build-arg:
Running that command, with the above Dockerfile, will result in the following line being printed in the process:
When you try to set a variable which is not ARG mentioned in the Dockerfile, you’ll get a warning.
Notive how we use ARG? ARG are build-time variables, which are not available to future running containers anymore. ENV can be used to define default environment variables. More on this later. Here is an overview of the ARG and ENV availability:
Building the Image with Docker Compose
So, how does this translate to using docker-compose? In docker-compose, you can specify values to pass on for ARG, in an args block:
- version: '3'
- services:
- somename:
- build:
- context: ./app
- dockerfile: Dockerfile
- args:
- some_variable_name: a_value
When building an image, no other variables apart from those listed in “args” are used. Environment stuff only applies to containers, not images. Just a heads-up to prevent confusion. Read on for more info on that. Those ARG variables will not be available in containers started based on the built image without further work.
If you want ARG entries to change and take effect, you need to build a new image. Probably you’ll need to manually delete any old ones.
Setting Environment Variables in Your Dockerfiles
So, how do you set stuff so it’s available to future running containers? ENV. Take a look at this Dockerfile snippet:
- ENV foo /bar
- # or ENV foo=/bar
- ADD . $foo
- # or ADD . ${foo}
- # translates to: ADD . /bar
Setting Dynamic Default ENV Values During The Image Build
Let’s combine ARG and ENV. Assuming we want to set default ENV values for future containers on build, here’s how you would do that:
- ARG some_variable_name
- ENV env_var_name=$some_variable_name
Setting Environment Variables When Running a Container
So, are we bound to setting ENV values only when building images? Nope. You can override ENV entries in images when starting containers, by specifying your own values. When using the Docker commandline, this looks this way:
the -e flag sets a variable with name “env_var_name”. Maybe your value is secret and you don’t want to type it out? Well, read on. Do variables from the host automatically get passed to the container? Nope again. Only those environment variables will be set when starting a container. Your host environment does not get passed through. Unless…
Passing Environment Variables From the Host Into a Container
Unless, you don’t specify the value of the environmant variable in the command line, but just the name:
In this case, the local value of the host environment variable env_var_name will be passed through to the container. Just don’t specify the value. To be honest, this feels kinda dangerous as it’s not explicit enough for my taste. Luckily, there’s another way.
Using an ‘env_file’ to Set Environment Variables When Running a Container
Instead of writing the variables out or hard-coding them (not in good taste according to the 12-factor folks), we can specify a file to read values from. The contents of such a file look something like this:
- env_var_name=another_value
So much for plain-docker-CLI. On to docker-compose.
Environment Variables using Docker Compose
As above, you can either spell the values out, or reference an env_file to read from. In both cases, the values will be passed into the container which is being started.
- version: '3'
- services:
- plex:
- image: linuxserver/plex
- environment:
- - env_var_name=another_value
- version: '3'
- services:
- plex:
- image: linuxserver/plex
- env_file: env_file_name
When working with docker-compose, you have one more way to use variables. You can do string substitution inside of the docker-compose file. Neat-o, but also a bit confusing, when you don’t have an overview. This one has nothing to do with ENV, ARG, or anything Docker-specifig explained above. It’s exclusively a docker-compose thing.
It’s also known as the .env file.
An .env file resides in the same folder as your docker-compose.yml file. It’s the same folder from which you run the docker-compose commands. It contains values like:
- VARIABLE_FOR_DOCKER_COMPOSE_1=yet_another_value
Those values don’t get injected into container environments. They are however available inside the docker-compose.yml file. They are used to substitute strings in the format of ${some_name} or $some_name. That’s it.
Of course, we can use this to pass values into args, or environments, to name your images, and many more. Basically, you can think of your docker-compose.yml file as a template, from which a temporary docker-compose.yml file is created and used with the values from the .env file.
Llet’s look at an example! In the case below, we simply set an environment variable of the future container, based on the value we got from the .env file. Just putting it directly into the docker-compose.yml file. Think string replacement.
- version: '3'
- services:
- plex:
- image: linuxserver/plex
- environment:
- - env_var_name=$VARIABLE_FOR_DOCKER_COMPOSE_1
Supplement
* Dockerfile - ENV 與 ARG 參數
沒有留言:
張貼留言