我眼中的 Docker(二)Image
Docker 安裝
如何安裝 docker 詳見官網: installation 或者 中文指南.
不過 linux 上我推薦用 curl 安裝,因為 apt-get 中源要麽沒有 docker,要麽版本較低。
$ sudo apt-get install curl
$ sudo curl -sSL https://get.docker.com/ | sh
$ sudo docker run hello-world
- 1
- 2
- 3
最後一個命令成功的話說明 docker 可以正常運行。
然而因為中國顯而易見的國情原因,推薦還是使用 DaoCloud 服務安裝吧:
# curl -sSL https://get.daocloud.io/docker | sh
- 1
好了之後最好配置一下 DaoCloud 的加速服務(加速器),即設置 mirror:
$ echo "DOCKER_OPTS=\"\$DOCKER_OPTS --registry-mirror=http://f9495414.m.daocloud.io\"" | sudo tee -a /etc/default/docker
$ sudo service docker restart
- 1
- 2
Image 命令
Image 是 docker 的基石,命令的介紹可以直接看官方文檔: doc
常用命令有:
$ # 列出所有鏡像
$ sudo docker images
$ # pull 新鏡像
$ sudo docker pull hello-world
$ # tag 一個鏡像,tag 對於一個鏡像就像引用計數一樣
$ sudo docker tag hello-world myname/hello-world
$ # push 鏡像到 docker hub
$ sudo docker push myname/hello-world
$ # 在 docker hub 搜索鏡像
$ sudo docker search ubuntu
$ # 刪除一個鏡像
$ sudo docker rmi hello-world
$ # 刪除名字為 <none> 的鏡像(可能在構建過程或 pull 過程不成功留下的中間鏡像)
$ sudo docker images | grep "<none>" | tr -s ‘ ‘ | cut -f3 -d " " | sudo parallel docker rmi {}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
Image 組成
Image 是一個可運行的基本單元,那麽當我們運行 docker images 時,顯示出來的一個個 image 究竟是什麽?
Image 裏面是一層層文件系統,叫做 Union FS,聯合文件系統,可以將幾層目錄掛載到一起,成為同一個虛擬文件系統。文件系統的目錄結構就像普通 linux 的目錄結構一樣,docker 通過這些文件與宿主機的內核提供了一個 linux 的虛擬環境。每一層文件系統我們叫做一層 layer,聯合文件系統可以對每一層文件系統設置三種權限,只讀(readonly)、讀寫(readwrite)和寫出(whiteout-able),但是 docker 鏡像中每一層文件系統都是只讀的。
構建鏡像的時候,從一個最基本的操作系統開始,每個構建的操作都相當於做一層修改,增加了一層文件系統,一層層往上疊加,上層的修改會覆蓋底層該位置的可見性,這也很容易理解,就像上層把底層遮住了一樣。當你使用的時候,你只會看到一個完全的整體,你不知道裏面有幾層,也不清楚每一層所做的修改是什麽。結構類似這樣:
從基本的看起,一個典型的 Linux 文件系統由 bootfs 和 rootfs 兩部分組成,bootfs(boot file system) 主要包含 bootloader 和 kernel,bootloader 主要用於引導加載 kernel,當 kernel 被加載到內存中後 bootfs 會被 umount 掉。 rootfs (root file system) 包含的就是典型 Linux 系統中的/dev,/proc,/bin,/etc 等標準目錄和文件。見下圖,就是 docker image 中最基礎的兩層結構:
不同的 linux 發行版(如 ubuntu 和 CentOS ) 在 rootfs 這一層會有所區別,體現發行版本的差異性:
傳統的 Linux 加載 bootfs 時會先將 rootfs 設為 read-only,然後在系統自檢之後將 rootfs 從 read-only 改為 read-write,然後我們就可以在 rootfs 上進行讀寫操作了。但 Docker 在 bootfs 自檢完畢之後並不會把 rootfs 的 read-only 改為 read-write,而是利用 union mount(UnionFS 的一種掛載機制)將 image 中的其他的 layer 加載到之前的 read-only 的 rootfs 層之上,每一層 layer 都是 rootfs 的結構,並且是read-only 的。所以,我們是無法修改一個已有鏡像裏面的 layer 的!只有當我們創建一個容器,也就是將 Docker 鏡像進行實例化,系統會分配一層空的 read-write 的 rootfs ,用於保存我們做的修改。一層 layer 所保存的修改是增量式的,就像 git 一樣。
Image 結構
假如我們有一個 ubuntu:14.04 的鏡像,那麽我們可以把它保存成 tar 文件,觀察一下:
? ~ sudo docker save -o ubuntu_image.tar ubuntu:14.04
? ~ tar -tf ubuntu_image.tar
428b411c28f0c33e561a95400a729552db578aee0553f87053b96fc0008cca6a/
428b411c28f0c33e561a95400a729552db578aee0553f87053b96fc0008cca6a/VERSION
428b411c28f0c33e561a95400a729552db578aee0553f87053b96fc0008cca6a/json
428b411c28f0c33e561a95400a729552db578aee0553f87053b96fc0008cca6a/layer.tar
435050075b3f881611b0f4c141bb723f38603caacd31a13a185c1a38acfb4ade/
435050075b3f881611b0f4c141bb723f38603caacd31a13a185c1a38acfb4ade/VERSION
435050075b3f881611b0f4c141bb723f38603caacd31a13a185c1a38acfb4ade/json
435050075b3f881611b0f4c141bb723f38603caacd31a13a185c1a38acfb4ade/layer.tar
6d4946999d4fb403f40e151ecbd13cb866da125431eb1df0cdfd4dc72674e3c6/
6d4946999d4fb403f40e151ecbd13cb866da125431eb1df0cdfd4dc72674e3c6/VERSION
6d4946999d4fb403f40e151ecbd13cb866da125431eb1df0cdfd4dc72674e3c6/json
6d4946999d4fb403f40e151ecbd13cb866da125431eb1df0cdfd4dc72674e3c6/layer.tar
9fd3c8c9af32dddb1793ccb5f6535e12d735eacae16f8f8c4214f42f33fe3d29/
9fd3c8c9af32dddb1793ccb5f6535e12d735eacae16f8f8c4214f42f33fe3d29/VERSION
9fd3c8c9af32dddb1793ccb5f6535e12d735eacae16f8f8c4214f42f33fe3d29/json
9fd3c8c9af32dddb1793ccb5f6535e12d735eacae16f8f8c4214f42f33fe3d29/layer.tar
repositories
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
我們可以看到,實際上 ubuntu 裏的鏡像是一個壓縮文件,裏面有 4 個文件夾,其實就是 4 個 layer, 每個 layer 一個文件夾,還有一個 repositories 的文件。更直觀一點,可以解壓到文件夾中,用 tree 命令查看:
? ubuntu:14.04 tree
.
├── 428b411c28f0c33e561a95400a729552db578aee0553f87053b96fc0008cca6a
│ ├── json
│ ├── layer.tar
│ └── VERSION
├── 435050075b3f881611b0f4c141bb723f38603caacd31a13a185c1a38acfb4ade
│ ├── json
│ ├── layer.tar
│ └── VERSION
├── 6d4946999d4fb403f40e151ecbd13cb866da125431eb1df0cdfd4dc72674e3c6
│ ├── json
│ ├── layer.tar
│ └── VERSION
├── 9fd3c8c9af32dddb1793ccb5f6535e12d735eacae16f8f8c4214f42f33fe3d29
│ ├── json
│ ├── layer.tar
│ └── VERSION
└── repositories
4 directories, 13 files
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
可以說,每個文件夾的結構都是一樣的,這意味著每一層 layer 的組織方式也一樣,由 json、layer.tar、VERSION 表示。我們先看 repositories 文件,裏面是一個 JSON 定義,保存了三個信息:鏡像名字、tag、tag 對應的 layer(這個 layer 是 ubuntu:14.04 的最上層 layer 的摘要)。
? ~ cat repositories
{"ubuntu":{"14.04":"6d4946999d4fb403f40e151ecbd13cb866da125431eb1df0cdfd4dc72674e3c6"}}
- 1
- 2
進入某個文件夾,查看 json 文件,是一份保存了很多信息的 json 定義,主要是關於鏡像的配置信息,簡要結構如下:
而 layer.tar 也是一份打包文件,通過下面可以看到,裏面是一個類 Linux 文件目錄的結構,保存著這個 layer 所做的修改:
? 435050075b3f881611b0f4c141bb723f38603caacd31a13a185c1a38acfb4ade tar -tf layer.tar
etc/
etc/apt/
etc/apt/apt.conf.d/
etc/apt/apt.conf.d/docker-clean
etc/apt/apt.conf.d/docker-gzip-indexes
etc/apt/apt.conf.d/docker-no-languages
etc/dpkg/
etc/dpkg/dpkg.cfg.d/
etc/dpkg/dpkg.cfg.d/docker-apt-speedup
sbin/
sbin/initctl
sbin/initctl.distrib
usr/
usr/sbin/
usr/sbin/policy-rc.d
var/
var/lib/
var/lib/dpkg/
var/lib/dpkg/diversions
var/lib/dpkg/diversions-old
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
最後,要註意的是 layer 在鏡像間是共享的,不同鏡像間,對於摘要一樣的 layer 只會保存一份,以樹的形式進行繼承,可以用 docker images -tree
查看:
? ~ sudo docker images -tree
Warning: ‘-tree‘ is deprecated, it will be removed soon. See usage.
..... #略
├─428b411c28f0 Virtual Size: 188.1 MB
│ └─435050075b3f Virtual Size: 188.3 MB
│ └─9fd3c8c9af32 Virtual Size: 188.3 MB
│ └─6d4946999d4f Virtual Size: 188.3 MB Tags: ubuntu:latest, ubuntu:14.04
│ └─cf73ddbcb12b Virtual Size: 375.1 MB
│ └─7cb6f45e653d Virtual Size: 377.6 MB
│ └─c624e1a476d0 Virtual Size: 377.6 MB
│ └─4b087f2af755 Virtual Size: 389.1 MB
│ └─6940f969b4ed Virtual Size: 413.9 MB
│ └─1bc2ae3e600b Virtual Size: 414 MB
│ └─c35a7b3ee359 Virtual Size: 414 MB
│ └─b4696f4e4d61 Virtual Size: 414 MB
│ └─7413e661f075 Virtual Size: 414 MB
│ └─9a2409206c78 Virtual Size: 414 MB Tags: registry:latest
..... #略
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
我眼中的 Docker(二)Image