docker學(xué)習(xí)(4) 一些常用操作

摘要:繼續(xù)docker的學(xué)習(xí)之旅,今天練習(xí)一些常用的命令: 一、鏡像相關(guān) 1.1 列出本機(jī)所有鏡像 docker images 后面的操作,都以u(píng)buntu做為練習(xí)的目標(biāo)。 另外:如果某些鏡像文件不想要了,可以用下面的命令刪除 1.2 刪除鏡像 docker rmi 鏡像Id(即:1.1圖中的IMAGE ID) 有時(shí)候刪除會(huì)失敗,比如:有一個(gè)容器正在使用該鏡像文件。

繼續(xù)docker的學(xué)習(xí)之旅,今天練習(xí)一些常用的命令:

一、鏡像相關(guān)

1.1列出本機(jī)所有鏡像

docker images

后面的操作,都以u(píng)buntu做為練習(xí)的目標(biāo)。

另外:如果某些鏡像文件不想要了,可以用下面的命令刪除

1.2刪除鏡像

docker rmi 鏡像Id(即:1.1圖中的IMAGE ID)

有時(shí)候刪除會(huì)失敗,比如:有一個(gè)容器正在使用該鏡像文件。這時(shí)可以加參數(shù)-f 強(qiáng)制刪除,如果不清楚每個(gè)命令可以加哪些參數(shù),可以用

docker 命令 --help

查看幫助,比如:

bin? docker rmi --help

Usage: docker rmi [OPTIONS] IMAGE [IMAGE...]

Remove one or more images

-f, --force=false? ? Force removal of the image

--help=false? ? ? ? Print usage

--no-prune=false? ? Do not delete untagged parents

二、容器相關(guān)

2.1最基本的啟動(dòng)

docker run -it ubuntu

參數(shù)-it的含義,可以用docker run --help查看,就不展開了

2.2啟動(dòng)后執(zhí)行命令

docker run -it ubuntu echo 'hello world'

2.3啟動(dòng)時(shí)指定容器名稱

docker run -it --name 'myubuntu' ubuntu

容器名稱是一個(gè)很有意思的東東,后面馬上會(huì)講到。上面的命令運(yùn)行完以后,先用exit退出,以便后面學(xué)習(xí)其它命令。

2.4查看最近運(yùn)行過的所有容器

docker ps -a

從圖上可以看出,如果啟動(dòng)時(shí)未顯示指定容器名稱,docker會(huì)自動(dòng)生成一個(gè)好玩的名稱,命令的風(fēng)格大致是:什么樣的_誰(shuí)誰(shuí),比如圖中的insane_lamarr,字面的意思為"瘋狂的拉馬爾",從這些細(xì)節(jié)可以感受到,docker的創(chuàng)造者們都是一幫很愛玩的家伙。

除了容器名稱,還有二列非常重要:CONTAINER ID及STATUS,其中STATUS中以Up開頭的,表示容器正在運(yùn)行(注:容器是否處于運(yùn)行狀態(tài),排除人為docker stop的因素外,很大程序上是由docker run 最后的命令參數(shù)決定的,如果啟動(dòng)時(shí)不指定任何命令參數(shù),默認(rèn)執(zhí)行/bin/bash,如果指定了類似echo "hello world"之類瞬間就執(zhí)行完的命令,run起來,馬上就會(huì)轉(zhuǎn)為關(guān)閉,因?yàn)槊钜呀?jīng)執(zhí)行完了),而CONTAINER ID在很多場(chǎng)景中都會(huì)用到(比如:刪除容器)

另外,對(duì)于同一個(gè)鏡像(比如ubuntu),默認(rèn)不指定容器名稱的話,每次容器啟動(dòng)docker都會(huì)生成一個(gè)唯一的名稱,這個(gè)有點(diǎn)象OOP編程,鏡像相當(dāng)于Class類定義,是一個(gè)只讀的模板,而容器則是類的運(yùn)行實(shí)例,java中每次new出來的實(shí)例,其hashcode必然不同,所以每次啟動(dòng)的docker容器,名稱也不一樣,只不過與OOP不同的是,OOP中實(shí)例消亡了,所有關(guān)聯(lián)的信息全清掉了,而docker容器就算停止掉,docker仍會(huì)記住其最后的運(yùn)行狀態(tài)。

可以做一個(gè)小試驗(yàn),剛才我們已經(jīng)創(chuàng)建了一個(gè)名為myubuntu的容器:

docker run -it --name 'myubuntu' ubuntu

這一行命令再次運(yùn)行的話,就會(huì)報(bào)錯(cuò):

Error response from daemon: Conflict. The name "myubuntu" is already in use by container d1c261ad0b1e. You have to remove (or rename) that container to be able to reuse that name.

大意是容器名稱mybutun已經(jīng)被另一個(gè)容器(ID為d1c261ad0b1e)占用了,要么把原來的容器刪除,要么換個(gè)名字。

這其中的設(shè)計(jì)思想,可以仔細(xì)琢磨一二,想想也十分合理:類比一下,我們寫代碼時(shí),同一個(gè)類new出多個(gè)實(shí)例,每個(gè)實(shí)例都會(huì)有自己不同的應(yīng)用場(chǎng)景,比如:同樣是一個(gè)Order實(shí)例,可以用在訂單創(chuàng)建的業(yè)務(wù)場(chǎng)景中,也可以用在訂單查詢的返回結(jié)果中...,docker的鏡像也是如此,同樣一個(gè)ubuntu鏡像文件,有人用它創(chuàng)建容器是為了安裝nginx當(dāng)成web server,有人用它創(chuàng)建容器是為了學(xué)習(xí)hadoop...,為了能以一種友好的方式來區(qū)分,所以名字不能沖突,然后,同一個(gè)名字的容器,今天安裝了軟件A,玩事兒后將它關(guān)閉,明天可能會(huì)繼續(xù)在這個(gè)容器上折騰其它事情,所以每次容器停止,不可能象OOP中的實(shí)例一樣,徹底丟棄實(shí)例的所有信息,否則明天就沒辦法接著玩了。

2.5停止運(yùn)行中的容器

docker stop 容器名稱

2.6刪除容器

docker rm 容器ID

如果容器處于運(yùn)行狀態(tài),上面的操作會(huì)失敗,可以加-f參數(shù)強(qiáng)制刪除

2.7在已運(yùn)行的容器中,直接執(zhí)行命令

docker exec 容器名稱 命令

例如:

docker exec myubuntu apg-get update

2.8附加到已經(jīng)運(yùn)行的容器

docker attach 容器名稱

注:該命令運(yùn)行后,mac上屏幕沒任何輸出,還以為卡死了,這是假象,直接繼續(xù)輸入命令,比如pwd之類的就能看到結(jié)果了.

attach這個(gè)命令不太好用,進(jìn)入終端后,沒辦法退出而不停止容器,要退出只能輸入exit,但這樣就將容器停止了,另外一個(gè)缺點(diǎn)是,如果多個(gè)容器同時(shí)attach到相同的容器,在一個(gè)窗口中操作的結(jié)果,會(huì)同步顯示到所有窗口。

建議用下面的命令代替:

docker exec -it 容器名稱 sh

當(dāng)然進(jìn)入容器還有其它一些辦法,比如網(wǎng)絡(luò)端口22映射本機(jī)某個(gè)端口,容器里啟動(dòng)ssh服務(wù),然后ssh連接進(jìn)入,或者用nsenter結(jié)合進(jìn)程id進(jìn)入,但個(gè)人覺得這些方法操作都太復(fù)雜,遠(yuǎn)不如上面這行命令簡(jiǎn)單

2.9保存對(duì)容器所做的修改

在容器上做了一堆操作后,比如在ubuntu的基礎(chǔ)上安裝了一些軟件、部署了一些應(yīng)用之類,希望分發(fā)到其它機(jī)器,最簡(jiǎn)單的辦法就是把容器重新生成一個(gè)新鏡像,然后其它人直接docker pull你的新鏡像就可以了。

docker commit -a 作者名字 -m 提交原因 -p 容器ID 鏡像名稱:版本號(hào)

比如:

docker commit -a 'yjmyzz' -m 'test commit' -p d1c261ad0b1e yjmyzz/ubuntu:V2

提交完成后,可以

docker images 查看

從圖中可以看出,在ubuntu原來的基礎(chǔ)上,生成一個(gè)名為yjmyzz/ubuntu的新鏡像,然后用新鏡像創(chuàng)建容器試試看

docker run -it --name 'myubuntu2' yjmyzz/ubuntu:V2

三、卷(volumn)相關(guān)

我們平時(shí)在使用電腦的過程中,會(huì)經(jīng)常通過usb插入一些外部存儲(chǔ)設(shè)備,比如:u盤之類,插好后,就能象常規(guī)硬盤目錄一樣訪問外部存儲(chǔ)設(shè)備。卷(volume)的意思其實(shí)跟這個(gè)差不多,可以把host機(jī)上的某個(gè)目錄"插入"到容器中,然后容器中就能直接訪問host機(jī)上的文件了,即使容器刪除掉,卷里的數(shù)據(jù)仍然可能持久保存。

3.1創(chuàng)建卷

docker run -it -v /Users/yjmyzz/docker_volumn:/opt/webapp --name myubuntu ubuntu /bin/bash

這個(gè)命令略長(zhǎng),但并不復(fù)雜,跟前面提到的啟動(dòng)容器相比,只是多了一個(gè)-v /Users/yjmyzz/docker_volumn:/opt/webapp的部分,意思就是將本機(jī)/Users/yjmyzz/docker_volumn這個(gè)目錄映射到容器中的/opt/webapp,啟動(dòng)成功后,保持當(dāng)前窗口不退出,可以再新開一個(gè)terminal容器,進(jìn)入容器驗(yàn)證一下

可以嘗試在host本機(jī)修改下/Users/yjmyzz/docker_volumn/index.html這個(gè)文件,然后在容器中cat看下內(nèi)容,應(yīng)該馬上就能看到最新的內(nèi)容。

三個(gè)大坑:

其一:

-v 參數(shù)可以只寫前面第一部分,-v /Users/yjmyzz/docker_volumn 這樣啟動(dòng)也不會(huì)報(bào)錯(cuò),但是這樣做的效果,在最新版本的docker(1.9.1)上,只會(huì)把本機(jī)目錄掛到容器中,容器中看不到本機(jī)的任何文件,所以一定要記得寫:后的部分

其二:

權(quán)限問題,mac機(jī)上如果從網(wǎng)上down(非apple store官方)了一個(gè)文件到本機(jī),該文件甚至保存文件的目錄權(quán)限,都會(huì)被設(shè)置成特殊權(quán)限@,見下面的截圖:

這本來是mac 10.5以后做的一項(xiàng)安全改進(jìn),有此標(biāo)識(shí)的程序,在首次執(zhí)行時(shí)會(huì)提示

但是有這類特殊權(quán)限的目錄或文件,被掛到容器中后,docker容器內(nèi)根本看不到,也就是無權(quán)讀取。處理辦法:

ll -l@ -a

先用這個(gè)顯示特殊權(quán)限的詳細(xì)信息:

然后用xattr -r -d 詳細(xì)信息 *去掉這些特殊權(quán)限(參考下圖),然后再重新掛到容器中,就能正常使用了

其三:

mac上掛載的本機(jī)目錄,必須是在~/(即:當(dāng)前用戶的目錄)下,類似/opt/www這樣的目錄,就算給它所有權(quán)限,掛到容器中后,也只能看到目錄,讀不到任何文件,centOS上沒這問題。

此外,還可以用命令

docker inspect myubuntu

查看此時(shí)容器的所有狀態(tài),會(huì)看到一段長(zhǎng)長(zhǎng)的json輸出,類似下面這樣:

[

{

"Id": "21d15713166ae83b022eea8806bd466da9917422e487e874cc098a0f1329dd48",

"Created": "2016-01-28T02:23:43.91086474Z",

"Path": "/bin/bash",

"Args": [],

"State": {

"Status": "running",

"Running": true,

"Paused": false,

"Restarting": false,

"OOMKilled": false,

"Dead": false,

"Pid": 1843,

"ExitCode": 0,

"Error": "",

"StartedAt": "2016-01-28T02:26:09.414485616Z",

"FinishedAt": "2016-01-28T02:25:43.868883111Z"

},

"Image": "8693db7e8a0084b8aacba184cfc4ff9891924ed2270c6dec6a9d99bdcff0d1aa",

"ResolvConfPath": "/mnt/sda1/var/lib/docker/containers/21d15713166ae83b022eea8806bd466da9917422e487e874cc098a0f1329dd48/resolv.conf",

"HostnamePath": "/mnt/sda1/var/lib/docker/containers/21d15713166ae83b022eea8806bd466da9917422e487e874cc098a0f1329dd48/hostname",

"HostsPath": "/mnt/sda1/var/lib/docker/containers/21d15713166ae83b022eea8806bd466da9917422e487e874cc098a0f1329dd48/hosts",

"LogPath": "/mnt/sda1/var/lib/docker/containers/21d15713166ae83b022eea8806bd466da9917422e487e874cc098a0f1329dd48/21d15713166ae83b022eea8806bd466da9917422e487e874cc098a0f1329dd48-json.log",

"Name": "/myubuntu",

"RestartCount": 0,

"Driver": "aufs",

"ExecDriver": "native-0.2",

"MountLabel": "",

"ProcessLabel": "",

"AppArmorProfile": "",

"ExecIDs": null,

"HostConfig": {

"Binds": [

"/Users/yjmyzz/docker_volumn:/opt/webapp"

],

"ContainerIDFile": "",

"LxcConf": [],

"Memory": 0,

"MemoryReservation": 0,

"MemorySwap": 0,

"KernelMemory": 0,

"CpuShares": 0,

"CpuPeriod": 0,

"CpusetCpus": "",

"CpusetMems": "",

"CpuQuota": 0,

"BlkioWeight": 0,

"OomKillDisable": false,

"MemorySwappiness": -1,

"Privileged": false,

"PortBindings": {},

"Links": null,

"PublishAllPorts": false,

"Dns": [],

"DnsOptions": [],

"DnsSearch": [],

"ExtraHosts": null,

"VolumesFrom": null,

"Devices": [],

"NetworkMode": "default",

"IpcMode": "",

"PidMode": "",

"UTSMode": "",

"CapAdd": null,

"CapDrop": null,

"GroupAdd": null,

"RestartPolicy": {

"Name": "no",

"MaximumRetryCount": 0

},

"SecurityOpt": null,

"ReadonlyRootfs": false,

"Ulimits": null,

"LogConfig": {

"Type": "json-file",

"Config": {}

},

"CgroupParent": "",

"ConsoleSize": [

0,

0

],

"VolumeDriver": ""

},

"GraphDriver": {

"Name": "aufs",

"Data": null

},

"Mounts": [

{

"Source": "/Users/yjmyzz/docker_volumn",

"Destination": "/opt/webapp",

"Mode": "",

"RW": true

}

],

"Config": {

"Hostname": "21d15713166a",

"Domainname": "",

"User": "",

"AttachStdin": true,

"AttachStdout": true,

"AttachStderr": true,

"Tty": true,

"OpenStdin": true,

"StdinOnce": true,

"Env": null,

"Cmd": [

"/bin/bash"

],

"Image": "ubuntu",

"Volumes": null,

"WorkingDir": "",

"Entrypoint": null,

"OnBuild": null,

"Labels": {},

"StopSignal": "SIGTERM"

},

"NetworkSettings": {

"Bridge": "",

"SandboxID": "893c76e283a75e3eebb474bf1b5bce901a37778de3514b526312134fcc858d2c",

"HairpinMode": false,

"LinkLocalIPv6Address": "",

"LinkLocalIPv6PrefixLen": 0,

"Ports": {},

"SandboxKey": "/var/run/docker/netns/893c76e283a7",

"SecondaryIPAddresses": null,

"SecondaryIPv6Addresses": null,

"EndpointID": "a7fee41964177719fbd149df820bf66dbd976ebe7cea0b68497ae2fe4c06efc5",

"Gateway": "172.17.0.1",

"GlobalIPv6Address": "",

"GlobalIPv6PrefixLen": 0,

"IPAddress": "172.17.0.2",

"IPPrefixLen": 16,

"IPv6Gateway": "",

"MacAddress": "02:42:ac:11:00:02",

"Networks": {

"bridge": {

"EndpointID": "a7fee41964177719fbd149df820bf66dbd976ebe7cea0b68497ae2fe4c06efc5",

"Gateway": "172.17.0.1",

"IPAddress": "172.17.0.2",

"IPPrefixLen": 16,

"IPv6Gateway": "",

"GlobalIPv6Address": "",

"GlobalIPv6PrefixLen": 0,

"MacAddress": "02:42:ac:11:00:02"

}

}

}

}

]

90~97行的Mounts節(jié)點(diǎn)描述了當(dāng)前容器掛載的"卷"信息。

最后指出一點(diǎn):目前docker僅支持在run(創(chuàng)建)容器時(shí)使用-v創(chuàng)建卷,對(duì)于一個(gè)已經(jīng)start的容器,如果想動(dòng)態(tài)添加卷,是十分困難的。雖然國(guó)外有牛人,實(shí)現(xiàn)了在容器啟動(dòng)后動(dòng)態(tài)添加卷,但過程十分曲折,而且并不能能用,有興趣的可以參考下面的文章

http://jpetazzo.github.io/2015/01/13/docker-mount-dynamic-volumes/

3.2列出所有卷

docker volume ls

3.3刪除卷

docker volume rm 卷名稱

注:刪除一個(gè)容器時(shí),默認(rèn)不會(huì)刪除容器關(guān)聯(lián)的卷,所以隨著時(shí)間的推移,host上可能會(huì)存在大量的"僵尸"卷,占用硬盤空間。建議每次docker rm 容器時(shí),加上參數(shù)-v,這樣刪除容器時(shí)會(huì)一并將對(duì)應(yīng)的卷刪除,但是這樣也會(huì)有一個(gè)副作用,如果多個(gè)容器同時(shí)關(guān)聯(lián)到同一個(gè)卷,可能會(huì)影響到其它容器。所以在使用卷的時(shí)候要規(guī)劃清楚,最好一個(gè)容器只對(duì)應(yīng)一個(gè)卷。

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

a) 進(jìn)入docker虛擬機(jī)defaut

docker-machine ssh default

b) 查看volume所在的目錄

docker volume inspect 卷名

c)切換到sudo模式

sudo -i

d) 進(jìn)入volume所在根目錄

cd /var/lib/docker/volumes/

上圖的ls命令已經(jīng)說明,所謂的數(shù)據(jù)卷,其實(shí)就是一個(gè)個(gè)目錄,再次印證了linux里的一句名言『一切皆是文件』,剩下的事情,地球人都知道了,邪惡的

rm -rf *

,最后還要重啟虛擬機(jī),退回到mac主機(jī)

docker-machine restart default

3.4數(shù)據(jù)卷容器

如果多個(gè)容器之間希望共享一份數(shù)據(jù),除了上面的方式外,docker還允許定義一個(gè)專用的容器,這個(gè)容器啥也不干,只用來放數(shù)據(jù),這種容器稱為『數(shù)據(jù)卷容器』

示例:

docker run -it -v /Users/yjmyzz/docker_volumn:/sites --name site_files kitematic/hello-world-nginx echo 'only for nginx web files'

上面的命令跟之前創(chuàng)建卷的完全一樣,現(xiàn)在我們有了一個(gè)名為site_files的數(shù)據(jù)卷容器,注意:創(chuàng)建數(shù)據(jù)卷容器時(shí),最后的命令通常都是些打醬油的echo之類,反正只是一個(gè)存數(shù)據(jù)的容器,不用執(zhí)行其它命令,甚至它本身都不需要處于啟動(dòng)狀態(tài)。

然后,其它容器創(chuàng)建時(shí),就可以使用它了:

docker run -d --volumes-from site_files --name nginx1 kitematic/hello-world-nginx sh ./start.sh

注意上面的--volumes-fromsite_files 這個(gè)就是使用數(shù)據(jù)卷容器的關(guān)鍵,其它跟之前的完全相同,多個(gè)容器可以掛同一個(gè)數(shù)據(jù)卷容器,一個(gè)容器也可以掛多個(gè)數(shù)據(jù)卷容器。

四、網(wǎng)絡(luò)相關(guān)

4.1端口映射

-p IP:host_port:container_port

上面的參數(shù)表示將本機(jī)IP上的hostport映射到容器的container_port,示例:

docker run -it -v /Users/yjmyzz/Documents/Kitematic/hello-world-nginx/website_files:/website_files -p 0.0.0.0:10080:80 --name my-nginx kitematic/hello-world-nginx sh /start.sh

這個(gè)命令更長(zhǎng)了,結(jié)合了之前所有學(xué)習(xí)到的參數(shù),注意多出的問題-p 0.0.0.0:10080:80,表示將本機(jī)10080端口映射到容器80端口

注:如果把-p換成大寫的-P,系統(tǒng)會(huì)隨機(jī)映射到本機(jī)一個(gè)空閑的端口號(hào)

4.2 指定hostname

默認(rèn)創(chuàng)建容器時(shí),hostname是一個(gè)唯一的隨機(jī)字符串,很難記,可以在docker run -h hostname名稱來指定,這個(gè)就不演示了

4.3容器間的網(wǎng)絡(luò)連接

假如有二個(gè)容器mysql, appserver,通常appserver中要訪問數(shù)據(jù)庫(kù),所以需要appserver能直接訪問mysql,下面演示了如何實(shí)現(xiàn):

a)先創(chuàng)建mysql容器

docker run -it -h mysql --name mysql ubuntu /bin/bash

b)再創(chuàng)建appserver容器

docker run -it -h appserver --name appserver --link mysql:mysqlserver ubuntu /bin/bash

注意其中的--link mysql:mysqlserver,冒號(hào)前的為容器名稱,冒號(hào)后的為容器別名,啟動(dòng)后appserver中就能直接ping通mysql容器了,見下圖:

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

本文為云棲社區(qū)原創(chuàng)內(nèi)容,未經(jīng)允許不得轉(zhuǎn)載,如需轉(zhuǎn)載請(qǐng)發(fā)送郵件至yqeditor@list.alibaba-inc.com;如果您發(fā)現(xiàn)本社區(qū)中有涉嫌抄襲的內(nèi)容,歡迎發(fā)送郵件至:yqgroup@service.aliyun.com 進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),本社區(qū)將立刻刪除涉嫌侵權(quán)內(nèi)容。

原文鏈接

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容