Docker 讀書心得小記 ARG 與 ENV
2018 年的讀書會又開始啟動了
這次的用書是 Mastering Docker - 2nd edition
上次的讀書會內, 大家有討論到在 Dockerfile 內 ENV 以及 ARG
為了避免自己忘記就來寫一下心得 :)
先來觀察原來書中的範例 Dockerfile
# cat Dockerfile
FROM alpine:latest
LABEL maintainer="Russ McKendrick <russ@mckendrick.io>"
LABEL description="This example Dockerfile installs Apache & PHP."
ENV PHPVERSION 7
RUN apk add --update apache2 php${PHPVERSION}-apache2 php${PHPVERSION} && \
rm -rf /var/cache/apk/* && \
mkdir /run/apache2/ && \
rm -rf /var/www/localhost/htdocs/index.html && \
echo "<?php phpinfo(); ?>" > /var/www/localhost/htdocs/index.php && \
chmod 755 /var/www/localhost/htdocs/index.php
EXPOSE 80/tcp
ENTRYPOINT ["httpd"]
CMD ["-D", "FOREGROUND"]
這邊使用 ENV 的方式指定變數 PHPVERSION 為 7
在Dockerfile 新增套件的時候增加 php7-apache2 ( php${PHPVERSION}-apache2 )與 php7 (php${PHPVERSION}) 套件到系統內, 所以 docker images 建立起來的時候就是使用 php7
所以在執行 docker build 的時候, 建立 image 內 php 版本為 php7
# docker build --tag local/apache-php:7 .
然後再次編輯 Dockerfile, 將 PHPVERSION 變數的值改為 5
FROM alpine:latest
LABEL maintainer="Russ McKendrick <russ@mckendrick.io>"
LABEL description="This example Dockerfile installs Apache & PHP."
ENV PHPVERSION 5
RUN apk add --update apache2 php${PHPVERSION}-apache2 php${PHPVERSION} && \
rm -rf /var/cache/apk/* && \
mkdir /run/apache2/ && \
rm -rf /var/www/localhost/htdocs/index.html && \
echo "<?php phpinfo(); ?>" > /var/www/localhost/htdocs/index.php && \
chmod 755 /var/www/localhost/htdocs/index.php
EXPOSE 80/tcp
ENTRYPOINT ["httpd"]
CMD ["-D", "FOREGROUND"]
所以在執行 docker build 的時候, 建立 image 內 php 版本為 php5
# docker build --tag local/apache-php:5 .
這樣的方式是不錯, 可是個人而言就會覺得好像太麻煩, 或是彈性太小
- 需要去編輯 Dockfile
- 不能在 docker build 的時候從指令上面指定嗎?
所以就在網路上面找到 ARG 的方式
- ARG 可以在 docker build 的時候藉由 --build-arg 指定
所以就來進行實驗吧
Lab 1: 使用 ARG, 但是沒有給初始值
# cat Dockerfile
FROM alpine:latest
LABEL maintainer="Russ McKendrick <russ@mckendrick.io>"
LABEL description="This example Dockerfile installs Apache & PHP."
#ENV PHPVERSION 7
ARG PHPVERSION
RUN apk add --update apache2 php${PHPVERSION}-apache2 php${PHPVERSION} && \
rm -rf /var/cache/apk/* && \
mkdir /run/apache2/ && \
rm -rf /var/www/localhost/htdocs/index.html && \
echo "<?php phpinfo(); ?>" > /var/www/localhost/htdocs/index.php && \
chmod 755 /var/www/localhost/htdocs/index.php
EXPOSE 80/tcp
ENTRYPOINT ["httpd"]
CMD ["-D", "FOREGROUND"]
來進行 docker build 測試, 因為沒有指定 PHPVERSION 的值, ARG 也沒有給預設值, 所以在新增套件的時候會失敗
# docker build --tag local/apache-php:argtest .
Sending build context to Docker daemon 2.56kB
Step 1/8 : FROM alpine:latest
latest: Pulling from library/alpine
Digest: sha256:7df6db5aa61ae9480f52f0b3a06a140ab98d427f86d8d5de0bedab9b8df6b1c0
Status: Downloaded newer image for alpine:latest
---> 3fd9065eaf02
Step 2/8 : LABEL maintainer "Russ McKendrick <russ@mckendrick.io>"
---> Using cache
---> b91a98043232
Step 3/8 : LABEL description "This example Dockerfile installs Apache & PHP."
---> Running in db14ad6c1ad9
---> c195f953eabb
Removing intermediate container db14ad6c1ad9
Step 4/8 : ARG PHPVERSION
---> Running in 6e30a023e3b1
---> d503211faf4f
Removing intermediate container 6e30a023e3b1
Step 5/8 : RUN apk add --update apache2 php${PHPVERSION}-apache2 php${PHPVERSION} && rm -rf /var/cache/apk/* && mkdir /run/apache2/ && rm -rf /var/www/localhost/htdocs/index.html && echo "<?php phpinfo(); ?>" > /var/www/localhost/htdocs/index.php && chmod 755 /var/www/localhost/htdocs/index.php
---> Running in 31ce8064f962
fetch http://dl-cdn.alpinelinux.org/alpine/v3.7/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.7/community/x86_64/APKINDEX.tar.gz
ERROR: unsatisfiable constraints:
接下來使用 --build-arg 的方式在 docker build 中指定 PHPVERSION 為 7
# docker build --build-arg PHPVERSION=7 --tag local/apache-php:argtest7 .
這樣編譯就沒有問題, 接下來驗證一下 PHP 是否為 7 的版本, 啟動 local/apache-php:argtest7 來檢查吧
# docker run -d -p 80:80 local/apache-php:argtest7
a34e911c75bb54fcbdc3958be835bb93e0e87288efd6751c79b944a52abb91ba
再來實驗 --build-arg 將 PHPVERSION 指定為 5 建立 image
# docker build --build-arg PHPVERSION=5 --tag local/apache-php:argtest5 .
用同樣的方式在 port 81 啟動 local/apche-php:argtest5
# docker run -d -p 81:80 local/apache-php:argtest5
dd75d69b2953243a8a6bbf166385e479a22e4dfd31eee37d1f35facd924975df
開啟瀏覽器, 觀察 http://localhost:81
果然是我們要的 PHP 5
Lab 2: 使用 ARG, 有給初始值
跟上個練習很像, 只是這次的 Dockerfile 內的 ARG 有給初始值
# cat Dockerfile
FROM alpine:latest
LABEL maintainer="Russ McKendrick <russ@mckendrick.io>"
LABEL description="This example Dockerfile installs Apache & PHP."
#ENV PHPVERSION 7
ARG PHPVERSION=7
RUN apk add --update apache2 php${PHPVERSION}-apache2 php${PHPVERSION} && \
rm -rf /var/cache/apk/* && \
mkdir /run/apache2/ && \
rm -rf /var/www/localhost/htdocs/index.html && \
echo "<?php phpinfo(); ?>" > /var/www/localhost/htdocs/index.php && \
chmod 755 /var/www/localhost/htdocs/index.php
EXPOSE 80/tcp
ENTRYPOINT ["httpd"]
CMD ["-D", "FOREGROUND"]
來嘗試剛剛的 docker build 吧 :)
# docker build --tag local/apache-php:argdefault .
因為有給預設值, 所以就算沒有透過 --build-arg 指定, 他會使用預設值來建立, 所以就沒有問題
接下來實驗 --build-arg 指定一個值, 但是跟預設值不同
# docker build --build-arg PHPVERSION=5 --tag local/apache-php:argover5 .
是的, 這樣的方式, 指定的 PHPVERSION=5 會覆蓋掉預設值的 PHPVERSION=7 :)
達成彈性的目的
Lab 3: ARG 與 ENV 優先性
其實我也覺得我自己的問題很多 :p
不得不說讀書會的好處就是, 可以討論很多自己不會去想的問題
讀書會有人提出, 那 ARG 與 ENV 都存在的時候, 以誰為準 ???
修改剛剛的 Dockfile, 故意讓同一個變數分別被 ENV 與 ARG 指定
# cat Dockerfile
FROM alpine:latest
LABEL maintainer="Russ McKendrick <russ@mckendrick.io>"
LABEL description="This example Dockerfile installs Apache & PHP."
ENV PHPVERSION 5
ARG PHPVERSION=7
RUN apk add --update apache2 php${PHPVERSION}-apache2 php${PHPVERSION} && \
rm -rf /var/cache/apk/* && \
mkdir /run/apache2/ && \
rm -rf /var/www/localhost/htdocs/index.html && \
echo "<?php phpinfo(); ?>" > /var/www/localhost/htdocs/index.php && \
chmod 755 /var/www/localhost/htdocs/index.php
EXPOSE 80/tcp
ENTRYPOINT ["httpd"]
CMD ["-D", "FOREGROUND"]
執行 docker build 測試
# docker build --tag local/apache-php:argvsenv .
測試結果
安裝的是 PHP 5 , 也就是 ENV 指定的版本
為了排除是變數指定順序的問題 再次修改 Dockerfile
# cat Dockerfile
FROM alpine:latest
LABEL maintainer="Russ McKendrick <russ@mckendrick.io>"
LABEL description="This example Dockerfile installs Apache & PHP."
ARG PHPVERSION=7
ENV PHPVERSION 5
RUN apk add --update apache2 php${PHPVERSION}-apache2 php${PHPVERSION} && \
rm -rf /var/cache/apk/* && \
mkdir /run/apache2/ && \
rm -rf /var/www/localhost/htdocs/index.html && \
echo "<?php phpinfo(); ?>" > /var/www/localhost/htdocs/index.php && \
chmod 755 /var/www/localhost/htdocs/index.php
EXPOSE 80/tcp
ENTRYPOINT ["httpd"]
CMD ["-D", "FOREGROUND"]
測試結果
安裝的是 PHP 5 , 也就是 ENV 指定的版本
也就是跟 Dockerfile 內的順序無關, 排除 overwrite 考量
最後, 另外一個觀察點是變數有效範圍
- ARG 的變數只在 build image 範圍內有效
- ENV 是在 build image 以及之後執行 image 都有效
這一點可以藉由 docker inspect 來驗證
觀察剛剛由 ARG 建立的 image
# docker inspect -f {{.Config.Env}} local/apache-php:argtest5
[PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin]
觀察剛剛 ENV 擊敗 ARG 建立的 image
# docker inspect -f {{.Config.Env}} local/apache-php:argvsenv
[PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin PHPVERSION=5]
感謝讀書會讓我多會一些東西
Reference
~ enjoy it
沒有留言:
張貼留言