天天看點

docker學習(4) 一些常用操作

繼續docker的學習之旅,今天練習一些常用的指令:

一、鏡像相關

1.1 列出本機所有鏡像

docker學習(4) 一些常用操作

後面的操作,都以ubuntu做為練習的目标。

另外:如果某些鏡像檔案不想要了,可以用下面的指令删除

1.2 删除鏡像

有時候删除會失敗,比如:有一個容器正在使用該鏡像檔案。這時可以加參數-f 強制删除,如果不清楚每個指令可以加哪些參數,可以用

檢視幫助,比如:

二、容器相關

2.1 最基本的啟動

參數-it的含義,可以用docker run --help檢視,就不展開了

2.2 啟動後執行指令

2.3 啟動時指定容器名稱

容器名稱是一個很有意思的東東,後面馬上會講到。上面的指令運作完以後,先用exit退出,以便後面學習其它指令。

2.4 檢視最近運作過的所有容器

docker學習(4) 一些常用操作

  

從圖上可以看出,如果啟動時未顯示指定容器名稱,docker會自動生成一個好玩的名稱,指令的風格大緻是:什麼樣的_誰誰,比如圖中的insane_lamarr,字面的意思為"瘋狂的拉馬爾",從這些細節可以感受到,docker的創造者們都是一幫很愛玩的家夥。

除了容器名稱,還有二列非常重要:CONTAINER ID及STATUS,其中STATUS中以Up開頭的,表示容器正在運作(注:容器是否處于運作狀态,排除人為docker stop的因素外,很大程式上是由docker run 最後的指令參數決定的,如果啟動時不指定任何指令參數,預設執行/bin/bash,如果指定了類似echo "hello world"之類瞬間就執行完的指令,run起來,馬上就會轉為關閉,因為指令已經執行完了),而CONTAINER ID在很多場景中都會用到(比如:删除容器)

docker學習(4) 一些常用操作

另外,對于同一個鏡像(比如ubuntu),預設不指定容器名稱的話,每次容器啟動docker都會生成一個唯一的名稱,這個有點象OOP程式設計,鏡像相當于Class類定義,是一個隻讀的模闆,而容器則是類的運作執行個體,java中每次new出來的執行個體,其hashcode必然不同,是以每次啟動的docker容器,名稱也不一樣,隻不過與OOP不同的是,OOP中執行個體消亡了,所有關聯的資訊全清掉了,而docker容器就算停止掉,docker仍會記住其最後的運作狀态。

可以做一個小試驗,剛才我們已經建立了一個名為myubuntu的容器:

這一行指令再次運作的話,就會報錯:

大意是容器名稱mybutun已經被另一個容器(ID為d1c261ad0b1e)占用了,要麼把原來的容器删除,要麼換個名字。

這其中的設計思想,可以仔細琢磨一二,想想也十分合理:類比一下,我們寫代碼時,同一個類new出多個執行個體,每個執行個體都會有自己不同的應用場景,比如:同樣是一個Order執行個體,可以用在訂單建立的業務場景中,也可以用在訂單查詢的傳回結果中...,docker的鏡像也是如此,同樣一個ubuntu鏡像檔案,有人用它建立容器是為了安裝nginx當成web server,有人用它建立容器是為了學習hadoop...,為了能以一種友好的方式來區分,是以名字不能沖突,然後,同一個名字的容器,今天安裝了軟體A,玩事兒後将它關閉,明天可能會繼續在這個容器上折騰其它事情,是以每次容器停止,不可能象OOP中的執行個體一樣,徹底丢棄執行個體的所有資訊,否則明天就沒辦法接着玩了。

2.5 停止運作中的容器

2.6 删除容器

如果容器處于運作狀态,上面的操作會失敗,可以加-f參數強制删除  

2.7 在已運作的容器中,直接執行指令

例如:  

2.8 附加到已經運作的容器

注:該指令運作後,mac上螢幕沒任何輸出,還以為卡死了,這是假象,直接繼續輸入指令,比如pwd之類的就能看到結果了.

attach這個指令不太好用,進入終端後,沒辦法退出而不停止容器,要退出隻能輸入exit,但這樣就将容器停止了,另外一個缺點是,如果多個容器同時attach到相同的容器,在一個視窗中操作的結果,會同步顯示到所有視窗。

建議用下面的指令代替:

當然進入容器還有其它一些辦法,比如網絡端口22映射本機某個端口,容器裡啟動ssh服務,然後ssh連接配接進入,或者用nsenter結合程序id進入,但個人覺得這些方法操作都太複雜,遠不如上面這行指令簡單

2.9 儲存對容器所做的修改

在容器上做了一堆操作後,比如在ubuntu的基礎上安裝了一些軟體、部署了一些應用之類,希望分發到其它機器,最簡單的辦法就是把容器重新生成一個新鏡像,然後其它人直接docker pull你的新鏡像就可以了。

比如:

送出完成後,可以

docker images 檢視

docker學習(4) 一些常用操作

從圖中可以看出,在ubuntu原來的基礎上,生成一個名為yjmyzz/ubuntu的新鏡像,然後用新鏡像建立容器試試看

三、卷(volumn)相關 

我們平時在使用電腦的過程中,會經常通過usb插入一些外部儲存設備,比如:u盤之類,插好後,就能象正常硬碟目錄一樣通路外部儲存設備。卷(volume)的意思其實跟這個差不多,可以把host機上的某個目錄"插入"到容器中,然後容器中就能直接通路host機上的檔案了,即使容器删除掉,卷裡的資料仍然可能持久儲存。

3.1 建立卷

這個指令略長,但并不複雜,跟前面提到的啟動容器相比,隻是多了一個-v /Users/yjmyzz/docker_volumn:/opt/webapp的部分,意思就是将本機/Users/yjmyzz/docker_volumn這個目錄映射到容器中的/opt/webapp,啟動成功後,保持目前視窗不退出,可以再新開一個terminal容器,進入容器驗證一下

docker學習(4) 一些常用操作

可以嘗試在host本機修改下/Users/yjmyzz/docker_volumn/index.html這個檔案,然後在容器中cat看下内容,應該馬上就能看到最新的内容。

三個大坑:

其一:

-v 參數可以隻寫前面第一部分,-v /Users/yjmyzz/docker_volumn 這樣啟動也不會報錯,但是這樣做的效果,在最新版本的docker(1.9.1)上,隻會把本機目錄挂到容器中,容器中看不到本機的任何檔案,是以一定要記得寫:後的部分

其二:

權限問題,mac機上如果從網上down(非apple store官方)了一個檔案到本機,該檔案甚至儲存檔案的目錄權限,都會被設定成特殊權限@,見下面的截圖:

docker學習(4) 一些常用操作

這本來是mac 10.5以後做的一項安全改進,有此辨別的程式,在首次執行時會提示

docker學習(4) 一些常用操作

但是有這類特殊權限的目錄或檔案,被挂到容器中後,docker容器内根本看不到,也就是無權讀取。處理辦法:

先用這個顯示特殊權限的詳細資訊:

docker學習(4) 一些常用操作

然後用xattr -r -d 詳細資訊 * 去掉這些特殊權限(參考下圖),然後再重新挂到容器中,就能正常使用了

docker學習(4) 一些常用操作

其三:

mac上挂載的本機目錄,必須是在~/(即:目前使用者的目錄)下,類似/opt/www這樣的目錄,就算給它所有權限,挂到容器中後,也隻能看到目錄,讀不到任何檔案,centOS上沒這問題。

此外,還可以用指令

檢視此時容器的所有狀态,會看到一段長長的json輸出,類似下面這樣:

90~97行的Mounts節點描述了目前容器挂載的"卷"資訊。

最後指出一點:目前docker僅支援在run(建立)容器時使用-v建立卷,對于一個已經start的容器,如果想動态添加卷,是十分困難的。雖然國外有牛人,實作了在容器啟動後動态添加卷,但過程十分曲折,而且并不能能用,有興趣的可以參考下面的文章

<a href="http://jpetazzo.github.io/2015/01/13/docker-mount-dynamic-volumes/" target="_blank">http://jpetazzo.github.io/2015/01/13/docker-mount-dynamic-volumes/</a>

3.2 列出所有卷

docker學習(4) 一些常用操作

3.3 删除卷

注:删除一個容器時,預設不會删除容器關聯的卷,是以随着時間的推移,host上可能會存在大量的"僵屍"卷,占用硬碟空間。建議每次docker rm 容器時,加上參數-v,這樣删除容器時會一并将對應的卷删除,但是這樣也會有一個副作用,如果多個容器同時關聯到同一個卷,可能會影響到其它容器。是以在使用卷的時候要規劃清楚,最好一個容器隻對應一個卷。

tips:如果要批量删除所有卷,一個一個rm顯然太麻煩了,可以用下面的方式快速搞定

a) 進入docker虛拟機defaut

b) 檢視volume所在的目錄

docker學習(4) 一些常用操作

c)切換到sudo模式

d) 進入volume所在根目錄

docker學習(4) 一些常用操作

上圖的ls指令已經說明,所謂的資料卷,其實就是一個個目錄,再次印證了linux裡的一句名言『一切皆是檔案』,剩下的事情,地球人都知道了,邪惡的

,最後還要重新開機虛拟機,退回到mac主機

3.4 資料卷容器

如果多個容器之間希望共享一份資料,除了上面的方式外,docker還允許定義一個專用的容器,這個容器啥也不幹,隻用來放資料,這種容器稱為『資料卷容器』

示例:

上面的指令跟之前建立卷的完全一樣,現在我們有了一個名為site_files的資料卷容器,注意:建立資料卷容器時,最後的指令通常都是些打醬油的echo之類,反正隻是一個存資料的容器,不用執行其它指令,甚至它本身都不需要處于啟動狀态。

然後,其它容器建立時,就可以使用它了:

注意上面的--volumes-from site_files 這個就是使用資料卷容器的關鍵,其它跟之前的完全相同,多個容器可以挂同一個資料卷容器,一個容器也可以挂多個資料卷容器。

四、網絡相關

4.1 端口映射

上面的參數表示将本機IP上的hostport映射到容器的container_port,示例:  

這個指令更長了,結合了之前所有學習到的參數,注意多出的問題-p 0.0.0.0:10080:80,表示将本機10080端口映射到容器80端口 

注:如果把-p換成大寫的-P,系統會随機映射到本機一個空閑的端口号 

4.2 指定hostname

預設建立容器時,hostname是一個唯一的随機字元串,很難記,可以在docker run -h hostname名稱來指定,這個就不示範了

4.3 容器間的網絡連接配接

假如有二個容器mysql, appserver,通常appserver中要通路資料庫,是以需要appserver能直接通路mysql,下面示範了如何實作:

a) 先建立mysql容器

b) 再建立appserver容器  

注意其中的--link mysql:mysqlserver,冒号前的為容器名稱,冒号後的為容器别名,啟動後appserver中就能直接ping通mysql容器了,見下圖:

docker學習(4) 一些常用操作

注:這個連接配接是單向的,即appserver可以ping通mysql容器,但反過來不行。而且最新版的docker在ps時,Name列也不再象之前網上說的那個顯示成A/B這種格式,要檢視一個容器是否有連接配接,最直接的方式還是docker inspect 容器名稱

docker學習(4) 一些常用操作