第二口docker的感覺 —— Dockerfile

前言

首先我們來思考這樣一個問題:如果將改變了一些配置的Container在生成一個鏡像?

正文

就前言的問題,我做一下解答:
通過docker commit命令,這個命令的目的是將我們的最新修改作爲鏡像的一層進行構建,命令詳情參考:

https://docs.docker.com/engine/reference/commandline/commit/

❌但是這種方式方式我們並不提倡,因爲這種構建方式相當於一個黑盒的構建,別人也不知道你具體做了那些操作,這個時候就需要引出我們的"構建好助手"——DockerFile

dockerfile是把你所有想要需要的地方都表現在了紙面上,這樣我們可以明確知道所有的修改內容。

dockerfile的具體寫法我們在後面進行詳細的討論。 但是在這裏我們要明確一個問題,Dockerfile其實並不是向鏡像裏直接寫入的,因爲鏡像是隻讀的。docker在這個時候創建了一個臨時的容器,然後寫入內容之後,再把臨時容器刪除。

DockerFile使用說明

我們創建自己需要的鏡像的時候,可以通過commit和dockerfile的形式進行構建,但是前面也說了,官方推薦的還是dockerfile的形式。我們其實很容易的把它理解爲一個構建腳本,docker爲我們提供了很多可以使用的命令,下面我會一一說明。

基本指令說明
  1. ARG指令**
    定義創建鏡像過程中使用的變量,相當於我們爲docker build - -build-arg賦值。鏡像編譯結束後,這個變量將不會被保存

    ARG version=1.0
  2. FROM指令
    指定我們要在哪個image之上再進行構建,儘量使用官方image進行base image,爲了安全。並且一個Dockerfile,必須要以From指令作爲開頭(ARG是唯一一個可以先於From命令的)

    FROM debian:latest
  3. LABLE指令
    像是代碼裏的註釋一樣,一些概括的維護者信息。

    LABLE author=harry
  4. ENV指令
    定義變量,可以在dockerfile下方進行使用,例如我們定義了 ENV USER harry,那麼下面可以這樣使用 "${USER}"

    ENV FILE_LOCATION /usr/local/file
  5. USER指令
    指定運行容器時的用戶是誰
  6. WORKDIR指令
    進入到我們指定的目錄中,如果沒有這個目錄會自動進行創建,用WORKDIR,代替 RUN cd。儘量使用絕對目錄,不要使用相對目錄。

    WORKDIR /usr/local
    WORKDIR tomcat/config
    # 可以連續指定路徑,如果像上述一樣,指定的路徑爲/usr/local/tomcat/configs
  7. RUN指令
    每執行一次RUN就是就會產生鏡像的一層,使用 "&&" 將多個命令串聯起來,如果需要換行在最後需要使用" " 反斜槓。環境的運行與搭建,大多數情況下需要這個命令

    RUN yum update \
            && yum install -y nginx
    #上述操作先更新yum,然後下載nginx
  8. CMD指令
    設置啓動後默認執行的命令和參數。如果docker run 進行了指定了命令,例如 docker run -it … /bin/bash。則不會運行CMD中的命令,而且CMD定義多個,後面會覆蓋之前的。

    啓動tomcat命令
    CMD ['catalina.sh', 'run']
  9. ENTRYPOINT指令
    設置容器啓動時默認執行的命令和參數,該命令會在啓動容器後作爲根命令執行,通過名稱可以看出來是入口。讓容器以應用程序或者服務去執行。並且ENTRYPOINT一定會執行

    將一個shell腳本作爲docker啓動的入口。
    ENTRYPOINT ['/entry.sh']
  10. COPY指令
    把本地文件拷貝到docker裏去,COPY指令優於ADD指令,如果需要添加遠程文件可以使用 curl或者wget

    COPY . /temp
  11. ADD指令
    是把本地的文件複製到docker裏去,不過不光如此,還會對壓縮文件自動進行解壓縮

    ADD . /temp
  12. VOLUME指令
    啓動容器時,可以在本地或者是其他容器創建數據卷掛載點,用於存放數據庫和持久化數據

    #指定掛載點爲 /temp/mount
    VOLUME /temp/mount
  13. EXPOSE指令
    聲明鏡像內部服務監聽的端口,一次可以暴露多個端口

    #暴露22端口,和8888端口
    EXPOSE 22 8888
  14. ONBUILD指令
    指定自己的子鏡像都會執行哪些命令

    #把當前目錄下的所有東西拷貝到/app/src目錄下
    ONBUILD COPY . /app/src

DockerFile的寫法的關鍵在於:環境 + 工程代碼 + 運行
DockerFile的最佳實踐,請看官網:https://docs.docker.com/develop/develop-images/dockerfile_best-practices/

ARG和ENV的區別

兩個看起來都是生命變量用的,他們之間的區別在於ARG時創建鏡像過程中使用的變量,在啓動後的容器中不能使用。而ENV在容器中可以使用

RUN,CMD以及ENTRYPOINT的相同點以及區別

這裏要着重說一下RUN 和 CMD和ENTRYPOINT,他們都可以使用exec格式和shell格式

exec格式舉例:

CMD ['/bin/echo', 'hello world']

shell格式舉例:

CMD echo 'hello world'

但是要注意:如果使用exec格式,打印一個環境變量

CMD['/bin/echo', 'hello world $name'],打印的會是 hello world name的。

這個時候可以考慮使用shell格式,或者說把exec格式進行改造一下,改成如下格式:

CMD['/bin/bash','-c','echo hello world $name ']

另外值得注意的是,RUN命令用於構建鏡像,CMD和ENTRYPOINT用於指定容器啓動時的一些默認指令和參數。

CMD與ENTRYPOINT的共同點

兩者在dockerfile中各自都只能聲明一次,聲明多次,不會報錯,但是隻有最後一條命令會生效。

CMD與ENTRYPOINT的區別

二者既然都是作爲容器啓動時的命令,那麼他們的區別在哪裏呢?

通過我去查閱官網,官網的意思是說ENTRYPOINT是docker容器的主命令,而默認的一些參數會在CMD中進行指定。

請看下方代碼:

ENTRYPOINT ['/bin/echo', 'hello']
CMD ['world']

如果我們運行
docker run -it < image > 會輸出 hello world

而如果我們運行

docker run -it < image > harry 會輸出 hello harry

這就是因爲我上面說過的,如果run的時候沒有指定CMD會執行,如果指定了命令就不會執行CMD了。

所以總結起來他們兩者的關鍵區別在於:

CMD會被作爲命令或者參數在ENTRYPOINT 參數後追加。

CMD可被覆蓋,ENTRYPOINT不會被覆蓋

CMD結合ENTRYPOINT的使用

想象一下這樣一個簡單的場景,我們只希望我們的docker,不作爲一個應用程序啓動,而是用做一個工具。假設爲一個壓力測試的工具,這個工具需要被指定一些參數例如說 --vm 之類的我們可以通過 ->

CMD["/usr/bin/strees",'--vm 1']這種形式進行啓動。但是有沒有想過,這樣的話變量值就被限制死了,有什麼好辦法做到docker啓動的時候動態傳入嗎?我都這麼說了,當然是有的:

FROM ubuntu
RUN apt-get update && apt-install -y stress
ENTRYPOINT ["/usr/bin/stress"]
CMD[]

這樣在啓動的使用就可以動態的將變量傳入:

docker run -it dockerImage名稱 --vm 1

最後總結一下,其實如果CMD和ENTRYPOINT結合的來,那麼ENTRYPOINT是用來指定命令的,而CMD中的則是用來指定參數的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章