程式扎記: Docker Practice - Image File

標籤

2015年5月20日 星期三

Docker Practice - Image File

(Source)

Docker 映像檔#

在之前的介紹中,我們知道映像檔是 Docker 的三大組件之一。Docker 在執行容器前需要本地端存在對應的映像檔,如果映像檔不存在本地端,Docker 會從映像檔倉庫下載(預設是 Docker Hub 公共註冊伺服器中的倉庫)。

本章將介紹更多關於映像檔的內容,包括:
  • 從倉庫取得映像檔;
  • 管理本地主機上的映像檔;
  • 介紹映像檔實作的基本原理

取得映像檔#

(P18)可以使用 docker pull 命令從倉庫取得所需要的映像檔。
Usage: docker pull [OPTIONS] NAME[:TAG]
Pull an image or a repository from the registry

  -a, --all-tags=false    Download all tagged images in the repository

下面的例子將從 Docker Hub 倉庫下載一個 Ubuntu 12.04 作業系統的映像檔。
$ sudo docker pull ubuntu:12.04
Pulling repository ubuntu 
... 
8615058f3e1f: Download complete


下載過程中,會輸出取得映像檔的每一層訊息。該命令實際上相當於 $ sudo docker pull registry.hub.docker.com/ubuntu:12.04 命令,即從註冊服務器registry.hub.docker.com 中的 ubuntu 倉庫來下載標記為 12.04 的映像檔。

有時候官方倉庫註冊服務器下載較慢,可以從其他倉庫下載。 從其它倉庫下載時需要指定完整的倉庫伺服器位址。例如


完成後,即可隨時使用該映像檔了,例如建立一個容器,讓其中執行 bash (docker run)。
$ sudo docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
ubuntu 12.04 9610cfc68e8d 7 days ago 131.9 MB 

$ sudo docker run -t -i ubuntu:12.04 /bin/bash
root@5267ecf0f4ee:/# // Now you are inside container
// You can use Ctrl+p then Ctrl+q to quit container.

列出本機映像檔#

(P19) 使用 docker images 顯示本機已有的映像檔。


在列出訊息中,可以看到幾段文字訊息:

  • 來自於哪個倉庫,比如 ubuntu
  • 映像檔的標記,比如 14.04
  • 它的 ID 號(唯一)
  • 建立時間
  • 映像檔大小
其中映像檔的 ID 唯一標識了映像檔,注意到 ubuntu:14.04 和 ubuntu:trusty 具有相同的映像檔 ID ,說明它們實際上是同一映像檔。

TAG 用來標記來自同一個倉庫的不同映像檔。例如 ubuntu 倉庫中有多個映像檔,通過 TAG 來區分發行 版本,例如 10.04 、 12.04 、 12.10 、 13.04 、 14.04 等。例如下面的命令指定使用映像檔 ubuntu:14.04 來啟動一個容器。
$ sudo docker run -t -i ubuntu:14.04 /bin/bash

如果沒有指定 TAG ,預設的 TAG 為 latest!

建立映像檔#

建立映像檔有很多方法,使用者可以從 Docker Hub 取得已有映像檔並更新,也可以在本機建立一個。

修改已有映像檔#

(P20) 先使用下載的映像檔啟動容器。
$ sudo docker pull training/sinatra // 下載測試使用的 Image 檔.
$ sudo docker run -t -i training/sinatra /bin/bash // 使用剛剛下載的 Image 檔啟動容器
root@b37ac4bbaee8:/# // Now we are inside Container's bash

記住容器的 ID=b37ac4bbaee8,稍後還會用到, 接著在容器中加入 json 的 gem 套件:
root@b37ac4bbaee8:/# gem install json
...
root@b37ac4bbaee8:/# exit // Exit Container

當結束後,我們使用 exit 來退出,現在我們的容器已經被改變了,使用 docker commit 命令來提交更新後的副本。
# docker commit -m "Added json gem" -a "Docker Newbee" b37ac4bbaee8 johnklee/tutorial
3c6f5bae3acaf66fd0ff1bc2400f9689725ab3500287cf38977823bdf3f68ea1
# docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
johnklee/tutorial latest 3c6f5bae3aca 5 minutes ago 452 MB

其中, -m 指定提交的說明信息,跟我們使用的版本控制工具一樣; -a 可以指定更新的使用者信息;之後是用來建立映像檔的容器的 ID;最後指定新映像檔的名稱和 tag 。建立成功後會印出新映像檔的 ID。

之後,可以使用新的映像檔來啟動容器:
# docker run -t -i johnklee/tutorial /bin/bash
root@e769aa87ff69:/#

利用 Dockerfile 建立映像檔#

使用 docker commit 擴展一個映像檔比較簡單,但是不方便在一個團隊中分享。我們可以使用 docker build 來建立一個新的映像檔。為此,首先需要建立一個 Dockerfile,裡面包含一些用來建立映像檔的指令。首先新建一個目錄和一個 Dockerfile:
# mkdir sinatra
# cd sinatra/ 
# touch Dockerfile

Dockerfile 中每一條指令都會建立一層映像檔,例如:
# This is a comment
FROM ubuntu:14.04
MAINTAINER Docker Newbee <newbee@docker.com>
RUN apt-get -qq update
RUN apt-get -qqy install ruby ruby-dev
RUN gem install sinatra

Dockerfile 基本的語法是:
  • 使用 # 來註釋
  • FROM 指令告訴 Docker 使用哪個映像檔作為基底
  • 接著是使用 MAINTAINER 設定維護者的信息
  • RUN 開頭的指令會在建立中執行,比如安裝一個套件,在這裏使用 apt-get 來安裝了一些套件

完成 Dockerfile 後可以使用 docker build 建立映像檔:
// Usage: docker build [OPTIONS] PATH | URL | - 
# docker build -t="johnklee/tutorial:v2" .
... 
Pulling repository ubuntu 
b7cf8f0d9e82: Download complete 
706766fe1019: Download complete 
a62a42e77c9c: Download complete 
2c014f14d3d9: Download complete 
---> b7cf8f0d9e82 
Step 1 : MAINTAINER Docker Newbee  
---> Running in c02024862949 
---> 77922cc1f854 
Removing intermediate container c02024862949 
Step 2 : RUN apt-get -qq update 
---> Running in 388c086574ef 
---> eab7bd84884d 
Removing intermediate container 388c086574ef 
Step 3 : RUN apt-get -qqy install ruby ruby-dev 
... 
---> 0664466a35f7 
Removing intermediate container abce60eb8ce3 
Successfully built 0664466a35f7 


# docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
johnklee/tutorial v2 0664466a35f7 10 minutes ago 318 MB 
...

其中 -t 標記添加 tag,指定新的映像檔的使用者信息。 “.” 是 Dockerfile 所在的路徑(當前目錄),也可以換成具體的 Dockerfile 的路徑。

可以看到 build 指令後執行的操作。它要做的第一件事情就是上傳這個 Dockerfile 內容,因為所有的操作都要依據 Dockerfile 來進行。 然後,Dockfile 中的指令被一條一條的執行。每一步都建立了一個新的容器,在容器中執行指令並提交修改(就跟之前介紹過的 docker commit 一樣)。當所有的指令都執行完畢之後,返回了最終的映像檔 id。所有的中間步驟所產生的容器都會被刪除和清理
Ps. 注意一個映像檔不能超過 127 層

此外,還可以利用 ADD 命令複製本地檔案到映像檔;用 EXPOSE 命令向外部開放埠號;用 CMD 命令描述容器啟動後執行的程序等。例如:
# put my local web site in myApp folder to /var/www
ADD myApp /var/www# expose httpd port
EXPOSE 80
# the command to run
CMD ["/usr/sbin/apachectl", "-D", "FOREGROUND"]

現在可以利用新建立的映像檔啟動一個容器:
# docker run -t -i johnklee/tutorial:v2 /bin/bash
root@5af0078144aa:/#

還可以用 docker tag 命令修改映像檔的標籤:
# docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE 
johnklee/tutorial v2 0664466a35f7 About an hour ago 318 MB 


# docker tag 0664466a35f7 johnklee/tutorial:devel
# docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
johnklee/tutorial v2 0664466a35f7 About an hour ago 318 MB
johnklee/tutorial devel 0664466a35f7 About an hour ago 318 MB

註:更多用法,請參考 Dockerfile 使用文件

從本機匯入#

(P22) 要從本機匯入一個映像檔,可以使用 OpenVZ(容器虛擬化的先鋒技術)的模板來建立: OpenVZ 的模板下載位址為http://openvz.org/Download/templates/precreated。比如,先下載一個 ubuntu-14.04 的映像檔,之後使用以下命令匯入:
# cat ubuntu-14.04-x86_64-minimal.tar.gz |docker import - ubuntu:14.04
# docker images // 查看新匯入的映像檔

上傳映像檔#

使用者可以通過 docker push 命令,把自己建立的映像檔上傳到倉庫中來共享。例如,使用者在 Docker Hub 上完成註冊後,可以推送自己的映像檔到倉庫中。
Usage: docker push NAME[:TAG]
Push an image or a repository to the registry

一個使用範例如下:
# docker push johnklee/tutorial:v2
The push refers to a repository [johnklee/tutorial] (len: 1) 
Sending image list 

Please login prior to push: 
Username:
 johnklee
Password: // Enter your password
Email: puremonkey2001@yahoo.com.tw
Login Succeeded 
The push refers to a repository [johnklee/tutorial] (len: 1)
Sending image list 
...

本地映像檔的管理#

儲存映像檔#

如果要建立映像檔到本地檔案,可以使用 docker save 命令。
Usage: docker save [OPTIONS] IMAGE [IMAGE...]
Save an image(s) to a tar archive (streamed to STDOUT by default)

  -o, --output=""    Write to a file, instead of STDOUT

一個使用範例如下:
# docker images // 檢視當前 local 的 images
... 
ubuntu 14.04 b7cf8f0d9e82 12 days ago 188.3 MB 
... 

# docker save -o ubuntu_14.04.tar ubuntu:14.04
# ls -hs ubuntu_14.04.tar // 檢視 image 被導出成功
193M ubuntu_14.04.tar

載入映像檔#

可以使用 docker load 從建立的本地檔案中再匯入到本地映像檔庫,例如:
# docker load --input ubuntu_14.04.tar
Or
# docker load < ubuntu_14.04.tar

這將匯入映像檔以及其相關的元資料信息(包括標籤等)。

移除本地端映像檔#

如果要移除本地端的映像檔,可以使用 docker rmi 命令。注意 docker rm 命令是移除容器。
# docker images // Check exist images
...
training/sinatra v2 3c59e02ddd1a 11 months ago 446.4 MB 
# docker rmi training/sinatra:v2 // Remove image training/sinatra:v2
Untagged: training/sinatra:v2 
Deleted: 3c59e02ddd1ae03ae128fa5d1c255e0d2ac68793fade3135a7a6397a8d1a36a7 
Deleted: fbc9a83d93d94a02c365368bcc78b5206d817db3b2000565bf4405dd05571949 
Deleted: 08ebafdba9085997236f42c4c32e60a9ffab2215c1c6e9ae12260d991dca0813 
Deleted: 1fd0d1b3b7853cc4f511550609ac6e354f56a13bef84884644353e05778031b1 
Deleted: 99ec81b80c55d906afd8179560fdab0ee93e32c52053816ca1d531597c1ff48f 
...

*注意:在刪除映像檔之前要先用 docker rm 刪掉依賴於這個映像檔的所有容器。

映像檔的實作原理#

Docker 映像檔是怎麽實作增量的修改和維護的? 每個映像檔都由很多層次構成,Docker 使用 Union FS 將這些不同的層結合到一個映像檔中去。

通常 Union FS 有兩個用途, 一方面可以實作不借助 LVMRAID 將多個 disk 掛到同一個目錄下,另一個更常用的就是將一個唯讀的分支和一個可寫的分支聯合在一起,Live CD 正是基於此方法可以允許在映像檔不變的基礎上允許使用者在其上進行一些寫操作。 Docker 在 AUFS 上建立的容器也是利用了類似的原理。
When Docker mounts the rootfs, it starts read-only, as in a traditional Linux boot, but then, instead of changing the file system to read-write mode, it takes advantage of a union mount to add a read-write file system over the read-only file system. In fact there may be multiple read-only file systems stacked on top of each other. We think of each one of these file systems as a layer.


沒有留言:

張貼留言

網誌存檔

關於我自己

我的相片
Where there is a will, there is a way!