1. 獲取最近運(yùn)行容器的id
這是我們經(jīng)常會用到的一個操作,按照官方示例,你可以這樣做(環(huán)境ubuntu):
$?ID=$(docker?run?ubuntuechohello?world)
hello?world
$?docker?commit?$ID?helloworld
fd08a884dc79
這種方式在編寫腳本的時候很有用弄屡,比如你想在腳本中批量獲取id艳丛,然后進(jìn)一步操作荔茬。但是這種方式要求你必須給ID賦值霞揉,如果是直接敲命令,這樣做就不太方便了癣猾。 這時敛劝,你可以換一種方式:
$aliasdl=’dockerps-l?-q’
$?docker?run?ubuntuechohello?world
hello?world
$?dl
1904cf045887
$?docker?commit?`dl`?helloworld
fd08a884dc79
docker ps -l -q命令將返回最近運(yùn)行的容器的id,通過設(shè)置別名(alias)纷宇,dl命令就是獲取最近容器的id夸盟。這樣,就無需再輸入冗長的docker ps -l -q命令了像捶。通過兩個斜引號“上陕,可以獲取dl命令的值桩砰,也就是最近運(yùn)行的容器的id。
2.盡量在Dockerfile中指定要安裝的軟件释簿,而不用Docker容器的shell直接安裝軟件
說實(shí)話亚隅,我有時候也喜歡在shell中安裝軟件,也許你也一樣庶溶,喜歡在shell中把所有軟件安裝都搞定煮纵。但是,搞來搞去偏螺,最后還是發(fā)現(xiàn)行疏,你還是需要在Doockerfile中指定安裝文件。在shell中安裝軟件套像,你要這樣做:
$?docker?run?-i?-t?ubuntubash#登陸到docker容器
root@db0c3967abf8:/#
然后輸入下面的命令來安裝文件:
apt-getinstallpostgresql
然后再調(diào)用exit:
root@db0c3978abf8:/#?exit
退出docker容器酿联,再給docker commit命令傳遞一個復(fù)雜的JSON字符串來提交新的鏡像:
$?docker?commit?-run=”{“Cmd”:[“postgres”,”-too?-many?-opts”]?}”?`dl`?postgres
太麻煩了,不是嗎夺巩?還是在Dockerfile中指定安裝文件吧贞让,只要兩個步驟:
1.在一個小巧的Dockerfile中,指定當(dāng)前操作的鏡像為FROM命令的參數(shù)
2.然后在Dockerfile中指定一些docker的命令劲够,如CMD,?ENTERPOINT,?VOLUME等等來指定安裝的軟件
3.超-超-超級用戶
你可能需要一直用超級用戶來操作docker震桶,就像早期示例里一直提示的:
#?添加docker用戶組
$sudogroupadd?docker
#?把自己加到docker用戶組中
$sudogpasswd?-a?myusername?docker
#?重啟docker后臺服務(wù)
$sudoservice?docker?restart
#?注銷休傍,然后再登陸
$exit
Wow征绎!連續(xù)三個sudo!三次化身“超級用戶”磨取,真可謂是“超-超-超級用戶”叭耸痢!別擔(dān)心忙厌,設(shè)置完畢凫岖,以后你就再也不用打那么多sudo了!
4. 清理垃圾
如果你想刪除所有停止運(yùn)行的容器逢净,用這個命令:
$?dockerrm$(dockerps-a?-q)
順便說一句哥放,docker ps命令很慢,不知道為啥這么慢爹土,按理說Go語言是很快的啊甥雕。docker ps -a -q命令列出所有容器的id,然后根據(jù)id刪除容器胀茵。docker rm命令遇到正在運(yùn)行的容器就會失效社露,所以這個命令完美的刪除了所有沒在運(yùn)行的容器。
5. docker inspect輸出結(jié)果的解析利器:jq
要對docker inspect的輸出結(jié)果進(jìn)行過濾琼娘,一般情況下峭弟,用grep命令附鸽,你需要這樣操作:
$docker?inspect?`dl`?|grepIPAddress?|cut-d?‘“‘?-f?4?172.17.0.52
哦!看上去很復(fù)雜瞒瘸,用jq吧坷备,專業(yè)解析docker inspect輸出結(jié)果,具有更強(qiáng)的可讀性情臭,方便易用:
$docker?inspect?`dl`?|?jq?-r?‘.[0].NetworkSettings.IPAddress’?172.17.0.52
其中第一個’.’代表所有的結(jié)果击你。’[0]’代表數(shù)組的第一個元素谎柄。就像JavaScript訪問一個JSON對象一樣丁侄,簡單方便。
6.鏡像有哪些環(huán)境變量朝巫?
有時候鸿摇,你需要知道自己創(chuàng)建的鏡像有哪些環(huán)境變量。簡單劈猿!只要這樣:
$?docker?run?ubuntuenv
輸出結(jié)果如下:
HOME=/
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
container=lxc
HOSTNAME=5e1560b7f757
調(diào)用env查看環(huán)境變量拙吉,對于后面要講到的“鏈接”(-link)很有用,在連接兩個容器時候需要用到這些環(huán)境變量揪荣,具體請看最后一個要點(diǎn)“鏈接”筷黔。
7.RUN命令 vs CMD命令
Docker的新手用戶比較容易混淆RUN和CMD這兩個命令。
RUN命令在構(gòu)建(Build)Docker時執(zhí)行仗颈,這時CMD命令不執(zhí)行佛舱。CMD命令在RUN命令執(zhí)行時才執(zhí)行。我們來理清關(guān)系挨决,假設(shè)Dockerfile內(nèi)容如下:
FROM?thelanddownunder
MAINTAINER?crocdundee
我們要向系統(tǒng)中安裝一些軟件请祖,那么:
#?docker?build將會執(zhí)行下面的命令:
RUN?apt-get?update
RUN?apt-getinstallsoftwares
#?dokcer?run默認(rèn)執(zhí)行下面的命令:
CMD?[“softwares”]
Build時執(zhí)行RUN,RUN時執(zhí)行CMD脖祈,也就是說肆捕,CMD才是鏡像最終執(zhí)行的命令。
8.CMD命令 vs ENTRYPOINT命令
又是兩條容易混淆的命令盖高!具體細(xì)節(jié)我們就不說了慎陵,舉個例子,假設(shè)一個容器的Dockerfile指定CMD命令喻奥,如下:
FROM?ubuntu
CMD?[“echo”]
另一個容器的Dockerfile指定ENTRYPOINT命令席纽,如下:
FROM?ubuntu
ENTRYPOINT?[“echo”]
運(yùn)行第一個容器:
docker?run?image1echohello
得到的結(jié)果:
hello
運(yùn)行第二個容器:
docker?run?image2echohello
得到的結(jié)果:
echohello
看到不同了吧?實(shí)際上映凳,CMD命令是可覆蓋的胆筒,docker
run后面輸入的命令與CMD指定的命令匹配時,會把CMD指定的命令替換成docker
run中帶的命令。而ENTRYPOINT指定的命令只是一個“入口”仆救,docker
run后面的內(nèi)容會全部傳給這個“入口”抒和,而不是進(jìn)行命令的替換,所以得到的結(jié)果就是“echo hello”彤蔽。
9.Docker容器有自己的IP地址嗎摧莽?
剛接觸Docker的人或許會有這樣的疑問:Docker容器有自己的IP地址嗎?Docker容器是一個進(jìn)程顿痪?還是一個虛擬機(jī)镊辕?嗯…也許兩者兼
具?哈哈蚁袭,其實(shí)征懈,Docker容器確實(shí)有自己的IP,就像一個具有IP的進(jìn)程揩悄。只要分別在主機(jī)和Docker容器中執(zhí)行查看ip的命令就知道了卖哎。
查看主機(jī)的ip:
$?ip?-4?-o?addr?show?eth0
得到結(jié)果:
2:?eth0?inet?162.243.139.222/24
查看Docker容器的ip:
$?docker?run?ubuntu?ip?-r?-o?addr?show?eth0
得到結(jié)果:
149:?eth0???inet?172.17.0.43/16
兩者并不相同,說明Docker容器有自己的ip删性。
10.基于命令行的瘦客戶端亏娜,使用UNIX Socket和Docker后臺服務(wù)的REST接口進(jìn)行通信
Docker默認(rèn)是用UNIX socket通信的,一直到大概0.5蹬挺、0.6的版本還是用端口來通信维贺,但現(xiàn)在則改成UNIX socket,所以從外部無法控制Docker容器的內(nèi)部細(xì)節(jié)巴帮。下面我們來搞點(diǎn)有趣的事情溯泣,從主機(jī)鏈接到docker的UNIX socket:
#?像HTTP客戶端一樣連接到UNIX?socket
$?nc?-U?//var/run/docker.sock
連接成功后,輸入:
GET/images/jsonHTTP/1.1
輸入后連敲兩個回車晰韵,第二個回車表示輸入結(jié)束发乔。然后,得到的結(jié)果應(yīng)該是:
HTTP/1.1?200?OK
Content-Type:?application/json
Date:?Tue,?05?Nov?2013?23:18:09?GMT
Transfer-Encoding:?chunked
16aa
[{“Repository”:”postgres”,”Tag”:”......
有一天雪猪,我不小心把提交的名稱打錯了,名字開頭打成”-xxx”(我把命令和選項(xiàng)的順序搞混了)起愈,所以當(dāng)我刪除的時候出了問題只恨,docker rm
-xxx,會把-xxx當(dāng)成參數(shù)而不是鏡像的名稱抬虽。所以我只得通過socket直接連到容器來調(diào)用REST Server把錯誤的東西刪掉官觅。
11.把鏡像的依賴關(guān)系繪制成圖
docker images命令有一個很拉風(fēng)的選項(xiàng):-viz,可以把鏡像的依賴關(guān)系繪制成圖并通過管道符號保存到圖片文件:
#?生成一個依賴關(guān)系的圖表
$?docker?images?-viz?|?dot?-T?png?-o?docker.png
這樣阐污,主機(jī)的當(dāng)前路徑下就生成了一張png圖休涤,然后,用python開啟一個微型的HTTP服務(wù)器:
python?-m?SimpleHTTPServer
然后在別的機(jī)器上用瀏覽器打開:
http://machinename:8000/docker.png
OK,依賴關(guān)系一目了然功氨!
(譯者注:要使用dot命令序苏,主機(jī)要安裝graphviz包。另外捷凄,如果主機(jī)ip沒有綁定域名忱详,machinename換成主機(jī)的ip即可。)
12.Docker把東西都存到哪里去了跺涤?
Docker實(shí)際上把所有東西都放到/var/lib/docker路徑下了匈睁。切換成super用戶,到/var/lib/docker下看看桶错,你能學(xué)到很多有趣的東西航唆。執(zhí)行下面的命令:
$sudosu
#?cd?/var/lib/docker
#?ls?-F
containers/?graph/?repositories?volumes/
可以看到不少目錄,containers目錄當(dāng)然就是存放容器(container)了院刁,graph目錄存放鏡像佛点,文件層(file system
layer)存放在graph/imageid/layer路徑下,這樣你就可以看看文件層里到底有哪些東西黎比,利用這種層級結(jié)構(gòu)可以清楚的看到文件層是如
何一層一層疊加起來的超营。
13.Docker源代碼:Go, Go, Go, Golang!
Docker的源代碼全部是用Go語言寫的。Go是一門非吃某妫酷的語言演闭。其實(shí),不只是Docker颓帝,很多優(yōu)秀的軟件都是用Go寫的米碰。對我來說,Docker源文件中购城,有4個是我非常喜歡閱讀的:
commands.go
docker的命令行接口吕座,是對REST API的一個輕量級封裝。Docker團(tuán)隊(duì)不希望在命令中出現(xiàn)邏輯瘪板,因此commands.go只是向REST API發(fā)送指令吴趴,確保其較小的顆粒性。
api.go
REST API的路由(接受commands.go中的請求侮攀,轉(zhuǎn)發(fā)到server.go)
server.go
大部分REST API的實(shí)現(xiàn)
buildfile.go
Dockerfile的解析器
有的伙計(jì)驚嘆”Wow!Docker是怎么實(shí)現(xiàn)的锣枝?!我無法理解兰英!”沒關(guān)系撇叁,Docker是開源軟件,去看它的源代碼就可以了畦贸。如果你不太清楚Dockerfile中的命令是怎么回事陨闹,直接去看buildfile.go就明白了。
14.運(yùn)行幾個Docker后臺程序,再退出容器趋厉,會發(fā)生什么寨闹?
OK,倒數(shù)第二個要點(diǎn)觅廓。如果在Docker中運(yùn)行幾個后臺程序鼻忠,再退出Docker容器,會發(fā)生什么杈绸?答案是:不要這么做帖蔓!因?yàn)檫@樣做后臺程序就全丟了。
Dockerfile中用RUN命令去開啟一個后臺程序瞳脓,如:
RUN?pg_ctl?start
這樣的話塑娇,RUN命令開啟的后臺程序就會丟失。調(diào)用容器的bash連到容器的shell:
$?docker?run?-i?-t?postgresimagebash
然后調(diào)用 ps aux查看進(jìn)程劫侧,你會發(fā)現(xiàn)postgres的進(jìn)程并沒有跑起來埋酬。
RUN命令會影響文件系統(tǒng)。因此烧栋,不要再Dockerfile中用啟動后臺程序写妥,要把后臺程序啟動成前臺進(jìn)程∩笮眨或者珍特,像一些高手提議的那樣,寫一個啟動腳
本魔吐,在腳本中啟動這些后臺程序或進(jìn)程扎筒。
15.容器之間進(jìn)行友好溝通:鏈接
這是最拉風(fēng)的功能!我把它留到最后壓軸酬姆!這是0.6.5中最重要的新功能嗜桌,我們前面已經(jīng)提過兩次了。運(yùn)行一個容器辞色,給它一個名稱骨宠,在下面的例子中,我們通過-name參數(shù)給容器指定名稱”loldb”:
$?docker?run?-d?-name?loldb?loldbimage
再運(yùn)行另一個容器淫僻,加上-link參數(shù)來連接到第一個容器(別名為loldb)诱篷,并給第二個容器也指定一個別名(這里用的是cheez):
$?docker?run?-link/loldb:cheez?otherimageenv
順便得到cheez的環(huán)境變量:
CHEEZ_PORT=tcp://172.17.0.8:6379
CHEEZ_PORT_1337_TCP=tcp://172.17.0.8.6379
CHEEZ_PORT_1337_TCP_ADDR=tcp://172.17.0.12
CHEEZ_PORT_1337_TCP_PORT=6379
CHEEZ_PORT_1337_TCP_PROTO=tcp
這樣,我們就在兩個容器間建立起一個網(wǎng)絡(luò)通道(bridge)雳灵,基于此,我們可以建立一個類似rails的程序:一個容器可以訪問數(shù)據(jù)庫容器而不對外暴露其他接口闸盔。非趁跽蓿酷!數(shù)據(jù)庫容器只需要知道第一個容器的別名(在本例中為cheez)和要打開的端口號。所以數(shù)據(jù)庫容器也可以env命令來查看這個端口是否打開躲撰。