摘要:進(jìn)程啟動(dòng)后,就會(huì)按照的標(biāo)準(zhǔn)準(zhǔn)備好相關(guān)運(yùn)行時(shí)環(huán)境,然后啟動(dòng)進(jìn)程。涉及到標(biāo)準(zhǔn)輸入輸出重定向,這里不細(xì)說(shuō)這里是它們之間的交互流程流程對(duì)應(yīng)的文字描述如下客戶(hù)端發(fā)送創(chuàng)建容器請(qǐng)求給,收到請(qǐng)求后,發(fā)現(xiàn)本地沒(méi)有相應(yīng)的額,于是返回失敗。
在程序員的世界里,hello world是個(gè)很特殊的存在,當(dāng)我們接觸一門(mén)新的語(yǔ)言、新的開(kāi)發(fā)庫(kù)或者框架時(shí),第一時(shí)間想了解的一般都是怎么實(shí)現(xiàn)一個(gè)hello world,然后思考hello world的背后發(fā)生了什么,在學(xué)習(xí)docker的時(shí)候,也是同樣的思路,本篇將會(huì)介紹hello world背后的故事
運(yùn)行hello worlddocker的安裝不在本篇的介紹范圍內(nèi),本文假設(shè)你已經(jīng)安裝好了17.03版本的docker。先來(lái)看看hello world運(yùn)行的效果:
dev@dev:~$ docker run hello-world Hello from Docker! This message shows that your installation appears to be working correctly. To generate this message, Docker took the following steps: 1. The Docker client contacted the Docker daemon. 2. The Docker daemon pulled the "hello-world" image from the Docker Hub. 3. The Docker daemon created a new container from that image which runs the executable that produces the output you are currently reading. 4. The Docker daemon streamed that output to the Docker client, which sent it to your terminal. ......
hello-world這個(gè)容器運(yùn)行的時(shí)候就是打印上面一段話到終端,然后退出。它在輸出結(jié)果中給我們描述了它運(yùn)行的大概步驟,下面我們將對(duì)這個(gè)過(guò)程做進(jìn)一步的分析。
關(guān)系圖這里是運(yùn)行hello-world過(guò)程中,進(jìn)程之間的關(guān)系
+------------+ | | | Docker Hub | | | +------------+ ↑ | 2 | REST | ↓ +---------+ +--------+ REST | | grpc +-------------------+ | docker |<------------------->| dockerd |<------------>| docker-containerd | +--------+ 1 | | 3 +-------------------+ +---------+ ↑ | | 4 ↓ +------------------------+ 5 +-------------+ | docker-containerd-shim |<---->| docker-runc | +------------------------+ +-------------+ ↑ | 6 ↓ +-------+ | hello | +-------+步驟過(guò)程 1. docker <--> dockerd
docker進(jìn)程是docker客戶(hù)端,dockerd進(jìn)程是docker服務(wù)器端,它們的代碼都在moby項(xiàng)目里面。
當(dāng)在shell里面運(yùn)行docker run hello-world后,docker程序被啟動(dòng),這個(gè)程序就是docker的客戶(hù)端,它的任務(wù)就是解析命令行參數(shù),然后構(gòu)造相應(yīng)的啟動(dòng)容器請(qǐng)求,通過(guò)rest的方式發(fā)給dockerd。
Engine API里描述了dockerd支持的所有請(qǐng)求,docker v17.03.0對(duì)應(yīng)的API版本為v1.26,而docker v17.03.1對(duì)應(yīng)的版本為v1.27,API版本之間的差別可以參考version-history。
2. dockerd <--> "docker hub"當(dāng)dockerd收到客戶(hù)端的運(yùn)行容器請(qǐng)求后,發(fā)現(xiàn)本地沒(méi)有相應(yīng)的鏡像(image),就會(huì)從docker hub取相應(yīng)image。(實(shí)際過(guò)程要比這個(gè)步驟多,這里為了簡(jiǎn)單直觀,省略掉了其它的步驟,后面有詳細(xì)的說(shuō)明)
docker hub是docker官方存放鏡像(image)的服務(wù)器,dockerd和它之間也是使用rest接口,協(xié)議為Registry HTTP API V2。
取image的大概過(guò)程如下:
首先獲取image的manifests,manifests里面包含兩部分內(nèi)容,一是image的配置文件的digest(sha256),另一個(gè)是image包含的所有filesystem layer的digest(sha256)
根據(jù)上一步得到的image的配置文件的digest,在本地找是否已經(jīng)存在對(duì)應(yīng)的image,如果已經(jīng)存在的話,就不用再往下走了,用現(xiàn)成的就可以了,如果沒(méi)有,則繼續(xù)
遍歷manifests里面的所有l(wèi)ayer,根據(jù)其digest在本地找,如果找到對(duì)應(yīng)的layer,則跳過(guò)當(dāng)前l(fā)ayer,否則從服務(wù)器取相應(yīng)layer的壓縮包
等上面的所有步驟完成后,就會(huì)拼出完整的image
3. dockerd <--> docker-containerd這里的每個(gè)layer都是相對(duì)于上一個(gè)文件系統(tǒng)layer的變化情況。
從上面的過(guò)程可以看出,docker只會(huì)拉取本地沒(méi)有的layer。
dockerd拿到image后,就會(huì)在本地創(chuàng)建相應(yīng)的容器,然后再做一些初始化工作后,最后通過(guò)grpc的方式通知docker-containerd進(jìn)程啟動(dòng)指定的容器
docker-containerd是和dockerd一起啟動(dòng)的后臺(tái)進(jìn)程,他們之間使用unix socket通信,協(xié)議是grpc.
4. docker-containerd <--> docker-containerd-shimdocker-containerd和docker-containerd-shim都屬于containerd項(xiàng)目,當(dāng)docker-containerd收到dockerd的啟動(dòng)容器請(qǐng)求之后,會(huì)做一些初始化工作,然后啟動(dòng)docker-containerd-shim進(jìn)程,并將相關(guān)配置所在的目錄作為參數(shù)傳給它。
可以簡(jiǎn)單的理解成docker-containerd管理所有本機(jī)正在運(yùn)行的容器,而docker-containerd-shim只負(fù)責(zé)管理一個(gè)運(yùn)行的容器,相當(dāng)于是對(duì)runc的一個(gè)包裝,充當(dāng)containerd和runc之間的橋梁,runc能干的就交給runc來(lái)做,runc做不了的就放到這里來(lái)做。
5. docker-containerd-shim <--> docker-runcdocker-containerd-shim進(jìn)程啟動(dòng)后,就會(huì)按照runtime的標(biāo)準(zhǔn)準(zhǔn)備好相關(guān)運(yùn)行時(shí)環(huán)境,然后啟動(dòng)docker-runc進(jìn)程。
docker-runc就是runc程序的重命名,它們是相等的,若無(wú)特殊情況,后面介紹中不區(qū)分docker-runc和runc
image和runtime標(biāo)準(zhǔn)都由Open Container Initiative(OCI)負(fù)責(zé)定義維護(hù),而runc就是docker貢獻(xiàn)給OCI的一個(gè)標(biāo)準(zhǔn)runtime實(shí)現(xiàn)。
如何啟動(dòng)runc是公開(kāi)的標(biāo)準(zhǔn),大概過(guò)程就是準(zhǔn)備好rootfs和配置文件,然后使用合適的參數(shù)啟動(dòng)runc進(jìn)程就可以了。
6. docker-runc <--> hellorunc進(jìn)程打開(kāi)容器的配置文件,找到rootfs的位置,并啟動(dòng)配置文件中指定的相應(yīng)進(jìn)程,在hello-world的這個(gè)例子中,runc會(huì)啟動(dòng)容器中的hello程序。
到此為止,容器啟動(dòng)成功。
進(jìn)程間的關(guān)系等runc將容器啟動(dòng)起來(lái)后,runc進(jìn)程就退出了,于是容器里面的第一個(gè)進(jìn)程(hello)的父進(jìn)程就變成了docker-containerd-shim,在pstree的輸出里面,進(jìn)程樹(shù)的關(guān)系大概如下:
systemd───dockerd───docker-containerd───docker-containerd-shim───hello
實(shí)際操作過(guò)程中可能看不到這樣的輸出,因?yàn)閔ello很快就運(yùn)行退出了,接著docker-containerd-shim也退出了。
其中dockerd和docker-containerd是后臺(tái)常駐進(jìn)程,而docker-containerd-shim則由docker-containerd按需啟動(dòng)。
輸出runc退出后其子進(jìn)程hello不是應(yīng)該由init進(jìn)程接管嗎?怎么就變成了docker-containerd-shim的子進(jìn)程了呢?這是因?yàn)閺腖inux 3.4開(kāi)始,prctl增加了對(duì)PR_SET_CHILD_SUBREAPER的支持,這樣就可以控制孤兒進(jìn)程可以被誰(shuí)接管,而不是像以前一樣只能由init進(jìn)程接管。
hello進(jìn)程啟動(dòng)之后,往標(biāo)準(zhǔn)輸出打印一段話后就退出了,那這個(gè)標(biāo)準(zhǔn)輸出輸出到哪里去了呢?docker客戶(hù)端是怎么得到這段話的呢?這就取決于docker將這個(gè)標(biāo)準(zhǔn)輸出重定向到哪里去了,以及它是怎么管理容器的這些輸出的,這涉及到docker的日志管理方式,該部分內(nèi)容會(huì)在后續(xù)做詳細(xì)介紹,這里只需要知道容器的標(biāo)準(zhǔn)輸出的內(nèi)容能被docker的這些進(jìn)程一層一層的轉(zhuǎn)發(fā)給客戶(hù)端就行了。
詳細(xì)步驟上面介紹的是一個(gè)精簡(jiǎn)版的hello world運(yùn)行步驟,實(shí)際過(guò)程要多幾個(gè)回合,下面用curl命令來(lái)模擬一下實(shí)際的操作流程:
#這里假設(shè)已經(jīng)配置了dockerd監(jiān)聽(tīng)本地tcp端口2375 #請(qǐng)求dockerd創(chuàng)建容器,但由于dockerd在本地找不到相應(yīng)的image,于是返回失敗 dev@debian:~$ curl 127.0.0.1:2375/v1.27/containers/create -X POST -H "Content-Type: application/json" -d "{"Image": "hello-world"}" {"message":"No such image: hello-world:latest"} #請(qǐng)求dockerd去找registry服務(wù)器拿image #這里的http應(yīng)答中的內(nèi)容包含了很多跟進(jìn)度條相關(guān)的內(nèi)容 dev@debian:~$ curl "127.0.0.1:2375/v1.27/images/create?fromImage=hello-world&tag=latest" -X POST {"status":"Pulling from library/hello-world","id":"latest"} {"status":"Pulling fs layer","progressDetail":{},"id":"78445dd45222"} {"status":"Downloading","progressDetail":{"current":971,"total":971},"progress":"[==================================================u003e] 971 B/971 B","id":"78445dd45222"} {"status":"Verifying Checksum","progressDetail":{},"id":"78445dd45222"} {"status":"Download complete","progressDetail":{},"id":"78445dd45222"} {"status":"Extracting","progressDetail":{"current":971,"total":971},"progress":"[==================================================u003e] 971 B/971 B","id":"78445dd45222"} {"status":"Extracting","progressDetail":{"current":971,"total":971},"progress":"[==================================================u003e] 971 B/971 B","id":"78445dd45222"} {"status":"Pull complete","progressDetail":{},"id":"78445dd45222"} {"status":"Digest: sha256:c5515758d4c5e1e838e9cd307f6c6a0d620b5e07e6f927b07d05f6d12a1ac8d7"} {"status":"Status: Downloaded newer image for hello-world:latest"} #再次創(chuàng)建容器成功,得到容器ID dev@debian:~$ curl 127.0.0.1:2375/v1.27/containers/create -X POST -H "Content-Type: application/json" -d "{"Image": "hello-world"}" {"Id":"2a4717ffb830bf4cff12ef6e6f1e93129970df273387797fd023e10292e3e928","Warnings":null} #attach到容器的標(biāo)準(zhǔn)輸出,curl程序會(huì)暫停在這里,等待容器的輸出 dev@debian:~$ curl "127.0.0.1:2375/v1.27/containers/2a4717ffb830bf4cff12ef6e6f1e93129970df273387797fd023e10292e3e928/attach?stderr=1&stdout=1&stream=1" -d "{"Connection": "Upgrade", "Upgrade":"tcp"}" #等下一步容器啟動(dòng)后,在這里可以看到容器的輸出 #另外打開(kāi)一個(gè)shell窗口,啟動(dòng)容器 dev@debian:~$ curl 127.0.0.1:2375/v1.27/containers/2a4717ffb830bf4cff12ef6e6f1e93129970df273387797fd023e10292e3e928/start -X POST
從上面的curl命令可以看出,在hello-world這個(gè)場(chǎng)景中,docker客戶(hù)端主要發(fā)送了四個(gè)請(qǐng)求給dockerd,首先創(chuàng)建image,然后創(chuàng)建容器,接著attach標(biāo)準(zhǔn)輸出,最后啟動(dòng)容器。(attach涉及到標(biāo)準(zhǔn)輸入輸出重定向,這里不細(xì)說(shuō))
這里是它們之間的交互流程:
+---------+ +--------+ | | | | 1.create container | | | |-------------------->| | | | | | | | 2.image not found | | | |<--------------------| | | | | | | | 3.create image | | | |-------------------->| | | | | | | | 4.image created | | | |<--------------------| | | docker | | dockerd | | | 5.create container | | | |-------------------->| | | | | | | | 6.container id | | | |<--------------------| | | | | | | | 7.start container | | | |-------------------->| | | | | | | | 8.container started | | | |<--------------------| | +--------+ | | +---------+
流程對(duì)應(yīng)的文字描述如下:
客戶(hù)端發(fā)送創(chuàng)建容器請(qǐng)求給dockerd,dockerd收到請(qǐng)求后,發(fā)現(xiàn)本地沒(méi)有相應(yīng)的額image,于是返回失敗。
客戶(hù)端收到失敗的響應(yīng)后,立即發(fā)送創(chuàng)建image的請(qǐng)求過(guò)來(lái),dockerd收到后,會(huì)去docker hub上拿相應(yīng)的image,拿到后返回成功。
客戶(hù)端再次發(fā)送創(chuàng)建容器請(qǐng)求給dockerd,dockerd收到會(huì)根據(jù)拿到的image創(chuàng)建一個(gè)新容器,并初始化容器運(yùn)行時(shí)要用到的相關(guān)目錄和配置文件,里面就包含了rootfs,容器創(chuàng)建完成后,dockerd返回容器的ID給客戶(hù)端。
客戶(hù)端發(fā)啟動(dòng)容器請(qǐng)求給dockerd,dockerd收到請(qǐng)求后,會(huì)通知docker-containerd啟動(dòng)容器,啟動(dòng)成功后返回成功給客戶(hù)端。
結(jié)束語(yǔ)dockerd去docker hub上取image發(fā)生在這里的3~4步之間,而docker-containerd───docker-containerd-shim───hello這些事發(fā)生在這里的7~8步之間。
本文大概的介紹了一下hello-world是如何工作的,以及涉及了docker的哪些進(jìn)程,里面還有大量的細(xì)節(jié)沒(méi)有涉及,留給后續(xù)文章做進(jìn)一步介紹。
參考DOCKER 1.11: THE FIRST RUNTIME BUILT ON CONTAINERD AND BASED ON OCI TECHNOLOGY
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/26900.html
摘要:包含的內(nèi)容本系列主要介紹三個(gè)上的項(xiàng)目由于只介紹核心的東西,所以不會(huì)包含下面這些項(xiàng)目使用語(yǔ)言開(kāi)發(fā),將多個(gè)相關(guān)的容器配置在一起,從而可以同時(shí)創(chuàng)建啟動(dòng)停止和監(jiān)控它們。由于本人時(shí)間安排發(fā)生變化,本系列停止更新,后面不確定是否會(huì)繼續(xù),非常抱歉。 本人docker初學(xué)者,邊學(xué)習(xí)邊總結(jié),一方面加深自己的理解,另一方面希望對(duì)其他想深入了解docker的同學(xué)有所幫助。 由于本人缺乏實(shí)戰(zhàn)經(jīng)驗(yàn),錯(cuò)誤在所難免...
摘要:相關(guān)工具本文將用到三個(gè)工具,分別是和。根據(jù)生成的的就是運(yùn)行容器時(shí)需要的東西的集合。使用運(yùn)行該有了后,就可以用來(lái)運(yùn)行該容器了這里直接用的代替命令,如果你自己編譯了的,那么用命令也是一樣的。 上一篇介紹了image的格式,這里我們就來(lái)用一下hello-world這個(gè)image,看怎么輸出和docker run hello-world同樣的內(nèi)容。 相關(guān)工具 本文將用到三個(gè)工具,分別是skop...
摘要:包含的內(nèi)容一個(gè)由可選和四部分組成。對(duì)于這兩種不同類(lèi)型的文件格式,標(biāo)準(zhǔn)定義了兩個(gè)新的,分別是和。最新的標(biāo)準(zhǔn)里面并沒(méi)有涉及到,不過(guò)估計(jì)后續(xù)會(huì)加上。 上一篇介紹了hello-world的大概流程,那么hello-world的image里面到底包含了些什么呢?里面的格式是怎么樣的呢? image所包含的內(nèi)容以及格式都是有標(biāo)準(zhǔn)的,由Open Containers Initiative(OCI)負(fù)...
摘要:結(jié)束語(yǔ)命令干的活比較少,主要是準(zhǔn)備的和配置文件,配置文件中的項(xiàng)比較多,后續(xù)會(huì)挑一些常用的項(xiàng)進(jìn)行專(zhuān)門(mén)介紹。 有了image之后,就可以開(kāi)始創(chuàng)建并啟動(dòng)容器了,平時(shí)我們都是用docker run命令直接創(chuàng)建并運(yùn)行一個(gè)容器,它的背后其實(shí)包含獨(dú)立的兩步,一步是docker create創(chuàng)建容器,另一步是docker start啟動(dòng)容器,本篇將先介紹在docker create這一步中,docke...
閱讀 2458·2021-11-19 09:40
閱讀 3586·2021-11-17 17:08
閱讀 3784·2021-09-10 10:50
閱讀 2214·2019-08-27 10:56
閱讀 1942·2019-08-27 10:55
閱讀 2638·2019-08-26 12:14
閱讀 994·2019-08-26 11:58
閱讀 1493·2019-08-26 10:43