面試官留步!聽我跟你侃會(huì)兒Docker原理
本文轉(zhuǎn)載自微信公眾號(hào)「sowhat1412」,作者sowhat1412。轉(zhuǎn)載本文請(qǐng)聯(lián)系sowhat1412公眾號(hào)。
開發(fā)人員開發(fā)完一個(gè)電商項(xiàng)目,該 Jar 項(xiàng)目包含 Redis、MySQL、ES、Haddop等若干組件。開發(fā)人員自測(cè)無(wú)誤后提交給測(cè)試進(jìn)行預(yù)生產(chǎn)測(cè)試了。
測(cè)試:你的這個(gè)服務(wù),我在進(jìn)行單元測(cè)試跟數(shù)據(jù)核對(duì)的時(shí)候總是出現(xiàn)不知名的bug!你要不要來看下啊?
開發(fā):你咋測(cè)試的?是按照操作文檔一步步來的么?
測(cè)試:絕對(duì)是按照文檔來的啊!
開發(fā):你重啟了嗎?清緩存了嗎?代碼是最新版嗎?你用的是Chrome瀏覽器? 你是不是動(dòng)啥東西了?
測(cè)試:這.. 這.. 這.. 我啥也沒干啊!
至此,開發(fā)跟測(cè)試之間的愛恨情仇正式開始!
1 Docker 簡(jiǎn)介
1.1 Docker 由來
Docker 是基于 Go 語(yǔ)言開發(fā)的一個(gè)容器引擎,Docker是應(yīng)用程序與系統(tǒng)之間的隔離層。通常應(yīng)用程序?qū)Π惭b的系統(tǒng)環(huán)境會(huì)有各種嚴(yán)格要求,當(dāng)服務(wù)器很多時(shí)部署時(shí)系統(tǒng)環(huán)境的配置工作是非常繁瑣的。Docker讓應(yīng)用程序不必再關(guān)心主機(jī)環(huán)境,各個(gè)應(yīng)用安裝在Docker鏡像里,Docker引擎負(fù)責(zé)運(yùn)行包裹了應(yīng)用程序的docker鏡像。
Docker的理念是讓開發(fā)人員可以簡(jiǎn)單地把應(yīng)用程序及依賴裝載到容器中,然后輕松地部署到任何地方,Docker具有如下特性。
Docker容器是輕量級(jí)的虛擬技術(shù),占用更少系統(tǒng)資源。
使用 Docker容器,不同團(tuán)隊(duì)(如開發(fā)、測(cè)試,運(yùn)維)之間更容易合作。
可以在任何地方部署 Docker 容器,比如在任何物理和虛擬機(jī)上,甚至在云上。
由于Docker容器非常輕量級(jí),因此可擴(kuò)展性很強(qiáng)。
1.2 Docker 基本組成
鏡像(image):
Docker 鏡像就好比是一個(gè)目標(biāo),可以通過這個(gè)目標(biāo)來創(chuàng)建容器服務(wù),可以簡(jiǎn)單的理解為編程語(yǔ)言中的類。
容器(container):
Docker 利用容器技術(shù),獨(dú)立運(yùn)行一個(gè)或者一組應(yīng)用,容器是通過鏡像來創(chuàng)建的,在容器中可執(zhí)行啟動(dòng)、停止、刪除等基本命令,最終服務(wù)運(yùn)行或者項(xiàng)目運(yùn)行就是在容器中的,可理解為是類的實(shí)例。
倉(cāng)庫(kù)(repository):
倉(cāng)庫(kù)就是存放鏡像的地方!倉(cāng)庫(kù)分為公有倉(cāng)庫(kù)和私有倉(cāng)庫(kù),類似Git。一般我們用的時(shí)候都是用國(guó)內(nèi)docker鏡像來加速。
1.3 VM 跟 Docker
虛擬機(jī):
傳統(tǒng)的虛擬機(jī)需要模擬整臺(tái)機(jī)器包括硬件,每臺(tái)虛擬機(jī)都需要有自己的操作系統(tǒng),虛擬機(jī)一旦被開啟,預(yù)分配給他的資源將全部被占用。每一個(gè)虛擬機(jī)包括應(yīng)用,必要的二進(jìn)制和庫(kù),以及一個(gè)完整的用戶操作系統(tǒng)。
Docker:
容器技術(shù)是和我們的宿主機(jī)共享硬件資源及操作系統(tǒng)可以實(shí)現(xiàn)資源的動(dòng)態(tài)分配。容器包含應(yīng)用和其所有的依賴包,但是與其他容器共享內(nèi)核。容器在宿主機(jī)操作系統(tǒng)中,在用戶空間以分離的進(jìn)程運(yùn)行。
比對(duì)項(xiàng) | Container(容器) | VM(虛擬機(jī)) |
---|---|---|
啟動(dòng)速度 | 秒級(jí) | 分鐘級(jí) |
運(yùn)行性能 | 接近原生 | 有所損失 |
磁盤占用 | MB | GB |
數(shù)量 | 成百上千 | 一般幾十臺(tái) |
隔離性 | 進(jìn)程級(jí)別 | 系統(tǒng)級(jí)別 |
操作系統(tǒng) | 只支持Linux | 幾乎所有 |
封裝程度 | 只打包項(xiàng)目代碼和依賴關(guān)系 共享宿主機(jī)內(nèi)核 |
完整的操作系統(tǒng) |
1.4 Docker 跟 DevOps
DevOps 是一組過程、方法與系統(tǒng)的統(tǒng)稱,用于促進(jìn)開發(fā)(應(yīng)用程序/軟件工程)、技術(shù)運(yùn)營(yíng)和質(zhì)量保障(QA)部門之間的溝通、協(xié)作與整合。
DevOps 是兩個(gè)傳統(tǒng)角色 Dev(Development) 和 Ops(Operations) 的結(jié)合,Dev 負(fù)責(zé)開發(fā),Ops 負(fù)責(zé)部署上線,但 Ops 對(duì) Dev 開發(fā)的應(yīng)用缺少足夠的了解,而 Dev 來負(fù)責(zé)上線,很多服務(wù)軟件不知如何部署運(yùn)行,二者中間有一道明顯的鴻溝,DevOps 就是為了彌補(bǔ)這道鴻溝。DevOps 要做的事,是偏 Ops 的;但是做這個(gè)事的人,是偏 Dev 的, 說白了就是要有一個(gè)了解 Dev 的人能把 Ops 的事干了。而Docker 是適合 DevOps 的。
1.5 Docker 跟 k8s
k8s 的全稱是 kubernetes,它是基于容器的集群管理平臺(tái),是管理應(yīng)用的全生命周期的一個(gè)工具,從創(chuàng)建應(yīng)用、應(yīng)用的部署、應(yīng)用提供服務(wù)、擴(kuò)容縮容應(yīng)用、應(yīng)用更新、都非常的方便,而且可以做到故障自愈,例如一個(gè)服務(wù)器掛了,可以自動(dòng)將這個(gè)服務(wù)器上的服務(wù)調(diào)度到另外一個(gè)主機(jī)上進(jìn)行運(yùn)行,無(wú)需進(jìn)行人工干涉。k8s 依托于Google自家的強(qiáng)大實(shí)踐應(yīng)用,目前市場(chǎng)占有率已經(jīng)超過Docker自帶的Swarm了。
如果你有很多 Docker 容器要啟動(dòng)、維護(hù)、監(jiān)控,那就上k8s吧!
1.6 hello world
docker run hello-world 的大致流程圖如下:
2 Docker 常見指令
官方文檔:
https://docs.docker.com/engine/reference/commandline/build/
3 Docker 運(yùn)行原理
Docker 只提供一個(gè)運(yùn)行環(huán)境,他跟 VM 不一樣,是不需要運(yùn)行一個(gè)獨(dú)立的 OS,容器中的系統(tǒng)內(nèi)核跟宿主機(jī)的內(nèi)核是公用的。docker容器本質(zhì)上是宿主機(jī)的進(jìn)程。對(duì) Docker 項(xiàng)目來說,它最核心的原理實(shí)際上就是為待創(chuàng)建的用戶進(jìn)程做如下操作:
- 啟用 Linux Namespace 配置。
- 設(shè)置指定的 Cgroups 參數(shù)。
- 切換進(jìn)程的根目錄(Change Root),優(yōu)先使用 pivot_root 系統(tǒng)調(diào)用,如果系統(tǒng)不支持,才會(huì)使用 chroot。
3.1 namespace 進(jìn)程隔離
Linux Namespaces 機(jī)制提供一種進(jìn)程資源隔離方案。PID、IPC、Network 等系統(tǒng)資源不再是全局性的,而是屬于某個(gè)特定的Namespace。每個(gè)namespace下的資源對(duì)于其他namespace 下的資源都是透明,不可見的。系統(tǒng)中可以同時(shí)存在兩個(gè)進(jìn)程號(hào)為0、1、2的進(jìn)程,由于屬于不同的namespace,所以它們之間并不沖突。
PS:Linux 內(nèi)核提拱了6種 namespace 隔離的系統(tǒng)調(diào)用,如下圖所示。
3.2 CGroup 分配資源
Docker 通過 Cgroup 來控制容器使用的資源配額,一旦超過這個(gè)配額就發(fā)出OOM。配額主要包括 CPU、內(nèi)存、磁盤三大方面, 基本覆蓋了常見的資源配額和使用量控制。
Cgroup 是 Control Groups 的縮寫,是Linux 內(nèi)核提供的一種可以限制、記錄、隔離進(jìn)程組所使用的物理資源(如 CPU、內(nèi)存、磁盤 IO 等等)的機(jī)制,被 LXC(Linux container)、Docker 等很多項(xiàng)目用于實(shí)現(xiàn)進(jìn)程資源控制。Cgroup 本身是提供將進(jìn)程進(jìn)行分組化管理的功能和接口的基礎(chǔ)結(jié)構(gòu),I/O 或內(nèi)存的分配控制等具體的資源管理是通過該功能來實(shí)現(xiàn)的,這些具體的資源 管理功能稱為 Cgroup 子系統(tǒng)。
3.3 chroot 跟 pivot_root 文件系統(tǒng)
chroot(change root file system)命令的功能是 改變進(jìn)程的根目錄到指定的位置。比如我們現(xiàn)在有一個(gè)$HOME/test目錄,想要把它作為一個(gè) /bin/bash 進(jìn)程的根目錄。
首先,創(chuàng)建一個(gè)目錄和幾個(gè)文件夾HOME/test/{bin,lib64,lib}
把bash命令拷貝到test目錄對(duì)應(yīng)的bin路徑下 cp -v /bin/{bash,ls} $HOME/test/bin
把bash命令需要的所有so文件,也拷貝到test目錄對(duì)應(yīng)的lib路徑下
執(zhí)行chroot命令,告訴操作系統(tǒng),我們將使用HOME/test /bin/bash
被chroot的進(jìn)程此時(shí)執(zhí)行 ls / 返回的都是$HOME/test目錄下面的內(nèi)容,Docker就是這樣實(shí)現(xiàn)容器根目錄的。為了能夠讓容器的這個(gè)根目錄看起來更真實(shí),一般在容器的根目錄下掛載一個(gè)完整操作系統(tǒng)的文件系統(tǒng),比如Ubuntu16.04的ISO。這樣在容器啟動(dòng)之后,容器里執(zhí)行l(wèi)s /查看到的就是Ubuntu 16.04的所有目錄和文件。
而掛載在容器根目錄上、用來為容器進(jìn)程提供隔離后執(zhí)行環(huán)境的文件系統(tǒng),就是所謂的容器鏡像。更專業(yè)的名字叫作:rootfs(根文件系統(tǒng))。所以一個(gè)最常見的 rootfs 會(huì)包括如下所示的一些目錄和文件:
- $ ls /
- bin dev etc home lib lib64 mnt opt proc root run sbin sys tmp usr var
chroot 只改變當(dāng)前進(jìn)程的 /,pivot_root改變當(dāng)前 mount namespace的 / 。pivot_root 可以認(rèn)為是 chroot 的改良版。
3.4 一致性
由于 rootfs 里打包的不只是應(yīng)用,而是整個(gè)操作系統(tǒng)的文件和目錄,也就意味著應(yīng)用以及它運(yùn)行所需要的所有依賴都被封裝在了一起。有了容器鏡像打包操作系統(tǒng)的能力,這個(gè)最基礎(chǔ)的依賴環(huán)境也終于變成了應(yīng)用沙盒的一部分。這就賦予了容器所謂的一致性:
無(wú)論在本地、云端,還是在一臺(tái)任何地方的機(jī)器上,用戶只需要解壓打包好的容器鏡像,那么這個(gè)應(yīng)用運(yùn)行所需要的完整的執(zhí)行環(huán)境就被重現(xiàn)出來了。
3.5 UnionFS 聯(lián)合文件系統(tǒng)
如何實(shí)現(xiàn)rootfs的高效可重復(fù)利用呢?Docker在鏡像的設(shè)計(jì)中引入了層(layer)的概念。也就是說用戶制作鏡像的每一步操作都會(huì)生成一個(gè)層,也就是一個(gè)增量rootfs。介紹分層前我們先說個(gè)重要知識(shí)點(diǎn),聯(lián)合文件系統(tǒng)。
聯(lián)合文件系統(tǒng)(UnionFS)是一種分層、輕量級(jí)并且高性能的文件系統(tǒng),它支持對(duì)文件系統(tǒng)的修改作為一次提交來一層層的疊加,同時(shí)可以將不同目錄掛載到同一個(gè)虛擬文件系統(tǒng)下。比如現(xiàn)在有水果fruits、蔬菜vegetables兩個(gè)目錄,其中水果中有蘋果和蕃茄,蔬菜有胡蘿卜和蕃茄:
- $ tree
- .
- ├── fruits
- │ ├── apple
- │ └── tomato
- └── vegetables
- ├── carrots
- └── tomato
然后使用聯(lián)合掛載的方式將這兩個(gè)目錄掛載到一個(gè)公共的目錄 mnt 上:
- $ mkdir mnt
- $ sudo mount -t aufs -o dirs=./fruits:./vegetables none ./mnt
這時(shí)再查看目錄 mnt 的內(nèi)容,就能看到目錄 fruits 和 vegetables 下的文件被合并到了一起:
- $ tree ./mnt
- ./mnt
- ├── apple
- ├── carrots
- └── tomato
可以看到在 mnt 目錄下有三個(gè)文件,蘋果apple、胡蘿卜carrots和蕃茄tomato。水果和蔬菜的目錄被union到了 mnt 目錄下了。
- $ echo mnt > ./mnt/apple
- $ cat ./mnt/apple
- mnt
- $ cat ./fruits/apple
- mnt
可以看到./mnt/apple的內(nèi)容改了,./fruits/apple的內(nèi)容也改了。
- $ echo mnt_carrots > ./mnt/carrots
- $ cat ./vegetables/carrots
- old
- $ cat ./fruits/carrots
- mnt_carrots
./vegetables/carrots 并沒有變化,反而是 ./fruits/carrots 的目錄中出現(xiàn)了 carrots 文件,其內(nèi)容是我們?cè)? ./mnt/carrots 里的內(nèi)容。
結(jié)論:
在mount aufs命令時(shí)候,沒有對(duì) vegetables 跟 fruits 設(shè)置權(quán)限,默認(rèn)命令行上第一個(gè)的目錄是可讀可寫的,后面的全都是只讀的。有重復(fù)的文件名,在mount命令行上,越往前的被操作的優(yōu)先級(jí)越高。
3.6 layer 分層
說完聯(lián)合文件系統(tǒng)后我們?cè)僬f下Docker中的分層,鏡像可以通過分層來進(jìn)行繼承,基于基礎(chǔ)鏡像(沒有父鏡像)用戶可以制作各種具體的應(yīng)用鏡像。不同 Docker 容器可以共享一些基礎(chǔ)的文件系統(tǒng)層,同時(shí)再加上自己獨(dú)有的改動(dòng)層,大大提高了存儲(chǔ)的效率。
Docker 中使用一種叫 AUFS(Anothe rUnionFS)的聯(lián)合文件系統(tǒng)。AUFS 支持為每一個(gè)成員目錄設(shè)定不同的讀寫權(quán)限。
- rw 表示可寫可讀read-write。
- ro 表示read-only,如果你不指權(quán)限,那么除了第一個(gè)外,ro是默認(rèn)值,對(duì)于ro分支,其永遠(yuǎn)不會(huì)收到寫操作,也不會(huì)收到查找whiteout的操作。
- rr 表示 real-read-only,與read-only不同的是,rr 標(biāo)記的是天生就是只讀的分支,這樣,AUFS可以提高性能,比如不再設(shè)置inotify來檢查文件變動(dòng)通知。
當(dāng)我們想修改ro層的文件時(shí)咋辦?因?yàn)閞o是不允許修改的啊!Docker中一般ro層還帶個(gè)wh的能力。我們就需要對(duì)這個(gè)ro目錄里的文件作whiteout。AUFS的whiteout的實(shí)現(xiàn)是通過在上層的可寫的目錄下建立對(duì)應(yīng)的whiteout隱藏文件來實(shí)現(xiàn)的。比如我們有三個(gè)目錄和文件如下所示:
- $ tree
- .
- ├── fruits
- │ ├── apple
- │ └── tomato
- ├── test #目錄為空
- └── vegetables
- ├── carrots
- └── tomato
執(zhí)行如下:
- $ mkdir mnt
- $ mount -t aufs -o dirs=./test=rw:./fruits=ro:./vegetables=ro none ./mnt
- $ ls ./mnt/
- apple carrots tomato
在權(quán)限為 rw 的 test 目錄下建個(gè) whiteout 的隱藏文件 .wh.apple,你就會(huì)發(fā)現(xiàn) ./mnt/apple 這個(gè)文件就消失了,跟執(zhí)行了 rm ./mnt/apple 是一樣的結(jié)果:
- $ touch ./test/.wh.apple
- $ ls ./mnt
- carrots tomato
對(duì)于AUFS來說鏡像的若干基礎(chǔ)層放置在/var/lib/docker/aufs/diff目錄下,然后通過查詢/sys/fs/aufs 查看被聯(lián)合掛載在一起的各個(gè)層的信息,多個(gè)基礎(chǔ)層最終被聯(lián)合掛載在/var/lib/docker/aufs/mnt里面,這里面存儲(chǔ)的就是一個(gè)成品。
Docker 目前支持的聯(lián)合文件系統(tǒng)包括 OverlayFS, AUFS, Btrfs, VFS, ZFS 和 Device Mapper。推薦使用 overlay2 存儲(chǔ)驅(qū)動(dòng),overlay2 是目前 Docker 默認(rèn)的存儲(chǔ)驅(qū)動(dòng),以前則是 AUFS。
3.6.1 只讀層
我們以Ubuntu為例,當(dāng)執(zhí)行docker image inspect ubuntu:latest 會(huì)發(fā)現(xiàn)容器的rootfs最下面的四層,對(duì)應(yīng)的正是ubuntu:latest鏡像的四層。它們的掛載方式都是只讀的(ro+wh),都以增量的方式分別包含了Ubuntu操作系統(tǒng)的一部分,四層聯(lián)合起來組成了一個(gè)成品。
3.6.2 可讀寫層
rootfs 最上層的操作權(quán)限為 rw, 在沒有寫入文件之前,這個(gè)目錄是空的。而一旦在容器里做了寫操作,你修改產(chǎn)生的內(nèi)容就會(huì)以增量的方式出現(xiàn)在這個(gè)層中。如果你想刪除只讀層里的文件,咋辦呢?這個(gè)問題上面已經(jīng)講解過了。
最上面這個(gè)可讀寫層就是專門用來存放修改 rootfs 后產(chǎn)生的增量,無(wú)論是增、刪、改,都發(fā)生在這里。而當(dāng)我們使用完了這個(gè)被修改過的容器之后,還可以使用 docker commit 和 push 指令,保存這個(gè)被修改過的可讀寫層,并上傳到 Docker Hub上,供其他人使用。并且原先的只讀層里的內(nèi)容則不會(huì)有任何變化,這就是增量 rootfs 的好處。
3.6.3 init 層
它是一個(gè)以-init結(jié)尾的層,夾在只讀層和讀寫層之間。Init層是Docker項(xiàng)目單獨(dú)生成的一個(gè)內(nèi)部層,專門用來存放 /etc/hosts 等信息。
需要這樣一層的原因是這些文件本來屬于只讀的Ubuntu鏡像的一部分,但是用戶往往需要在啟動(dòng)容器時(shí)寫入一些指定的值比如 hostname,那就需要在可讀寫層對(duì)它們進(jìn)行修改??墒?,這些修改往往只對(duì)當(dāng)前的容器有效,我們并不希望執(zhí)行 docker commit 時(shí),把 init 層的信息連同可讀寫層一起提交。
最后這6層被組合起來形成了一個(gè)完整的 Ubuntu 操作系統(tǒng)供容器使用。
4 Docker 網(wǎng)絡(luò)
由上面的 Docker 原理可知 Docker 使用了 Linux 的 Namespaces 技術(shù)來進(jìn)行資源隔離,如 PID Namespace 隔離進(jìn)程,Mount Namespace 隔離文件系統(tǒng),Network Namespace 隔離網(wǎng)絡(luò)等。一個(gè)Network Namespace 提供了一份獨(dú)立的網(wǎng)絡(luò)環(huán)境(包括網(wǎng)卡、路由、Iptable規(guī)則)與其他的Network Namespace隔離,一個(gè)Docker容器一般會(huì)分配一個(gè)獨(dú)立的Network Namespace。
當(dāng)你安裝Docker時(shí),執(zhí)行docker network ls會(huì)發(fā)現(xiàn)它會(huì)自動(dòng)創(chuàng)建三個(gè)網(wǎng)絡(luò)。
- [root@server1 ~]$ docker network ls
- NETWORK ID NAME DRIVER SCOPE
- 0147b8d16c64 bridge bridge local
- 2da931af3f0b host host local
- 63d31338bcd9 none null local
我們?cè)谑褂胐ocker run創(chuàng)建Docker容器時(shí),可以用 --net 選項(xiàng)指定容器的網(wǎng)絡(luò)模式,Docker可以有以下4種網(wǎng)絡(luò)模式:
網(wǎng)絡(luò)模式 | 使用注意 |
---|---|
host | 和宿主機(jī)共享網(wǎng)絡(luò) |
none | 不配置網(wǎng)絡(luò) |
bridge | docker默認(rèn),也可自創(chuàng) |
container | 容器網(wǎng)絡(luò)連通,容器直接互聯(lián),用的很少 |
4.1 Host 模式
等價(jià)于Vmware中的橋接模式,當(dāng)啟動(dòng)容器的時(shí)候用host模式,容器將不會(huì)虛擬出自己的網(wǎng)卡,配置自己的IP等,而是使用宿主機(jī)的IP和端口。但是容器的其他方面,如文件系統(tǒng)、進(jìn)程列表等還是和宿主機(jī)隔離的。
4.2 Container 模式
Container 模式指定新創(chuàng)建的容器和已經(jīng)存在的一個(gè)容器共享一個(gè) Network Namespace,而不是和宿主機(jī)共享。新創(chuàng)建的容器不會(huì)創(chuàng)建自己的網(wǎng)卡,配置自己的IP,而是和一個(gè)指定的容器共享IP、端口范圍等。同樣,兩個(gè)容器除了網(wǎng)絡(luò)方面,其他的如文件系統(tǒng)、進(jìn)程列表等還是隔離的。兩個(gè)容器的進(jìn)程可以通過lo網(wǎng)卡設(shè)備通信。
4.3 None 模式
None 模式將容器放置在它自己的網(wǎng)絡(luò)棧中,并不進(jìn)行任何配置。實(shí)際上,該模式關(guān)閉了容器的網(wǎng)絡(luò)功能,該模式下容器并不需要網(wǎng)絡(luò)(例如只需要寫磁盤卷的批處理任務(wù))。
4.4 Bridge 模式
Bridge 模式是 Docker 默認(rèn)的網(wǎng)絡(luò)設(shè)置,此模式會(huì)為每一個(gè)容器分配 Network Namespace、設(shè)置IP等。當(dāng)Docker Server啟動(dòng)時(shí),會(huì)在主機(jī)上創(chuàng)建一個(gè)名為docker0的虛擬網(wǎng)橋,此主機(jī)上啟動(dòng)的Docker容器會(huì)連接到這個(gè)虛擬網(wǎng)橋上。虛擬網(wǎng)橋的工作方式和物理交換機(jī)類似,主機(jī)上的所有容器就通過交換機(jī)連在了一個(gè)二層網(wǎng)絡(luò)中。

Docker 會(huì)從RFC1918所定義的私有IP網(wǎng)段中,選擇一個(gè)和宿主機(jī)不同的IP地址和子網(wǎng)分配給docker0,連接到 docker0 的容器從子網(wǎng)中選擇個(gè)未占用 IP 使用。一般 Docker 會(huì)用 172.17.0.0/16 這個(gè)網(wǎng)段,并將172.17.0.1/16 分配給 docker0 網(wǎng)橋(在主機(jī)上使用ifconfig命令是可以看到docker0的,可以認(rèn)為它是網(wǎng)橋的管理接口,在宿主機(jī)上作為一塊虛擬網(wǎng)卡使用)。
網(wǎng)絡(luò)配置的過程大致3步:
在主機(jī)上創(chuàng)建一對(duì)虛擬網(wǎng)卡 veth pair 設(shè)備。veth設(shè)備總是成對(duì)出現(xiàn)的,它們組成了一個(gè)數(shù)據(jù)的通道,數(shù)據(jù)從一個(gè)設(shè)備進(jìn)入,就會(huì)從另一個(gè)設(shè)備出來。因此veth設(shè)備常用來連接兩個(gè)網(wǎng)絡(luò)設(shè)備。
- Docker 將 veth pair 設(shè)備的一端放在新創(chuàng)建的容器中,并命名為eth0。另一端放在主機(jī)中,以veth65f9 這樣類似的名字命名,并將這個(gè)網(wǎng)絡(luò)設(shè)備加入到docker0網(wǎng)橋中,可以通過brctl show命令查看。
- 從 docker0 子網(wǎng)中分配一個(gè)IP給容器使用,并設(shè)置 docker0 的IP地址為容器的默認(rèn)網(wǎng)關(guān)。
- Bridge 模式下容器的通信
容器訪問外部
假設(shè)主機(jī)網(wǎng)卡為eth0,IP地址10.10.101.105/24,網(wǎng)關(guān)10.10.101.254。從主機(jī)上一個(gè)IP為172.17.0.1/16 的容器中ping百度(180.76.3.151)。首先IP包從容器發(fā)往自己的默認(rèn)網(wǎng)關(guān) docker0,包到達(dá)docker0后,會(huì)查詢主機(jī)的路由表,發(fā)現(xiàn)包應(yīng)該從主機(jī)的 eth0 發(fā)往主機(jī)的網(wǎng)關(guān)10.10.105.254/24。接著包會(huì)轉(zhuǎn)發(fā)給eth0,并從eth0發(fā)出去。這時(shí)Iptable規(guī)則就會(huì)起作用,將源地址換為 eth0 的地址。這樣,在外界看來,這個(gè)包就是從10.10.101.105上發(fā)出來的,Docker容器對(duì)外是不可見的。
外部訪問容器
創(chuàng)建容器并將容器的80端口映射到主機(jī)的80端口。當(dāng)我們對(duì)主機(jī) eth0 收到的目的端口為80的訪問時(shí)候,Iptable規(guī)則會(huì)進(jìn)行DNAT轉(zhuǎn)換,將流量發(fā)往172.17.0.2:80,也就是我們上面創(chuàng)建的Docker容器。所以,外界只需訪問10.10.101.105:80就可以訪問到容器中的服務(wù)。
4.5 --link
容器創(chuàng)建后我們想通過容器名字來ping。此時(shí)需要用到--link,如下:
- docker run -d -P --name linux03 --link linux02 linux
- docker exec -it linux03 ping linux02 可ping通。
- docker exec -it linux02 ping linux03 不可ping通。
追本溯源 看下 linux03 的 /etc/hosts 會(huì)發(fā)現(xiàn)本質(zhì)只是做了個(gè)host映射。
- 172.17.0.3 linux03 12ft4tesa # 跟Windows的host文件一樣,只是做了地址綁定
4.6 自建Bridge
我們之前直接啟動(dòng)的命令 (默認(rèn)是使用--net bridge,可省),這個(gè)bridge就是我們的docker0。下面?zhèn)z是等價(jià)的。
- docker run -d -P --name linux01 LinuxSelf
- docker run -d -P --name linux01 --net bridge LinuxSelf
docker0默認(rèn)不支持域名訪問 , 只能用 --link 打通連接。如果我們使用自定義的網(wǎng)絡(luò)時(shí),docker底層已經(jīng)幫我們維護(hù)好了對(duì)應(yīng)關(guān)系,可以實(shí)現(xiàn)域名訪問。
- # --driver bridge 網(wǎng)絡(luò)模式定義為 :橋接
- # --subnet 192.168.0.0/16 定義子網(wǎng) ,范圍為:192.168.0.2 ~ 192.168.255.255
- # --gateway 192.168.0.1 子網(wǎng)網(wǎng)關(guān)設(shè)為: 192.168.0.1
- docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
接下來
- docker run -d -P --name linux-net-01 --net mynet LinuxSelf
- docker run -d -P --name linux-net-02 --net mynet LinuxSelf
- docker exec -it linux-net-01 ping linux-net-02的IP # 結(jié)果OK
- docker exec -it linux-net-01 ping linux-net-02 # 結(jié)果OK
5 可視化界面
5.1 Portainer
Portainer 是 Docker 的圖形化管理工具,提供狀態(tài)顯示面板、應(yīng)用模板快速部署、容器鏡像網(wǎng)絡(luò)數(shù)據(jù)卷的基本操作(包括上傳下載鏡像,創(chuàng)建容器等操作)、事件日志顯示、容器控制臺(tái)操作、Swarm集群和服務(wù)等集中管理和操作、登錄用戶管理和控制等功能。功能十分全面,基本能滿足中小型單位對(duì)容器管理的全部需求。
5.2 DockerUI
DockerUI基于Docker API,提供等同Docker命令行的大部分功能,支持container管理,image管理。不過DockerUI一個(gè)致命的缺點(diǎn)就是 不支持多主機(jī)。
5.3 Shipyard
Shipyard 是一個(gè)集成管理docker容器、鏡像、Registries的系統(tǒng),它可以簡(jiǎn)化對(duì)橫跨多個(gè)主機(jī)的Docker容器集群進(jìn)行管理. 通過Web用戶界面,你可以大致瀏覽相關(guān)信息,比如你的容器在使用多少處理器和內(nèi)存資源、在運(yùn)行哪些容器,還可以檢查所有集群上的事件日志。
6 Docker 學(xué)習(xí)指南
本來也想寫常見指令、Dockerfile、Docker Compose、Docker Swarm的,不過感覺還是拉閘吧,官方文檔他不香啊!推薦幾個(gè)學(xué)習(xí)指南。
官方文檔:https://docs.docker.com/engine/reference/commandline/build/
從入門到實(shí)踐:https://github.com/yeasy/docker_practice
在線教程:https://vuepress.mirror.docker-practice.com