容器化的概念很早就有了趟脂。2013 年 Docker 引擎 的出現(xiàn)使應(yīng)用程序容器化變得更加容易南蹂。
根據(jù) Stack Overflow 開發(fā)者調(diào)查-2020凳谦,Docker 是開發(fā)者 #1 最想要的平臺、#2 最喜歡的平臺犁功,以及 #3 最流行的平臺氓轰。
盡管 Docker 功能強(qiáng)大,但上手確并不容易浸卦。因此署鸡,本文將介紹從基礎(chǔ)知識到更高層次容器化的的所有內(nèi)容。讀完本文之后限嫌,你應(yīng)該能夠:
- 容器化(幾乎)任何應(yīng)用程序
- 將自定義 Docker 鏡像上傳到在線倉庫
- 使用 Docker Compose 處理多個(gè)容器
前提
- 熟悉 Linux 終端操作
- 熟悉 JavaScript(稍后的的演示項(xiàng)目用到了 JavaScript)
容器化和 Docker 簡介
摘自 IBM,
容器化意味著封裝或打包軟件代碼及其所有依賴項(xiàng)靴庆,以便它可以在任何基礎(chǔ)架構(gòu)上統(tǒng)一且一致地運(yùn)行。
換句話說怒医,容器化可以將軟件及其所有依賴項(xiàng)打包在一個(gè)自包含的軟件包中炉抒,這樣就可以省略麻煩的配置,直接運(yùn)行稚叹。
舉一個(gè)現(xiàn)實(shí)生活的場景焰薄。假設(shè)你已經(jīng)開發(fā)了一個(gè)很棒的圖書管理應(yīng)用程序,該應(yīng)用程序可以存儲所有圖書的信息扒袖,還可以為別人提供圖書借閱服務(wù)塞茅。
如果列出依賴項(xiàng),如下所示:
- Node.js
- Express.js
- SQLite3
理論上應(yīng)該是這樣季率。但是實(shí)際上還要搞定其他一些事情野瘦。 Node.js 使用了 node-gyp
構(gòu)建工具來構(gòu)建原生加載項(xiàng)。根據(jù) 官方存儲庫 中的 安裝說明蚀同,此構(gòu)建工具需要 Python 2 或 3 和相應(yīng)的的 C/C ++ 編譯器工具鏈缅刽。
考慮到所有這些因素啊掏,最終的依賴關(guān)系列表如下:
- Node.js
- Express.js
- SQLite3
- Python 2 or 3
- C/C++ tool-chain
無論使用什么平臺蠢络,安裝 Python 2 或 3 都非常簡單。在 Linux 上迟蜜,設(shè)置 C/C ++ 工具鏈也非常容易刹孔,但是在 Windows 和 Mac 上,這是一項(xiàng)繁重的工作。
在 Windows 上髓霞,C++ 構(gòu)建工具包有數(shù) GB 之大卦睹,安裝需要花費(fèi)相當(dāng)長的時(shí)間。在 Mac 上方库,可以安裝龐大的 Xcode 應(yīng)用程序结序,也可以安裝小巧的 Xcode 命令行工具 包。
不管安裝了哪一種纵潦,它都可能會在 OS 更新時(shí)中斷徐鹤。實(shí)際上,該問題非常普遍邀层,甚至連官方倉庫都專門提供了 macOS Catalina 的安裝說明返敬。
這里假設(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ù)甚至都不是針對 Windows 預(yù)先構(gòu)建的预厌。
即使你完成了整個(gè)開發(fā),如果負(fù)責(zé)管理服務(wù)器的人員部署流程搞錯了元媚,該怎么辦轧叽?
所有這些問題都可以通過以下方式解決:
- 在與最終部署環(huán)境匹配的隔離環(huán)境(稱為容器)中開發(fā)和運(yùn)行應(yīng)用程序。
- 將你的應(yīng)用程序及其所有依賴項(xiàng)和必要的部署配置放入一個(gè)文件(稱為鏡像)中刊棕。
- 并通過具有適當(dāng)授權(quán)的任何人都可以訪問的中央服務(wù)器(稱為倉庫)共享該鏡像炭晒。
然后,你的同事就可以從倉庫中下載鏡像甥角,可以在沒有平臺沖突的隔離環(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)在的問題是:Docker 在這里扮演什么角色当犯?
正如我之前講的垢村,容器化是一種將一切統(tǒng)一放入盒子中來解決軟件開發(fā)過程中的問題的思想。
這個(gè)想法有很多實(shí)現(xiàn)嚎卫。Docker 就是這樣的實(shí)現(xiàn)嘉栓。這是一個(gè)開放源代碼的容器化平臺,可讓你對應(yīng)用程序進(jìn)行容器化,使用公共或私有倉庫共享它們侵佃,也可以編排它們麻昼。
目前,Docker 并不是市場上唯一的容器化工具馋辈,卻是最受歡迎的容器化工具抚芦。我喜歡的另一個(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è)過程都非常簡單蚕脏。
Docker可在 Mac侦副、Windows 和 Linux 這三個(gè)主要平臺上完美運(yùn)行。在這三者中驼鞭,在 Mac 上的安裝過程是最簡單的秦驯,因此我們從這里開始。
怎樣在 macOS 里安裝 Docker
在 Mac 上挣棕,要做的就是跳轉(zhuǎn)到官方的下載頁面译隘,然后單擊Download for Mac(stable)按鈕。
你會看到一個(gè)常規(guī)的 Apple Disk Image 文件洛心,在該文件的內(nèi)有 Docker 應(yīng)用程序固耘。所要做的就是將文件拖放到 Applications 目錄中。
只需雙擊應(yīng)用程序圖標(biāo)即可啟動 Docker词身。應(yī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),然后按照說明在 Windows 10 上安裝 WSL2墓塌。
- 然后跳轉(zhuǎn)到官方下載頁面 并單擊 Download for Windows(stable) 按鈕瘟忱。
- 雙擊下載的安裝程序,然后使用默認(rèn)設(shè)置進(jìn)行安裝苫幢。
安裝完成后访诱,從開始菜單或桌面啟動 Docker Desktop。Docker 圖標(biāo)應(yīng)顯示在任務(wù)欄上韩肝。
現(xiàn)在触菜,打開 Ubuntu 或從 Microsoft Store 安裝的任何發(fā)行版。執(zhí)行 docker --version
和 docker-compose --version
命令以確保安裝成功哀峻。
也可以從常規(guī)命令提示符或 PowerShell 訪問 Docker涡相,只是我更喜歡使用 WSL2。
怎樣在 Linux 上安裝 Docker
在 Linux 上安裝 Docker 的過程有所不同剩蟀,具體操作取決于你所使用的發(fā)行版催蝗,它們之間差異可能更大。但老實(shí)說育特,安裝與其他兩個(gè)平臺一樣容易(如果不能算更容易的話)丙号。
Windows 或 Mac 上的 Docker Desktop 軟件包是一系列工具的集合,例如Docker Engine
缰冤、Docker Compose
犬缨、Docker Dashboard
、Kubernetes
和其他一些好東西棉浸。
但是怀薛,在 Linux 上,沒有得到這樣的捆綁包迷郑≈α担可以手動安裝所需的所有必要工具。 不同發(fā)行版的安裝過程如下:
- 如果你使用的是 Ubuntu嗡害,則可以遵循官方文檔中的 在 Ubuntu 上安裝 Docker 引擎 部分鼓择。
- 對于其他發(fā)行版,官方文檔中提供了 不同發(fā)行版的安裝指南就漾。
- 如果你使用的發(fā)行版未在文檔中列出呐能,則可以參考從二進(jìn)制文件安裝 Docker 引擎指南。
- 無論參考什么程序抑堡,都必須完成一些非常重要的 Linux 的安裝后續(xù)步驟摆出。
- 完成 docker 安裝后,必須安裝另一個(gè)名為 Docker Compose 的工具首妖。 可以參考官方文檔中的 Install Docker Compose 指南偎漫。
安裝完成后,打開終端并執(zhí)行 docker --version
和 docker-compose --version
以確保安裝成功有缆。
盡管無論使用哪個(gè)平臺象踊,Docker 的性能都很好温亲,但與其他平臺相比,我更喜歡 Linux杯矩。在本文中栈虚,我將使用Ubuntu 20.10 或者 Fedora 33。
一開始就需要闡明的另一件事是史隆,在本文中魂务,我不會使用任何 GUI 工具操作 Docker。
我在各個(gè)平臺用過很多不錯的 GUI 工具泌射,但是介紹常見的 docker 命令是本文的主要目標(biāo)之一粘姜。
初識 Docker - 介紹 Docker 基本知識
已經(jīng)在計(jì)算機(jī)上啟動并運(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)行或過去運(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)識為 128ec8ceab71
。它已經(jīng)在 Exited (0) 13 seconds ago
阴颖,其中 (0)
退出代碼表示在容器運(yùn)行時(shí)未發(fā)生任何錯誤活喊。
現(xiàn)在,為了了解背后發(fā)生的事情量愧,必須熟悉 Docker 體系結(jié)構(gòu)和三個(gè)非臣鼐眨基本的容器化概念,如下所示:
- 容器
- 鏡像
- 倉庫
我已經(jīng)按字母順序列出了這三個(gè)概念偎肃,并且將從列表中的第一個(gè)開始介紹煞烫。
什么是容器?
在容器化世界中累颂,沒有什么比容器的概念更基礎(chǔ)的了滞详。
官方 Docker resources 網(wǎng)站說 -
容器是應(yīng)用程序?qū)拥某橄螅梢詫⒋a和依賴項(xiàng)打包在一起紊馏。容器不虛擬化整個(gè)物理機(jī)料饥,僅虛擬化主機(jī)操作系統(tǒng)。
可以認(rèn)為容器是下一代虛擬機(jī)朱监。
就像虛擬機(jī)一樣岸啡,容器是與主機(jī)系統(tǒng)是彼此之間完全隔離的環(huán)境。它也比傳統(tǒng)虛擬機(jī)輕量得多赫编,因此可以同時(shí)運(yùn)行大量容器巡蘸,而不會影響主機(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è)施之間存在很長的通信鏈炕柔。在虛擬機(jī)內(nèi)部運(yùn)行的應(yīng)用程序可能只擁有少量資源酌泰,因?yàn)?guest 操作系統(tǒng)會占用很大的開銷。
與虛擬機(jī)不同匕累,容器以更智能的方式完成虛擬化工作陵刹。在容器內(nèi)部沒有完整的 guest 操作系統(tǒng),它只是通過容器運(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ī)相比,容器的更輕量虑省,資源占用更少斗搞。
為了說明這一點(diǎn),請看下面的代碼片段:
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/Linux
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
在上面的代碼片段中慷妙,在主機(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ī)狞山,則會發(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é)只讀副本。 鏡像可以通過倉庫進(jìn)行共享驳遵。
過去淫奔,不同的容器引擎具有不同的鏡像格式。但是后來堤结,開放式容器計(jì)劃(OCI)定義了容器鏡像的標(biāo)準(zhǔn)規(guī)范唆迁,該規(guī)范被主要的容器化引擎所遵循。這意味著使用 Docker 構(gòu)建的映像可以與 Podman 等其他運(yùn)行時(shí)一起使用竞穷,而不會有兼容性問題唐责。
容器只是處于運(yùn)行狀態(tài)的鏡像。當(dāng)從互聯(lián)網(wǎng)上獲取鏡像并使用該鏡像運(yùn)行容器時(shí)瘾带,實(shí)際上是在先前的只讀層之上創(chuàng)建了另一個(gè)臨時(shí)可寫層鼠哥。
在本文的后續(xù)部分中,這一概念將變得更加清晰月弛。但就目前而言肴盏,請記住,鏡像是分層只讀文件帽衙,其中保留著應(yīng)用程序所需的狀態(tài)菜皂。
什么是倉庫?
已經(jīng)了解了這個(gè)難題的兩個(gè)非常重要的部分厉萝,即 Containers 和 Images 恍飘。 最后一個(gè)是 Registry。
鏡像倉庫是一個(gè)集中式的位置谴垫,可以在其中上傳鏡像章母,也可以下載其他人創(chuàng)建的鏡像。 Docker Hub 是 Docker 的默認(rèn)公共倉庫翩剪。另一個(gè)非常流行的鏡像倉庫是 Red Hat 的 Quay乳怎。
在本文中,我將使用 Docker Hub 作為首選倉庫前弯。
可以免費(fèi)在 Docker Hub 上共享任意數(shù)量的公共鏡像蚪缀。供世界各地的人們下載免費(fèi)使用秫逝。
除了 Docker Hub 或 Quay,還可以創(chuàng)建自己的鏡像倉庫來托管私有鏡像询枚。計(jì)算機(jī)中還運(yùn)行著一個(gè)本地倉庫违帆,該倉庫緩存從遠(yuǎn)程倉庫提取的鏡像。
Docker 架構(gòu)概述
既然已經(jīng)熟悉了有關(guān)容器化和 Docker 的大多數(shù)基本概念金蜀,那么現(xiàn)在是時(shí)候了解 Docker 作為軟件的架構(gòu)了刷后。
該引擎包括三個(gè)主要組件:
-
Docker 守護(hù)程序: 守護(hù)程序(
dockerd
)是一個(gè)始終在后臺運(yùn)行并等待來自客戶端的命令的進(jìn)程。守護(hù)程序能夠管理各種 Docker 對象渊抄。 -
Docker 客戶端: 客戶端(
docker
)是一個(gè)命令行界面程序尝胆,主要負(fù)責(zé)傳輸用戶發(fā)出的命令。 - REST API: REST API 充當(dāng)守護(hù)程序和客戶端之間的橋梁抒线。使用客戶端發(fā)出的任何命令都將通過 API 傳遞班巩,最終到達(dá)守護(hù)程序渣慕。
根據(jù)官方 文檔,
“ Docker 使用客戶端-服務(wù)器體系結(jié)構(gòu)嘶炭。Docker client 與 Docker daemon 對話,daemon 繁重地構(gòu)建逊桦、運(yùn)行和分發(fā) Docker 容器”眨猎。
作為用戶,通常將使用客戶端組件執(zhí)行命令强经。然后睡陪,客戶端使用 REST API 來訪問長期運(yùn)行的守護(hù)程序并完成工作。
全景圖
好吧匿情,說的夠多了兰迫。 現(xiàn)在是時(shí)候了解剛剛學(xué)習(xí)的所有這些知識如何和諧地工作了。在深入解釋運(yùn)行 docker run hello-world
命令時(shí)實(shí)際發(fā)生的情況之前炬称,看一下下面的圖片:
該圖像是在官方文檔中找到的圖像的略微修改版本汁果。 執(zhí)行命令時(shí)發(fā)生的事件如下: