1. 程式人生 > >Docker學習<二>

Docker學習<二>

映象的快取特性

Docker會快取已有的映象層,構建新映象時,如果映象層已經存在,就直接使用,無需重新構建

舉例說明

在前面構建的test/ubuntu映象中新增新的內容,往裡面複製一個檔案

[email protected]:~# ls           ①

Dockerfile  testfile

[email protected]:~#

[email protected]:~# docker build -t test/ubuntu:v2 .

Sending build context to Docker daemon 32.77 kB

Step 
1 : FROM ubuntu ---> f753707788c5 Step 2 : RUN apt-get update && apt-get install -y vim ---> Using cache ② ---> 35ca89798937 Step 3 : COPY testfile /---> 8d02784a78f4 Removing intermediate container bf2b4040f4e9 Successfully built 8d02784a78f4

 

對上面的步驟進行相應的說明:先確保testfile檔案存在。在Dockerfile檔案執行過程中,執行RUN指令時,由於之前已經執行過相同的RUN指令,這次直接使用快取中的映象層。最後直接執行COPY指令,其過程是啟動臨時容器,複製testfile檔案,提交新的映象層,再刪除生成的臨時容器。全部過程執行完畢,就得到了所需的在test/ubuntu映象上直接新增一層新的映象的test/ubuntu:v2

 

如果構建映象時不想使用快取,可以在docker build命令中新增--no-cache引數

Dockerfile中每一個指令都會建立一個映象層,上層依賴下層。無論什麼時候,只要某一層發生變化,其上面的所有層的快取都會失效。也就是說,如果我們修改Dockerfile指令的順序,或者修改、新增指令,都會使快取失效

 

比如這裡修改前面的Dockerfile檔案,交換一下指令的執行順序

從邏輯上說,這對整個映象的構建沒有什麼影響,但對於docker映象的快取來說,這裡已經改變了下層映象的結構,而上層映象依賴於下層映象,當下層映象發生變化時,原來的映象快取則不再生效。這裡的執行過程:先執行FROM指令,在本地找到基礎映象並執行一個容器,然後在該容器中執行COPY指令,該指令執行完畢後刪除生成的臨時容器,最後再執行RUN指令。如果是前面的順序,執行RUN指令時會直接用test/ubuntu映象的快取,但這裡先是執行了COPY指令,導致下層映象發生變化,所以這裡得重新執行RUN指令,其過程與test/ubuntu的過程一樣

 

除錯Dockerfile

先後顧Dockerfile構建映象的過程

1. 從基礎映象執行一個容器

2. 執行一條指令,對容器進行修改

3. 執行類似docker commit的操作,生成一個新的映象層

4. Docker再基於剛提交的映象執行一個新的容器

5. 重複2-4步,直到Dockerfile中的所有指令執行完畢

從這個過程可以看出,如果Dockerfile由於某種原因執行到某個指令失敗了,我們也能夠得到前一個指令成功執行構建出的映象,這對除錯很有幫助,可以執行最新的映象來定位指令失敗的原因

下面來看一個除錯的例子,Dockerfile檔案的內容如下 

執行docker build

Dockerfile執行到第三部時失敗,我們可以利用第二步得到的映象進行除錯,方法是docker run -it啟動映象的一個容器 

手工執行RUN命令很容易定位失敗的原因,此處是因為busybox映象中沒有bash。這個例子很好的展示了Dockerfile的除錯方法

 

Dockerfile常用的指令

FROM:指定基礎映象

MAINTAINER:說明映象作者資訊,可以是任意字串。它不是Dockerfile的必要內容,但為了便於映象的維護,建議寫上去

COPY:將檔案從build context複製到映象

ADD:與COPY類似,從build context複製檔案到映象。不同的是,如果src是歸檔檔案,檔案會被自動解壓到dest

ENV:設定環境變數,環境變數可被後面的指令使用

EXPOSE:指定容器中的程序會監聽某個埠,Docker可以將該埠暴露出來

VOLUME:將檔案或目錄宣告為volume

WORKDIR:為後面的RUN、CMD、ENTRYPOINT、ADD、COPY指令設定映象中的當前工作目錄

RUN:在容器中執行指定的命令

CMD:容器啟動時執行指定的命令。Dockerfile中可以有多個CMD指令,但只有最後一個生效。CMD可被docker run之後的引數替換

ENTRYPOINT:設定容器啟動時執行的命令。Dockerfile中可以有多個ENTRYPOINT指令,但只有最後一個生效。CMD或docker run之後的引數會被當做引數傳遞給ENTRYPOINT

 

RUN、CMD、ENTRYPOINT的區別

1. RUN執行命令並建立新的映象層,RUN經常用於安裝軟體包

2. CMD設定容器啟動後預設執行的命令及其引數,但CMD能夠被docker run後面跟的命令列引數替換

3. ENTRYPOINT配置容器啟動時執行的命令

 

RUN

下面是使用RUN安裝多個軟體包的例子

RUN apt-get update && apt-get install -y \  

 wireshark\

 vim\

 wget \

 mercurial \

 subversion

注意:apt-get update和apt-get install被放在一個RUN指令中執行,這樣能夠保證每次安裝的是最新的包。如果apt-get install在單獨的RUN中執行,則會使用apt-get update建立的映象層,而這一層可能是很久以前的快取了

CMD

此命令在容器啟動且docker run沒有指定其他命令時執行

1. 如果docker run指定了其他命令,CMD指定的預設命令會被忽略

2. 如果Dockerfile中有多個CMD指令,只有最後一個有效

下面看看CMD是如何工作的,Dockerfile片段如下

CMD echo “Hello world”

執行容器docker run -it [ image ] 將輸出

Hello world

但當後面加一個命令,比如docker run -it [ image ] /bin/bash,CMD會被忽略掉,命令bash將被執行

[email protected]:/#

 

 

ENTRYPOINT

ENTRYPOINT指令可讓容器以應用程式或者服務的形式執行

ENTRYPOINT看上去和CMD很像,它們都可以指定要執行的命令及其引數,不同的地方在於ENTRYPOINT不會被忽略,一定會被執行,即使執行docker run時指定了其他命令

 

使用公共Registry

下面介紹如何使用Docker Hub存放映象

1. 首先得在Docker Hub上註冊一個賬號(當我們在hub.docker.com上註冊賬號時發現不能註冊,可以在用谷歌瀏覽器登入,並在上面安裝谷歌訪問助手,安裝完成後並可以註冊。另一種方法是直接FQ)

2. 在Docker Hub上登入 

這裡用的是我自己的賬號,使用者名稱為chenjin2018,輸入密碼即可登入

3. 修改映象的repository使之與Docker Hub賬號匹配

Docker Hub為了區分不同使用者名稱的同名映象,映象的registry中要包含使用者名稱,完整個格式為:[username]/xxx:tag

我們通過docker tag命令重新命名映象 

4. 通過docker push將映象上傳到Docker Hub 

5. 登入hub.docker.com,在Public Repository中就可以看到上傳的映象 

如果要刪除映象,只能在Docker Hub介面上操作

6. 其他使用者只需用docker pull就可以下載並使用這個映象了

 

搭建本地的Registry

1. 啟動registry容器

我們使用的映象是registry:2

-d是以守護方式啟動容器

-p將容器的5000埠對映到Host的5000埠。5000是registry服務埠

-v將容器/var/lib/registry目錄對映到Host的/myregistry,用於存放映象資料

2. 通過docker tag重新命名映象,使之與registry匹配 

我們在映象前面加了執行registry的主機名稱和埠

repositroy的完整格式:[registry-host]:[port]/[username]/xxx

只有Docker Hub上的映象可以省略[registry-host]:[port]

3. 通過docker push上傳映象 

4. 現在已經可以通過docker pull從本地registry下載映象了

 

Docker映象小結

下面是映象的常用操作子命令

images   顯示映象列表

history  顯示映象構建歷史

commit   從容器建立新映象

build    從Dockerfile中構建新映象

tag      給映象打tag

pull     從registry下載映象

push     將映象上傳到registry

rmi      刪除Docker host中的映象

search   搜尋Docker Hub中的映象