Docker鏡像文件(images)的存儲結構
原文作者: Troy Howard(http://blog.thoward37.me/)
原文地址:http://blog.thoward37.me/articles/where-are-docker-images-stored/
翻譯:劉斌(http://liubin.org/)
本文地址:http://liubin.org/2014/03/10/about-docker-images-storage/ ?
如果你是剛開始接觸 Docker的話,按照官方文檔里的例子,很容易入門并且進行一些簡單的工作。但是,如果再深入一些,比如要創建自己的Dockerfile的話,你就可能會有點感到困惑了。在眾多初學者比較容易迷惑的問題中,這是一個非常普遍的問題:
我的Docker鏡像(images)保存在哪里呢?
- 每個人
這個問題也著實讓我撓頭。更糟糕的是,作為一個新手,你的最終目標是將自己笨手笨腳創建的Docker鏡像發布到官方的Docker鏡像索引上。
快來看看我創建的Docker鏡像吧,它非常棒 thoward/i_have_no_idea_what_im_doing.
但這不是我想要做的。
還有更糟糕的事情,在這之前很長的一段時間里,你都沒法刪除你發布的鏡像,你那些讓人羞愧尷尬的學習過程將永久性的貼在那里。
幸運的是,現在刪除一個自己發布的鏡像文件已經變得非常簡單了。
所以,在這里我做一下小小的澄清。如果你滿足下面的條件的話,那么請放心,你的鏡像文件是不可能被發布為公開鏡像的:
-
你還沒有在官方的public index注冊賬號。
-
你沒有通過 docker login 命令登錄。
-
你沒有運行 docker push 命令將自己的鏡像發布到public index上。
術語(用語、關鍵概念)
Docker所使用的術語,也是其致使用戶產生困惑的原因。比如Docker可能會使用overlap,或者含義模糊,或者被錯誤使用的用語,也可能使用有悖于人們常識認識的用語。
所以,在這里我們先對一些術語做一下解釋。
鏡像(Image) vs Dockerfile
這組概念很少會讓人產生疑惑,但是這兩者的區別非常重要。Docker在鏡像(image)中運行你的代碼,而不是Dockerfile。Dockerfile是通過docker build命令來編譯鏡像的配置文件。
如果你去瀏覽一下public index的話,你將會看到那里羅列了很多鏡像文件。但是,也許有些奇怪的是,你將看不到任何編譯出它們的dockerfile。鏡像文件就是從Dockerfile編譯而得到的不透明資產(opaque asset )。
當你用docker push命令發布自己的鏡像的時候,你發布的不是任何你的代碼,而是由你的代碼編譯出來的鏡像文件。
注冊表(Registry) vs 索引(Index)
注冊表(鏡像注冊表,registry)和索引(鏡像索引,index)這兩個概念,以及它們的區別也很特殊。
一個索引(index)用來管理用戶賬號,權限,搜索,打標簽(tagging),以及其它可以方便的通過Web界面來完成的工作。
一個注冊表(registry)則是真正的用來保存、提供鏡像文件的概念。它通過索引(index)來完成用戶認證步驟。
當你執行docker search命令的時候,Docker會到index里執行查找工作,而不是registry。從實際上來說,Docker會在索引(index)所知道的多個注冊表(registry)中進行查找。
而 當你執行docker push 或者 docker pull操作的時候,index會判斷你是否有權限訪問或者修改該鏡像文件,如果通過index的認證操作的話,registry則進行實際的鏡像存儲工 作或者將鏡像文件發送給請求端。同樣,index會知道你想訪問的鏡像的存儲位置(哪個registry上),然后將訪問請求轉向到相應的 registry。
另外,當你在本地環境下,執行類似docker images工作的時候,你所打交道的既不是一個index,也不是一個registry,而是兩者都會有一點。
鏡像倉庫(Repository )
Docker 使用類似于Github或者其他SCM工具的倉庫概念。當然,它們也不完全等價。
下面這三個問題值得我們先好好思考一下:
-
倉庫和注冊表的區別是什么?
-
倉庫和鏡像的區別是什么?
-
倉庫和 an index username的區別是什么?
實際上,這是一個問題,因為鏡像倉庫是所有這些概念的合集,而不是單獨的任何一個。 此外,當你執行docker images的話你將得到類似如下的輸出:
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu 12.04 8dbd9e392a96 8 months ago 131.3 MB (virtual 131.3 MB)
ubuntu latest 8dbd9e392a96 8 months ago 131.3 MB (virtual 131.3 MB)
ubuntu precise 8dbd9e392a96 8 months ago 131.3 MB (virtual 131.3 MB)
ubuntu 12.10 b750fe79269d 8 months ago 24.65 kB (virtual 179.7 MB)
ubuntu quantal b750fe79269d 8 months ago 24.65 kB (virtual 179.7 MB)
上面鏡像列表的東西看起來像一個倉庫列表?嗯?實際上,那些GUID才是Docker鏡像,但你并不和他們進行交互。
讓我們來仔細看看這個問題。
當 你執行docker build或者docker commit的時候,你可以給它指定一個鏡像名稱。這個名稱一般來說都是類似username/image_name這樣的格式,但這不是必須的。實際上 你可以給鏡像名稱指定任何字符,甚至是那些已經公開的眾所周知鏡像的名稱。
但 是,等你進行docker push的時候,index將會檢查鏡像的名字,查看是否有和其匹配的倉庫(respsitory)。如果找到了匹配的倉庫,將會繼續檢查你是否有權限操 作這個倉庫。如果你有權限的話,那么一個新版本的鏡像將成功的存儲(發布)到這個倉庫中。從中我們可以看出,registry會保持一個倉庫列表,每個倉 庫都有自己的名字。而每個倉庫都保存的都是通過GUID來標識的鏡像文件列表。
這里又出現了標簽的概念。你可以對任何一個鏡像進行打標簽操作,并且在同一個倉庫中,為同一個鏡像保存不同的版本,不同的版本通過GUID來進行區分。我們可以通過username/image_name:tag這種方式來通過標簽訪問不同版本的鏡像。
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu 12.04 8dbd9e392a96 8 months ago 131.3 MB (virtual 131.3 MB)
ubuntu latest 8dbd9e392a96 8 months ago 131.3 MB (virtual 131.3 MB)
ubuntu precise 8dbd9e392a96 8 months ago 131.3 MB (virtual 131.3 MB)
ubuntu 12.10 b750fe79269d 8 months ago 24.65 kB (virtual 179.7 MB)
ubuntu quantal b750fe79269d 8 months ago 24.65 kB (virtual 179.7 MB)
我 們再來重新看一下docker images的輸出結果,應該會有新的認識吧。我們有5個不同版本的ubuntu的鏡像,這些鏡像通過標簽來區分。鏡像倉庫通過ubuntu這個名字來管 理所有這些鏡像。也許你會認為ubuntu是一個鏡像的名字,但實際上這是一個倉庫的名字,它告訴我們它從哪里取得,或者在發布鏡像的時候將保存到何處。
此外,倉庫名稱還有它特殊的命名模式(schema),索引(index)會將倉庫名字的第一部分解析為用戶名,并且將定位倉庫的位置。
那么問題就出現了,假設我們有一個Docker鏡像 thoward/scooby_snacks。
這個鏡像的“正式的名字”應該是thoward/scooby_snacks,盡管實際上我們潛意識里會認為它的名字就是scooby_snacks (這有點類似Github等服務里的倉庫的概念)
實際上,當Docker的文檔里說道倉庫的時候,有時候指的是包含用戶名在內的所有東西,而有時則只是去掉用戶名后的部分。
這是因為一些倉庫(比如ubuntu)等沒有用戶名。對用戶名做特殊處理非常重要,因為index會用它來做認證操作,所以倉庫名字里的用戶名部分有它自己獨特的意思。
Docker主機上的本地存儲
到這里我們已經對Docker復雜的遠程存儲體系做出了說明,以及這里面容易讓人混淆的幾個概念。但是,docker images命令顯示的內容都是本機上存在的資源。
那么本地資源都保存在什么位置呢?我們首先來看看 /var/lib/docker/這個文件夾下的內容。
打開這個文件夾下的 repositories 文件,你將會看到類似下面這樣的JSON 文件:
$ sudo cat /var/lib/docker/repositories | python -mjson.tool
{
“Repositories”: {
“ubuntu”: {
“12.04″: “8dbd9e392a964056420e5d58ca5cc376ef18e2de93b5cc90e868a1bbc8318c1c”,
“12.10″: “b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc”,
“latest”: “8dbd9e392a964056420e5d58ca5cc376ef18e2de93b5cc90e868a1bbc8318c1c”,
“precise”: “8dbd9e392a964056420e5d58ca5cc376ef18e2de93b5cc90e868a1bbc8318c1c”,
“quantal”: “b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc”
}
}
}
看看,是不是正好和docker images的內容一致呢。
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu 12.04 8dbd9e392a96 8 months ago 131.3 MB (virtual 131.3 MB)
ubuntu latest 8dbd9e392a96 8 months ago 131.3 MB (virtual 131.3 MB)
ubuntu precise 8dbd9e392a96 8 months ago 131.3 MB (virtual 131.3 MB)
ubuntu 12.10 b750fe79269d 8 months ago 24.65 kB (virtual 179.7 MB)
ubuntu quantal b750fe79269d 8 months ago 24.65 kB (virtual 179.7 MB)
接著,我們再來看看 /var/lib/docker/graph/這個文件夾:
$ sudo ls -al /var/lib/docker/graph
total 24
drwx—— 6 root root 4096 Nov 22 06:52 .
drwx—— 5 root root 4096 Dec 13 04:25 ..
drwxr-xr-x 3 root root 4096 Dec 13 04:26 27cf784147099545
drwxr-xr-x 3 root root 4096 Nov 22 06:52 8dbd9e392a964056420e5d58ca5cc376ef18e2de93b5cc90e868a1bbc8318c1c
drwxr-xr-x 3 root root 4096 Nov 22 06:52 b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc
drwx—— 3 root root 4096 Nov 22 06:52 _tmp
這些輸出結果可能有點晦澀(Not terribly friendly),但是從中我們可以看出Docker是使用repositories JSON文件來記述鏡像信息的,此JSON文件包含了倉庫名、標簽、以及標簽對應的鏡像ID。
我 們有兩個來自ubuntu倉庫的鏡像,這其中標簽為12.04,precise和latest都指向的是同一個鏡像,其ID 為 8dbd9e392a964056420e5d58ca5cc376ef18e2de93b5cc90e868a1bbc8318c1c (這個ID長度為64位,但是我們可以使用其12位的簡短模式,比如8dbd9e392a96)。
那么這些以鏡像ID命名的文件夾下面又保存了什么東西呢?
$ sudo ls -al /var/lib/docker/graph/8dbd9e392a964056420e5d58ca5cc376ef18e2de93b5cc90e868a1bbc8318c1c
total 20
drwxr-xr-x 3 root root 4096 Nov 22 06:52 .
drwx—— 6 root root 4096 Nov 22 06:52 ..
-rw——- 1 root root 437 Nov 22 06:51 json
drwxr-xr-x 22 root root 4096 Apr 11 2013 layer
-rw——- 1 root root 9 Nov 22 06:52 layersize
這個文件夾下的內容如下:
-
json -保存著關于這個鏡像的元數據
-
layersize – 一個整數,表示layer的大小。
-
layer/ – 子文件夾,保存著rootfs該容器的鏡像
$ sudo cat /var/lib/docker/graph/8dbd9e392a964056420e5d58ca5cc376ef18e2de93b5cc90e868a1bbc8318c1c/json | python -mjson.tool
{
“comment”: “Imported from -”,
“container_config”: {
“AttachStderr”: false,
“AttachStdin”: false,
“AttachStdout”: false,
“Cmd”: null,
“Env”: null,
“Hostname”: “”,
“Image”: “”,
“Memory”: 0,
“MemorySwap”: 0,
“OpenStdin”: false,
“PortSpecs”: null,
“StdinOnce”: false,
“Tty”: false,
“User”: “”
},
“created”: “2013-04-11T14:13:15.57812-07:00″,
“docker_version”: “0.1.4″,
“id”: “8dbd9e392a964056420e5d58ca5cc376ef18e2de93b5cc90e868a1bbc8318c1c”
}$ sudo cat /var/lib/docker/graph/8dbd9e392a964056420e5d58ca5cc376ef18e2de93b5cc90e868a1bbc8318c1c/layersize
131301903$ sudo ls -al /var/lib/docker/graph/8dbd9e392a964056420e5d58ca5cc376ef18e2de93b5cc90e868a1bbc8318c1c/layer
total 88
drwxr-xr-x 22 root root 4096 Apr 11 2013 .
drwxr-xr-x 3 root root 4096 Nov 22 06:52 ..
drwxr-xr-x 2 root root 4096 Apr 11 2013 bin
drwxr-xr-x 2 root root 4096 Apr 19 2012 boot
drwxr-xr-x 4 root root 4096 Nov 22 06:51 dev
drwxr-xr-x 41 root root 4096 Nov 22 06:51 etc
drwxr-xr-x 2 root root 4096 Apr 19 2012 home
drwxr-xr-x 11 root root 4096 Nov 22 06:51 lib
drwxr-xr-x 2 root root 4096 Nov 22 06:51 lib64
drwxr-xr-x 2 root root 4096 Apr 11 2013 media
drwxr-xr-x 2 root root 4096 Apr 19 2012 mnt
drwxr-xr-x 2 root root 4096 Apr 11 2013 opt
drwxr-xr-x 2 root root 4096 Apr 19 2012 proc
drwx—— 2 root root 4096 Nov 22 06:51 root
drwxr-xr-x 4 root root 4096 Nov 22 06:51 run
drwxr-xr-x 2 root root 4096 Nov 22 06:51 sbin
drwxr-xr-x 2 root root 4096 Mar 5 2012 selinux
drwxr-xr-x 2 root root 4096 Apr 11 2013 srv
drwxr-xr-x 2 root root 4096 Apr 14 2012 sys
drwxrwxrwt 2 root root 4096 Apr 11 2013 tmp
drwxr-xr-x 10 root root 4096 Nov 22 06:51 usr
drwxr-xr-x 11 root root 4096 Nov 22 06:51 var
看到這里你應該有些頓悟了吧,這就是我們為什么即使我們不和遠程索引或者注冊表交互也能通過倉庫名來使用一個鏡像的原理了。因為一旦你講鏡像從遠程下載到本地,Docker可以通過倉庫名稱來使用它們。當你創建自己的Dockerfile的時候也不例外。
創建自己的Dockerfiles
首先我們來看一個最簡單的例子。創建如下的Dockerfile:
FROM ubuntu
這個配置文件除了引入ubuntu這個鏡像作為基礎層(base layer)之外,幾乎什么都沒干。不過這樣也足以保證他能正常工作了。
接著,我們來運行 docker build -t scooby_snacks 命令。這個命令將會在我們指定的位置(例子里是當前文件夾,即”.”)尋找Dockerfile文件,并基于此進行鏡像編譯。這里的 scooby_snacks 是倉庫的名字。
$ docker build -t scooby_snacks .
Uploading context 64184320 bytes
Step 1 : FROM ubuntu
—> 8dbd9e392a96
Successfully built 8dbd9e392a96
怎么樣,標準輸出立顯示了出現了“Uploading context”的字眼,這是把此鏡像發布到官網上的意思么?
讓我們來檢查一下就知道了:
$ docker search scooby_snacks
NAME DESCRIPTION STARS OFFICIAL TRUSTED
看來上面我們創建的鏡像還沒有被公開發布。
那上面那句話是什么意思呢?
我也不知道,但是我們可以忽略它。也許它是將鏡像文件保存到本機的意思吧。
$ sudo cat /var/lib/docker/repositories | python -mjson.tool
{
“Repositories”: {
“scooby_snacks”: {
“latest”: “8dbd9e392a964056420e5d58ca5cc376ef18e2de93b5cc90e868a1bbc8318c1c”
},
“ubuntu”: {
“12.04″: “8dbd9e392a964056420e5d58ca5cc376ef18e2de93b5cc90e868a1bbc8318c1c”,
“12.10″: “b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc”,
“latest”: “8dbd9e392a964056420e5d58ca5cc376ef18e2de93b5cc90e868a1bbc8318c1c”,
“precise”: “8dbd9e392a964056420e5d58ca5cc376ef18e2de93b5cc90e868a1bbc8318c1c”,
“quantal”: “b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc”
}
}
}
從上面的結果來看,Docker只是將它“uploaded”到了/var/lib/docker。
同樣,我們也可以通過docker images命令來確認這一結果:
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu 12.04 8dbd9e392a96 8 months ago 131.3 MB (virtual 131.3 MB)
ubuntu latest 8dbd9e392a96 8 months ago 131.3 MB (virtual 131.3 MB)
ubuntu precise 8dbd9e392a96 8 months ago 131.3 MB (virtual 131.3 MB)
scooby_snacks latest 8dbd9e392a96 8 months ago 131.3 MB (virtual 131.3 MB)
ubuntu 12.10 b750fe79269d 8 months ago 24.65 kB (virtual 179.7 MB)
ubuntu quantal b750fe79269d 8 months ago 24.65 kB (virtual 179.7 MB)
這就是我們構建鏡像文件的結果。Docker很聰明,由于我們是基于ubuntu:latest這個鏡像來創建的scooby_snacks,而且沒有做任何定制修改,所以它的鏡像ID也是8dbd9e392a96。
下面,我們來試著對基礎層做一些修改,然后編譯出一個新的層(layer)來。
我們通過修改 Dockerfile 文件增加如下內容來實現:
FROM ubuntu
RUN touch scooby_snacks.txt
編輯完之后,我們再次運行“docker build -t scooby_snacks .”來構建這個鏡像。
$ docker build -t scooby_snacks .
Uploading context 64184320 bytes
Step 1 : FROM ubuntu
—> 8dbd9e392a96
Step 2 : RUN touch scooby_snacks.txt
—> Running in 86664242766c
—> 91acef3a5936
Successfully built 91acef3a5936
新的構建完成之后,會在/var/lib/docker/graph下面一個新的文件夾
$ sudo ls -al /var/lib/docker/graph
total 28
drwx—— 7 root root 4096 Dec 13 06:27 .
drwx—— 5 root root 4096 Dec 13 06:27 ..
drwxr-xr-x 3 root root 4096 Dec 13 04:26 27cf784147099545
drwxr-xr-x 3 root root 4096 Nov 22 06:52 8dbd9e392a964056420e5d58ca5cc376ef18e2de93b5cc90e868a1bbc8318c1c
drwxr-xr-x 3 root root 4096 Dec 13 06:27 91acef3a5936769f763729529e736681e5079dc6ddf6ab0e61c327a93d163df9
drwxr-xr-x 3 root root 4096 Nov 22 06:52 b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc
drwx—— 3 root root 4096 Dec 13 06:27 _tmp
Docker為這個鏡像分配了一個新的 ID:
91acef3a5936769f763729529e736681e5079dc6ddf6ab0e61c327a93d163df9
這個新的鏡像已經被更新到了/var/lib/docker/repositories 并且可以通過docker images命令來確認。
$ sudo cat /var/lib/docker/repositories | python -mjson.tool
{
“Repositories”: {
“scooby_snacks”: {
“latest”: “91acef3a5936769f763729529e736681e5079dc6ddf6ab0e61c327a93d163df9″
},
“ubuntu”: {
“12.04″: “8dbd9e392a964056420e5d58ca5cc376ef18e2de93b5cc90e868a1bbc8318c1c”,
“12.10″: “b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc”,
“latest”: “8dbd9e392a964056420e5d58ca5cc376ef18e2de93b5cc90e868a1bbc8318c1c”,
“precise”: “8dbd9e392a964056420e5d58ca5cc376ef18e2de93b5cc90e868a1bbc8318c1c”,
“quantal”: “b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc”
}
}
}
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
scooby_snacks latest 91acef3a5936 5 minutes ago 12.29 kB (virtual 131.3 MB)
ubuntu 12.04 8dbd9e392a96 8 months ago 131.3 MB (virtual 131.3 MB)
ubuntu latest 8dbd9e392a96 8 months ago 131.3 MB (virtual 131.3 MB)
ubuntu precise 8dbd9e392a96 8 months ago 131.3 MB (virtual 131.3 MB)
ubuntu 12.10 b750fe79269d 8 months ago 24.65 kB (virtual 179.7 MB)
ubuntu quantal b750fe79269d 8 months ago 24.65 kB (virtual 179.7 MB)
讓我們來看看文件/var/lib/docker/graph/91acef3a5936769f763729529e736681e5079dc6ddf6ab0e61c327a93d163df9 的內容:
$ sudo cat /var/lib/docker/graph/91acef3a5936769f763729529e736681e5079dc6ddf6ab0e61c327a93d163df9/json | python -mjson.tool
{
“Size”: 0,
“architecture”: “x86_64″,
“config”: {
“AttachStderr”: false,
“AttachStdin”: false,
“AttachStdout”: false,
“Cmd”: null,
“CpuShares”: 0,
“Dns”: null,
“Domainname”: “”,
“Entrypoint”: [],
“Env”: [
"HOME=/",
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
“ExposedPorts”: {},
“Hostname”: “86664242766c”,
“Image”: “8dbd9e392a964056420e5d58ca5cc376ef18e2de93b5cc90e868a1bbc8318c1c”,
“Memory”: 0,
“MemorySwap”: 0,
“NetworkDisabled”: false,
“OpenStdin”: false,
“PortSpecs”: null,
“StdinOnce”: false,
“Tty”: false,
“User”: “”,
“Volumes”: {},
“VolumesFrom”: “”,
“WorkingDir”: “”
},
“container”: “86664242766c5548f8118716e873835c171811176a710e425c1fcf1fa367b505″,
“container_config”: {
“AttachStderr”: false,
“AttachStdin”: false,
“AttachStdout”: false,
“Cmd”: [
"/bin/sh",
"-c",
"touch scooby_snacks.txt"
],
“CpuShares”: 0,
“Dns”: null,
“Domainname”: “”,
“Entrypoint”: [],
“Env”: [
"HOME=/",
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
“ExposedPorts”: {},
“Hostname”: “86664242766c”,
“Image”: “8dbd9e392a964056420e5d58ca5cc376ef18e2de93b5cc90e868a1bbc8318c1c”,
“Memory”: 0,
“MemorySwap”: 0,
“NetworkDisabled”: false,
“OpenStdin”: false,
“PortSpecs”: null,
“StdinOnce”: false,
“Tty”: false,
“User”: “”,
“Volumes”: {},
“VolumesFrom”: “”,
“WorkingDir”: “”
},
“created”: “2013-12-13T06:27:03.234029255Z”,
“docker_version”: “0.6.7″,
“id”: “91acef3a5936769f763729529e736681e5079dc6ddf6ab0e61c327a93d163df9″,
“parent”: “8dbd9e392a964056420e5d58ca5cc376ef18e2de93b5cc90e868a1bbc8318c1c”
}$ sudo cat /var/lib/docker/graph/91acef3a5936769f763729529e736681e5079dc6ddf6ab0e61c327a93d163df9/layersize
12288$ sudo ls -al /var/lib/docker/graph/91acef3a5936769f763729529e736681e5079dc6ddf6ab0e61c327a93d163df9/layer
total 16
drwxr-xr-x 4 root root 4096 Dec 13 06:27 .
drwxr-xr-x 3 root root 4096 Dec 13 06:27 ..
-rw-r–r– 1 root root 0 Dec 13 06:27 scooby_snacks.txt
-r–r–r– 1 root root 0 Dec 13 06:27 .wh..wh.aufs
drwx—— 2 root root 4096 Dec 13 06:27 .wh..wh.orph
drwx—— 2 root root 4096 Dec 13 06:27 .wh..wh.plnk
我們對Dockerfile小小的修改,卻給編譯后的結果帶來了莫大的影響。另外需要注意的是Docker的鏡像文件里只會記錄和parent image的差分信息,這也是理解layer概念的一個關鍵。
運行新的鏡像文件
下面我們就可以使用我們的新鏡像了。這里我們使用bash這個交互控制臺來操作。
$ docker run -i -t scooby_snacks /bin/bash
root@1f8602a7d589:/# ls -al
total 12308
drwxr-xr-x 30 root root 4096 Dec 13 06:43 .
drwxr-xr-x 30 root root 4096 Dec 13 06:43 ..
-rw——- 1 root root 208 Dec 13 06:43 .dockerenv
-rwxr-xr-x 1 root root 12516574 Nov 22 02:34 .dockerinit
drwxr-xr-x 2 root root 4096 Apr 11 2013 bin
drwxr-xr-x 2 root root 4096 Apr 19 2012 boot
drwxr-xr-x 6 root root 4096 Nov 22 06:52 dev
drwxr-xr-x 41 root root 4096 Nov 22 06:52 etc
drwxr-xr-x 2 root root 4096 Apr 19 2012 home
drwxr-xr-x 11 root root 4096 Nov 22 06:51 lib
drwxr-xr-x 2 root root 4096 Nov 22 06:51 lib64
drwxr-xr-x 2 root root 4096 Apr 11 2013 media
drwxr-xr-x 2 root root 4096 Apr 19 2012 mnt
drwxr-xr-x 2 root root 4096 Apr 11 2013 opt
dr-xr-xr-x 102 root root 0 Dec 13 06:43 proc
drwx—— 2 root root 4096 Nov 22 06:51 root
drwxr-xr-x 4 root root 4096 Nov 22 06:51 run
drwxr-xr-x 2 root root 4096 Nov 22 06:51 sbin
-rw-r–r– 1 root root 0 Dec 13 06:27 scooby_snacks.txt
drwxr-xr-x 2 root root 4096 Mar 5 2012 selinux
drwxr-xr-x 2 root root 4096 Apr 11 2013 srv
dr-xr-xr-x 13 root root 0 Dec 13 06:43 sys
drwxrwxrwt 2 root root 4096 Apr 11 2013 tmp
drwxr-xr-x 10 root root 4096 Nov 22 06:51 usr
drwxr-xr-x 11 root root 4096 Nov 22 06:51 var
root@1f8602a7d589:/#
從上面的結果可以看出,我們在Dockerfile里添加的如下一行:
RUN touch scooby_snacks.txt
在鏡像里成功的創建了scooby_snacks.txt這個文件。
發布鏡像
到目前為止,我們的所有操作都是基于本地的,沒有和外界進行任何交互。這非常重要,因為我們可以精心的準備一個完美的Dockerfile,直到我們完成它為止。現在,我覺得我已經完成了本地鏡像文件的制作,已經可以發布它了。
在進行發布之前,你需要確保在官方網站創建了自己的賬號( make an account ),然后通過docker login來登錄進去。
$ docker login
Username: thoward
Password:
Email: thoward37@gmail.com
Login Succeeded
我們通過docker push scooby_snacks命令來發布上面創建的鏡像文件。
$ docker push scooby_snacks
2013/12/13 06:49:36 Impossible to push a “root” repository. Please rename your repository in <user>/<repo> (ex: thoward/scooby_snacks)
從上面的消息可以看出,Docker不允許我們直接將鏡像發布到根倉庫(root repository)下,我們必須提供類似<user>/<repo>這樣的格式。
我們需要重新構建我們的鏡像,并指定用戶名屬性,命令為 docker build -t thoward/scooby_snacks .(注意不要丟掉最后的點,代表當前文件夾)
$ docker build -t thoward/scooby_snacks .
Uploading context 64184320 bytes
Step 1 : FROM ubuntu
—> 8dbd9e392a96
Step 2 : RUN touch scooby_snacks.txt
—> Using cache
—> 91acef3a5936
Successfully built 91acef3a5936
Nice!上面的輸出里有”Using cache”字眼,這說明Docker很聰明,知道我們在這次鏡像構建中,并未做任何修改(除了名字),所以它不會真的重新再構建一遍的。
然后我們就可以重新發布鏡像了。當然,我們需要指定正確的倉庫名稱:
$ docker push thoward/scooby_snacks
The push refers to a repository [thoward/scooby_snacks] (len: 1)
Sending image list
Pushing repository thoward/scooby_snacks (1 tags)
Pushing 8dbd9e392a964056420e5d58ca5cc376ef18e2de93b5cc90e868a1bbc8318c1c
Image 8dbd9e392a964056420e5d58ca5cc376ef18e2de93b5cc90e868a1bbc8318c1c already pushed, skipping
Pushing tags for rev [8dbd9e392a964056420e5d58ca5cc376ef18e2de93b5cc90e868a1bbc8318c1c] on {https://registry-1.docker.io/v1/repositories/thoward/scooby_snacks/tags/latest}
Pushing 91acef3a5936769f763729529e736681e5079dc6ddf6ab0e61c327a93d163df9Pushing tags for rev [91acef3a5936769f763729529e736681e5079dc6ddf6ab0e61c327a93d163df9] on {https://registry-1.docker.io/v1/repositories/thoward/scooby_snacks/tags/latest}
這樣,我們就完成了鏡像的發布工作。同時,我們也可以用docker search命令來查看這個鏡像。
$ docker search scooby_snacks
NAME DESCRIPTION STARS OFFICIAL TRUSTED
thoward/scooby_snacks 0
鏡像文件已經成功發布了,下面我們需要將剛才沒有發布成功的鏡像刪除。
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
scooby_snacks latest 91acef3a5936 30 minutes ago 12.29 kB (virtual 131.3 MB)
thoward/scooby_snacks latest 91acef3a5936 30 minutes ago 12.29 kB (virtual 131.3 MB)
ubuntu 12.04 8dbd9e392a96 8 months ago 131.3 MB (virtual 131.3 MB)
ubuntu latest 8dbd9e392a96 8 months ago 131.3 MB (virtual 131.3 MB)
ubuntu precise 8dbd9e392a96 8 months ago 131.3 MB (virtual 131.3 MB)
ubuntu 12.10 b750fe79269d 8 months ago 24.65 kB (virtual 179.7 MB)
ubuntu quantal b750fe79269d 8 months ago 24.65 kB (virtual 179.7 MB)$ docker rmi scooby_snacks
Untagged: 91acef3a5936769f763729529e736681e5079dc6ddf6ab0e61c327a93d163df9$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
thoward/scooby_snacks latest 91acef3a5936 29 minutes ago 12.29 kB (virtual 131.3 MB)
ubuntu 12.04 8dbd9e392a96 8 months ago 131.3 MB (virtual 131.3 MB)
ubuntu latest 8dbd9e392a96 8 months ago 131.3 MB (virtual 131.3 MB)
ubuntu precise 8dbd9e392a96 8 months ago 131.3 MB (virtual 131.3 MB)
ubuntu 12.10 b750fe79269d 8 months ago 24.65 kB (virtual 179.7 MB)
ubuntu quantal b750fe79269d 8 months ago 24.65 kB (virtual 179.7 MB)
上面的docker rmi命令就是刪除鏡像的命令。
不過,老實說我們剛才所發布的鏡像對其他人來說沒有任何意義,我也不想被別人當做菜鳥看待,所以我要刪掉它。
$ docker rmi thoward/scooby_snacks
Untagged: 91acef3a5936769f763729529e736681e5079dc6ddf6ab0e61c327a93d163df9
Deleted: 91acef3a5936769f763729529e736681e5079dc6ddf6ab0e61c327a93d163df9$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu 12.04 8dbd9e392a96 8 months ago 131.3 MB (virtual 131.3 MB)
ubuntu latest 8dbd9e392a96 8 months ago 131.3 MB (virtual 131.3 MB)
ubuntu precise 8dbd9e392a96 8 months ago 131.3 MB (virtual 131.3 MB)
ubuntu 12.10 b750fe79269d 8 months ago 24.65 kB (virtual 179.7 MB)
ubuntu quantal b750fe79269d 8 months ago 24.65 kB (virtual 179.7 MB)
注意上面docker rmi命令的輸出,和之前的命令相比,這次多了一條Deleted: 91acef3a….的內容。這是因為Docker知道現在的系統里沒有再對這個ID的鏡像的引用了,所以可以刪除了,而不只是僅僅刪除標簽(untagging)。
但是,docker rmi命令并不會Docker Index上刪除這個鏡像。我們可以測試下:
$ docker search scooby_snacks
NAME DESCRIPTION STARS OFFICIAL TRUSTED
thoward/scooby_snacks 0
不錯,它還在那里。我們可以通過docker pull命令來下載它并繼續使用。
$ docker pull thoward/scooby_snacks
Pulling repository thoward/scooby_snacks
91acef3a5936: Download complete
8dbd9e392a96: Download complete$ docker run -i -t thoward/scooby_snacks /bin/bash
root@90f6546bf3b7:/# ls -al
total 12308
drwxr-xr-x 30 root root 4096 Dec 13 07:03 .
drwxr-xr-x 30 root root 4096 Dec 13 07:03 ..
-rw——- 1 root root 208 Dec 13 07:03 .dockerenv
-rwxr-xr-x 1 root root 12516574 Nov 22 02:34 .dockerinit
drwxr-xr-x 2 root root 4096 Apr 11 2013 bin
drwxr-xr-x 2 root root 4096 Apr 19 2012 boot
drwxr-xr-x 6 root root 4096 Nov 22 06:52 dev
drwxr-xr-x 41 root root 4096 Nov 22 06:52 etc
drwxr-xr-x 2 root root 4096 Apr 19 2012 home
drwxr-xr-x 11 root root 4096 Nov 22 06:51 lib
drwxr-xr-x 2 root root 4096 Nov 22 06:51 lib64
drwxr-xr-x 2 root root 4096 Apr 11 2013 media
drwxr-xr-x 2 root root 4096 Apr 19 2012 mnt
drwxr-xr-x 2 root root 4096 Apr 11 2013 opt
dr-xr-xr-x 105 root root 0 Dec 13 07:03 proc
drwx—— 2 root root 4096 Nov 22 06:51 root
drwxr-xr-x 4 root root 4096 Nov 22 06:51 run
drwxr-xr-x 2 root root 4096 Nov 22 06:51 sbin
-rw-r–r– 1 root root 0 Dec 13 06:27 scooby_snacks.txt
drwxr-xr-x 2 root root 4096 Mar 5 2012 selinux
drwxr-xr-x 2 root root 4096 Apr 11 2013 srv
dr-xr-xr-x 13 root root 0 Dec 13 07:03 sys
drwxrwxrwt 2 root root 4096 Apr 11 2013 tmp
drwxr-xr-x 10 root root 4096 Nov 22 06:51 usr
drwxr-xr-x 11 root root 4096 Nov 22 06:51 var
root@90f6546bf3b7:/#