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 Step1 : 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中的映象