如果要安裝最新的docker版本,那麼需要安裝https支持
apt-get install apt-transport-https
$ sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 36A1D7869245C8950F966E92D8576A8BA88D21E9
$ sudo sh -c "echo debhttps://get.docker.io/ubuntu docker main\
> /etc/apt/sources.list.d/docker.list"
$ sudo apt-get update
$ sudo apt-get install lxc-docker
這樣就安裝完畢了。
1 確保Docker已經就緒
首先,我們會查看Docker是否能正常工作,然後學習基本的Docker的工作流:創建並管理容器。我們將浏覽容器的典型生命周期:從創建、管理到停止,直到最終刪除。
第一步,查看
docker
程序是否存在,功能是否正常,如代碼清單3-1所示。
代碼清單3-1 查看
docker
程序是否正常工作
[code]$ sudo docker info
Containers: 1
Images: 8
Storage Driver: aufs
Root Dir: /var/lib/docker/aufs
Backing Filesystem: extfs
Dirs: 10
Execution Driver: native-0.2
Kernel Version: 3.13.0-43-generic
Operating System: Ubuntu 14.04.2 LTS
CPUs: 1
Total Memory: 994 MiB
Name: riemanna
ID: DOIT:XN5S:WNYP:WP7Q:BEUP:EBBL:KGIX:GO3V:NDR7:YW6E:VFXT:FXHM
WARNING: No swap limit support
在這裡我們調用了
docker
可執行程序的
info
命令,該命令會返回所有容器和鏡像(鏡像即是Docker用來構建容器的“構建塊”)的數量、Docker使用的執行驅動和存儲驅動(execution
and storage driver),以及Docker的基本配置。
在前面幾章已經介紹過,Docker是基於客戶端-服務器構架的。它有一個
docker
程序,既能作為客戶端,也可以作為服務器端。作為客戶端時,
docker
程序向Docker守護進程發送請求(如請求返回守護進程自身的信息),然後再對返回的請求結果進行處理。
2 運行我們的第一個容器
現在,讓我們嘗試啟動第一個Docker容器。我們可以使用
docker run
命令創建容器,如代碼清單3-2所示。
docker
run
命令提供了Docker容器的創建到啟動的功能,在本書中我們也會使用該命令來創建新容器。
代碼清單3-2 運行我們的第一個容器
[code]$ sudo docker run -i -t ubuntu /bin/bash
Unable to find image 'ubuntu' locally
ubuntu:latest: The image you are pulling has been verified
511136ea3c5a: Pull complete
d497ad3926c8: Pull complete
ccb62158e970: Pull complete
e791be0477f2: Pull complete
3680052c0f5c: Pull complete
22093c35d77b: Pull complete
5506de2b643b: Pull complete
Status: Downloaded newer image for ubuntu:latest
root@fcd78e1a3569:/#
提示
官方文檔列出了完整的Docker命令列表,也可以使用docker help獲取這些命令。此外,還可以使用Docker的man頁(即執行man docker-run)。
代碼清單3-3所示的命令的輸出結果非常豐富,下面來逐條解析。
代碼清單3-3
docker run
命令
[code]$ sudo docker run -i -t ubuntu /bin/bash
首先,我們告訴Docker執行
docker run
命令,並指定了
-i
和
-t
兩個命令行參數。
-i
標志保證容器中
STDIN
是開啟的,盡管我們並沒有附著到容器中。持久的標准輸入是交互式shell的“半邊天”,
-t
標志則是另外“半邊天”,它告訴Docker為要創建的容器分配一個偽tty終端。這樣,新創建的容器才能提供一個交互式shell。若要在命令行下創建一個我們能與之進行交互的容器,而不是一個運行後台服務的容器,則這兩個參數已經是最基本的參數了。
提示
官方文檔上列出了docker run命令的所有標志,此外還可以用命令docker help run查看這些標志。或者,也可以用Docker的man頁(也就是執行man docker-run命令)。
接下來,我們告訴Docker基於什麼鏡像來創建容器,示例中使用的是
ubuntu
鏡像。
ubuntu
鏡像是一個常備鏡像,也可以稱為“基礎”(base)鏡像,它由Docker公司提供,保存在Docker
Hub ** Registry上。可以以
ubuntu
基礎鏡像(以及類似的
fedora
、
debian
、
centos
等鏡像)為基礎,在選擇的操作系統上構建自己的鏡像。到目前為止,我們基於此基礎鏡像啟動了一個容器,並且沒有對容器增加任何東西。
提示
我們將在第4章對鏡像做更詳細的介紹,包括如何構建我們自己的鏡像。
那麼,在這一切的背後又都發生了什麼呢?首先Docker會檢查本地是否存在
ubuntu
鏡像,如果本地還沒有該鏡像的話,那麼Docker就會連接官方維護的Docker Hub Registry,查看Docker Hub中是否有該鏡像。Docker一旦找到該鏡像,就會下載該鏡像並將其保存到本地宿主機中。
隨後,Docker在文件系統內部用這個鏡像創建了一個新容器。該容器擁有自己的網絡、IP地址,以及一個用來和宿主機進行通信的橋接網絡接口。最後,我們告訴Docker在新容器中要運行什麼命令,在本例中我們在容器中運行
/bin/bash
命令啟動了一個Bash
shell。
當容器創建完畢之後,Docker就會執行容器中的
/bin/bash
命令,這時就可以看到容器內的shell了,就像代碼清單3-4所示。
代碼清單3-4 第一個容器的shell
[code]root@f7cbdac22a02:/#
3 使用第一個容器
現在,我們已經以
root
用戶登錄到了新容器中,容器的ID
f7cbdac22a02``,乍看起來有些令人迷惑的字符串
。這是一個完整的Ubuntu系統,可以用它來做任何事情。下面就來研究一下這個容器。首先,我們可以獲取該容器的主機名,如代碼清單3-5所示。
代碼清單3-5 檢查容器的主機名
[code]root@f7cbdac22a02:/# hostname
f7cbdac22a02
可以看到,容器的主機名就是該容器的ID。再來看看
/etc/hosts
文件,如代碼清單3-6所示。
代碼清單3-6 檢查容器的/etc/hosts文件
[code]root@f7cbdac22a02:/# cat /etc/hosts
172.17.0.4 f7cbdac22a02
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
Docker已在
hosts
文件中為該容器的IP地址添加了一條主機配置項。再來看看容器的網絡配置情況,如代碼清單3-7所示。
代碼清單3-7 檢查容器的接口
[code]root@f7cbdac22a02:/# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 1500 qdisc noqueue state
UNKNOWN group default
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
899: eth0: <BROADCAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast
state UP group default qlen 1000
link/ether 16:50:3a:b6:f2:cc brd ff:ff:ff:ff:ff:ff
inet 172.17.0.4/16 scope global eth0
inet6 fe80::1450:3aff:feb6:f2cc/64 scope link
valid_lft forever preferred_lft forever
可以看到,這裡有
lo
的環回接口,還有IP為
172.17.0.4
的標准
eth0
網絡接口,和普通宿主機是完全一樣的。我們還可以查看容器中運行的進程,如代碼清單3-8所示。
代碼清單3-8 檢查容器的進程
[code]root@f7cbdac22a02:/# ps -aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 18156 1936 ? Ss May30 0:00 /bin/bash
root 21 0.0 0.0 15568 1100 ? R+ 02:38 0:00 ps -aux
接下來要干些什麼呢?安裝一個軟件包怎麼樣?如代碼清單3-9所示。
代碼清單3-9 在第一個容器中安裝軟件包
[code]root@f7cbdac22a02:/# apt-get update && apt-get install vim
通過上述命令,就在容器中安裝了Vim軟件。
用戶可以繼續在容器中做任何自己想做的事情。當所有工作都結束時,輸入
exit
,就可以返回到Ubuntu宿主機的命令行提示符了。
這個容器現在怎樣了?容器現在已經停止運行了!只有在指定的
/bin/bash
命令處於運行狀態的時候,我們的容器也才會相應地處於運行狀態。一旦退出容器,
/bin/bash
命令也就結束了,這時容器也隨之停止了運行。
但容器仍然是存在的,可以用
docker ps -a
命令查看當前系統中容器的列表,如代碼清單3-10所示。
代碼清單3-10 列出Docker容器
[code]CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1cd57c2cdf7f ubuntu:14.04 "/bin/bash" A minute Exited
gray_cat
默認情況下,當執行
docker ps
命令時,只能看到正在運行的容器。如果指定
-a
標志的話,那麼
docker
ps
命令會列出所有容器,包括正在運行的和已經停止的。
提示
也可以為docker ps命令指定-l標志,列出最後一個運行的容器,無論其正在運行還是已經停止。也可以通過--format標志,進一步控制顯示哪些信息,以及如何顯示這些信息。
從該命令的輸出結果中我們可以看到關於這個容器的很多有用信息:ID、用於創建該容器的鏡像、容器最後執行的命令、創建時間以及容器的退出狀態(在上面的例子中,退出狀態是
0
,因為容器是通過正常的
exit
命令退出的)。我們還可以看到,每個容器都有一個名稱。
注意
有3種方式可以唯一指代容器:短UUID(如f7cbdac22a02)、長UUID(如f7cbdac 22a02e03c9438c729345e54db9d20cfa2ac1fc3494b6eb60872e74778)或者名稱(如gray_cat)。
4 容器命名
Docker會為我們創建的每一個容器自動生成一個隨機的名稱。例如,上面我們剛剛創建的容器就被命名為
gray_cat
。如果想為容器指定一個名稱,而不是使用自動生成的名稱,則可以用
--name
標志來實現,如代碼清單3-11所示。
代碼清單3-11 給容器命名
[code]$ sudo docker run --name bob_the_container -i -t ubuntu /bin/bash
root@aa3f365f0f4e:/# exit
上述命令將會創建一個名為
bob_the_container
的容器。一個合法的容器名稱只能包含以下字符:小寫字母a~z、大寫字母A~Z、數字0~9、下劃線、圓點、橫線(如果用正則表達式來表示這些符號,就是
[a-zA-Z0-9``_``.-]
)。
在很多Docker命令中,都可以用容器的名稱來替代容器ID,後面我們將會看到。容器名稱有助於分辨容器,當構建容器和應用程序之間的邏輯連接時,容器的名稱也有助於從邏輯上理解連接關系。具體的名稱(如
web
、
db
)比容器ID和隨機容器名好記多了。我推薦大家都使用容器名稱,以更加方便地管理容器。
注意
我們將會在第5章詳細介紹如何連接到Docker容器。
容器的命名必須是唯一的。如果試圖創建兩個名稱相同的容器,則命令將會失敗。如果要使用的容器名稱已經存在,可以先用
docker rm
命令刪除已有的同名容器後,再來創建新的容器。
5 重新啟動已經停止的容器
bob_the_container
容器已經停止了,接下來我們能對它做些什麼呢?如果願意,我們可以用下面的命令重新啟動一個已經停止的容器,如代碼清單3-12所示。
代碼清單3-12 啟動已經停止運行的容器
[code]$ sudo docker start bob_the_container
除了容器名稱,也可以用容器ID來指定容器,如代碼清單3-13所示。
代碼清單3-13 通過ID啟動已經停止運行的容器
[code]$ sudo docker start aa3f365f0f4e
提示
也可以使用docker restart命令來重新啟動一個容器。
這時運行不帶
-a
標志的
docker
ps
命令,就應該看到我們的容器已經開始運行了。
注意
類似地,Docker也提供了docker create命令來創建一個容器,但是並不運行它。這讓我們可以在自己的容器工作流中對其進行細粒度的控制。
6 附著到容器上
Docker容器重新啟動的時候,會沿用
docker run
命令時指定的參數來運行,因此我們的容器重新啟動後會運行一個交互式會話shell。此外,也可以用
docker
attach
命令,重新附著到該容器的會話上,如代碼清單3-14所示。
代碼清單3-14 附著到正在運行的容器
[code]$ sudo docker attach bob_the_container
也可以使用容器ID,重新附著到容器的會話上,如代碼清單3-15所示。
代碼清單3-15 通過ID附著到正在運行的容器
[code]$ sudo docker attach aa3f365f0f4e
現在,又重新回到了容器的Bash提示符,如代碼清單3-16所示。
代碼清單3-16 重新附著到容器的會話
[code]root@aa3f365f0f4e:/_#_
提示
可能需要按下回車鍵才能進入該會話。
如果退出容器的shell,容器會再次停止運行。
7 創建守護式容器
除了這些交互式運行的容器(interactive container),也可以創建長期運行的容器。守護式容器(daemonized container)沒有交互式會話,非常適合運行應用程序和服務。大多數時候我們都需要以守護式來運行我們的容器。下面就來啟動一個守護式容器,如代碼清單3-17所示。
代碼清單3-17 創建長期運行的容器
[code]$ sudo docker run --name daemon_dave -d ubuntu /bin/sh -c "while
true; do echo hello world; sleep 1; done"
1333bb1a66af402138485fe44a335b382c09a887aa9f95cb9725e309ce5b7db3
我們在上面的
docker run
命令使用了
-d
參數,因此Docker會將容器放到後台運行。
我們還在容器要運行的命令裡使用了一個
while
循環,該循環會一直打印
hello
world
,直到容器或其進程停止運行。
通過組合使用上面的這些參數,你會發現
docker run
命令並沒有像上一個容器一樣將主機的控制台附著到新的shell會話上,而是僅僅返回了一個容器ID而已,我們還是在主機的命令行之中。如果執行
docker
ps
命令,可以看到一個正在運行的容器,如代碼清單3-18所示。
代碼清單3-18 查看正在運行的
daemon_dave
容器
[code]CONTAINER ID IMAGE COMMAND CREATED
STATUS PORTS NAMES
1333bb1a66af ubuntu:14.04 /bin/sh -c 'while tr 32 secs ago Up 27
daemon_dave