這是我在某招聘網(wǎng)站上看到的招聘 Java開(kāi)發(fā)工程師 的招聘要求歇竟,其中有一條熟悉 docker
成為了你快速入職的加分項(xiàng),由此可見(jiàn)熟悉 docker
在互聯(lián)網(wǎng)公司的地位之重要滔吠。
當(dāng)然對(duì)于我們 CTF選手 而言纲菌,熟悉 docker
可以快速搭建 CTF環(huán)境
,完美地還原比賽真實(shí)漏洞的場(chǎng)景疮绷,幫助我們快速提升自己翰舌。
市面上已經(jīng)有很多優(yōu)秀的教程,但是很多原理性的東西冬骚,筆者認(rèn)為那些教程對(duì)初學(xué)者而言還是很難理解椅贱,感覺(jué)沒(méi)有說(shuō)清楚(筆者自己都覺(jué)得挺懵逼的)懂算,為了讓初學(xué)者少走彎路,我將以我的學(xué)習(xí)經(jīng)歷以及作為一個(gè) CTF選手 的角度庇麦,編寫(xiě)此套教程计技,來(lái)帶大家去了解并熟練運(yùn)用 docker
,祝愿各位讀者朋友們學(xué)完此套教程后山橄,在未來(lái)企業(yè)面試中能夠多一項(xiàng)加分的籌碼垮媒,能夠幫助到大家,我覺(jué)得就很值了航棱。
既然說(shuō)了這么多睡雇, docker
到底是個(gè)什么東西呢?
我們?cè)诶斫?docker
之前饮醇,首先我們得先區(qū)分清楚兩個(gè)概念它抱,容器和虛擬機(jī)。
可能很多讀者朋友都用過(guò)虛擬機(jī)驳阎,而對(duì)容器這個(gè)概念比較的陌生抗愁。
我們用的傳統(tǒng)虛擬機(jī)如 VMware
馁蒂, VisualBox
之類的需要模擬整臺(tái)機(jī)器包括硬件呵晚,每臺(tái)虛擬機(jī)都需要有自己的操作系統(tǒng),虛擬機(jī)一旦被開(kāi)啟沫屡,預(yù)分配給它的資源將全部被占用饵隙。每一臺(tái)虛擬機(jī)包括應(yīng)用,必要的二進(jìn)制和庫(kù)沮脖,以及一個(gè)完整的用戶操作系統(tǒng)金矛。
而容器技術(shù)是和我們的宿主機(jī)共享硬件資源及操作系統(tǒng),可以實(shí)現(xiàn)資源的動(dòng)態(tài)分配勺届。容器包含應(yīng)用和其所有的依賴包驶俊,但是與其他容器共享內(nèi)核。容器在宿主機(jī)操作系統(tǒng)中免姿,在用戶空間以分離的進(jìn)程運(yùn)行饼酿。
容器技術(shù)是實(shí)現(xiàn)操作系統(tǒng)虛擬化的一種途徑,可以讓您在資源受到隔離的進(jìn)程中運(yùn)行應(yīng)用程序及其依賴關(guān)系胚膊。通過(guò)使用容器故俐,我們可以輕松打包應(yīng)用程序的代碼、配置和依賴關(guān)系紊婉,將其變成容易使用的構(gòu)建塊药版,從而實(shí)現(xiàn)環(huán)境一致性、運(yùn)營(yíng)效率喻犁、開(kāi)發(fā)人員生產(chǎn)力和版本控制等諸多目標(biāo)槽片。容器可以幫助保證應(yīng)用程序快速何缓、可靠、一致地部署筐乳,其間不受部署環(huán)境的影響歌殃。容器還賦予我們對(duì)資源更多的精細(xì)化控制能力,讓我們的基礎(chǔ)設(shè)施效率更高蝙云。通過(guò)下面這幅圖我們可以很直觀的反映出這兩者的區(qū)別所在氓皱。
Docker 屬于 Linux 容器的一種封裝,提供簡(jiǎn)單易用的容器使用接口勃刨。它是目前最流行的 Linux
容器解決方案波材。
而 Linux
容器是 Linux
發(fā)展出了另一種虛擬化技術(shù),簡(jiǎn)單來(lái)講身隐, Linux
容器不是模擬一個(gè)完整的操作系統(tǒng)廷区,而是對(duì)進(jìn)程進(jìn)行隔離,相當(dāng)于是在正常進(jìn)程的外面套了一個(gè)保護(hù)層贾铝。對(duì)于容器里面的進(jìn)程來(lái)說(shuō)隙轻,它接觸到的各種資源都是虛擬的,從而實(shí)現(xiàn)與底層系統(tǒng)的隔離垢揩。
Docker
將應(yīng)用程序與該程序的依賴玖绿,打包在一個(gè)文件里面。運(yùn)行這個(gè)文件叁巨,就會(huì)生成一個(gè)虛擬容器斑匪。程序在這個(gè)虛擬容器里運(yùn)行,就好像在真實(shí)的物理機(jī)上運(yùn)行一樣锋勺。有了 Docker
蚀瘸,就不用擔(dān)心環(huán)境問(wèn)題。
總體來(lái)說(shuō)庶橱, Docker
的接口相當(dāng)簡(jiǎn)單贮勃,用戶可以方便地創(chuàng)建和使用容器,把自己的應(yīng)用放入容器苏章。容器還可以進(jìn)行版本管理寂嘉、復(fù)制、分享布近、修改垫释,就像管理普通的代碼一樣。
Docker的優(yōu)勢(shì)
Docker相比于傳統(tǒng)虛擬化方式具有更多的優(yōu)勢(shì):
-
docker
啟動(dòng)快速屬于秒級(jí)別撑瞧。虛擬機(jī)通常需要幾分鐘去啟動(dòng) -
docker
需要的資源更少棵譬,docker
在操作系統(tǒng)級(jí)別進(jìn)行虛擬化,docker
容器和內(nèi)核交互预伺,幾乎沒(méi)有性能損耗订咸,性能優(yōu)于通過(guò)Hypervisor
層與內(nèi)核層的虛擬化 -
docker
更輕量曼尊,docker
的架構(gòu)可以共用一個(gè)內(nèi)核與共享應(yīng)用程序庫(kù),所占內(nèi)存極小脏嚷。同樣的硬件環(huán)境骆撇,Docker
運(yùn)行的鏡像數(shù)遠(yuǎn)多于虛擬機(jī)數(shù)量,對(duì)系統(tǒng)的利用率非常高 - 與虛擬機(jī)相比父叙,
docker
隔離性更弱神郊,docker
屬于進(jìn)程之間的隔離,虛擬機(jī)可實(shí)現(xiàn)系統(tǒng)級(jí)別隔離 - 安全性:
docker
的安全性也更弱趾唱。Docker
的租戶root
和宿主機(jī)root
等同涌乳,一旦容器內(nèi)的用戶從普通用戶權(quán)限提升為root權(quán)限,它就直接具備了宿主機(jī)的root權(quán)限甜癞,進(jìn)而可進(jìn)行無(wú)限制的操作夕晓。虛擬機(jī)租戶root
權(quán)限和宿主機(jī)的root
虛擬機(jī)權(quán)限是分離的,并且虛擬機(jī)利用如Intel
的VT-d
和VT-x
的ring-1
硬件隔離技術(shù)悠咱,這種隔離技術(shù)可以防止虛擬機(jī)突破和彼此交互蒸辆,而容器至今還沒(méi)有任何形式的硬件隔離,這使得容器容易受到攻擊 - 可管理性:
docker
的集中化管理工具還不算成熟析既。各種虛擬化技術(shù)都有成熟的管理工具躬贡,例如VMware vCenter
提供完備的虛擬機(jī)管理能力 - 高可用和可恢復(fù)性:
docker
對(duì)業(yè)務(wù)的高可用支持是通過(guò)快速重新部署實(shí)現(xiàn)的。虛擬化具備負(fù)載均衡渡贾,高可用逗宜,容錯(cuò)雄右,遷移和數(shù)據(jù)保護(hù)等經(jīng)過(guò)生產(chǎn)實(shí)踐檢驗(yàn)的成熟保障機(jī)制空骚,VMware
可承諾虛擬機(jī)99.999%
高可用,保證業(yè)務(wù)連續(xù)性 - 快速創(chuàng)建擂仍、刪除:虛擬化創(chuàng)建是分鐘級(jí)別的囤屹,
Docker
容器創(chuàng)建是秒級(jí)別的,Docker
的快速迭代性逢渔,決定了無(wú)論是開(kāi)發(fā)肋坚、測(cè)試、部署都可以節(jié)約大量時(shí)間 - 交付肃廓、部署:虛擬機(jī)可以通過(guò)鏡像實(shí)現(xiàn)環(huán)境交付的一致性智厌,但鏡像分發(fā)無(wú)法體系化。
Docker
在Dockerfile
中記錄了容器構(gòu)建過(guò)程盲赊,可在集群中實(shí)現(xiàn)快速分發(fā)和快速部署
我們可以從下面這張表格很清楚地看到容器相比于傳統(tǒng)虛擬機(jī)的特性的優(yōu)勢(shì)所在:
特性 | 容器 | 虛擬機(jī) |
---|---|---|
啟動(dòng) | 秒級(jí) | 分鐘級(jí) |
硬盤(pán)使用 | 一般為MB | 一般為GB |
性能 | 接近原生 | 弱于 |
系統(tǒng)支持量 | 單機(jī)支持上千個(gè)容器 | 一般是幾十個(gè) |
Docker的三個(gè)基本概念
從上圖我們可以看到铣鹏,Docker
中包括三個(gè)基本的概念:
-
Image
(鏡像) -
Container
(容器) -
Repository
(倉(cāng)庫(kù))
鏡像是 Docker
運(yùn)行容器的前提,倉(cāng)庫(kù)是存放鏡像的場(chǎng)所哀蘑,可見(jiàn)鏡像更是 Docker
的核心诚卸。
Image (鏡像)
那么鏡像到底是什么呢葵第?
Docker
鏡像可以看作是一個(gè)特殊的文件系統(tǒng),除了提供容器運(yùn)行時(shí)所需的程序合溺、庫(kù)卒密、資源、配置等文件外棠赛,還包含了一些為運(yùn)行時(shí)準(zhǔn)備的一些配置參數(shù)(如匿名卷哮奇、環(huán)境變量、用戶等)睛约。鏡像不包含任何動(dòng)態(tài)數(shù)據(jù)屏镊,其內(nèi)容在構(gòu)建之后也不會(huì)被改變。
鏡像(Image)
就是一堆只讀層(read-only layer)
的統(tǒng)一視角痰腮,也許這個(gè)定義有些難以理解而芥,下面的這張圖能夠幫助讀者理解鏡像的定義。
從左邊我們看到了多個(gè)只讀層膀值,它們重疊在一起棍丐。除了最下面一層,其它層都會(huì)有一個(gè)指針指向下一層沧踏。這些層是Docker
內(nèi)部的實(shí)現(xiàn)細(xì)節(jié)歌逢,并且能夠在主機(jī)的文件系統(tǒng)上訪問(wèn)到。統(tǒng)一文件系統(tǒng) (union file system)
技術(shù)能夠?qū)⒉煌膶诱铣梢粋€(gè)文件系統(tǒng)翘狱,為這些層提供了一個(gè)統(tǒng)一的視角秘案,這樣就隱藏了多層的存在,在用戶的角度看來(lái)潦匈,只存在一個(gè)文件系統(tǒng)阱高。我們可以在圖片的右邊看到這個(gè)視角的形式。
Container (容器)
容器 (container)
的定義和鏡像 (image)
幾乎一模一樣茬缩,也是一堆層的統(tǒng)一視角赤惊,唯一區(qū)別在于容器的最上面那一層是可讀可寫(xiě)的。
由于容器的定義并沒(méi)有提及是否要運(yùn)行容器凰锡,所以實(shí)際上未舟,容器 = 鏡像 + 讀寫(xiě)層。
Repository (倉(cāng)庫(kù))
Docker
倉(cāng)庫(kù)是集中存放鏡像文件的場(chǎng)所掂为。鏡像構(gòu)建完成后裕膀,可以很容易的在當(dāng)前宿主上運(yùn)行,但是勇哗, 如果需要在其它服務(wù)器上使用這個(gè)鏡像昼扛,我們就需要一個(gè)集中的存儲(chǔ)、分發(fā)鏡像的服務(wù)智绸,Docker Registry
(倉(cāng)庫(kù)注冊(cè)服務(wù)器)就是這樣的服務(wù)野揪。有時(shí)候會(huì)把倉(cāng)庫(kù) (Repository)
和倉(cāng)庫(kù)注冊(cè)服務(wù)器 (Registry)
混為一談访忿,并不嚴(yán)格區(qū)分。Docker
倉(cāng)庫(kù)的概念跟 Git
類似斯稳,注冊(cè)服務(wù)器可以理解為 GitHub
這樣的托管服務(wù)海铆。實(shí)際上,一個(gè) Docker Registry
中可以包含多個(gè)倉(cāng)庫(kù) (Repository)
挣惰,每個(gè)倉(cāng)庫(kù)可以包含多個(gè)標(biāo)簽 (Tag)
卧斟,每個(gè)標(biāo)簽對(duì)應(yīng)著一個(gè)鏡像。所以說(shuō)憎茂,鏡像倉(cāng)庫(kù)是 Docker
用來(lái)集中存放鏡像文件的地方類似于我們之前常用的代碼倉(cāng)庫(kù)珍语。
通常,一個(gè)倉(cāng)庫(kù)會(huì)包含同一個(gè)軟件不同版本的鏡像竖幔,而標(biāo)簽就常用于對(duì)應(yīng)該軟件的各個(gè)版本 板乙。我們可以通過(guò)<倉(cāng)庫(kù)名>:<標(biāo)簽>
的格式來(lái)指定具體是這個(gè)軟件哪個(gè)版本的鏡像坐搔。如果不給出標(biāo)簽拴事,將以 latest
作為默認(rèn)標(biāo)簽.。
倉(cāng)庫(kù)又可以分為兩種形式:
-
public
(公有倉(cāng)庫(kù)) -
private
(私有倉(cāng)庫(kù))
Docker Registry
公有倉(cāng)庫(kù)是開(kāi)放給用戶使用驱显、允許用戶管理鏡像的 Registry
服務(wù)馋评。一般這類公開(kāi)服務(wù)允許用戶免費(fèi)上傳放接、下載公開(kāi)的鏡像,并可能提供收費(fèi)服務(wù)供用戶管理私有鏡像留特。
除了使用公開(kāi)服務(wù)外纠脾,用戶還可以在本地搭建私有 Docker Registry
。Docker
官方提供了 Docker Registry
鏡像蜕青,可以直接使用做為私有 Registry
服務(wù)苟蹈。當(dāng)用戶創(chuàng)建了自己的鏡像之后就可以使用 push
命令將它上傳到公有或者私有倉(cāng)庫(kù),這樣下次在另外一臺(tái)機(jī)器上使用這個(gè)鏡像時(shí)候市咆,只需要從倉(cāng)庫(kù)上 pull
下來(lái)就可以了汉操。
我們主要把 Docker
的一些常見(jiàn)概念如 Image
再来, Container
蒙兰, Repository
做了詳細(xì)的闡述,也從傳統(tǒng)虛擬化方式的角度闡述了 docker
的優(yōu)勢(shì)芒篷,我們從下圖可以直觀地看到 Docker
的架構(gòu):
Docker
使用 C/S
結(jié)構(gòu)搜变,即客戶端/服務(wù)器體系結(jié)構(gòu)。 Docker
客戶端與 Docker
服務(wù)器進(jìn)行交互针炉,Docker服務(wù)端負(fù)責(zé)構(gòu)建挠他、運(yùn)行和分發(fā) Docker
鏡像。 Docker
客戶端和服務(wù)端可以運(yùn)行在一臺(tái)機(jī)器上篡帕,也可以通過(guò) RESTful
殖侵、 stock
或網(wǎng)絡(luò)接口與遠(yuǎn)程 Docker
服務(wù)端進(jìn)行通信贸呢。
這張圖展示了 Docker
客戶端、服務(wù)端和 Docker
倉(cāng)庫(kù)(即 Docker Hub
和 Docker Cloud
)拢军,默認(rèn)情況下Docker
會(huì)在 Docker
中央倉(cāng)庫(kù)尋找鏡像文件楞陷,這種利用倉(cāng)庫(kù)管理鏡像的設(shè)計(jì)理念類似于 Git
,當(dāng)然這個(gè)倉(cāng)庫(kù)是可以通過(guò)修改配置來(lái)指定的茉唉,甚至我們可以創(chuàng)建我們自己的私有倉(cāng)庫(kù)固蛾。
Docker的安裝和使用
Docker
的安裝和使用有一些前提條件,主要體現(xiàn)在體系架構(gòu)和內(nèi)核的支持上度陆。對(duì)于體系架構(gòu)艾凯,除了 Docker
一開(kāi)始就支持的 X86-64
,其他體系架構(gòu)的支持則一直在不斷地完善和推進(jìn)中懂傀。
Docker
分為 CE
和 EE
兩大版本趾诗。 CE
即社區(qū)版(免費(fèi),支持周期 7
個(gè)月)蹬蚁, EE
即企業(yè)版沧竟,強(qiáng)調(diào)安全,付費(fèi)使用缚忧,支持周期 24
個(gè)月悟泵。
我們?cè)诎惭b前可以參看官方文檔獲取最新的 Docker
支持情況,官方文檔在這里:
https://docs.docker.com/install/
Docker
對(duì)于內(nèi)核支持的功能闪水,即內(nèi)核的配置選項(xiàng)也有一定的要求(比如必須開(kāi)啟 Cgroup
和 Namespace
相關(guān)選項(xiàng)糕非,以及其他的網(wǎng)絡(luò)和存儲(chǔ)驅(qū)動(dòng)等), Docker
源碼中提供了一個(gè)檢測(cè)腳本來(lái)檢測(cè)和指導(dǎo)內(nèi)核的配置球榆,腳本鏈接在這里:
https://raw.githubusercontent.com/docker/docker/master/contrib/check-config.sh
在滿足前提條件后朽肥,安裝就變得非常的簡(jiǎn)單了。
Docker CE
的安裝請(qǐng)參考官方文檔:
-
MacOS
:https://docs.docker.com/docker-for-mac/install/ -
Windows
:https://docs.docker.com/docker-for-windows/install/ -
Ubuntu
:https://docs.docker.com/install/linux/docker-ce/ubuntu/ -
Debian
:https://docs.docker.com/install/linux/docker-ce/debian/ -
CentOS
:https://docs.docker.com/install/linux/docker-ce/centos/ -
Fedora
:https://docs.docker.com/install/linux/docker-ce/fedora/ - 其他
Linux
發(fā)行版:https://docs.docker.com/install/linux/docker-ce/binaries/
這里我們以 CentOS7
作為本文的演示持钉。
環(huán)境準(zhǔn)備
- 阿里云服務(wù)器(1核2G衡招,1M帶寬)
- CentOS 7.4 64位
由于 Docker-CE
支持 64
位版本的 CentOS7
,并且要求內(nèi)核版本不低于 3.10
首先我們需要卸載掉舊版本的 Docker
$ sudo yum remove docker \ docker-client \ docker-client-latest \ docker-common \ docker-latest \ docker-latest-logrotate \ docker-logrotate \ docker-selinux \ docker-engine-selinux \ docker-engine
我們執(zhí)行以下安裝命令去安裝依賴包:
$ sudo yum install -y yum-utils \ device-mapper-persistent-data \ lvm2
這里我事先已經(jīng)安裝過(guò)了每强,所以提示我已經(jīng)安裝了最新版本
安裝Docker
Docker
軟件包已經(jīng)包括在默認(rèn)的 CentOS-Extras
軟件源里始腾。因此想要安裝 docker
,只需要運(yùn)行下面的 yum
命令
$ sudo yum install docker
當(dāng)然在測(cè)試或開(kāi)發(fā)環(huán)境中 Docker
官方為了簡(jiǎn)化安裝流程空执,提供了一套便捷的安裝腳本浪箭,CentOS
系統(tǒng)上可以使用這套腳本安裝:
curl -fsSL get.docker.com -o get-docker.shsh get-docker.sh
具體可以參看 docker-install
的腳本:
https://github.com/docker/docker-install
執(zhí)行這個(gè)命令后,腳本就會(huì)自動(dòng)的將一切準(zhǔn)備工作做好辨绊,并且把 Docker CE
的 Edge
版本安裝在系統(tǒng)中奶栖。
安裝完成后,運(yùn)行下面的命令,驗(yàn)證是否安裝成功:
docker versionordocker info
返回docker的版本相關(guān)信息宣鄙,證明 docker
安裝成功
啟動(dòng)Docker-CE
$ sudo systemctl enable docker$ sudo systemctl start docker
Docker的簡(jiǎn)單運(yùn)用---Hello World
由于服務(wù)器日常崩潰了袍镀, docker
出了點(diǎn)問(wèn)題,所以以下案例的演示是基于 Kali Linux
環(huán)境下進(jìn)行的冻晤。
我們通過(guò)最簡(jiǎn)單的 image
文件 hello world
流椒,感受一下 Docker
的魅力吧!
我們直接運(yùn)行下面的命令明也,將名為 hello-world
的 image
文件從倉(cāng)庫(kù)抓取到本地宣虾。
docker pull library/hello-world
docker pull images
是抓取 image
文件, library/hello-world
是 image
文件在倉(cāng)庫(kù)里面的位置温数,其中 library
是 image
文件所在的組绣硝, hello-world
是 image
文件的名字。
抓取成功以后撑刺,就可以在本機(jī)看到這個(gè) image
文件了鹉胖。
docker images
我們可以看到如下結(jié)果:
現(xiàn)在,我們可以運(yùn)行 hello-world
這個(gè) image
文件
docker run hello-world
我們可以看到如下結(jié)果:
輸出這段提示以后够傍,hello world
就會(huì)停止運(yùn)行甫菠,容器自動(dòng)終止。有些容器不會(huì)自動(dòng)終止冕屯,因?yàn)樘峁┑氖欠?wù)寂诱,比如Mysql鏡像等。
是不是很 easy
呢安聘?我們從上面可以看出痰洒, docker
的功能是十分強(qiáng)大的,除此之外浴韭,我們還可以拉去一些 Ubuntu
丘喻, Apache
等鏡像,在未來(lái)的教程中我們將會(huì)一一提到念颈。
Docker
提供了一套簡(jiǎn)單實(shí)用的命令來(lái)創(chuàng)建和更新鏡像泉粉,我們可以通過(guò)網(wǎng)絡(luò)直接下載一個(gè)已經(jīng)創(chuàng)建好了的應(yīng)用鏡像,并通過(guò) Docker RUN
命令就可以直接使用榴芳。當(dāng)鏡像通過(guò) RUN
命令運(yùn)行成功后嗡靡,這個(gè)運(yùn)行的鏡像就是一個(gè) Docker
容器啦,容器可以理解為一個(gè)輕量級(jí)的沙箱翠语, Docker
利用容器來(lái)運(yùn)行和隔離應(yīng)用叽躯,容器是可以被啟動(dòng)、停止肌括、刪除的,這并不會(huì)影響 Docker
鏡像。
我們可以看看下面這幅圖:
Docker
客戶端是 Docker
用戶與 Docker
交互的主要方式谍夭。當(dāng)您使用 docker
命令行運(yùn)行命令時(shí)黑滴, Docker
客戶端將這些命令發(fā)送給服務(wù)器端,服務(wù)端將執(zhí)行這些命令紧索。 docker
命令使用 docker API
袁辈。 Docker
客戶端可以與多個(gè)服務(wù)端進(jìn)行通信。
我們將剖析一下 Docker
容器是如何工作的珠漂,學(xué)習(xí)好Docker容器工作的原理晚缩,我們就可以自己去管理我們的容器了。
Docker架構(gòu)
在上面的學(xué)習(xí)中媳危,我們簡(jiǎn)單地講解了Docker的基本架構(gòu)荞彼。了解到了Docker
使用的是 C/S
結(jié)構(gòu),即客戶端/服務(wù)器體系結(jié)構(gòu)待笑。明白了 Docker
客戶端與 Docker
服務(wù)器進(jìn)行交互時(shí)鸣皂, Docker
服務(wù)端負(fù)責(zé)構(gòu)建、運(yùn)行和分發(fā) Docker
鏡像暮蹂。 也知道了Docker
客戶端和服務(wù)端可以運(yùn)行在一臺(tái)機(jī)器上寞缝,可以通過(guò) RESTful
、 stock
或網(wǎng)絡(luò)接口與遠(yuǎn)程 Docker
服務(wù)端進(jìn)行通信仰泻。
我們從下圖可以很直觀的了解到Docker的架構(gòu):
Docker
的核心組件包括:
- Docker Client
- Docker daemon
- Docker Image
- Docker Registry
- Docker Container
Docker
采用的是 Client/Server
架構(gòu)荆陆。客戶端向服務(wù)器發(fā)送請(qǐng)求集侯,服務(wù)器負(fù)責(zé)構(gòu)建慎宾、運(yùn)行和分發(fā)容器∏诚ぃ客戶端和服務(wù)器可以運(yùn)行在同一個(gè) Host
上趟据,客戶端也可以通過(guò) socket
或 REST API
與遠(yuǎn)程的服務(wù)器通信∈踅。可能很多朋友暫時(shí)不太理解一些東西汹碱,比如 REST API
是什么東西等,不過(guò)沒(méi)關(guān)系荞估,在后面的文章中會(huì)一一給大家講解清楚咳促。
Docker Client
Docker Client
,也稱 Docker
客戶端勘伺。它其實(shí)就是 Docker
提供命令行界面 (CLI)
工具跪腹,是許多 Docker
用戶與 Docker
進(jìn)行交互的主要方式》勺恚客戶端可以構(gòu)建冲茸,運(yùn)行和停止應(yīng)用程序,還可以遠(yuǎn)程與Docker_Host
進(jìn)行交互。最常用的 Docker
客戶端就是 docker
命令轴术,我們可以通過(guò) docker
命令很方便地在 host
上構(gòu)建和運(yùn)行 docker
容器难衰。
Docker daemon
Docker daemon
是服務(wù)器組件,以 Linux
后臺(tái)服務(wù)的方式運(yùn)行逗栽,是 Docker
最核心的后臺(tái)進(jìn)程盖袭,我們也把它稱為守護(hù)進(jìn)程。它負(fù)責(zé)響應(yīng)來(lái)自 Docker Client
的請(qǐng)求彼宠,然后將這些請(qǐng)求翻譯成系統(tǒng)調(diào)用完成容器管理操作鳄虱。該進(jìn)程會(huì)在后臺(tái)啟動(dòng)一個(gè) API Server
,負(fù)責(zé)接收由 Docker Client
發(fā)送的請(qǐng)求凭峡,接收到的請(qǐng)求將通過(guò)Docker daemon
內(nèi)部的一個(gè)路由分發(fā)調(diào)度拙已,由具體的函數(shù)來(lái)執(zhí)行請(qǐng)求。
我們大致可以將其分為以下三部分:
- Docker Server
- Engine
- Job
Docker Daemon的架構(gòu)如下所示:
Docker Daemon
可以認(rèn)為是通過(guò) Docker Server
模塊接受 Docker Client
的請(qǐng)求想罕,并在 Engine
中處理請(qǐng)求悠栓,然后根據(jù)請(qǐng)求類型,創(chuàng)建出指定的 Job
并運(yùn)行按价。 Docker Daemon
運(yùn)行在 Docker host
上惭适,負(fù)責(zé)創(chuàng)建、運(yùn)行楼镐、監(jiān)控容器癞志,構(gòu)建、存儲(chǔ)鏡像框产。
運(yùn)行過(guò)程的作用有以下幾種可能:
- 向
Docker Registry
獲取鏡像 - 通過(guò)
graphdriver
執(zhí)行容器鏡像的本地化操作 - 通過(guò)
networkdriver
執(zhí)行容器網(wǎng)絡(luò)環(huán)境的配置 - 通過(guò)
execdriver
執(zhí)行容器內(nèi)部運(yùn)行的執(zhí)行工作
由于 Docker Daemon
和 Docker Client
的啟動(dòng)都是通過(guò)可執(zhí)行文件 docker
來(lái)完成的凄杯,因此兩者的啟動(dòng)流程非常相似。 Docker
可執(zhí)行文件運(yùn)行時(shí)秉宿,運(yùn)行代碼通過(guò)不同的命令行 flag
參數(shù)戒突,區(qū)分兩者,并最終運(yùn)行兩者各自相應(yīng)的部分描睦。
啟動(dòng) Docker Daemon
時(shí)膊存,一般可以使用以下命令來(lái)完成
docker --daemon = truedocker –ddocker –d = true
再由 docker
的 main()
函數(shù)來(lái)解析以上命令的相應(yīng) flag
參數(shù),并最終完成 Docker Daemon
的啟動(dòng)忱叭。
下圖可以很直觀地看到 Docker Daemon
的啟動(dòng)流程:
默認(rèn)配置下隔崎, Docker daemon
只能響應(yīng)來(lái)自本地 Host
的客戶端請(qǐng)求。如果要允許遠(yuǎn)程客戶端請(qǐng)求韵丑,需要在配置文件中打開(kāi) TCP
監(jiān)聽(tīng)爵卒。我們可以照著如下步驟進(jìn)行配置:
1、編輯配置文件 /etc/systemd/system/multi-user.target.wants/docker.service
撵彻,在環(huán)境變量 ExecStart
后面添加 -H tcp://0.0.0.0
钓株,允許來(lái)自任意 IP 的客戶端連接实牡。
2、重啟 Docker daemon
systemctl daemon-reloadsystemctl restart docker.service
3享幽、我們通過(guò)以下命令即可實(shí)現(xiàn)與遠(yuǎn)程服務(wù)器通信
docker -H 服務(wù)器IP地址 info
-H
是用來(lái)指定服務(wù)器主機(jī)铲掐, info
子命令用于查看 Docker
服務(wù)器的信息
Docker Image
Docker
鏡像可以看作是一個(gè)特殊的文件系統(tǒng)拾弃,除了提供容器運(yùn)行時(shí)所需的程序值桩、庫(kù)、資源豪椿、配置等文件外奔坟,還包含了一些為運(yùn)行時(shí)準(zhǔn)備的一些配置參數(shù)(如匿名卷、環(huán)境變量搭盾、用戶等)咳秉。鏡像不包含任何動(dòng)態(tài)數(shù)據(jù),其內(nèi)容在構(gòu)建之后也不會(huì)被改變鸯隅。我們可將 Docker
鏡像看成只讀模板澜建,通過(guò)它可以創(chuàng)建 Docker
容器。
鏡像有多種生成方法:
- 從無(wú)到有開(kāi)始創(chuàng)建鏡像
- 下載并使用別人創(chuàng)建好的現(xiàn)成的鏡像
- 在現(xiàn)有鏡像上創(chuàng)建新的鏡像
我們可以將鏡像的內(nèi)容和創(chuàng)建步驟描述在一個(gè)文本文件中蝌以,這個(gè)文件被稱作 Dockerfile
炕舵,通過(guò)執(zhí)行 docker build <docker-file>
命令可以構(gòu)建出 Docker 鏡像,在后續(xù)的教程中跟畅,我們會(huì)用一篇專門(mén)討論這個(gè)問(wèn)題咽筋。
Docker Registry
Docker registry
是存儲(chǔ) docker image
的倉(cāng)庫(kù),它在 docker
生態(tài)環(huán)境中的位置如下圖所示:
運(yùn)行docker push
徊件、docker pull
奸攻、docker search
時(shí),實(shí)際上是通過(guò) docker daemon
與 docker registry
通信虱痕。
Docker Container
Docker
容器就是 Docker
鏡像的運(yùn)行實(shí)例睹耐,是真正運(yùn)行項(xiàng)目程序、消耗系統(tǒng)資源部翘、提供服務(wù)的地方硝训。 Docker Container
提供了系統(tǒng)硬件環(huán)境,我們可以使用 Docker Images
這些制作好的系統(tǒng)盤(pán)略就,再加上我們所編寫(xiě)好的項(xiàng)目代碼捎迫, run
一下就可以提供服務(wù)啦。
Docker組件是如何協(xié)作運(yùn)行容器
看到這里表牢,我相信各位讀者朋友們應(yīng)該已經(jīng)對(duì)Docker基礎(chǔ)架構(gòu)已經(jīng)熟悉的差不多了窄绒,我們還記得運(yùn)行的第一個(gè)容器嗎?現(xiàn)在我們?cè)偻ㄟ^(guò)hello-world這個(gè)例子來(lái)體會(huì)一下 Docker
各個(gè)組件是如何協(xié)作的崔兴。
容器啟動(dòng)過(guò)程如下:
-
Docker
客戶端執(zhí)行docker run
命令 -
Docker daemon
發(fā)現(xiàn)本地沒(méi)有hello-world
鏡像 -
daemon
從Docker Hub
下載鏡像 - 下載完成彰导,鏡像
hello-world
被保存到本地 -
Docker daemon
啟動(dòng)容器
具體過(guò)程可以看如下這幅演示圖:
我們可以通過(guò)docker images
可以查看到 hello-world
已經(jīng)下載到本地
我們可以通過(guò)docker ps
或者 docker container ls
顯示正在運(yùn)行的容器蛔翅,我們可以看到, hello-world
在輸出提示信息以后就會(huì)停止運(yùn)行位谋,容器自動(dòng)終止山析,所以我們?cè)诓榭吹臅r(shí)候沒(méi)有發(fā)現(xiàn)有容器在運(yùn)行。
我們把 Docker
容器的工作流程剖析的十分清楚了掏父,我們大體可以知道 Docker
組件協(xié)作運(yùn)行容器可以分為以下幾個(gè)過(guò)程:
-
Docker
客戶端執(zhí)行docker run
命令 -
Docker daemon
發(fā)現(xiàn)本地沒(méi)有我們需要的鏡像 -
daemon
從Docker Hub
下載鏡像 - 下載完成后笋轨,鏡像被保存到本地
-
Docker daemon
啟動(dòng)容器
了解了這些過(guò)程以后,我們?cè)賮?lái)理解這些命令就不會(huì)覺(jué)得很突兀了赊淑,下面我來(lái)給大家講講 Docker
常用的一些命令操作吧爵政。
Docker常用命令
我們可以通過(guò) docker -h
去查看命令的詳細(xì)的幫助文檔。在這里我只會(huì)講一些平常日常比賽或者生活中我們可能會(huì)用的比較多的一些命令陶缺。
例如钾挟,我們需要拉取一個(gè) docker
鏡像,我們可以用如下命令:
docker pull image_name
image_name
為鏡像的名稱饱岸,而如果我們想從 Docker Hub
上去下載某個(gè)鏡像掺出,我們可以使用以下命令:
docker pull centos:latest
centos:lastest
是鏡像的名稱, Docker daemon
發(fā)現(xiàn)本地沒(méi)有我們需要的鏡像苫费,會(huì)自動(dòng)去 Docker Hub
上去下載鏡像汤锨,下載完成后,該鏡像被默認(rèn)保存到 /var/lib/docker
目錄下黍衙。
接著我們?nèi)绻氩榭聪轮鳈C(jī)下存在多少鏡像泥畅,我們可以用如下命令:
docker images
我們要想知道當(dāng)前有哪些容器在運(yùn)行,我們可以用如下命令:
docker ps -a
-a
是查看當(dāng)前所有的容器琅翻,包括未運(yùn)行的
我們?cè)撊绾稳?duì)一個(gè)容器進(jìn)行啟動(dòng)位仁,重啟和停止呢?我們可以用如下命令:
docker start container_name/container_iddocker restart container_name/container_iddocker stop container_name/container_id
這個(gè)時(shí)候我們?nèi)绻脒M(jìn)入到這個(gè)容器中方椎,我們可以使用 attach
命令:
docker attach container_name/container_id
那如果我們想運(yùn)行這個(gè)容器中的鏡像的話聂抢,并且調(diào)用鏡像里面的 bash
,我們可以使用如下命令:
docker run -t -i container_name/container_id /bin/bash
那如果這個(gè)時(shí)候棠众,我們想刪除指定鏡像的話琳疏,由于 image
被某個(gè) container
引用(拿來(lái)運(yùn)行),如果不將這個(gè)引用的 container
銷毀(刪除)闸拿,那 image
肯定是不能被刪除空盼。我們首先得先去停止這個(gè)容器:
docker psdocker stop container_name/container_id
然后我們用如下命令去刪除這個(gè)容器:
docker rm container_name/container_id
然后這個(gè)時(shí)候我們?cè)偃h除這個(gè)鏡像:
docker rmi image_name
此時(shí),常用的 Docker
相關(guān)的命令就講到這里為止了新荤,我們?cè)诤罄m(xù)的文章中還會(huì)反復(fù)地提到這些命令揽趾。
Dockerfile是什么
前面我們已經(jīng)提到了 Docker
的一些基本概念。以 CTF
選手的角度來(lái)看苛骨,我們可以去使用 Dockerfile
定義鏡像篱瞎,依賴鏡像來(lái)運(yùn)行容器苟呐,可以去模擬出一個(gè)真實(shí)的漏洞場(chǎng)景。因此毫無(wú)疑問(wèn)的說(shuō)俐筋, Dockerfile
是鏡像和容器的關(guān)鍵牵素,并且 Dockerfile
還可以很輕易的去定義鏡像內(nèi)容,說(shuō)了這么多澄者,那么 Dockerfile
到底是個(gè)什么東西呢笆呆?
Dockerfile
是自動(dòng)構(gòu)建 docker
鏡像的配置文件, 用戶可以使用 Dockerfile
快速創(chuàng)建自定義的鏡像闷哆。Dockerfile
中的命令非常類似于 linux
下的 shell
命令腰奋。
我們可以通過(guò)下面這幅圖來(lái)直觀地感受下 Docker 鏡像单起、容器和 Dockerfile 三者之間的關(guān)系抱怔。
我們從上圖中可以看到, Dockerfile
可以自定義鏡像嘀倒,通過(guò) Docker
命令去運(yùn)行鏡像屈留,從而達(dá)到啟動(dòng)容器的目的。
Dockerfile
是由一行行命令語(yǔ)句組成测蘑,并且支持已 #
開(kāi)頭的注釋行灌危。
一般來(lái)說(shuō),我們可以將 Dockerfile
分為四個(gè)部分:
- 基礎(chǔ)鏡像(父鏡像)信息指令
FROM
- 維護(hù)者信息指令
MAINTAINER
- 鏡像操作指令
RUN
碳胳、EVN
勇蝙、ADD
和WORKDIR
等 - 容器啟動(dòng)指令
CMD
、ENTRYPOINT
和USER
等
下面是一段簡(jiǎn)單的Dockerfile的例子:
FROM python:2.7MAINTAINER Angel_Kitty <angelkitty6698@gmail.com>COPY . /appWORKDIR /appRUN pip install -r requirements.txtEXPOSE 5000ENTRYPOINT ["python"]CMD ["app.py"]
我們可以分析一下上面這個(gè)過(guò)程:
- 1挨约、從
Docker Hub
上pull
下python 2.7
的基礎(chǔ)鏡像 - 2味混、顯示維護(hù)者的信息
- 3、
copy
當(dāng)前目錄到容器中的/app
目錄下 復(fù)制本地主機(jī)的<src>
(Dockerfile
所在目錄的相對(duì)路徑)到容器里<dest>
- 4诫惭、指定工作路徑為
/app
- 5翁锡、安裝依賴包
- 6、暴露
5000
端口 - 7夕土、啟動(dòng)
app
這個(gè)例子是啟動(dòng)一個(gè) python flask app
的 Dockerfile
( flask
是 python
的一個(gè)輕量的 web
框架)馆衔,相信大家從這個(gè)例子中能夠稍微理解了Dockfile的組成以及指令的編寫(xiě)過(guò)程。
Dockerfile常用的指令
根據(jù)上面的例子怨绣,我們已經(jīng)差不多知道了Dockerfile的組成以及指令的編寫(xiě)過(guò)程角溃,我們?cè)賮?lái)理解一下這些常用命令就會(huì)得心應(yīng)手了。
由于 Dockerfile
中所有的命令都是以下格式:INSTRUCTION argument
篮撑,指令 (INSTRUCTION)
不分大小寫(xiě)减细,但是推薦大寫(xiě),和sql語(yǔ)句是不是很相似呢咽扇?下面我們正式來(lái)講解一下這些指令集吧邪财。
FROM
FROM
是用于指定基礎(chǔ)的 images
陕壹,一般格式為 FROM <image>
or FORM <image>:<tag>
,所有的 Dockerfile
都用該以 FROM
開(kāi)頭树埠,FROM
命令指明 Dockerfile
所創(chuàng)建的鏡像文件以什么鏡像為基礎(chǔ)糠馆,FROM
以后的所有指令都會(huì)在 FROM
的基礎(chǔ)上進(jìn)行創(chuàng)建鏡像≡醣铮可以在同一個(gè) Dockerfile
中多次使用 FROM
命令用于創(chuàng)建多個(gè)鏡像又碌。比如我們要指定 python 2.7
的基礎(chǔ)鏡像,我們可以像如下寫(xiě)法一樣:
FROM python:2.7
MAINTAINER
MAINTAINER 是用于指定鏡像創(chuàng)建者和聯(lián)系方式绊袋,一般格式為 MAINTAINER <name>
毕匀。這里我設(shè)置成我的 ID
和郵箱:
MAINTAINER Angel_Kitty <angelkitty6698@gmail.com>
COPY
COPY
是用于復(fù)制本地主機(jī)的 <src>
(為 Dockerfile 所在目錄的相對(duì)路徑)到容器中的 <dest>
。
當(dāng)使用本地目錄為源目錄時(shí)癌别,推薦使用 COPY
皂岔。一般格式為 COPY <src><dest>
。例如我們要拷貝當(dāng)前目錄到容器中的 /app
目錄下展姐,我們可以這樣操作:
COPY . /app
WORKDIR
WORKDIR
用于配合 RUN
躁垛,CMD
,ENTRYPOINT
命令設(shè)置當(dāng)前工作路徑圾笨〗坦荩可以設(shè)置多次,如果是相對(duì)路徑擂达,則相對(duì)前一個(gè) WORKDIR
命令土铺。默認(rèn)路徑為/
。一般格式為 WORKDIR /path/to/work/dir
板鬓。例如我們?cè)O(shè)置/app
路徑悲敷,我們可以進(jìn)行如下操作:
WORKDIR /app
RUN
RUN
用于容器內(nèi)部執(zhí)行命令。每個(gè) RUN
命令相當(dāng)于在原有的鏡像基礎(chǔ)上添加了一個(gè)改動(dòng)層穗熬,原有的鏡像不會(huì)有變化镀迂。一般格式為 RUN <command>
。例如我們要安裝 python
依賴包唤蔗,我們做法如下:
RUN pip install -r requirements.txt
EXPOSE
EXPOSE
命令用來(lái)指定對(duì)外開(kāi)放的端口探遵。一般格式為 EXPOSE <port> [<port>...]
例如上面那個(gè)例子,開(kāi)放5000端口:
EXPOSE 5000
ENTRYPOINT
ENTRYPOINT
可以讓你的容器表現(xiàn)得像一個(gè)可執(zhí)行程序一樣妓柜。一個(gè) Dockerfile
中只能有一個(gè) ENTRYPOINT
箱季,如果有多個(gè),則最后一個(gè)生效棍掐。
ENTRYPOINT
命令也有兩種格式:
-
ENTRYPOINT ["executable", "param1", "param2"]
:推薦使用的exec
形式 -
ENTRYPOINT command param1 param2
:shell
形式
例如下面這個(gè)藏雏,我們要將 python
鏡像變成可執(zhí)行的程序,我們可以這樣去做:
ENTRYPOINT ["python"]
CMD
CMD
命令用于啟動(dòng)容器時(shí)默認(rèn)執(zhí)行的命令作煌,CMD
命令可以包含可執(zhí)行文件掘殴,也可以不包含可執(zhí)行文件赚瘦。不包含可執(zhí)行文件的情況下就要用 ENTRYPOINT
指定一個(gè),然后 CMD
命令的參數(shù)就會(huì)作為ENTRYPOINT
的參數(shù)奏寨。
CMD
命令有三種格式:
-
CMD ["executable","param1","param2"]
:推薦使用的exec
形式起意。 -
CMD ["param1","param2"]
:無(wú)可執(zhí)行程序形式 -
CMD command param1 param2
:shell 形式。
一個(gè) Dockerfile
中只能有一個(gè)CMD
病瞳,如果有多個(gè)揽咕,則最后一個(gè)生效。而 CMD
的 shell
形式默認(rèn)調(diào)用 /bin/sh -c
執(zhí)行命令套菜。
CMD
命令會(huì)被 Docker
命令行傳入的參數(shù)覆蓋:docker run busybox /bin/echo Hello
Docker
會(huì)把 CMD
里的命令覆蓋亲善。
例如我們要啟動(dòng) /app
,我們可以用如下命令實(shí)現(xiàn):
CMD ["app.py"]
當(dāng)然還有一些其他的命令逗柴,我們?cè)谟玫降臅r(shí)候再去一一講解一下蛹头。
構(gòu)建Dockerfile
我們大體已經(jīng)把Dockerfile的寫(xiě)法講述完畢,我們可以自己動(dòng)手寫(xiě)一個(gè)例子:
mkdir static_webcd static_webtouch Dockerfile然后 vi Dockerfile 開(kāi)始編輯該文件輸入 i 開(kāi)始編輯 以下是我們構(gòu)建的Dockerfile內(nèi)容``````````FROM nginxMAINTAINER Angel_Kitty <angelkitty6698@gmail.com>RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html`````````` 編輯完后 按 esc 退出編輯然后 :wq 寫(xiě)入 退出
我們?cè)?Dockerfile
文件所在目錄執(zhí)行:
docker build -t angelkitty/nginx_web:v1 .
我們解釋一下嚎于, -t
是為新鏡像設(shè)置倉(cāng)庫(kù)和名稱掘而,其中 angelkitty
為倉(cāng)庫(kù)名, nginx_web
為鏡像名于购, :v1
為標(biāo)簽(不添加為默認(rèn) latest
)
我們構(gòu)建完成之后,使用 docker images
命令查看所有鏡像知染,如果存在 REPOSITORY
為 nginx
和 TAG
是 v1
的信息肋僧,就表示構(gòu)建成功。
接下來(lái)使用 docker run
命令來(lái)啟動(dòng)容器
docker run --name nginx_web -d -p 8080:80 angelkitty/nginx_web:v1
這條命令會(huì)用 nginx 鏡像啟動(dòng)一個(gè)容器控淡,命名為 nginx_web
嫌吠,并且映射了 8080 端口,這樣我們可以用瀏覽器去訪問(wèn)這個(gè) nginx
服務(wù)器:http://localhost:8080/
或者 http://本機(jī)的IP地址:8080/掺炭,頁(yè)面返回信息:
這樣一個(gè)簡(jiǎn)單使用 Dockerfile
構(gòu)建鏡像辫诅,運(yùn)行容器的示例就完成了!