星期六, 2月 24, 2018

Docker 讀書心得小記 ARG 與 ENV

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


開啟瀏覽器, 觀察 http://localhost




再來實驗 --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

沒有留言: