筆者在《Docker Machine 簡(jiǎn)介》一文中簡(jiǎn)單介紹了 Docker Machine 及其基本用法,但是忽略的細(xì)節(jié)實(shí)在是太多了。比如 Docker 與 Docker Machine 的區(qū)別?又如當(dāng)我們執(zhí)行 docker-machine create 命令時(shí),Docker Machine 都做了哪些重要的事情使得我們可以遠(yuǎn)程操作 Docker daemon?這樣的遠(yuǎn)程操作安全嗎?本文將試圖解讀這些問(wèn)題。注:本文的演示環(huán)境為 Ubuntu16.04。

Docker 與 Docker Machine 的區(qū)別

Docker 是一個(gè) Client-Server 架構(gòu)的應(yīng)用,人家是有官稱(chēng)的:Docker Engine。Docker 只是大家對(duì) Docker Engine 的昵稱(chēng),當(dāng)然 Docker 還有其他的意思,比如一家公司的名稱(chēng)。簡(jiǎn)單起見(jiàn),本文中的 Docker 等同于 Docker Engine。

提到 Docker 我們必須要知道它包含了三部分內(nèi)容:

  1. Docker daemon

  2. 一套與 Docker daemon 交互的 REST API

  3. 一個(gè)命令行客戶端

下圖很清晰的展示了它們之間的關(guān)系:

萬(wàn)碼學(xué)堂,電腦培訓(xùn),計(jì)算機(jī)培訓(xùn),Java培訓(xùn),JavaEE開(kāi)發(fā)培訓(xùn),青島軟件培訓(xùn),軟件工程師培訓(xùn)

Docker Machine 則是一個(gè)安裝和管理 Docker 的工具。它有自己的命令行工具:docker-machine。

Docker daemon socket

既然 Docker 客戶端要和 Docker daemon 通過(guò) REST API 通信,那就讓我們看看它們可以采用的方法有哪些:

  1. Unix socket

  2. Systemd socket activation

  3. Tcp

我們可以簡(jiǎn)單的把 1 和 2 理解成一種方式,就是同一臺(tái)主機(jī)上的進(jìn)程間通信。至于 3 則很好理解:通過(guò) tcp 協(xié)議進(jìn)行跨網(wǎng)絡(luò)的通信。

既然 1 和 2 用于同一臺(tái)機(jī)器上的進(jìn)程間通信,那么我們可以猜想:安裝在同一主機(jī)上的 Docker 客戶端和 Docker daemon 就是通過(guò)這種方式來(lái)通信的。事實(shí)也正是如此,我們可以查看安裝 Docker 時(shí)默認(rèn)添加的 Docker daemon 啟動(dòng)配置,打開(kāi)文件 /etc/systemd/system/multi-user.target.wants/docker.service:

萬(wàn)碼學(xué)堂,電腦培訓(xùn),計(jì)算機(jī)培訓(xùn),Java培訓(xùn),JavaEE開(kāi)發(fā)培訓(xùn),青島軟件培訓(xùn),軟件工程師培訓(xùn)

圖中的 -H 用來(lái)指定 Docker Daemon 監(jiān)聽(tīng)的 socket,此處指定的類(lèi)型為 system socket activation。使用類(lèi)型 1 和 2 進(jìn)行通信需要進(jìn)程具有 root 權(quán)限。這也是 Docker 安裝過(guò)程中會(huì)自動(dòng)創(chuàng)建一個(gè)具有 root 權(quán)限的用戶和用戶組的主要原因。新創(chuàng)建的用戶和用戶組名稱(chēng)為 docker,建議大家把需要操作 Docker 的用戶都加入到這個(gè)組中,否則當(dāng)你執(zhí)行命令時(shí)就會(huì)碰到下圖顯示的問(wèn)題:

萬(wàn)碼學(xué)堂,電腦培訓(xùn),計(jì)算機(jī)培訓(xùn),Java培訓(xùn),JavaEE開(kāi)發(fā)培訓(xùn),青島軟件培訓(xùn),軟件工程師培訓(xùn)

我們還可以同時(shí)指定多個(gè) -H 參數(shù)讓 Docker daemon 同時(shí)監(jiān)聽(tīng)不同的 socket 類(lèi)型。比如要添加對(duì) TCP 端口 2376 的監(jiān)聽(tīng)就可以使用下面的命令行參數(shù):

$ sudo dockerd -H fd:// -H tcp://0.0.0.0:2376

運(yùn)行上面的命令,然后查看本機(jī)監(jiān)聽(tīng)的端口:

萬(wàn)碼學(xué)堂,電腦培訓(xùn),計(jì)算機(jī)培訓(xùn),Java培訓(xùn),JavaEE開(kāi)發(fā)培訓(xùn),青島軟件培訓(xùn),軟件工程師培訓(xùn)

此時(shí)我們就可以從遠(yuǎn)程主機(jī)上的 Docker 客戶端訪問(wèn)這部主機(jī)的 2376 端口了。

DOCKER_HOST 環(huán)境變量

Docker 客戶端默認(rèn)的配置是訪問(wèn)本機(jī)的 Docker daemon,當(dāng)你指定了 DOCKER_HOST 變量后,Docker 客戶端會(huì)訪問(wèn)這個(gè)變量中指定的 Docker daemon。讓我們回顧一下 docker-machine env 命令:

萬(wàn)碼學(xué)堂,電腦培訓(xùn),計(jì)算機(jī)培訓(xùn),Java培訓(xùn),JavaEE開(kāi)發(fā)培訓(xùn),青島軟件培訓(xùn),軟件工程師培訓(xùn)

原來(lái)我們?cè)?a target="_blank" style="margin: 0px; padding: 0px; color: black;">前文中執(zhí)行的 $ eval $(docker-machine env krdevdb) 命令就是在設(shè)置 DOCKER_HOST 環(huán)境變量。

解決安全問(wèn)題

我們的 Docker daemon 監(jiān)聽(tīng)了 tcp 端口,糟糕的是此時(shí)我們沒(méi)有做任何的保護(hù)措施。因此任何 Docker 客戶端都可以通過(guò) tcp 端口與我們的 Docker daemon 交互,這顯然是無(wú)法接受的。解決方案是同時(shí)啟用 Docker daemon 和 Docker 客戶端的 TLS 證書(shū)認(rèn)證機(jī)制。這樣 Docker daemon 和 Docker 客戶端之間的通信會(huì)被加密,并且只有安裝了特定證書(shū)的客戶端才能夠與對(duì)應(yīng)的 Docker daemon 交互。

至此本文的鋪墊部分終于結(jié)束了,接下來(lái)我們將討論 Docker Machine 相關(guān)的內(nèi)容。

Docker Machine create 命令

根據(jù) Docker Machine 驅(qū)動(dòng)的不同,create 命令執(zhí)行的操作也不太一樣,但其中有兩步是我們?cè)谶@里比較關(guān)心的:

docker-machine 會(huì)在您指定的主機(jī)上執(zhí)行下面的操作:

  1. 安裝 Docker,并進(jìn)行配置。

  2. 生成證書(shū)保護(hù) Docker 服務(wù)的安全。

配置 Docker daemon

Docker 的安裝過(guò)程并沒(méi)有什么秘密,這里不再贅述。我們重點(diǎn)關(guān)注 Docker daemon 的配置。仔細(xì)觀察我們會(huì)發(fā)現(xiàn),通過(guò) docker-machine 安裝的 Docker 在 /etc/systemd/system 目錄下多出了一個(gè) Docker 相關(guān)的目錄:docker.service.d。這個(gè)目錄中只有一個(gè)文件 10-machine.conf:

萬(wàn)碼學(xué)堂,電腦培訓(xùn),計(jì)算機(jī)培訓(xùn),Java培訓(xùn),JavaEE開(kāi)發(fā)培訓(xùn),青島軟件培訓(xùn),軟件工程師培訓(xùn)

好吧,-H tcp://0.0.0.0:2376 出現(xiàn)在這里并沒(méi)有讓我們太吃驚。在我們做了巨多的鋪墊之后,你應(yīng)該覺(jué)得這是理所當(dāng)然才是。--tls 開(kāi)頭的幾個(gè)參數(shù)主要和證書(shū)相關(guān),我們會(huì)在后面的安全設(shè)置中詳細(xì)的介紹它們。讓人多少有些疑惑的地方是上圖中的 /usr/bin/docker。當(dāng)前最新版本的 Docker Machine 還在使用舊的方式設(shè)置 Docker daemon,希望在接下來(lái)的版本中會(huì)有所更新。

這個(gè)配置文件至關(guān)重要,因?yàn)樗鼤?huì)覆蓋 Docker 默認(rèn)安裝時(shí)的配置文件,從而以 Docker Machine 指定的方式啟動(dòng) Docker daemon。至此我們有了一個(gè)可以被遠(yuǎn)程訪問(wèn)的 Docker daemon。

生成證書(shū)

我們?cè)?Docker daemon 的配置文件中看到四個(gè)以 --tls 開(kāi)頭的參數(shù),分別是 --tlsverify、--tlscacert、--tlscert和 –tlskey。其中的 --tlsverify 告訴 Docker daemon 需要通過(guò) TLS 來(lái)驗(yàn)證遠(yuǎn)程客戶端。其它三個(gè)參數(shù)分別指定了一個(gè) pem 格式文件的路徑,按照它們指定的文件路徑去查看一下:

萬(wàn)碼學(xué)堂,電腦培訓(xùn),計(jì)算機(jī)培訓(xùn),Java培訓(xùn),JavaEE開(kāi)發(fā)培訓(xùn),青島軟件培訓(xùn),軟件工程師培訓(xùn)

對(duì)比一下手動(dòng)安裝的 Docker,會(huì)發(fā)現(xiàn) /etc/docker 目錄下并沒(méi)有這三個(gè)文件。毫無(wú)疑問(wèn)它們是 Docker Machine 生成的,主要是為了啟用 Docker daemon 的 TLS 驗(yàn)證功能。關(guān)于 TLS,筆者在《局域網(wǎng)內(nèi)部署 Docker Registry》一文中略有涉及,當(dāng)時(shí)是手動(dòng)配置的證書(shū),感興趣的朋友可以參考一下。

現(xiàn)在讓我們回到安裝了 Docker Machine 的主機(jī)上。

查看 /home/nick/.docker/machines/krdevdb 目錄,發(fā)現(xiàn)了一些同名的文件(ca.pem、server-key.pem 和 server.pem),和主機(jī) drdevdb 上的文件對(duì)比一下,發(fā)現(xiàn)它們是一樣的!

讓我們?cè)賮?lái)觀察一下這幅圖:

萬(wàn)碼學(xué)堂,電腦培訓(xùn),計(jì)算機(jī)培訓(xùn),Java培訓(xùn),JavaEE開(kāi)發(fā)培訓(xùn),青島軟件培訓(xùn),軟件工程師培訓(xùn)

除了我們關(guān)注過(guò)的 DOCKER_HOST,還有另外三個(gè)環(huán)境變量。其中的 DOCKER_TLS_VERIFY 告訴 Docker 客戶端需要啟用 TLS 驗(yàn)證。DOCKER_CERT_PATH 則指定了 TLS 驗(yàn)證所依賴文件的目錄,這個(gè)目錄正是我們前面查看的 /home/nick/.docker/machines/krdevdb 目錄。

行文至此,困擾我們的安全問(wèn)題終于得到了解釋?zhuān)篋ocker Machine 在執(zhí)行 create 命令的過(guò)程中,生成了一系列保證安全性的秘鑰和數(shù)字證書(shū)(*.pem)文件。這些文件在本地和遠(yuǎn)程 Docker 主機(jī)上各存一份,本地的用于配置 Docker 客戶端,遠(yuǎn)程主機(jī)上的用于配置 Docker daemon,讓兩邊都設(shè)置 TLS 驗(yàn)證的標(biāo)記,依此實(shí)現(xiàn)安全的通信。

總結(jié)

從本文的前一部分可以看到,Docker 其實(shí)把該提供的都提供了,只是配置起來(lái)比較麻煩!但是對(duì)用戶來(lái)說(shuō),需要的總是更簡(jiǎn)單,更容易的配置。因此從使用者的角度來(lái)看,Docker Machine 確實(shí)很酷,一個(gè)命令下去不僅能夠安裝虛機(jī)和 Docker,還完成了很多手動(dòng)搞起來(lái)令人生畏的配置。然后帶來(lái)幾個(gè)清晰、簡(jiǎn)單的命令。再然后,同學(xué)們就可以開(kāi)心愉快的玩耍了!

作者:sparkdev

出處:http://www.cnblogs.com/sparkdev/

本文版權(quán)歸作者和博客園共有,歡迎轉(zhuǎn)載,但未經(jīng)作者同意必須保留此段聲明,且在文章頁(yè)面明顯位置給出原文連接,否則保留追究法律責(zé)任的權(quán)利。

http://www.cnblogs.com/sparkdev/p/7066789.html