2020年2月8日 星期六

[ 文章收集 ] Understanding Docker Build Args, Environment Variables and Docker Compose Variables

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?
* How can you set variables during build time?
* Who gets what environment vars, and what can you do to change them?
* How to override defaults or set your own in your Docker files?

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:
  1. ARG some_variable_name  
  2. # or with a default:  
  3. #ARG some_variable_name=default_value  
  4.   
  5. RUN echo "Oh dang look at that $some_variable_name"  
  6. # or with ${some_variable_name}  
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 USERas well. Docker is taking care of the substitution.

When building a Docker image from the commandline, you can set those values using –build-arg:
$ docker build --build-arg some_variable_name=a_value

Running that command, with the above Dockerfile, will result in the following line being printed in the process:
Oh dang look at that a_value

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 anymoreENV 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:
  1. version: '3'  
  2.   
  3. services:  
  4.   somename:  
  5.     build:  
  6.       context: ./app  
  7.       dockerfile: Dockerfile  
  8.       args:  
  9.         some_variable_name: a_value  
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:
  1. ENV foo /bar  
  2. # or ENV foo=/bar  
  3. ADD . $foo  
  4. # or ADD . ${foo}  
  5. # translates to: ADD . /bar  
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:
# first, get the images on your system and their ids
$ docker images
...

# use one of those ids to take a closer look
$ docker inspect

# look out for the "Env" entries

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:
  1. ARG some_variable_name  
  2. ENV env_var_name=$some_variable_name  
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:
$ docker run -e "env_var_name=another_value" alpine env

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:
$ docker run -e env_var_name alpine env

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:
  1. env_var_name=another_value  
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:
$ docker run --env-file=env_file_name alpine env

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.
  1. version: '3'  
  2.   
  3. services:  
  4.   plex:  
  5.     image: linuxserver/plex  
  6.       environment:  
  7.         - env_var_name=another_value  
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.
  1. version: '3'  
  2.   
  3. services:  
  4.   plex:  
  5.     image: linuxserver/plex  
  6.       env_file: env_file_name  
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 ENVARG, 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:
  1. VARIABLE_FOR_DOCKER_COMPOSE_1=yet_another_value  
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.
  1. version: '3'  
  2.   
  3. services:  
  4.   plex:  
  5.     image: linuxserver/plex  
  6.       environment:  
  7.         - env_var_name=$VARIABLE_FOR_DOCKER_COMPOSE_1  
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 參數
ENV 是在 build 的時候,可以定義一些變數,讓後面指令在執行時候可以參考...
  1. From resin/rpi-raspbian  
  2. ENV NODE_VER=node-v5.9.1-linux-armv7l  
  3. ADD ./${NODE_VER} /  
  4. RUN ln -s /${NODE_VER} /node  
  5. ENV PATH=/node/bin:$PATH  
  6. CMD ["node"]  
上面 Dockerfile 的第二行,定義 NODE_VER 變數,讓第三行中的 ADD 參考,因此 ADD 會在執行時間,使用 ENV 所定義的值來做 ADD 的動作。

ARG 在 build 時候是可以從外部以 --build-arg 帶入的變數,讓 build 的動作可結合外部的指令給定一些建構時候所需的參數:
  1. From resin/rpi-raspbian  
  2. ARG NODE_VER  
  3. ADD ./${NODE_VER:-node-v5.9.1-linux-armv7l} /  
  4. RUN ln -s /${NODE_VER} /node  
  5. ENV PATH=/node/bin:$PATH  
  6. CMD ["node"]  
上面 Dockerfile 在第二行的部分,會指定一個 NODE_VER 的變數. build的時候,可以這樣下參數:
# docker build --build-arg NODE_VER=node-v5.9.0-linux-armv7l .


沒有留言:

張貼留言

[Git 常見問題] error: The following untracked working tree files would be overwritten by merge

  Source From  Here 方案1: // x -----删除忽略文件已经对 git 来说不识别的文件 // d -----删除未被添加到 git 的路径中的文件 // f -----强制运行 #   git clean -d -fx 方案2: 今天在服务器上  gi...