Docker 入门教程 - 2021 最新版(上)
?
容器化的概念很早就有了。2013 年?Docker 引擎的出現(xiàn)使應(yīng)用程序容器化變得更加容易。
根據(jù)?Stack Overflow 開發(fā)者調(diào)查-2020,Docker是開發(fā)者?#1 最想要的平臺(tái)、#2 最喜歡的平臺(tái),以及#3 最流行的平臺(tái)。
盡管 Docker 功能強(qiáng)大,但上手確并不容易。因此,本書將介紹從基礎(chǔ)知識(shí)到更高層次容器化的的所有內(nèi)容。讀完整本書之后,你應(yīng)該能夠:
-
容器化(幾乎)任何應(yīng)用程序
-
將自定義 Docker 鏡像上傳到在線倉(cāng)庫(kù)
-
使用 Docker Compose 處理多個(gè)容器
前提
-
熟悉 Linux 終端操作
-
熟悉 JavaScript(稍后的的演示項(xiàng)目用到了 JavaScript)
目錄
-
容器化和 Docker 簡(jiǎn)介
-
怎樣安裝 Docker
-
怎樣在 macOS 里安裝 Docker
-
怎樣在 Windows 上安裝 Docker
-
怎樣在 Linux 上安裝 Docker
-
-
初識(shí) Docker - Docker 基本知識(shí)介紹
-
什么是容器?
-
什么是 Docker 鏡像?
-
什么是倉(cāng)庫(kù)?
-
Docker 架構(gòu)概述
-
全景圖
-
-
Docker 容器操作基礎(chǔ)知識(shí)
-
怎樣運(yùn)行容器
-
怎樣公開端口
-
如何使用分離模式
-
怎樣列表展示容器
-
怎樣命名或者重命名一個(gè)容器
-
怎樣停止或者殺死運(yùn)行中的容器
-
怎樣重新啟動(dòng)容器
-
怎樣創(chuàng)建而不運(yùn)行容器
-
怎樣移除掛起的容器
-
怎樣以交互式模式運(yùn)行容器
-
怎樣在容器里執(zhí)行命令
-
如何處理可執(zhí)行鏡像
-
-
Docker 鏡像操作基礎(chǔ)知識(shí)
-
如何創(chuàng)建 Docker 鏡像
-
如何標(biāo)記 Docker 鏡像
-
如何刪除、列表展示鏡像
-
理解 Docker 鏡像的分層
-
怎樣從源碼構(gòu)建 NGINX
-
怎樣優(yōu)化 Docker 鏡像
-
擁抱 Alpine Linux
-
怎樣創(chuàng)建可執(zhí)行 Docker 鏡像
-
怎樣在線共享 Docker 鏡像
-
-
怎樣容器化 JavaScript 應(yīng)用
-
如何編寫開發(fā) Dockerfile
-
如何在 Docker 中使用綁定掛載
-
如何在 Docker 中使用匿名卷
-
如何在 Docker 中執(zhí)行多階段構(gòu)建
-
如何忽略不必要的文件
-
-
Docker 中的網(wǎng)絡(luò)操作基礎(chǔ)知識(shí)
-
Docker 網(wǎng)絡(luò)基礎(chǔ)
-
如何在 Docker 中創(chuàng)建用戶定義的橋接網(wǎng)絡(luò)
-
如何在 Docker 中將容器連接到網(wǎng)絡(luò)
-
如何在 Docker 中從網(wǎng)絡(luò)分離容器
-
如何刪除 Docker 中的網(wǎng)絡(luò)
-
-
如何容器化多容器 JavaScript 應(yīng)用程序
-
如何運(yùn)行數(shù)據(jù)庫(kù)服務(wù)
-
如何在 Docker 中使用命名卷
-
如何從 Docker 中的容器訪問(wèn)日志
-
如何在 Docker 中創(chuàng)建網(wǎng)絡(luò)并連接數(shù)據(jù)庫(kù)服務(wù)
-
如何編寫 Dockerfile
-
如何在正在運(yùn)行的容器中執(zhí)行命令
-
如何在 Docker 中編寫管理腳本
-
-
如何使用 Docker-Compose 組合項(xiàng)目
-
Docker Compose 基礎(chǔ)
-
如何在 Docker Compose 中啟動(dòng)服務(wù)
-
如何在 Docker Compose 中列表展示服務(wù)
-
如何在 Docker Compose 正在運(yùn)行的服務(wù)中執(zhí)行命令
-
如何訪問(wèn) Docker Compose 中正在運(yùn)行的服務(wù)日志
-
如何在 Docker Compose 中停止服務(wù)
-
如何在 Docker Compose 中編寫全棧應(yīng)用程序
-
-
結(jié)論
項(xiàng)目代碼
可以在這個(gè)倉(cāng)庫(kù)中找到示例項(xiàng)目的代碼,歡迎 ?。
完整代碼在?containerized?分支。
貢獻(xiàn)
這本書是完全開源的,歡迎高質(zhì)量的貢獻(xiàn)??梢栽谶@個(gè)倉(cāng)庫(kù)中找到完整的內(nèi)容。
我通常先在本書的 GitBook 版本上進(jìn)行更改和更新,然后在將其發(fā)布在 freeCodeCamp 專欄。你可以在這個(gè)鏈接中找到本書的最新編輯中版本。別忘了評(píng)分支持。
如果你正在尋找本書的完整穩(wěn)定版本,那么 freeCodeCamp 是最好的選擇。如果你有所收獲,請(qǐng)分享給你的朋友。
不管閱讀本書的哪個(gè)版本,都不要忘記留下你的意見(jiàn)。歡迎提出建設(shè)性的批評(píng)。
容器化和 Docker 簡(jiǎn)介
摘自 IBM,
容器化意味著封裝或打包軟件代碼及其所有依賴項(xiàng),以便它可以在任何基礎(chǔ)架構(gòu)上統(tǒng)一且一致地運(yùn)行。
換句話說(shuō),容器化可以將軟件及其所有依賴項(xiàng)打包在一個(gè)自包含的軟件包中,這樣就可以省略麻煩的配置,直接運(yùn)行。
舉一個(gè)現(xiàn)實(shí)生活的場(chǎng)景。假設(shè)你已經(jīng)開發(fā)了一個(gè)很棒的圖書管理應(yīng)用程序,該應(yīng)用程序可以存儲(chǔ)所有圖書的信息,還可以為別人提供圖書借閱服務(wù)。
如果列出依賴項(xiàng),如下所示:
-
Node.js
-
Express.js
-
SQLite3
理論上應(yīng)該是這樣。但是實(shí)際上還要搞定其他一些事情。Node.js 使用了?node-gyp?構(gòu)建工具來(lái)構(gòu)建原生加載項(xiàng)。根據(jù)官方存儲(chǔ)庫(kù)中的安裝說(shuō)明,此構(gòu)建工具需要 Python 2 或 3 和相應(yīng)的的 C/C ++ 編譯器工具鏈。
考慮到所有這些因素,最終的依賴關(guān)系列表如下:
-
Node.js
-
Express.js
-
SQLite3
-
Python 2 or 3
-
C/C++ tool-chain
無(wú)論使用什么平臺(tái),安裝 Python 2 或 3 都非常簡(jiǎn)單。在 Linux 上,設(shè)置 C/C ++ 工具鏈也非常容易,但是在 Windows 和 Mac 上,這是一項(xiàng)繁重的工作。
在 Windows 上,C++ 構(gòu)建工具包有數(shù) GB 之大,安裝需要花費(fèi)相當(dāng)長(zhǎng)的時(shí)間。在 Mac 上,可以安裝龐大的 Xcode 應(yīng)用程序,也可以安裝小巧的 Xcode 命令行工具包。
不管安裝了哪一種,它都可能會(huì)在 OS 更新時(shí)中斷。實(shí)際上,該問(wèn)題非常普遍,甚至連官方倉(cāng)庫(kù)都專門提供了?macOS Catalina 的安裝說(shuō)明。
這里假設(shè)你已經(jīng)解決了設(shè)置依賴項(xiàng)的所有麻煩,并且已經(jīng)準(zhǔn)備好開始。這是否意味著現(xiàn)在開始就一帆風(fēng)順了?當(dāng)然不是。
如果你使用 Linux 而同事使用 Windows 該怎么辦?現(xiàn)在,必須考慮如何處理這兩個(gè)不同的操作系統(tǒng)不一致的路徑,或諸如 nginx 之類的流行技術(shù)在 Windows 上未得到很好的優(yōu)化的事實(shí),以及諸如 Redis 之類的某些技術(shù)甚至都不是針對(duì) Windows 預(yù)先構(gòu)建的。
即使你完成了整個(gè)開發(fā),如果負(fù)責(zé)管理服務(wù)器的人員部署流程搞錯(cuò)了,該怎么辦?
所有這些問(wèn)題都可以通過(guò)以下方式解決:
-
在與最終部署環(huán)境匹配的隔離環(huán)境(稱為容器)中開發(fā)和運(yùn)行應(yīng)用程序。
-
將你的應(yīng)用程序及其所有依賴項(xiàng)和必要的部署配置放入一個(gè)文件(稱為鏡像)中。
-
并通過(guò)具有適當(dāng)授權(quán)的任何人都可以訪問(wèn)的中央服務(wù)器(稱為倉(cāng)庫(kù))共享該鏡像。
然后,你的同事就可以從倉(cāng)庫(kù)中下載鏡像,可以在沒(méi)有平臺(tái)沖突的隔離環(huán)境中運(yùn)行應(yīng)用,甚至可以直接在服務(wù)器上進(jìn)行部署,因?yàn)樵撶R像也可以進(jìn)行生產(chǎn)環(huán)境配置。
這就是容器化背后的想法:將應(yīng)用程序放在一個(gè)獨(dú)立的程序包中,使其在各種環(huán)境中都可移植且可回溯。
現(xiàn)在的問(wèn)題是:Docker 在這里扮演什么角色?
正如我之前講的,容器化是一種將一切統(tǒng)一放入盒子中來(lái)解決軟件開發(fā)過(guò)程中的問(wèn)題的思想。
這個(gè)想法有很多實(shí)現(xiàn)。Docker 就是這樣的實(shí)現(xiàn)。這是一個(gè)開放源代碼的容器化平臺(tái),可讓你對(duì)應(yīng)用程序進(jìn)行容器化,使用公共或私有倉(cāng)庫(kù)共享它們,也可以編排它們。
目前,Docker 并不是市場(chǎng)上唯一的容器化工具,卻是最受歡迎的容器化工具。我喜歡的另一個(gè)容器化引擎是 Red Hat 開發(fā)的 Podman。其他工具,例如 Google 的 Kaniko,CoreOS 的 rkt 都很棒,但和 Docker 還是有差距。
此外,如果你想了解容器的歷史,可以閱讀?A Brief History of Containers: From the 1970s Till Now,它描述了該技術(shù)的很多重要節(jié)點(diǎn)。
怎樣安裝 Docker
Docker 的安裝因使用的操作系統(tǒng)而異。但這整個(gè)過(guò)程都非常簡(jiǎn)單。
Docker可在 Mac、Windows 和 Linux 這三個(gè)主要平臺(tái)上完美運(yùn)行。在這三者中,在 Mac 上的安裝過(guò)程是最簡(jiǎn)單的,因此我們從這里開始。
怎樣在 macOS 里安裝 Docker
在 Mac 上,要做的就是跳轉(zhuǎn)到官方的下載頁(yè)面,然后單擊_Download for Mac(stable)_按鈕。
你會(huì)看到一個(gè)常規(guī)的?Apple Disk Image?文件,在該文件的內(nèi)有 Docker 應(yīng)用程序。所要做的就是將文件拖放到 Applications 目錄中。
只需雙擊應(yīng)用程序圖標(biāo)即可啟動(dòng) Docker。應(yīng)用程序啟動(dòng)后,將看到 Docker 圖標(biāo)出現(xiàn)在菜單欄上。
現(xiàn)在,打開終端并執(zhí)行?docker --version?和?docker-compose --version?以驗(yàn)證是否安裝成功。
怎樣在 Windows 上安裝 Docker
在 Windows 上,步驟幾乎相同,當(dāng)然還需要執(zhí)行一些額外的操作。安裝步驟如下:
跳轉(zhuǎn)到此站點(diǎn),然后按照說(shuō)明在 Windows 10 上安裝 WSL2。
然后跳轉(zhuǎn)到官方下載頁(yè)面?并單擊?Download for Windows(stable)?按鈕。
雙擊下載的安裝程序,然后使用默認(rèn)設(shè)置進(jìn)行安裝。
安裝完成后,從開始菜單或桌面啟動(dòng)?Docker Desktop。Docker 圖標(biāo)應(yīng)顯示在任務(wù)欄上。
現(xiàn)在,打開 Ubuntu 或從 Microsoft Store 安裝的任何發(fā)行版。執(zhí)行?docker --version?和?docker-compose --version?命令以確保安裝成功。
也可以從常規(guī)命令提示符或 PowerShell 訪問(wèn) Docker,只是我更喜歡使用 WSL2。
怎樣在 Linux 上安裝 Docker
在 Linux 上安裝 Docker 的過(guò)程有所不同,具體操作取決于你所使用的發(fā)行版,它們之間差異可能更大。但老實(shí)說(shuō),安裝與其他兩個(gè)平臺(tái)一樣容易(如果不能算更容易的話)。
Windows 或 Mac 上的 Docker Desktop 軟件包是一系列工具的集合,例如Docker Engine、Docker Compose、Docker Dashboard、Kubernetes?和其他一些好東西。
但是,在 Linux 上,沒(méi)有得到這樣的捆綁包??梢允謩?dòng)安裝所需的所有必要工具。不同發(fā)行版的安裝過(guò)程如下:
-
如果你使用的是 Ubuntu,則可以遵循官方文檔中的在 Ubuntu 上安裝 Docker 引擎部分。
-
對(duì)于其他發(fā)行版,官方文檔中提供了?不同發(fā)行版的安裝指南。
-
在 Debian上安裝 Docker Engine
-
在 Fedora 上安裝 Docker Engine
-
在 CentOS 上安裝 Docker Engine
-
-
如果你使用的發(fā)行版未在文檔中列出,則可以參考從二進(jìn)制文件安裝 Docker 引擎指南。
-
無(wú)論參考什么程序,都必須完成一些非常重要的?Linux 的安裝后續(xù)步驟。
-
完成 docker 安裝后,必須安裝另一個(gè)名為 Docker Compose 的工具??梢詤⒖脊俜轿臋n中的?Install Docker Compose?指南。
安裝完成后,打開終端并執(zhí)行?docker --version?和?docker-compose --version?以確保安裝成功。
盡管無(wú)論使用哪個(gè)平臺(tái),Docker 的性能都很好,但與其他平臺(tái)相比,我更喜歡 Linux。在整本書中,我將使用?Ubuntu 20.10 或者 Fedora 33。
一開始就需要闡明的另一件事是,在整本書中,我不會(huì)使用任何 GUI 工具操作 Docker。
我在各個(gè)平臺(tái)用過(guò)很多不錯(cuò)的 GUI 工具,但是介紹常見(jiàn)的 docker 命令是本書的主要目標(biāo)之一。
初識(shí) Docker - 介紹 Docker 基本知識(shí)
已經(jīng)在計(jì)算機(jī)上啟動(dòng)并運(yùn)行了 Docker,現(xiàn)在該運(yùn)行第一個(gè)容器了。打開終端并執(zhí)行以下命令:
docker?run?hello-world#?Unable?to?find?image?'hello-world:latest'?locally #?latest:?Pulling?from?library/hello-world #?0e03bdcc26d7:?Pull?complete? #?Digest:?sha256:4cf9c47f86df71d48364001ede3a4fcd85ae80ce02ebad74156906caff5378bc #?Status:?Downloaded?newer?image?for?hello-world:latest #? #?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. #?????(amd64) #??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. # #?To?try?something?more?ambitious,?you?can?run?an?Ubuntu?container?with: #??$?docker?run?-it?ubuntu?bash #? #?Share?images,?automate?workflows,?and?more?with?a?free?Docker?ID: #??https://hub.docker.com/ # #?For?more?examples?and?ideas,?visit: #??https://docs.docker.com/get-started/hello-world 鏡像是使用 Docker 進(jìn)行最小化容器化的一個(gè)示例。它有一個(gè)從 hello.c 文件編譯的程序,負(fù)責(zé)打印出終端看到的消息。
現(xiàn)在,在終端中,可以使用?docker ps -a?命令查看當(dāng)前正在運(yùn)行或過(guò)去運(yùn)行的所有容器:
docker?ps?-a#?CONTAINER?ID????????IMAGE???????????????COMMAND?????????????CREATED?????????????STATUS?????????????????????PORTS???????????????NAMES #?128ec8ceab71????????hello-world?????????"/hello"????????????14?seconds?ago??????Exited?(0)?13?seconds?ago??????????????????????exciting_chebyshev在輸出中,使用?hello-world?鏡像運(yùn)行了名為?exciting_chebyshev?的容器,其容器標(biāo)識(shí)為?128ec8ceab71。它已經(jīng)在?Exited (0) 13 seconds ago,其中?(0)?退出代碼表示在容器運(yùn)行時(shí)未發(fā)生任何錯(cuò)誤。
現(xiàn)在,為了了解背后發(fā)生的事情,必須熟悉 Docker 體系結(jié)構(gòu)和三個(gè)非?;镜娜萜骰拍?#xff0c;如下所示:
-
容器
-
鏡像
-
倉(cāng)庫(kù)
我已經(jīng)按字母順序列出了這三個(gè)概念,并且將從列表中的第一個(gè)開始介紹。
什么是容器?
在容器化世界中,沒(méi)有什么比容器的概念更基礎(chǔ)的了。
官方 Docker?resources?網(wǎng)站說(shuō) -
容器是應(yīng)用程序?qū)拥某橄?#xff0c;可以將代碼和依賴項(xiàng)打包在一起。容器不虛擬化整個(gè)物理機(jī),僅虛擬化主機(jī)操作系統(tǒng)。
可以認(rèn)為容器是下一代虛擬機(jī)。
就像虛擬機(jī)一樣,容器是與主機(jī)系統(tǒng)是彼此之間完全隔離的環(huán)境。它也比傳統(tǒng)虛擬機(jī)輕量得多,因此可以同時(shí)運(yùn)行大量容器,而不會(huì)影響主機(jī)系統(tǒng)的性能。
容器和虛擬機(jī)實(shí)際上是虛擬化物理硬件的不同方法。兩者之間的主要區(qū)別是虛擬化方式。
虛擬機(jī)通常由稱為虛擬機(jī)監(jiān)控器的程序創(chuàng)建和管理,例如 Oracle VM VirtualBox,VMware Workstation,KVM,Microsoft Hyper-V 等等。該虛擬機(jī)監(jiān)控程序通常位于主機(jī)操作系統(tǒng)和虛擬機(jī)之間,充當(dāng)通信介質(zhì)。
每個(gè)虛擬機(jī)都有自己的 guest 操作系統(tǒng),該操作系統(tǒng)與主機(jī)操作系統(tǒng)一樣消耗資源。
在虛擬機(jī)內(nèi)部運(yùn)行的應(yīng)用程序與 guest 操作系統(tǒng)進(jìn)行通信,該 guest 操作系統(tǒng)在與虛擬機(jī)監(jiān)控器進(jìn)行通信,后者隨后又與主機(jī)操作系統(tǒng)進(jìn)行通信,以將必要的資源從物理基礎(chǔ)設(shè)施分配給正在運(yùn)行的應(yīng)用程序。
虛擬機(jī)內(nèi)部運(yùn)行的應(yīng)用程序與物理基礎(chǔ)設(shè)施之間存在很長(zhǎng)的通信鏈。在虛擬機(jī)內(nèi)部運(yùn)行的應(yīng)用程序可能只擁有少量資源,因?yàn)?guest 操作系統(tǒng)會(huì)占用很大的開銷。
與虛擬機(jī)不同,容器以更智能的方式完成虛擬化工作。在容器內(nèi)部沒(méi)有完整的 guest 操作系統(tǒng),它只是通過(guò)容器運(yùn)行時(shí)使用主機(jī)操作系統(tǒng),同時(shí)保持隔離 – 就像傳統(tǒng)的虛擬機(jī)一樣。
容器運(yùn)行時(shí)(即 Docker)位于容器和主機(jī)操作系統(tǒng)之間,而不是虛擬機(jī)監(jiān)控器中。容器與容器運(yùn)行時(shí)進(jìn)行通信,容器運(yùn)行時(shí)再與主機(jī)操作系統(tǒng)進(jìn)行通信,以從物理基礎(chǔ)設(shè)施中獲取必要的資源。
由于消除了整個(gè)主機(jī)操作系統(tǒng)層,因此與傳統(tǒng)的虛擬機(jī)相比,容器的更輕量,資源占用更少。
為了說(shuō)明這一點(diǎn),請(qǐng)看下面的代碼片段:
uname?-a #?Linux?alpha-centauri?5.8.0-22-generic?#23-Ubuntu?SMP?Fri?Oct?9?00:34:40?UTC?2020?x86_64?x86_64?x86_64?GNU/Linuxdocker?run?alpine?uname?-a #?Linux?f08dbbe9199b?5.8.0-22-generic?#23-Ubuntu?SMP?Fri?Oct?9?00:34:40?UTC?2020?x86_64?Linux在上面的代碼片段中,在主機(jī)操作系統(tǒng)上執(zhí)行了?uname -a?命令以打印出內(nèi)核詳細(xì)信息。然后在下一行,我在運(yùn)行 Alpine Linux 的容器內(nèi)執(zhí)行了相同的命令。
從輸出中可以看到,該容器確實(shí)正在使用主機(jī)操作系統(tǒng)中的內(nèi)核。這證明了容器虛擬化主機(jī)操作系統(tǒng)而不是擁有自己的操作系統(tǒng)這一點(diǎn)。
如果你使用的是 Windows 計(jì)算機(jī),則會(huì)發(fā)現(xiàn)所有容器都使用 WSL2 內(nèi)核。發(fā)生這種情況是因?yàn)?WSL2 充當(dāng)了 Windows 上 Docker 的后端。在 macOS 上,默認(rèn)后端是在 ?HyperKit 虛擬機(jī)管理程序上運(yùn)行的 VM。
什么是 Docker 鏡像?
鏡像是分層的自包含文件,充當(dāng)創(chuàng)建容器的模板。它們就像容器的凍結(jié)只讀副本。鏡像可以通過(guò)倉(cāng)庫(kù)進(jìn)行共享。
過(guò)去,不同的容器引擎具有不同的鏡像格式。但是后來(lái),開放式容器計(jì)劃(OCI)定義了容器鏡像的標(biāo)準(zhǔn)規(guī)范,該規(guī)范被主要的容器化引擎所遵循。這意味著使用 Docker 構(gòu)建的映像可以與 Podman 等其他運(yùn)行時(shí)一起使用,而不會(huì)有兼容性問(wèn)題。
容器只是處于運(yùn)行狀態(tài)的鏡像。當(dāng)從互聯(lián)網(wǎng)上獲取鏡像并使用該鏡像運(yùn)行容器時(shí),實(shí)際上是在先前的只讀層之上創(chuàng)建了另一個(gè)臨時(shí)可寫層。
在本書的后續(xù)部分中,這一概念將變得更加清晰。但就目前而言,請(qǐng)記住,鏡像是分層只讀文件,其中保留著應(yīng)用程序所需的狀態(tài)。
什么是倉(cāng)庫(kù)?
已經(jīng)了解了這個(gè)難題的兩個(gè)非常重要的部分,即?Containers?和?Images?。最后一個(gè)是?Registry。
鏡像倉(cāng)庫(kù)是一個(gè)集中式的位置,可以在其中上傳鏡像,也可以下載其他人創(chuàng)建的鏡像。Docker Hub 是 Docker 的默認(rèn)公共倉(cāng)庫(kù)。另一個(gè)非常流行的鏡像倉(cāng)庫(kù)是 Red Hat 的 Quay。
在本書中,我將使用 Docker Hub 作為首選倉(cāng)庫(kù)。
可以免費(fèi)在 Docker Hub 上共享任意數(shù)量的公共鏡像。供世界各地的人們下載免費(fèi)使用??稍谖业膫€(gè)人資料(fhsinchy)頁(yè)面上找到我上傳的鏡像。
除了 Docker Hub 或 Quay,還可以創(chuàng)建自己的鏡像倉(cāng)庫(kù)來(lái)托管私有鏡像。計(jì)算機(jī)中還運(yùn)行著一個(gè)本地倉(cāng)庫(kù),該倉(cāng)庫(kù)緩存從遠(yuǎn)程倉(cāng)庫(kù)提取的鏡像。
Docker 架構(gòu)概述
既然已經(jīng)熟悉了有關(guān)容器化和 Docker 的大多數(shù)基本概念,那么現(xiàn)在是時(shí)候了解 Docker 作為軟件的架構(gòu)了。
該引擎包括三個(gè)主要組件:
Docker 守護(hù)程序:?守護(hù)程序(dockerd)是一個(gè)始終在后臺(tái)運(yùn)行并等待來(lái)自客戶端的命令的進(jìn)程。守護(hù)程序能夠管理各種 Docker 對(duì)象。
Docker 客戶端:?客戶端(docker)是一個(gè)命令行界面程序,主要負(fù)責(zé)傳輸用戶發(fā)出的命令。
REST API:?REST API 充當(dāng)守護(hù)程序和客戶端之間的橋梁。使用客戶端發(fā)出的任何命令都將通過(guò) API 傳遞,最終到達(dá)守護(hù)程序。
根據(jù)官方文檔,
“ Docker 使用客戶端-服務(wù)器體系結(jié)構(gòu)。Docker?client?與 Docker?daemon?對(duì)話,daemon 繁重地構(gòu)建、運(yùn)行和分發(fā) Docker 容器”。
作為用戶,通常將使用客戶端組件執(zhí)行命令。然后,客戶端使用 REST API 來(lái)訪問(wèn)長(zhǎng)期運(yùn)行的守護(hù)程序并完成工作。
全景圖
好吧,說(shuō)的夠多了?,F(xiàn)在是時(shí)候了解剛剛學(xué)習(xí)的所有這些知識(shí)如何和諧地工作了。在深入解釋運(yùn)行?docker run hello-world?命令時(shí)實(shí)際發(fā)生的情況之前,看一下下面的圖片:
該圖像是在官方文檔中找到的圖像的略微修改版本。執(zhí)行命令時(shí)發(fā)生的事件如下:
執(zhí)行?docker run hello-world?命令,其中?hello-world?是鏡像的名稱。
Docker 客戶端訪問(wèn)守護(hù)程序,告訴它獲取?hello-world?鏡像并從中運(yùn)行一個(gè)容器。
Docker 守護(hù)程序在本地倉(cāng)庫(kù)中查找鏡像,并發(fā)現(xiàn)它不存在,所以在終端上打印?Unable to find image 'hello-world:latest' locally。
然后,守護(hù)程序訪問(wèn)默認(rèn)的公共倉(cāng)庫(kù) Docker Hub,拉取?hello-world?鏡像的最新副本,并在命令行中展示?Unable to find image 'hello-world:latest' locally。
Docker 守護(hù)程序根據(jù)新拉取的鏡像創(chuàng)建一個(gè)新容器。
最后,Docker 守護(hù)程序運(yùn)行使用?hello-world?鏡像創(chuàng)建的容器,該鏡像在終端上輸出文本。
Docker 守護(hù)程序的默認(rèn)行為是在 hub 中查找本地不存在的鏡像。但是,拉取了鏡像之后,它將保留在本地緩存中。因此,如果再次執(zhí)行該命令,則在輸出中將看不到以下幾行:
Unable?to?find?image?'hello-world:latest'?locally latest:?Pulling?from?library/hello-world 0e03bdcc26d7:?Pull?complete Digest:?sha256:d58e752213a51785838f9eed2b7a498ffa1cb3aa7f946dda11af39286c3db9a9 Status:?Downloaded?newer?image?for?hello-world:latest如果公共倉(cāng)庫(kù)中有可用鏡像的更新版本,則守護(hù)程序?qū)⒃俅卫≡撶R像。那個(gè)?:latest?是一個(gè)標(biāo)記。鏡像通常包含有意義的標(biāo)記以指示版本或內(nèi)部版本。稍后,將更詳細(xì)地介紹這一點(diǎn)。
Docker 容器操作基礎(chǔ)知識(shí)
在前面的部分中,已經(jīng)了解了 Docker 的構(gòu)建模塊,還使用?docker run?命令運(yùn)行了一個(gè)容器。
在本節(jié)中,將詳細(xì)介紹容器的操作。容器操作是每天要執(zhí)行的最常見(jiàn)的任務(wù)之一,因此,正確理解各種命令至關(guān)重要。
但是請(qǐng)記住,這并不是可以在 Docker 上執(zhí)行的所有命令的詳盡列表。我只會(huì)介紹最常見(jiàn)的那些。當(dāng)想知道某一命令的更多用法時(shí),可以訪問(wèn) Docker 命令行的官方參考。
怎樣運(yùn)行容器
之前,已經(jīng)使用?docker run?來(lái)使用?hello-world?鏡像創(chuàng)建和啟動(dòng)容器。此命令的通用語(yǔ)法如下:
docker?run?<image?name>盡管這是一個(gè)完全有效的命令,但是有一種更好的方式可以將命令分配給?docker?守護(hù)程序。
在版本?1.13?之前,Docker 僅具有前面提到的命令語(yǔ)法。后來(lái),命令行經(jīng)過(guò)了重構(gòu)具有了以下語(yǔ)法:
docker?<object>?<command>?<options>使用以下語(yǔ)法:
-
object?表示將要操作的 Docker 對(duì)象的類型。這可以是?container、image、network?或者?volume?對(duì)象。
-
command?表示守護(hù)程序要執(zhí)行的任務(wù),即?run?命令。
-
options?可以是任何可以覆蓋命令默認(rèn)行為的有效參數(shù),例如端口映射的?--publish?選項(xiàng)。
現(xiàn)在,遵循此語(yǔ)法,可以將?run?命令編寫如下:
docker?container?run?<image?name>image name?可以是在線倉(cāng)庫(kù)或本地系統(tǒng)中的任何鏡像。例如,可以嘗試使用fhsinchy / hello-dock 鏡像運(yùn)行容器。該鏡像包含一個(gè)簡(jiǎn)單的 Vue.js應(yīng)用程序,該應(yīng)用程序在容器內(nèi)部的端口 80 上運(yùn)行。
請(qǐng)?jiān)诮K端上執(zhí)行以下命令以使用此鏡像運(yùn)行容器:
docker?container?run?--publish?8080:80?fhsinchy/hello-dock#?/docker-entrypoint.sh:?/docker-entrypoint.d/?is?not?empty,?will?attempt?to?perform?configuration #?/docker-entrypoint.sh:?Looking?for?shell?scripts?in?/docker-entrypoint.d/ #?/docker-entrypoint.sh:?Launching?/docker-entrypoint.d/10-listen-on-ipv6-by-default.sh #?10-listen-on-ipv6-by-default.sh:?Getting?the?checksum?of?/etc/nginx/conf.d/default.conf #?10-listen-on-ipv6-by-default.sh:?Enabled?listen?on?IPv6?in?/etc/nginx/conf.d/default.conf #?/docker-entrypoint.sh:?Launching?/docker-entrypoint.d/20-envsubst-on-templates.sh #?/docker-entrypoint.sh:?Configuration?complete;?ready?for?start?up該命令不言自明。唯一需要說(shuō)明的部分是?--publish 8080:80?部分,將在下一個(gè)小節(jié)中進(jìn)行說(shuō)明。
怎樣公開端口
容器是隔離的環(huán)境。主機(jī)系統(tǒng)對(duì)容器內(nèi)部發(fā)生的事情一無(wú)所知。因此,從外部無(wú)法訪問(wèn)在容器內(nèi)部運(yùn)行的應(yīng)用程序。
要允許從容器外部進(jìn)行訪問(wèn),必須將容器內(nèi)的相應(yīng)端口發(fā)布到本地網(wǎng)絡(luò)上的端口。--publish?或?-p?選項(xiàng)的通用語(yǔ)法如下:
--publish?<host?port>:<container?port>在上一小節(jié)中編寫了?--publish 8080:80?時(shí),這意味著發(fā)送到主機(jī)系統(tǒng)端口 8080 的任何請(qǐng)求都將轉(zhuǎn)發(fā)到容器內(nèi)的端口 80。
現(xiàn)在要在瀏覽器上訪問(wèn)該應(yīng)用程序,只需訪問(wèn) ?http://127.0.0.1:8080。
可以在終端窗口按下?ctrl + c?組合鍵或關(guān)閉終端窗口來(lái)停止容器。
如何使用分離模式
run?命令的另一個(gè)非常流行的選項(xiàng)是?---detach?或?-d?選項(xiàng)。在上面的示例中,為了使容器繼續(xù)運(yùn)行,必須將終端窗口保持打開狀態(tài)。關(guān)閉終端窗口會(huì)停止正在運(yùn)行的容器。
這是因?yàn)?#xff0c;默認(rèn)情況下,容器在前臺(tái)運(yùn)行,并像從終端調(diào)用的任何其他普通程序一樣將其自身附加到終端。
為了覆蓋此行為并保持容器在后臺(tái)運(yùn)行,可以在?run?命令中包含?--detach?選項(xiàng),如下所示:
docker?container?run?--detach?--publish?8080:80?fhsinchy/hello-dock#?9f21cb77705810797c4b847dbd330d9c732ffddba14fb435470567a7a3f46cdc與前面的示例不同,這次不會(huì)看到很多文字,而只獲得新創(chuàng)建的容器的 ID。
提供選項(xiàng)的順序并不重要。如果將?--publish?選項(xiàng)放在?--detach?選項(xiàng)之前,效果相同。
使用?run?命令時(shí)必須記住的一件事是鏡像名稱必須最后出現(xiàn)。如果在鏡像名稱后放置任何內(nèi)容,則將其作為參數(shù)傳遞給容器入口點(diǎn)(在在容器內(nèi)執(zhí)行命令小節(jié)做了解釋),可能會(huì)導(dǎo)致意外情況。
怎樣列表展示容器
container ls?命令可用于列出當(dāng)前正在運(yùn)行的容器。執(zhí)行以下命令:
docker?container?ls#?CONTAINER?ID????????IMAGE?????????????????COMMAND??????????????????CREATED?????????????STATUS??????????????PORTS??????????????????NAMES #?9f21cb777058????????fhsinchy/hello-dock???"/docker-entrypoint.…"???5?seconds?ago???????Up?5?seconds????????0.0.0.0:8080->80/tcp???gifted_sammet一個(gè)名為?gifted_sammet?的容器正在運(yùn)行。它是在?5 seconds ago?前創(chuàng)建的,狀態(tài)為?Up 5 seconds,這表明自創(chuàng)建以來(lái),該容器一直運(yùn)行良好。
CONTAINER ID?為?9f21cb777058,這是完整容器 ID 的前 12 個(gè)字符。完整的容器 ID 是?9f21cb77705810797c4b847dbd330d9c732ffddba14fb435470567a7a3f46cdc,該字符長(zhǎng) 64 個(gè)字符。在上一節(jié)中?docker container run??命令行的輸?shù)木褪峭暾娜萜?ID 。
列表的?PORTS?列下,本地網(wǎng)絡(luò)的端口 8080 指向容器內(nèi)的端口 80。name?gifted_sammet?是由 Docker 生成的,可能與你的計(jì)算機(jī)的不同。
container ls?命令僅列出系統(tǒng)上當(dāng)前正在運(yùn)行的容器。為了列出過(guò)去運(yùn)行的所有容器,可以使用?--all?或?-a?選項(xiàng)。
docker?container?ls?--all#?CONTAINER?ID????????IMAGE?????????????????COMMAND??????????????????CREATED?????????????STATUS?????????????????????PORTS??????????????????NAMES #?9f21cb777058????????fhsinchy/hello-dock???"/docker-entrypoint.…"???2?minutes?ago???????Up?2?minutes???????????????0.0.0.0:8080->80/tcp???gifted_sammet #?6cf52771dde1????????fhsinchy/hello-dock???"/docker-entrypoint.…"???3?minutes?ago???????Exited?(0)?3?minutes?ago??????????????????????????reverent_torvalds #?128ec8ceab71????????hello-world???????????"/hello"?????????????????4?minutes?ago???????Exited?(0)?4?minutes?ago??????????????????????????exciting_chebyshev如你所見(jiàn),列表?reverent_torvalds?中的第二個(gè)容器是較早創(chuàng)建的,并以狀態(tài)代碼 0 退出,這表明在容器運(yùn)行期間未產(chǎn)生任何錯(cuò)誤。
怎樣命名或者重命名一個(gè)容器
默認(rèn)情況下,每個(gè)容器都有兩個(gè)標(biāo)識(shí)符。如下:
-
CONTAINER ID?- 64 個(gè)字符的隨機(jī)字符串。
-
NAME?- 兩個(gè)隨機(jī)詞的組合,下劃線連接。
基于這兩個(gè)隨機(jī)標(biāo)識(shí)符來(lái)引用容器非常不方便。如果可以使用自定義的名稱來(lái)引用容器,那就太好了。
可以使用?--name?選項(xiàng)來(lái)命名容器。要使用名為?hello-dock-container?的?fhsinchy/hello-dock?鏡像運(yùn)行另一個(gè)容器,可以執(zhí)行以下命令:
docker?container?run?--detach?--publish?8888:80?--name?hello-dock-container?fhsinchy/hello-dock#?b1db06e400c4c5e81a93a64d30acc1bf821bed63af36cab5cdb95d25e114f5fb本地網(wǎng)絡(luò)上的 8080 端口被?gifted_sammet?容器(在上一小節(jié)中創(chuàng)建的容器)占用了。這就是為什么必須使用其他端口號(hào)(例如 8888)的原因。要進(jìn)行驗(yàn)證,執(zhí)行?container ls?命令:
docker?container?ls#?CONTAINER?ID????????IMAGE?????????????????COMMAND??????????????????CREATED?????????????STATUS??????????????PORTS??????????????????NAMES #?b1db06e400c4????????fhsinchy/hello-dock???"/docker-entrypoint.…"???28?seconds?ago??????Up?26?seconds???????0.0.0.0:8888->80/tcp???hello-dock-container #?9f21cb777058????????fhsinchy/hello-dock???"/docker-entrypoint.…"???4?minutes?ago???????Up?4?minutes????????0.0.0.0:8080->80/tcp???gifted_sammet一個(gè)名為?hello-dock-container?的新容器已經(jīng)啟動(dòng)。
甚至可以使用?container rename?命令來(lái)重命名舊容器。該命令的語(yǔ)法如下:
docker?container?rename?<container?identifier>?<new?name>要將?gifted_sammet?容器重命名為?hello-dock-container-2,可以執(zhí)行以下命令:
docker?container?rename?gifted_sammet?hello-dock-container-2該命令不會(huì)產(chǎn)生任何輸出,但是可以使用?container ls?命令來(lái)驗(yàn)證是否已進(jìn)行更改。rename?命令不僅適用于處于運(yùn)行狀態(tài)的容器和還適用于處于停止?fàn)顟B(tài)的容器。
怎樣停止或者殺死運(yùn)行中的容器
可以通過(guò)簡(jiǎn)單地關(guān)閉終端窗口或單擊?ctrl + c?來(lái)停止在前臺(tái)運(yùn)行的容器。但是,不能以相同方式停止在后臺(tái)運(yùn)行的容器。
有兩個(gè)命令可以完成此任務(wù)。第一個(gè)是?container stop?命令。該命令的通用語(yǔ)法如下:
docker?container?stop?<container?identifier>其中?container identifier?可以是容器的 ID 或名稱。
應(yīng)該還記得上一節(jié)中啟動(dòng)的容器。它仍在后臺(tái)運(yùn)行。使用?docker container ls?獲取該容器的標(biāo)識(shí)符(在本演示中,我將使用?hello-dock-container?容器)?,F(xiàn)在執(zhí)行以下命令來(lái)停止容器:
docker?container?stop?hello-dock-container#?hello-dock-container如果使用 name 作為標(biāo)識(shí)符,則 name 將作為輸出返回。stop?命令通過(guò)發(fā)送信號(hào)SIGTERM?來(lái)正常關(guān)閉容器。如果容器在一定時(shí)間內(nèi)沒(méi)有停止運(yùn)行,則會(huì)發(fā)出?SIGKILL?信號(hào),該信號(hào)會(huì)立即關(guān)閉容器。
如果要發(fā)送?SIGKILL?信號(hào)而不是?SIGTERM?信號(hào),則可以改用?container kill?命令。container kill?命令遵循與?stop?命令相同的語(yǔ)法。
docker?container?kill?hello-dock-container-2#?hello-dock-container-2怎樣重新啟動(dòng)容器
當(dāng)我說(shuō)重啟時(shí),我指的如下是兩種情況:
-
重新啟動(dòng)先前已停止或終止的容器。
-
重新啟動(dòng)正在運(yùn)行的容器。
正如上一小節(jié)中學(xué)到的,停止的容器保留在系統(tǒng)中。如果需要,可以重新啟動(dòng)它們。container start??命令可用于啟動(dòng)任何已停止或終止的容器。該命令的語(yǔ)法如下:
docker?container?start?<container?identifier>可以通過(guò)執(zhí)行?container ls --all?命令來(lái)獲取所有容器的列表,然后尋找狀態(tài)為?Exited?的容器。
docker?container?ls?--all#?CONTAINER?ID????????IMAGE?????????????????COMMAND??????????????????CREATED?????????????STATUS????????????????????????PORTS???????????????NAMES #?b1db06e400c4????????fhsinchy/hello-dock???"/docker-entrypoint.…"???3?minutes?ago???????Exited?(0)?47?seconds?ago?????????????????????????hello-dock-container #?9f21cb777058????????fhsinchy/hello-dock???"/docker-entrypoint.…"???7?minutes?ago???????Exited?(137)?17?seconds?ago???????????????????????hello-dock-container-2 #?6cf52771dde1????????fhsinchy/hello-dock???"/docker-entrypoint.…"???7?minutes?ago???????Exited?(0)?7?minutes?ago??????????????????????????reverent_torvalds #?128ec8ceab71????????hello-world???????????"/hello"?????????????????9?minutes?ago???????Exited?(0)?9?minutes?ago??????????????????????????exciting_chebyshev現(xiàn)在要重新啟動(dòng)?hello-dock-container?容器,可以執(zhí)行以下命令:
docker?container?start?hello-dock-container#?hello-dock-container現(xiàn)在,可以使用?container ls?命令查看正在運(yùn)行的容器列表,以確保該容器正在運(yùn)行。
默認(rèn)情況下,container start?命令以分離模式啟動(dòng)容器,并保留之前進(jìn)行的端口配置。因此,如果現(xiàn)在訪問(wèn)?http://127.0.0.1:8080,應(yīng)該能夠像以前一樣訪問(wèn)?hello-dock?應(yīng)用程序。
現(xiàn)在,在想重新啟動(dòng)正在運(yùn)行的容器,可以使用?container restart?命令。container restart?命令遵循與?container start?命令完全相同的語(yǔ)法。
docker?container?restart?hello-dock-container-2#?hello-dock-container-2這兩個(gè)命令之間的主要區(qū)別在于,container restart?命令嘗試停止目標(biāo)容器,然后再次啟動(dòng)它,而 start 命令只是啟動(dòng)一個(gè)已經(jīng)停止的容器。
在容器停止的情況下,兩個(gè)命令完全相同。但是如果容器正在運(yùn)行,則必須使用container restart?命令。
怎樣創(chuàng)建而不運(yùn)行容器
到目前為止,在本節(jié)中,已經(jīng)使用?container run?命令啟動(dòng)了容器,該命令實(shí)際上是兩個(gè)單獨(dú)命令的組合。這兩個(gè)命令如下:
-
container create?命令從給定的鏡像創(chuàng)建一個(gè)容器。
-
container start?命令將啟動(dòng)一個(gè)已經(jīng)創(chuàng)建的容器。
現(xiàn)在,要使用這兩個(gè)命令執(zhí)行運(yùn)行容器部分中顯示的演示,可以執(zhí)行以下操作 :
docker?container?create?--publish?8080:80?fhsinchy/hello-dock#?2e7ef5098bab92f4536eb9a372d9b99ed852a9a816c341127399f51a6d053856docker?container?ls?--all#?CONTAINER?ID????????IMAGE?????????????????COMMAND??????????????????CREATED?????????????STATUS??????????????PORTS???????????????NAMES #?2e7ef5098bab????????fhsinchy/hello-dock???"/docker-entrypoint.…"???30?seconds?ago??????Created?????????????????????????????????hello-dock通過(guò)?container ls --all?命令的輸出可以明顯看出,已經(jīng)使用?fhsinchy/hello-dock鏡像創(chuàng)建了一個(gè)名稱為?hello-dock?的容器。容器的?STATUS?目前處于?Created?狀態(tài),并且鑒于其未運(yùn)行,因此不使用 ?--all?選項(xiàng)就不會(huì)列出該容器。
一旦創(chuàng)建了容器,就可以使用?container start?命令來(lái)啟動(dòng)它。
docker?container?start?hello-dock#?hello-dockdocker?container?ls#?CONTAINER?ID????????IMAGE?????????????????COMMAND??????????????????CREATED??????????????STATUS??????????????PORTS??????????????????NAMES #?2e7ef5098bab????????fhsinchy/hello-dock???"/docker-entrypoint.…"???About?a?minute?ago???Up?29?seconds???????0.0.0.0:8080->80/tcp???hello-dock容器?STATUS?已從?Created?更改為?Up 29 seconds,這表明容器現(xiàn)在處于運(yùn)行狀態(tài)。端口配置也顯示在以前為空的?PORTS?列中。
盡管可以在大多數(shù)情況下使用?container run?命令,但本書稍后還會(huì)有一些情況要求使用?container create?命令。
怎樣移除掛起的容器
如你所見(jiàn),已被停止或終止的容器仍保留在系統(tǒng)中。這些掛起的容器可能會(huì)占用空間或與較新的容器發(fā)生沖突。
可以使用?container rm?命令刪除停止的容器。通用語(yǔ)法如下:
docker?container?rm?<container?identifier>要找出哪些容器沒(méi)有運(yùn)行,使用?container ls --all?命令并查找狀態(tài)為?Exited?的容器。
docker?container?ls?--all#?CONTAINER?ID????????IMAGE?????????????????COMMAND??????????????????CREATED?????????????STATUS??????????????????????PORTS??????????????????NAMES #?b1db06e400c4????????fhsinchy/hello-dock???"/docker-entrypoint.…"???6?minutes?ago???????Up?About?a?minute???????????0.0.0.0:8888->80/tcp???hello-dock-container #?9f21cb777058????????fhsinchy/hello-dock???"/docker-entrypoint.…"???10?minutes?ago??????Up?About?a?minute???????????0.0.0.0:8080->80/tcp???hello-dock-container-2 #?6cf52771dde1????????fhsinchy/hello-dock???"/docker-entrypoint.…"???10?minutes?ago??????Exited?(0)?10?minutes?ago??????????????????????????reverent_torvalds #?128ec8ceab71????????hello-world???????????"/hello"?????????????????12?minutes?ago??????Exited?(0)?12?minutes?ago??????????????????????????exciting_chebyshev從輸出中可以看到,ID為?6cf52771dde1?和?128ec8ceab71?的容器未運(yùn)行。要?jiǎng)h除?6cf52771dde1,可以執(zhí)行以下命令:
docker?container?rm?6cf52771dde1#?6cf52771dde1可以使用?container ls?命令檢查容器是否被刪除。也可以一次刪除多個(gè)容器,方法是將其標(biāo)識(shí)符一個(gè)接一個(gè)地傳遞,每個(gè)標(biāo)識(shí)符之間用空格隔開。
也可以使用?container prune?命令來(lái)一次性刪除所有掛起的容器。
可以使用?container ls --all?命令檢查容器列表,以確保已刪除了掛起的容器:
docker?container?ls?--all#?CONTAINER?ID????????IMAGE?????????????????COMMAND??????????????????CREATED?????????????STATUS??????????????PORTS??????????????????NAMES #?b1db06e400c4????????fhsinchy/hello-dock???"/docker-entrypoint.…"???8?minutes?ago???????Up?3?minutes????????0.0.0.0:8888->80/tcp???hello-dock-container #?9f21cb777058????????fhsinchy/hello-dock???"/docker-entrypoint.…"???12?minutes?ago??????Up?3?minutes????????0.0.0.0:8080->80/tcp???hello-dock-container-2如果按照本書的順序進(jìn)行操作,則應(yīng)該只在列表中看到?hello-dock-container?和?hello-dock-container-2。建議停止并刪除兩個(gè)容器,然后再繼續(xù)進(jìn)行下一部分。
container run?和?container start?命令還有?--rm?選項(xiàng),它們表示希望容器在停止后立即被移除。執(zhí)行以下命令,使用?--rm?選項(xiàng)啟動(dòng)另一個(gè)?hello-dock?容器:
docker?container?run?--rm?--detach?--publish?8888:80?--name?hello-dock-volatile?fhsinchy/hello-dock#?0d74e14091dc6262732bee226d95702c21894678efb4043663f7911c53fb79f3可以使用?container ls?命令來(lái)驗(yàn)證容器是否正在運(yùn)行:
docker?container?ls#?CONTAINER?ID???IMAGE?????????????????COMMAND??????????????????CREATED??????????????STATUS??????????????PORTS??????????????????NAMES #?0d74e14091dc???fhsinchy/hello-dock???"/docker-entrypoint.…"???About?a?minute?ago???Up?About?a?minute???0.0.0.0:8888->80/tcp???hello-dock-volatile現(xiàn)在,如果停止了容器,使用?container ls --all?命令再次檢查:
docker?container?stop?hello-dock-volatile#?hello-dock-volatiledocker?container?ls?--all#?CONTAINER?ID???IMAGE?????COMMAND???CREATED???STATUS????PORTS?????NAMES該容器已被自動(dòng)刪除。從現(xiàn)在開始,我將對(duì)大多數(shù)容器使用?--rm?選項(xiàng)。不需要的地方我會(huì)明確提到。
怎樣以交互式模式運(yùn)行容器
到目前為止,只運(yùn)行了 hello-world 鏡像或 fhsinchy/hello-dock 鏡像。這些鏡像用于執(zhí)行非交互式的簡(jiǎn)單程序。
好吧,鏡像并不是那么簡(jiǎn)單。鏡像可以將整個(gè) Linux 發(fā)行版封裝在其中。
流行的發(fā)行版,例如 Ubuntu,Fedora 和 Debian 都在 hub 有官方的 Docker 鏡像。編程語(yǔ)言,例如 python、php、[go](https:// hub.docker.com/_/golang) 或類似 node 和 deno 都有其官方鏡像。
這些鏡像不但僅運(yùn)行某些預(yù)配置的程序。還將它們配置為默認(rèn)情況下運(yùn)行的 shell 程序。在鏡像是操作系統(tǒng)的情況下,它可以是諸如?sh?或?bash?之類的東西,在竟像是編程語(yǔ)言或運(yùn)行時(shí)的情況下,通常是它們的默認(rèn)語(yǔ)言的 shell。
正如可能從以前的計(jì)算機(jī)中學(xué)到的一樣,shell 是交互式程序。被配置為運(yùn)行這樣的程序的鏡像是交互式鏡像。這些鏡像需要在 ?container run??命令中傳遞特殊的?-it?選項(xiàng)。
例如,如果通過(guò)執(zhí)行?docker container run ubuntu?使用?ubuntu?鏡像運(yùn)行一個(gè)容器,將不會(huì)發(fā)生任何事情。但是,如果使用?-it?選項(xiàng)執(zhí)行相同的命令,會(huì)直接進(jìn)入到 Ubuntu 容器內(nèi)的 bash 上。
docker?container?run?--rm?-it?ubuntu#?root@dbb1f56b9563:/#?cat?/etc/os-release #?NAME="Ubuntu" #?VERSION="20.04.1?LTS?(Focal?Fossa)" #?ID=ubuntu #?ID_LIKE=debian #?PRETTY_NAME="Ubuntu?20.04.1?LTS" #?VERSION_ID="20.04" #?HOME_URL="https://www.ubuntu.com/" #?SUPPORT_URL="https://help.ubuntu.com/" #?BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/" #?PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy" #?VERSION_CODENAME=focal #?UBUNTU_CODENAME=focal從 ?cat /etc/os-release??命令的輸出中可以看到,我確實(shí)正在與在 Ubuntu 容器中運(yùn)行的 bash 進(jìn)行交互。
-it?選項(xiàng)提供了與容器內(nèi)的程序進(jìn)行交互的場(chǎng)景。此選項(xiàng)實(shí)際上是將兩個(gè)單獨(dú)的選項(xiàng)混在一起。
-
選項(xiàng) ?-i?或 ?--interactive?連接到容器的輸入流,以便可以將輸入發(fā)送到 bash。
-
-t?或?--tty??選項(xiàng)可通過(guò)分配偽 tty 來(lái)格式化展示并提供類似本機(jī)終端的體驗(yàn)。
當(dāng)想以交互方式運(yùn)行容器時(shí),可以使用?-it?選項(xiàng)。以交互式方式運(yùn)行?node?鏡像,如下:
docker?container?run?-it?node#?Welcome?to?Node.js?v15.0.0. #?Type?".help"?for?more?information. #?>?['farhan',?'hasin',?'chowdhury'].map(name?=>?name.toUpperCase()) #?[?'FARHAN',?'HASIN',?'CHOWDHURY'?]任何有效的 JavaScript 代碼都可以在 node shell 中執(zhí)行。除了輸入?-it,還可以輸入?--interactive --tty,效果一樣,只不過(guò)更冗長(zhǎng)。
怎樣在容器里執(zhí)行命令
在本書中初識(shí) Docker 部分中,已經(jīng)了解了在 Alpine Linux 容器內(nèi)執(zhí)行命令。 它是這樣的:
docker?run?alpine?uname?-a #?Linux?f08dbbe9199b?5.8.0-22-generic?#23-Ubuntu?SMP?Fri?Oct?9?00:34:40?UTC?2020?x86_64?Linux在此命令中,在 Alpine Linux 容器中執(zhí)行了?uname -a?命令。像這樣的場(chǎng)景(要做的就是在特定的容器內(nèi)執(zhí)行特定的命令)非常常見(jiàn)。
假設(shè)想使用?base64?程序?qū)ψ址M(jìn)行編碼。幾乎所有基于 Linux 或 Unix 的操作系統(tǒng)都可以使用此功能(但 Windows 則不可用)。
在這種情況下,可以使用 busybox 之類的鏡像快速啟動(dòng)容器,然后執(zhí)行命令。
使用?base64?編碼字符串的通用語(yǔ)法如下:
echo?-n?my-secret?|?base64#?bXktc2VjcmV0將命令傳遞到未運(yùn)行的容器的通用語(yǔ)法如下:
docker?container?run?<image?name>?<command>要使用 busybox 鏡像執(zhí)行 base64 ?編碼,可以執(zhí)行以下命令:
docker?container?run?--rm?busybox?echo?-n?my-secret?|?base64#?bXktc2VjcmV0這里發(fā)生的是,在?container run?命令中,鏡像名稱后傳遞的任何內(nèi)容都將傳遞到鏡像的默認(rèn)入口里。
入口點(diǎn)就像是通往鏡像的網(wǎng)關(guān)。除可執(zhí)行鏡像外的大多數(shù)鏡像(在使用可執(zhí)行鏡像小節(jié)中說(shuō)明)使用 shell 或?sh?作為默認(rèn)入口點(diǎn)。因此,任何有效的 shell 命令都可以作為參數(shù)傳遞給它們。
如何處理可執(zhí)行鏡像
在上一節(jié)中,我簡(jiǎn)要提到了可執(zhí)行鏡像。這些鏡像旨在表現(xiàn)得像可執(zhí)行程序。
以的 rmbyext 項(xiàng)目為例。這是一個(gè)簡(jiǎn)單的 Python 腳本,能夠遞歸刪除給定擴(kuò)展名的文件。 要了解有關(guān)該項(xiàng)目的更多信息,可以查看倉(cāng)庫(kù)。
如果同時(shí)安裝了 Git 和 Python,則可以通過(guò)執(zhí)行以下命令來(lái)安裝此腳本:
pip?install?git+https://github.com/fhsinchy/rmbyext.git#egg=rmbyext假設(shè)的系統(tǒng)上已經(jīng)正確設(shè)置了 Python,則該腳本應(yīng)該可以在終端的任何位置使用。使用此腳本的通用語(yǔ)法如下:
rmbyext?<file?extension>要對(duì)其進(jìn)行測(cè)試,請(qǐng)?jiān)谝粋€(gè)空目錄下打開終端,并在其中創(chuàng)建具有不同擴(kuò)展名的一些文件??梢允褂?touch?命令來(lái)做到這一點(diǎn)?,F(xiàn)在,計(jì)算機(jī)上有一個(gè)包含以下文件的目錄:
touch?a.pdf?b.pdf?c.txt?d.pdf?e.txtls#?a.pdf??b.pdf??c.txt??d.pdf??e.txt要從該目錄刪除所有?pdf?文件,可以執(zhí)行以下命令:
rmbyext?pdf#?Removing:?PDF #?b.pdf #?a.pdf #?d.pdf該程序的可執(zhí)行鏡像能夠?qū)⑽募U(kuò)展名用作參數(shù),并像?rmbyext?程序一樣刪除它們。
fhsinchy/rmbyext 鏡像的行為類似。該鏡像包含?rmbyext?腳本的副本,并配置為在容器內(nèi)的目錄?/zone上運(yùn)行該腳本。
現(xiàn)在的問(wèn)題是容器與本地系統(tǒng)隔離,因此在容器內(nèi)運(yùn)行的?rmbyext?程序無(wú)法訪問(wèn)本地文件系統(tǒng)。因此,如果可以通過(guò)某種方式將包含 pdf 文件的本地目錄映射到容器內(nèi)的?/zone目錄,則容器應(yīng)該可以訪問(wèn)這些文件。
授予容器直接訪問(wèn)本地文件系統(tǒng)的一種方法是使用綁定掛載。
綁定掛載可以在本地文件系統(tǒng)目錄(源)與容器內(nèi)另一個(gè)目錄(目標(biāo))之間形成雙向數(shù)據(jù)綁定。這樣,在目標(biāo)目錄中進(jìn)行的任何更改都將在源目錄上生效,反之亦然。
讓我們看一下綁定掛載的實(shí)際應(yīng)用。要使用此鏡像而不是程序本身刪除文件,可以執(zhí)行以下命令:
docker?container?run?--rm?-v?$(pwd):/zone?fhsinchy/rmbyext?pdf#?Removing:?PDF #?b.pdf #?a.pdf #?d.pdf已經(jīng)在命令中看到了?-v $(pwd):/zone??部分,你可能已經(jīng)猜到了?-v??或?--volume?選項(xiàng)用于為容器創(chuàng)建綁定掛載。該選項(xiàng)可以使用三個(gè)以冒號(hào)(:)分隔的字段。該選項(xiàng)的通用語(yǔ)法如下:
--volume?<local?file?system?directory?absolute?path>:<container?file?system?directory?absolute?path>:<read?write?access>第三個(gè)字段是可選的,但必須傳遞本地目錄的絕對(duì)路徑和容器內(nèi)目錄的絕對(duì)路徑。
在這里,源目錄是?/home/fhsinchy/the-zone。假設(shè)終端當(dāng)前在目錄中,則?$(pwd)?將替換為包含先前提到的?.pdf?和?.txt?文件的?/home/fhsinchy/the-zone。
可以在command substitution here 上了解更多信息。
--volume?或 ?-v??選項(xiàng)對(duì)?container run?以及?container create?命令均有效。我們將在接下來(lái)的部分中更詳細(xì)地探討卷,因此,如果在這里不太了解它們,請(qǐng)不要擔(dān)心。
常規(guī)鏡像和可執(zhí)行鏡像之間的區(qū)別在于,可執(zhí)行鏡像的入口點(diǎn)設(shè)置為自定義程序而不是?sh,在本例中為?rmbyext?程序。正如在上一小節(jié)中所學(xué)到的那樣,在?container run命令中在鏡像名稱之后編寫的所有內(nèi)容都將傳遞到鏡像的入口點(diǎn)。
所以最后,docker container run --rm -v $(pwd):/zone fhsinchy/rmbyext pdf?命令轉(zhuǎn)換為容器內(nèi)的 ?rmbyext pdf?。可執(zhí)行鏡像并不常見(jiàn),但在某些情況下可能非常有用。
總結(jié)
以上是生活随笔為你收集整理的Docker 入门教程 - 2021 最新版(上)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Nature子刊 | 神经义肢技术:从感
- 下一篇: 二次元日系游戏制作工具 - live2d