原文鏈接
前言
reference:https://vsupalov.com/docker-build-time-env-values/
很多時候,我們需要在docker鏡像中加入環境變量,本人了解的有2種方法可以做到
第一種
使用docker run --env VARIABLE=VALUE image:tag
直接添加變量,適用於直接用docker啟動的項目
root@ubuntu:/home/vickey/test_build# docker run --rm -it --env TEST=2 ubuntu:latest
root@2bbe75e5d8c7:/# env |grep "TEST"
TEST=2
第二種
使用dockerfile的ARG
和ENV
添加變量,適用於不能用docker run
命令啟動的項目,如k8s
ARG只在構建docker鏡像時有效(dockerfile的RUN指令等),在鏡像創建了並用該鏡像啟動容器后則無效(后面有例子驗證)。但可以配合ENV指令使用使其在創建后的容器也可以生效。
ARG buildtime_variable=default_value # if not set default_value buildtime_variable would be set ''
ENV env_var_name=$buildtime_variable
在構建映像時,可以使用--build-arg buildtime_variable=other_value
覆蓋dockerfile里的變量值default_value
$ docker build --build-arg buildtime_variable=other_value --tag image:tag
多階段構建
但是有時我們只是臨時需要環境變量或文件,最后的鏡像是不需要的這些變量的,設置ARG和ENV值就會在Docker鏡像中留下痕跡,比如保密信息等。多階段構建可以用來去掉包含保密信息的鏡像。
- dockerfile
FROM ubuntu as intermediate # 為第一階段構建設置別名,在第二階段引用
ARG TEST=deault_value # 設置環境變量
ENV ENV_TEST=$TEST # 設置環境變量
RUN echo test > /home/test.txt
RUN cat /home/test.txt # 查看文件是否正常
RUN env
RUN env |grep TEST # 查看環境變量是否已設置
FROM ubuntu
COPY --from=intermediate /home/test.txt /home/another_test.txt # 將第一階段生成的文件拷貝到第二階段鏡像中
RUN cat /home/another_test.txt # 查看拷貝的文件是否正常
RUN env
RUN env |grep TEST # 查看環境變量是否已設置
- 多階段構建
root@ubuntu:/home/vickey/test_build# docker build --build-arg TEST=2 -t ubuntu:test-multi-build --no-cache -f ./dockerfile .
Sending build context to Docker daemon 2.56kB
Step 1/12 : FROM ubuntu as intermediate
---> 94e814e2efa8
Step 2/12 : ARG TEST=deault_value
---> Running in 7da9180a6311
Removing intermediate container 7da9180a6311
---> 7e8420f3ecf2
Step 3/12 : ENV ENV_TEST=$TEST
---> Running in 256788d179ce
Removing intermediate container 256788d179ce
---> 11cf4e0581d9
Step 4/12 : RUN echo test > /home/test.txt
---> Running in c84799ba3831
Removing intermediate container c84799ba3831
---> f578ca5fe373
Step 5/12 : RUN cat /home/test.txt
---> Running in dbf8272fd10c
test
Removing intermediate container dbf8272fd10c
---> 9f8720732878
Step 6/12 : RUN env
---> Running in 9050cd9e36c9
HOSTNAME=9050cd9e36c9
HOME=/root
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
TEST=2
PWD=/
ENV_TEST=2
Removing intermediate container 9050cd9e36c9
---> f1f4daf42cc0
Step 7/12 : RUN env |grep TEST
---> Running in 1cc7968144f5
TEST=2
ENV_TEST=2
Removing intermediate container 1cc7968144f5
---> c6d390887082
Step 8/12 : FROM ubuntu
---> 94e814e2efa8
Step 9/12 : COPY --from=intermediate /home/test.txt /home/another_test.txt
---> 27480a945fab
Step 10/12 : RUN cat /home/another_test.txt
---> Running in de1f5a999fe1
test
Removing intermediate container de1f5a999fe1
---> 16c630eb6b1b
Step 11/12 : RUN env
---> Running in d13becd5ae77
HOSTNAME=d13becd5ae77
HOME=/root
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PWD=/
Removing intermediate container d13becd5ae77
---> ea52a6e9a7b2
Step 12/12 : RUN env |grep TEST
---> Running in 7ef585772e9a
The command '/bin/sh -c env |grep TEST' returned a non-zero code: 1
從dockerfile的注釋和構建時對應步驟的輸出可以看出,第一階段的環境變量和文件,在第二階段復制了文件后,環境變了沒有復制過來(最后一步報錯了,就是因為環境變量不存在了),正好達到我們想要的結果---將環境變量保密信息等刪除而保留了我們想要的文件。
驗證第二種方法實例(可忽略)
- 同一目錄下創建個dockerfile和至少一個文件
root@ubuntu:/home/vickey/test_build# tree -L 2
.
├── dockerfile
└── whatever
0 directories, 2 files
root@ubuntu:/home/vickey/test_build# cat dockerfile
FROM ubuntu
dockfile
FROM ubuntu
- docker構建鏡像
root@ubuntu:/home/vickey/test_build# docker build --build-arg TEST=1 -t ubuntu:test-build -f ./dockerfile .
Sending build context to Docker daemon 2.56kB
Step 1/1 : FROM ubuntu
---> 94e814e2efa8
[Warning] One or more build-args [TEST] were not consumed
Successfully built 94e814e2efa8
Successfully tagged ubuntu:test-build
root@ubuntu:/home/vickey/test_build# docker images |grep test-build
ubuntu test-build 94e814e2efa8 3 months ago 88.9MB
- 用鏡像啟動個容器
root@ubuntu:/home/vickey/test_build# docker run --rm -it ubuntu:test-build
root@383c30a1d6f5:/# env
HOSTNAME=383c30a1d6f5
PWD=/
HOME=/root
TERM=xterm
SHLVL=1
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
_=/usr/bin/env
root@383c30a1d6f5:/# env|grep "TEST"
root@383c30a1d6f5:/#
發現並沒有構建鏡像時--build-arg TEST=1
傳入的變量,因為構建時有個[Warning] One or more build-args [TEST] were not consumed
, 需要在dockfile里面引用TEST
才行。
- 在dockerfile加入變量
FROM ubuntu
ARG TEST
- 重新構建並創建容器
root@ubuntu:/home/vickey/test_build# docker build --build-arg TEST=1 -t ubuntu:test-build -f ./dockerfile .
Sending build context to Docker daemon 2.56kB
Step 1/2 : FROM ubuntu
---> 94e814e2efa8
Step 2/2 : ARG TEST
---> Running in f9ccda7b3a4b
Removing intermediate container f9ccda7b3a4b
---> dc95b444ffc5
Successfully built dc95b444ffc5
Successfully tagged ubuntu:test-build
root@ubuntu:/home/vickey/test_build# docker run --rm -it ubuntu:test-build
root@370dd8b3d2ca:/# env
... ignore...
root@370dd8b3d2ca:/# env|grep "TEST"
root@370dd8b3d2ca:/#
發現沒有warning了,但還是沒有變量TEST
,因為ARG只在構建docker鏡像時有效,在鏡像創建了並用該鏡像啟動容器后則無效。但可以配合ENV
指令使用使其在創建后的容器也可以生效。下面加入ENV
看看
- 在dockerfile加入
ENV
FROM ubuntu
ARG TEST
ENV ENV_TEST=$TEST
- 再次構建並啟動容器
root@ubuntu:/home/vickey/test_build# docker build --build-arg TEST=1 -t ubuntu:test-build -f ./dockerfile .
Sending build context to Docker daemon 2.56kB
Step 1/3 : FROM ubuntu
---> 94e814e2efa8
Step 2/3 : ARG TEST
---> Using cache
---> dc95b444ffc5
Step 3/3 : ENV ENV_TEST=$TEST
---> Running in d8cd0014b36b
Removing intermediate container d8cd0014b36b
---> ebd198fcb586
Successfully built ebd198fcb586
Successfully tagged ubuntu:test-build
root@ubuntu:/home/vickey/test_build# docker run --rm -it ubuntu:test-build
root@f9dd6cf0bb47:/# env|grep "TEST"
ENV_TEST=1
很好,這時dockerfile的ARG變量TEST
已經傳給ENV變量ENV_TEST
了。我們已經可以使用docker構建時傳入的變量了。