Dockerfile Instructions - ENV
The ENV instruction sets the environment variable <key> to the value <value>.
This value will be in the environment for all subsequent instructions in the build stage and can be replaced inline in many as well.
The environment variables set using ENV will persist when a container is run from the resulting image.
Take the following as an example:
Dockerfile:
FROM python:alpine3.16
ENV MY_ENV='Hello world'
Ex:
$ docker image build -t env-exp .
Result:
Sending build context to Docker daemon 2.048kB
Step 1/2 : FROM python:alpine3.16
---> b22cfbf3bfa6
Step 2/2 : ENV MY_ENV='Hello world'
---> Running in 66ff3946bdae
Removing intermediate container 66ff3946bdae
---> 215b48c4908f
Successfully built 215b48c4908f
Successfully tagged env-exp:latest
Ex:
$ docker container run -it env-exp sh
/ # printenv
Result:
...
MY_ENV=Hello world
...
According to the previous example, the env variables will be persisted inside container.
In addition, it can be adjusted when running a container.
Ex:
$ docker container run --env MY_ENV='modified_when_run' -it env-exp sh
/ # printenv
Result:
...
MY_ENV=modified_when_run
...
Environment Variables can be used in certain instructions as variables.
Dockerfile:
FROM python:alpine3.16
ENV MY_APP_DIR='/app/'
WORKDIR $MY_APP_DIR
ADD hello-world.py hello-world.py
Ex:
$ docker image build -t env-as-variable .
Result:
Sending build context to Docker daemon 3.072kB
Step 1/4 : FROM python:alpine3.16
---> b22cfbf3bfa6
Step 2/4 : ENV MY_APP_DIR='/app/'
---> Running in 263cd2a9d616
Removing intermediate container 263cd2a9d616
---> 62f999684aaa
Step 3/4 : WORKDIR $MY_APP_DIR
---> Running in 9e70090d46aa
Removing intermediate container 9e70090d46aa
---> 635bf8e45985
Step 4/4 : ADD hello-world.py hello-world.py
---> d0ee09cd29a5
Successfully built d0ee09cd29a5
Successfully tagged env-as-variable:latest
Ex:
$ docker container run -it env-as-variable sh
/app # ls -l
/app # printenv
Result:
-rw-rw-r-- 1 root root 21 Jun 7 11:59 hello-world.py
MY_APP_DIR=/app/
Environment variable persistence can cause unexpected side effects.
Therefore, if an environment variable is only needed during build, and not in the final image, consider setting a value for a single command instead or using ARG, which is not persisted in the final image.
Dockerfile Instructions - ARG
The ARG instruction defines a variable that users can pass at build-time to the builder with the docker build command using the --build-arg <varname>=<value> flag.
An ARG instruction can optionally include a default value. If an ARG instruction has a default value and if there is no value passed at build-time, the builder uses the default.
Take the following Dockerfile as an example:
* ARG VERSION and build_no include a default value.
* FROM can interact with ARG
* ${user:-default_user} means if ARG user is not set, then we use default_user instead
Dockerfile:
ARG VERSION=alpine3.16
FROM python:${VERSION}
ARG build_no=1
ARG user
WORKDIR app
RUN echo ${build_no} ${user:-default_user} > log.txt
Ex:
$ docker image build -t arg-exp .
Result:
Sending build context to Docker daemon 2.048kB
Step 1/6 : ARG VERSION=alpine3.16
Step 2/6 : FROM python:${VERSION}
alpine3.16: Pulling from library/python
2408cc74d12b: Pull complete
2f22aa6a21a6: Pull complete
54cc066f118a: Pull complete
03624af3d529: Pull complete
4ae78d2f3e6f: Pull complete
Digest: sha256:97725c6081f5670080322188827ef5cd95325...
Status: Downloaded newer image for python:alpine3.16
---> 27edb73bd1fc
Step 3/6 : ARG build_no=1
---> Running in cb48df4b6e52
Removing intermediate container cb48df4b6e52
---> c72fda3ca32e
Step 4/6 : ARG user
---> Running in 0f252e5d4c1a
Removing intermediate container 0f252e5d4c1a
---> 90e61bddcab5
Step 5/6 : WORKDIR app
---> Running in aecbaf0b83b3
Removing intermediate container aecbaf0b83b3
---> d9d2e1f5b94a
Step 6/6 : RUN echo ${build_no} ${user:-default_user} > log.txt
---> Running in 9072470ff1b3
Removing intermediate container 9072470ff1b3
---> 9de14e06b7e5
Successfully built 9de14e06b7e5
Successfully tagged arg-exp:latest
Ex:
$ docker container run -it --rm arg-exp sh
/app # ls
/app # more log.txt
Result:
log.txt
1 default_user
Impact on build cache?
ARG variables are not persisted into the built image as ENV variables are. However, ARG variables do impact the build cache in similar ways. If a Dockerfile defines an ARG variable whose value is different from a previous build, then a “cache miss” occurs upon its first usage, not its definition. In particular, all RUN instructions following an ARG instruction use the ARG variable implicitly (as an environment variable), thus can cause a cache miss. Reference
Continue with the previous exp, we build the image again.
Ex:
$ docker image build -t arg-exp .
Result:
Sending build context to Docker daemon 2.048kB
Step 1/6 : ARG VERSION=alpine3.16
Step 2/6 : FROM python:${VERSION}
---> 27edb73bd1fc
Step 3/6 : ARG build_no=1
---> Using cache
---> c72fda3ca32e
Step 4/6 : ARG user
---> Using cache
---> 90e61bddcab5
Step 5/6 : WORKDIR app
---> Using cache
---> d9d2e1f5b94a
Step 6/6 : RUN echo ${build_no} ${user:-default_user} > log.txt
---> Using cache
---> 9de14e06b7e5
Successfully built 9de14e06b7e5
Successfully tagged arg-exp:latest
As we can see, cache will be used.
Then if we build image again and pass some arg.
Ex:
$ docker image build --build-arg user=frank -t arg-exp .
Result:
Sending build context to Docker daemon 2.048kB
Step 1/6 : ARG VERSION=alpine3.16
Step 2/6 : FROM python:${VERSION}
---> 27edb73bd1fc
Step 3/6 : ARG build_no=1
---> Using cache
---> c72fda3ca32e
Step 4/6 : ARG user
---> Using cache
---> 90e61bddcab5
Step 5/6 : WORKDIR app
---> Using cache
---> d9d2e1f5b94a
Step 6/6 : RUN echo ${build_no} ${user:-default_user} > log.txt
---> Running in fd126c3a0481
Removing intermediate container fd126c3a0481
---> cd0ce55baeb9
Successfully built cd0ce55baeb9
Successfully tagged arg-exp:latest
And we can see on step 4, there is no cache miss.
Only on step 6, since it is the first time to use ARG user, so the cache miss occur.
No comments:
Post a Comment