建構一個自定義的Docker鏡像必定離不開Dockerfile,有了這個檔案我們就可以通過docker p_w_picpath build指令來建構我們自己的鏡像,是以我們從先從制作一個簡單的鏡像開始。
簡單的Dockerfile:
首先我們要先建立一個目錄,用于存放Dockerfile,這個目錄就是建構鏡像的環境,該環境稱作建構上下文,在建構鏡像的時候會将該上下文和該上下文中的檔案和目錄上傳到Docker守護程序,這樣守護程序就可以通路這裡的内容,隻有這樣才能把使用者想封裝到鏡像的東西添加到鏡像中,包括檔案、代碼或者其他資料。
我這裡在/work下建立一個叫做buildContext的目錄,這個目錄随意任何位置任何名稱都可以。
編輯Dockerfile檔案
建立鏡像
檢視剛剛建構的鏡像
現在我們說一下docker build指令中的參數
參數
說明
--build-art=[]
設定鏡像建立時的變量
--compress
是否在建構過程使用gzip進行壓縮,預設為否
--cpu-shares
設定CPU使用權重,預設為0
--cpu-period
設定CPU的CFS(完全公平排程算法)周期,預設為0,這個可以調整是否可以給該容器配置設定更多或更少的CPU時間。
--cpu-quota
設定CPU的CFS配額,預設為0
--cpuset-cpus
指定使用哪個CPU運作該容器,從0開始表示第一個CPU或者核心
--cpuset-mems
設定指定使用的記憶體ID,一根實體記憶體在系統上是有編号的,就跟CPU一樣,這個參數設定該容器使用哪根實體記憶體條。使用下面的指令檢視:
dmidecode -t 17 | less 其中Handle後面的表示記憶體ID,插上記憶體的插槽在Size中有值,沒插的顯示“No Module Installed”。
--disable-content-truse
忽略校驗,預設開啟
-f
設定使用哪個dockerfile,如果使用這個參數指定檔案位置那麼該Dockerfile的名稱可以是任意的,但是必須在建構上下文之中。之前示範建構的指令中最後是一個“.”,這個表示到本地目前目錄(也叫做建構上下文路徑)去找dockerfile,這時候你的Dockerfile檔案名稱就必須是“dockerfile”,而且它會讀取該目錄以及其子目錄的Dockerfile,并将所有的内容發送給docker守護程序來建立鏡像,是以一般建議建構上下文或者也叫做内容路徑為空目錄。如果你不使用建構上下文路徑下的Dockerfile,那麼就要使用-f參數來指定檔案。
--force-rm
是否允許強制删除容器,預設為false
--isolation
容器隔離技術
--lable=[]
為鏡像設定一個标簽
-m,--memory
設定記憶體限制,如果僅指定這一個參數,那麼實際限制會是這個值的2倍,因為單純的設定這個值其實是1倍給記憶體1倍給SWAP。如果要想固定就要和下面的--memory-swap一起使用,不但指定記憶體限制也要指定SWAP限制。如果使用-m參數遇到下面的錯誤:
"Your kernel does not support swap limit capabilities.memory limit without swap"
那就需要修改/etc/default/grub檔案
GRUB_COMMLINE_LINUX="cgroup_enable=memory swapaccount=1"
然後grub并且重新開機計算機。
--memory-swap
設定容器的SWAP限制
--network
設定網絡方式
--no-cache
建構鏡像時不适用緩存,預設為false。因為構件時,每一步都會送出為一個鏡像,是以Docker會把之前的看做緩存,假設建構分成5步,前三步都不需要修改,那麼Docker就會将前3步作為緩存适用,尤其是在建構鏡像調試的時候會用到,這樣可以節省時間。
--pull
總會嘗試拉取一個最新版本的鏡像進行使用,預設為false
--tag,-t
鏡像名稱 名稱:标簽
-q
不輸出建構鏡像過程,結束後輸出結果。預設是false,也就是輸出建構過程。
--rm
鏡像建構成功後,删除建構過程中的容器。
--shm-size
預設的/dev/shm大小,預設64M
--ulimit
設定容器的ulimit設定,就是我們使用ulimit -a看到的那些内容。
如果建構失敗怎麼辦:
找到失敗的那一步上面的一步,因為失敗的上一步才是成功的,這樣我們就可以使用docker run指令進入容器中進行調試。找到問題後再退出,然後修改Dockerfile,最後再次建構。從上圖看出是我的Dockerfile裡的一個指令寫錯了,進入容器我運作正确的指令進行調試
再次運作建構
從建構的鏡像啟動容器
我們這裡用了一個新的參數-p,這個是用來控制容器在運作時公開哪個端口給主控端。從上圖可以看到容器中的80(也就是在Dockerfile中EXPOSE定義的端口)映射到了本地主控端的32769端口上。我們可以通過下面的指令來檢視映射情況:
說一下這個-p|P參數:
-p
[IP]:[PORT]:PORT
-p PORT 表示使用主控端的0.0.0.0位址的任意高位端口映射到容器的PORT上
-p [PORT]:PORT 表示使用主控端0.0.0.0位址指定的端口映射到容器的PORT上
-p [IP]:[PORT]:PORT 表示使用主控端指定的IP和端口映射到容器的PORT上
-p [IP]::PORT 表示使用主控端指定的IP和随機高位端口映射到容器的PORT上
-P
大寫P,表示使用Dockerfile中定義的EXPOSE端口映射到主控端的随機端口上。
測試通路:
Dockerfile的格式和字段:
FROM
指定建立的鏡像的基礎鏡像,如果本地不存在就會去你所使用的倉庫去拉取。任何Dockerfile中該指令必須是第一條。如果在同一個Dockerfile中建立多個鏡像,可以使用多個FROM指令。
MAINTAINER
設定維護者資訊,也就是寫該Dockerfile的作者是誰,聯系方式等。該資訊會寫入鏡像的Author屬性中。如下圖:
RUN
建構鏡像過程中指定要運作的指令
前者預設會在shell終端中運作,也就是/bin/bash -c;後者會使用exec執行,不會啟動shell環境。每一條RUN指令會在目前鏡像基礎上執行,并送出為新的鏡像。如果指令較長可以使用“\”來換行。
CMD
用于指定一個在容器啟動時需要執行的指令,這個指令和RUN指令很像,隻不過這個指令是在容器啟動時預設執行的,而RUN指令是建構鏡像時執行的。書寫格式如下:
和RUN指令一樣前者預設會在shell終端中運作,也就是/bin/bash -c;後者會使用exec執行,不會啟動shell環境。每一條RUN指令會在目前鏡像基礎上執行,并送出為新的鏡像。如果指令較長可以使用“\”來換行。
注意:每個Dockerfile隻能有一條CMD指令。如果寫了多條,那麼隻有最後一條會被執行,另外docker run指令後面如果加上了要執行的指令,将會覆寫CMD中的指令。
LABEL
該指令用于生成鏡像的中繼資料标簽資訊,格式為:
EXPOSE
聲明鏡像内部服務監聽的端口,格式如下:
可以同時指定多個,每個用空格分割。這裡設定監聽的端口隻是聲明并不會自動完成端口映射,也就是完成主控端上的端口到容器監聽端口的映射。如果要進行端口映射,那麼需要在docker run指令中使用-p|P參數來設定。
ENV
用來定義環境變量,在鏡像建構時會被後續的RUN指令使用,同時在容器啟動時也會生效。
比如:
另外使用docker run指令加上-e "JAVA_HOME=/usr/local/java1.6"參數可以修改ENV設定的環境變量值,不過該值隻會在容器運作時有效。
ADD
該指令用于複制指定目錄下的内容到容器中的指定内容,格式如下:
注意:源路徑可以是一個URL,或者是建構上下文中的檔案或者目錄,不能是建構上下文目錄之外的檔案或者目錄,源檔案也可以是一個tar、tar.gz或者.gz的檔案,它将會被自動解壓縮到目标路徑下,目标路徑可以是一個鏡像内的絕對路徑,也可以是一個相對于WORKDIR的相對路徑。如果目标目錄不存在那麼Docker會自動建立。新建立的檔案和目錄的權限為755,UID和GID都為0.
Docker會自動判斷你要拷貝的檔案還是目錄,如果以“/”結尾表示目錄下的所有内容,如果不是則認為是檔案。
COPY
這個指令和ADD指令類似,差別是COPY隻複雜把檔案拷貝到目标,不會提取和解壓,如果你的源檔案不涉及到解壓縮工作,那麼你用COPY和ADD都一樣。COPY指令的使用方式和原則和ADD一樣。
ENTRYPOINT
這個指令和CMD指令很像,也很容易弄混。docker run指令可以覆寫CMD指令,它的主要作用是在容器啟動時作為根指令執行,所有傳入的值作為該指令的參數執行。其格式如下:
每個Dockerfile也隻能有一個ENTRYPOINT,如果有多個最後一個有效。看一個例子:
在Dockerfile中包括上面的一行,然後在啟動容器時:
這樣啟動容器時,-g和後面的參數将會傳遞給ENTRYPOINT,最終的指令将會是:
如果需要可以在容器啟動時使用--entrypoint這個标志來覆寫ENTRYPOINT的設定,這樣就可以實作自己指定運作的指令。
VOLUME
在容器中建立一個資料挂載點,它不是把你主控端的目錄挂載到容器中,而是在容器中建立一個卷,這個目錄不需要提前建立。
這個目錄可以繞過聯合檔案系統,通常情況下如果容器程式産生的資料需要儲存那麼會使用這個指令來挂載或者多個容器需要共享一些資料也可而已認證這個來完成。
該卷可以在容器間共享或者重用
對該卷的修改立即生效
對卷的修改不會對鏡像産生影響
如果單純的是使用VOLUME,而不在docker run指令中使用-v參數的話,那麼就是把VOLUME指定的目錄挂載到主控端中的某一個位置,這個位置在哪裡呢?你通過 docker inspect 容器ID 中的Mounts裡面來檢視,Destination是VOLUME指定的目錄,Source是主控端本地路徑,如果你再docker run中使用了-v參數,那麼Source就是你指定的路徑。
這個VOLUME的特點是繞過檔案系統,容器中的程式産生的資料就可以放在這個VOLUME指定的目錄中,這樣它不占容器空間,而是消耗主控端磁盤空間,預設本地的路徑可以通過docker inspect檢視,這個路徑裡面的資料不會因為容器的删除而删除。
USER
指定用哪個使用者來運作容器,預設是用root來運作容器的。
可以使用docker run指令中的-u參數來覆寫這個設定。
WORKDIR
指定容器内的工作目錄,就是容器内的目錄切換,在不同目錄下需要做不同的事情,就可以用這個指令。這個指令主要是配合後續要執行的RUN、CMD和ENTRYPOINT的。
在啟動容器時如果在docker run 指令中加入-w參數可以覆寫WORKDIR目錄,來指定一個新的工作目錄。
ARG
該參數用來定義在build建構鏡像是可以傳遞到建構過程中的變量,這樣可以使用--build-arg來傳遞變量進去。
A1變量沒有值,A2變量有一個預設值。
上面的命就會給A1指派,而A2則會用預設值。
ONBUILD
這個指令可以為鏡像添加一個觸發器,一旦具有ONBUILD參數的鏡像當做其他鏡像的基礎鏡像時,ONBUILD定義的指令就會被執行。格式如下:
如果上面的的鏡像是1,那麼基于1去建構鏡像2
這就相當于在新建構鏡像時,自動運作1鏡像中的ONBUILD
說明:這種繼承隻會一次,不會再次傳遞,也就是說如果鏡像3是基于鏡像2制作的,那麼将不會執行ONBUILD,因為也不會繼承過來。
STOPSIGNAL
用來設定停止容器時發送什麼系統信号調用信号給容器,這個信号必須是核心可以識别的。通過kill -l就可以檢視系統支援哪些信号。
HEALTHCHECK
配置容器啟動時如何進行健康檢查
OPTION有:
--interval=DURATION ,多久檢查一次,預設30秒
--timeout=DURATION ,每次檢查等待結果的時間,預設30秒
--retries=N ,如果失敗了,重試幾次才最終确定失敗
SHELL
指定使用SHELL的預設SHELL類型,預設值為:["/bin/sh","-c"]
為什麼不能用建構上下文之外的路徑?
因為建構上下文環境會上傳到Docker守護程序中,而COPY或者ADD是在Docker守護程序中進行的,任何建構環境之外的都找不到,是以就不能用。
舉例制作TOMCAT鏡像
上面講過了Dockerfile的格式以及可以使用的指令,我們現在制作一個TOMCAT的鏡像。環境如下:
編寫dockerfile,内容如下:
建構鏡像
過程如下
檢視建構的鏡像
檢視一下我們之前定義的标簽
啟動容器
測試通路