(五)Docker鏡像管理2之鏡像製作

構建一個自定義的Docker鏡像必定離不開Dockerfile,有了這個文件我們就可以通過docker image build命令來構建我們自己的鏡像,所以我們從先從製作一個簡單的鏡像開始。


簡單的Dockerfile:

首先我們要先建立一個目錄,用於存放Dockerfile,這個目錄就是構建鏡像的環境,該環境稱作構建上下文,在構建鏡像的時候會將該上下文和該上下文中的文件和目錄上傳到Docker守護進程,這樣守護進程就可以訪問這裏的內容,只有這樣才能把用戶想封裝到鏡像的東西添加到鏡像中,包括文件、代碼或者其他數據。

我這裏在/work下建立一個叫做buildContext的目錄,這個目錄隨意任何位置任何名稱都可以。

wKioL1joWyOBoIsrAACCU0yYth4436.png

編輯Dockerfile文件

wKioL1jokWyj2X_GAAGxcsjy7z8962.png

創建鏡像

1
docker image build -t 倉庫/標籤:版本號 .

wKiom1jodzCgGd20AAIS-IxwORM408.pngwKiom1joeFzieRfOAAIjDmb0lns482.png

查看剛剛構建的鏡像

1
docker image history ID

wKioL1joePWDU6odAAJflj87RQ0009.png

現在我們說一下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看到的那些內容。

如果構建失敗怎麼辦:

wKioL1joiD7A5tN9AAKxjcKnNl0499.png

找到失敗的那一步上面的一步,因爲失敗的上一步纔是成功的,這樣我們就可以使用docker run命令進入容器中進行調試。找到問題後再退出,然後修改Dockerfile,最後再次構建。從上圖看出是我的Dockerfile裏的一個命令寫錯了,進入容器我運行正確的命令進行調試

wKioL1joiS3B5Q4lAAFgVKANxVk466.png

再次運行構建

wKiom1joiWDCENC0AAHYLyZGpdM871.png

從構建的鏡像啓動容器

1
docker run -d -p 80 --name httpSrv rex/1stimage:0.1

wKiom1jokjuBg8V-AAJf_Uf0vUs870.png

我們這裏用了一個新的參數-p,這個是用來控制容器在運行時公開哪個端口給宿主機。從上圖可以看到容器中的80(也就是在Dockerfile中EXPOSE定義的端口)映射到了本地宿主機的32769端口上。我們可以通過下面的命令來查看映射情況:

1
2
docker port ID [PORT]
#不加後面的端口表示查看該容器的所有端口映射情況

wKioL1jok1yBQoMnAABhEr7eryI380.png

說一下這個-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端口映射到宿主機的隨機端口上。

測試訪問:

wKiom1jolfXTc2YMAAFsvLmzAsc750.png

Dockerfile的格式和字段:

FROM

指定創建的鏡像的基礎鏡像,如果本地不存在就會去你所使用的倉庫去拉取。任何Dockerfile中該命令必須是第一條。如果在同一個Dockerfile中創建多個鏡像,可以使用多個FROM命令。

1
FROM 鏡像:[標籤]  #如果不指定標籤,則默認爲leatest,最新鏡像


MAINTAINER

設置維護者信息,也就是寫該Dockerfile的作者是誰,聯繫方式等。該信息會寫入鏡像的Author屬性中。如下圖:

wKioL1jonEXwrx2CAAB8kOLLAcc888.png

RUN

構建鏡像過程中指定要運行的命令

1
2
3
4
RUN <COMMAND> 
#或者 
RUN ["COMMAND","ARG1"...]
#後面這張形式會被解析爲JSON數組,所以必須加引號

前者默認會在shell終端中運行,也就是/bin/bash -c;後者會使用exec執行,不會啓動shell環境。每一條RUN命令會在當前鏡像基礎上執行,並提交爲新的鏡像。如果命令較長可以使用“\”來換行。


CMD

用於指定一個在容器啓動時需要執行的命令,這個命令和RUN命令很像,只不過這個命令是在容器啓動時默認執行的,而RUN命令是構建鏡像時執行的。書寫格式如下:

1
2
3
CMD <COMMAND>
#或者
CMD ["COMMAND","ARG1","ARG2"...]

和RUN命令一樣前者默認會在shell終端中運行,也就是/bin/bash -c;後者會使用exec執行,不會啓動shell環境。每一條RUN命令會在當前鏡像基礎上執行,並提交爲新的鏡像。如果命令較長可以使用“\”來換行。

注意:每個Dockerfile只能有一條CMD命令。如果寫了多條,那麼只有最後一條會被執行,另外docker run命令後面如果加上了要執行的命令,將會覆蓋CMD中的命令。


LABEL

該指令用於生成鏡像的元數據標籤信息,格式爲:

1
LABEL <KEY>=<VALUE> <KEY>=<VALUE> ....


EXPOSE

聲明鏡像內部服務監聽的端口,格式如下:

1
EXPOSE <PORT> ....

可以同時指定多個,每個用空格分割。這裏設置監聽的端口只是聲明並不會自動完成端口映射,也就是完成宿主機上的端口到容器監聽端口的映射。如果要進行端口映射,那麼需要在docker run命令中使用-p|P參數來設置。


ENV

用來定義環境變量,在鏡像構建時會被後續的RUN命令使用,同時在容器啓動時也會生效。

1
2
3
ENV <NAME> <VALUE>
#或者
ENV <NAME>=<VALUE>

比如:

1
2
ENV JAVA_HOME /opt/java1.8.0_111
ENV PATH $JAVA_HOME:$PATH

另外使用docker run命令加上-e "JAVA_HOME=/usr/local/java1.6"參數可以修改ENV設定的環境變量值,不過該值只會在容器運行時有效。


ADD

該指令用於複製指定目錄下的內容到容器中的指定內容,格式如下:

1
ADD <SRC> <DES>

注意:源路徑可以是一個URL,或者是構建上下文中的文件或者目錄,不能是構建上下文目錄之外的文件或者目錄,源文件也可以是一個tar、tar.gz或者.gz的文件,它將會被自動解壓縮到目標路徑下,目標路徑可以是一個鏡像內的絕對路徑,也可以是一個相對於WORKDIR的相對路徑。如果目標目錄不存在那麼Docker會自動創建。新創建的文件和目錄的權限爲755,UID和GID都爲0.

1
2
ADD /構建上下文/apache/httpd.conf /etc/httpd/conf/
ADD /構建上下文/apache/httpd.d/*.conf /etc/httpd/conf.d/

Docker會自動判斷你要拷貝的文件還是目錄,如果以“/”結尾表示目錄下的所有內容,如果不是則認爲是文件。


COPY

這個命令和ADD命令類似,區別是COPY只複雜把文件拷貝到目標,不會提取和解壓,如果你的源文件不涉及到解壓縮工作,那麼你用COPY和ADD都一樣。COPY命令的使用方式和原則和ADD一樣。

1
COPY <SRC> <DES>


ENTRYPOINT

這個命令和CMD命令很像,也很容易弄混。docker run命令可以覆蓋CMD命令,它的主要作用是在容器啓動時作爲根命令執行,所有傳入的值作爲該命令的參數執行。其格式如下:

1
2
3
ENTRYPOINT <COMMAND ARG1 ARG2...>
#或者
ENTRYPOINT ["COMMAND","ARG1","ARG2"...]

每個Dockerfile也只能有一個ENTRYPOINT,如果有多個最後一個有效。看一個例子:

1
ENTRYPOINT ["/usr/sbin/nginx"]

在Dockerfile中包括上面的一行,然後在啓動容器時:

1
docker run -d 鏡像 -g "daemon off;"

這樣啓動容器時,-g和後面的參數將會傳遞給ENTRYPOINT,最終的命令將會是:

1
/usr/sbin/nginx -g "daemon off;"

如果需要可以在容器啓動時使用--entrypoint這個標誌來覆蓋ENTRYPOINT的設置,這樣就可以實現自己指定運行的命令。


VOLUME

容器中創建一個數據掛載點,它不是把你宿主機的目錄掛載到容器中,而是在容器中建立一個卷,這個目錄不需要提前建立。

1
VOLUME ["/目錄1","/目錄2"....]

這個目錄可以繞過聯合文件系統,通常情況下如果容器程序產生的數據需要保存那麼會使用這個命令來掛載或者多個容器需要共享一些數據也可而已通過這個來完成。

  • 該卷可以在容器間共享或者重用

  • 對該卷的修改立即生效

  • 對卷的修改不會對鏡像產生影響

如果單純的是使用VOLUME,而不在docker run命令中使用-v參數的話,那麼就是把VOLUME指定的目錄掛載到宿主機中的某一個位置,這個位置在哪裏呢?你通過 docker inspect 容器ID 中的Mounts裏面來查看,Destination是VOLUME指定的目錄,Source是宿主機本地路徑,如果你再docker run中使用了-v參數,那麼Source就是你指定的路徑。

這個VOLUME的特點是繞過文件系統,容器中的程序產生的數據就可以放在這個VOLUME指定的目錄中,這樣它不佔容器空間,而是消耗宿主機磁盤空間,默認本地的路徑可以通過docker inspect查看,這個路徑裏面的數據不會因爲容器的刪除而刪除。


USER

指定用哪個用戶來運行容器,默認是用root來運行容器的。

1
2
3
4
USER <USERNAME>
USER <UID>
USER <USERNAME>:<GROUPNAMD>
USER <UID>:<GID>

可以使用docker run命令中的-u參數來覆蓋這個設置。


WORKDIR

指定容器內的工作目錄,就是容器內的目錄切換,在不同目錄下需要做不同的事情,就可以用這個指令。這個命令主要是配合後續要執行的RUN、CMD和ENTRYPOINT的。

1
WORKDIR <PATH>

在啓動容器時如果在docker run 命令中加入-w參數可以覆蓋WORKDIR目錄,來指定一個新的工作目錄。


ARG

該參數用來定義在build構建鏡像是可以傳遞到構建過程中的變量,這樣可以使用--build-arg來傳遞變量進去。

1
2
ARG A1
ARG A2=HELLO

A1變量沒有值,A2變量有一個默認值。

1
docker build --build-arg A1=world -tNAME .

上面的命就會給A1賦值,而A2則會用默認值。


ONBUILD

這個指令可以爲鏡像添加一個觸發器,一旦具有ONBUILD參數的鏡像當做其他鏡像的基礎鏡像時,ONBUILD定義的命令就會被執行。格式如下:

1
ONBUILD RUN ["echo","hello world"]

如果上面的的鏡像是1,那麼基於1去構建鏡像2

1
2
3
FROM 1
 
.....

這就相當於在新構建鏡像時,自動運行1鏡像中的ONBUILD

說明:這種繼承只會一次,不會再次傳遞,也就是說如果鏡像3是基於鏡像2製作的,那麼將不會執行ONBUILD,因爲也不會繼承過來。


STOPSIGNAL

用來設置停止容器時發送什麼系統信號調用信號給容器,這個信號必須是內核可以識別的。通過kill -l就可以查看系統支持哪些信號。

1
STOPSIGNAL <SIGNAL>


HEALTHCHECK

配置容器啓動時如何進行健康檢查

1
2
3
4
#根據執行命令是否返回0來判斷
HEALTHCHECK [OPTION] CMD <COMMAND>
#禁止繼承鏡像中的健康檢查
HEALTHCHECK NONE

OPTION有:

  • --interval=DURATION ,多久檢查一次,默認30秒

  • --timeout=DURATION ,每次檢查等待結果的時間,默認30秒

  • --retries=N ,如果失敗了,重試幾次才最終確定失敗


SHELL

指定使用SHELL的默認SHELL類型,默認值爲:["/bin/sh","-c"]


爲什麼不能用構建上下文之外的路徑?

因爲構建上下文環境會上傳到Docker守護進程中,而COPY或者ADD是在Docker守護進程中進行的,任何構建環境之外的都找不到,所以就不能用。


舉例製作TOMCAT鏡像

上面講過了Dockerfile的格式以及可以使用的命令,我們現在製作一個TOMCAT的鏡像。環境如下:

wKioL1jp3pSjCKEPAAFF6O5E9aA504.png

編寫dockerfile,內容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# Version: 0.0.1
 
# 指定使用哪個基礎鏡像
FROM centos:6.6
# 說明該鏡像的製作者和聯繫方式
MAINTAINER Rex.chen [email protected]
#設置標籤,不是必須的只是爲了說明裏面的版本查看起來方便
LABEL Tomcat="8.5.13" JDK="1.8.0_111"
 
# 清理一下YUM源,這個不是必須的只是爲了臨時通過YUM安裝軟件方便
RUN yum clean all
 
# 複製安裝程序到指定目錄,我這裏使用COPY命令只是因爲我要自行解壓縮
ENV SOFT_DEST /usr/local/src
ENV TOMCAT_APP_NAME apache-tomcat-8.5.13.tar.gz
ENV JDK_APP_NAME jdk-8u111-linux-x64.tar.gz
ADD tomcat/$TOMCAT_APP_NAME $SOFT_DEST
ADD jdk/$JDK_APP_NAME $SOFT_DEST
 
# 拷貝程序到指定目錄並設置環境變量
WORKDIR $SOFT_DEST
RUN ["mv","./jdk1.8.0_111","/usr"]
RUN ["mkdir","/work/apps","-p"]
RUN ["mv","./apache-tomcat-8.5.13","/work/apps"]
 
ENV JAVA_HOME "/usr/jdk1.8.0_111"
ENV PATH $JAVA_HOME/bin:$PATH
 
ENV CATALINA_HOME "/work/apps/apache-tomcat-8.5.13"
ENV PATH $CATALINA_HOME/bin:$PATH
 
# ENTRYPOINT命令是指定在容器啓動時執行的命令,CMD中指定使用run,因爲catalina.sh start是後臺運行,run是前臺運行
ENTRYPOINT ["catalina.sh"]
CMD ["run"]
# 設置容器內的應用程序使用容器的哪個端口
EXPOSE 8080

構建鏡像

1
docker build -t tomcat8:0.1 .

過程如下

wKiom1jp7n3Sdbp7AAOV2lYd4X0594.png

wKioL1jp7n_gLS1PAAPJZpT7nCs833.png

查看構建的鏡像

wKiom1jp7rahCui1AAVVzv3VMs8182.png

查看一下我們之前定義的標籤

1
2
docker inspect tomcat8:0.1 --format='{{.ContainerConfig.Labels.Tomcat}}'
docker inspect tomcat8:0.1 --format='{{.ContainerConfig.Labels.JDK}}'

wKiom1jp6GziC4W_AADWUBNOt18059.png

啓動容器

1
docker run -d -p 8080 --name jspSrv01 tomcat8:0.1

wKioL1jp76Si84kLAAJ2NA1JJws152.png

測試訪問

wKiom1jp8KWhwDD0AADJQO6UFC4379.png

wKioL1jp8KfjWuGSAAL-EuIVHvI796.png


本文出自 “小惡魔的家” 博客,請務必保留此出處http://littledevil.blog.51cto.com/9445436/1914060

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