Docker 入門:簡化 DevOps

已發表: 2022-03-11

如果你喜歡鯨魚,或者只是對快速、輕鬆地將軟件持續交付到生產環境感興趣,那麼我邀請你閱讀這篇介紹性的 Docker 教程。 一切似乎都表明軟件容器是 IT 的未來,所以讓我們快速了解一下容器鯨 Moby Dock 和 Molly。

Docker,由帶有友好外觀的鯨魚的徽標表示

Docker 以帶有友好外觀的鯨魚標誌為代表,是一個開源項目,有助於在軟件容器內部署應用程序。 它的基本功能是由 Linux 內核的資源隔離特性啟用的,但它在其之上提供了一個用戶友好的 API。 第一個版本於 2013 年發布,此後非常受歡迎,並被 eBay、Spotify、百度等許多大玩家廣泛使用。 在上一輪融資中,Docker 獲得了 9500 萬美元的巨額資金,它有望成為 DevOps 服務的主要部分。

運輸貨物類比

Docker 背後的哲學可以用以下簡單的類比來說明。 在國際運輸行業,貨物必須通過叉車、卡車、火車、起重機和輪船等不同方式運輸。 這些貨物有不同的形狀和大小,並且有不同的存儲要求:一袋袋糖、牛奶罐、植物等。從歷史上看,這是一個痛苦的過程,依賴於每個中轉站的人工干預來裝卸。

一輛馬車、一輛皮卡、一輛運輸車,都是運送貨物的

隨著多式聯運集裝箱的採用,這一切都發生了變化。 由於它們採用標準尺寸並且在製造時考慮到了運輸,所有相關的機器都可以設計成以最少的人工干預來處理這些。 密封容器的另一個好處是它們可以保護敏感貨物的內部環境,如溫度和濕度。 因此,運輸業可以不再擔心貨物本身,而是專注於將貨物從 A 運送到 B。

使用海運集裝箱的陸路和海運運輸

這就是 Docker 的用武之地,它為軟件行業帶來了類似的好處。

它與虛擬機有何不同?

乍一看,虛擬機和 Docker 容器可能看起來很相似。 但是,當您查看下圖時,它們的主要區別將變得明顯:

虛擬機(VM)和容器對比圖

除了管理程序之外,在虛擬機中運行的應用程序需要完整的操作系統實例和任何支持庫。 另一方面,容器與主機共享操作系統。 Hypervisor 在某種意義上與容器引擎(在鏡像上表示為 Docker)相當,它管理容器的生命週期。 重要的區別在於容器內運行的進程就像主機上的本地進程一樣,並且不會引入與管理程序執行相關的任何開銷。 此外,應用程序可以重用庫並在容器之間共享數據。

由於兩種技術具有不同的優勢,因此通常會找到結合了虛擬機和容器的系統。 一個完美的例子是 Docker 安裝部分中描述的名為 Boot2Docker 的工具。

碼頭工人架構

碼頭工人架構

在架構圖的頂部有註冊表。 默認情況下,主註冊表是託管公共和官方鏡像的 Docker Hub。 如果他們願意,組織也可以託管他們的私有註冊表。

在右側,我們有圖像和容器。 可以在啟動容器時顯式( docker pull imageName )或隱式從註冊表中下載圖像。 下載圖像後,它會在本地緩存。

容器是圖像的實例——它們是有生命的東西。 可能有多個容器基於同一個鏡像運行。

在中心,有一個負責創建、運行和監控容器的 Docker 守護進程。 它還負責構建和存儲圖像。 最後,在左側有一個 Docker 客戶端。 它通過 HTTP 與守護進程對話。 在同一台機器上使用 Unix 套接字,但可以通過基於 HTTP 的 API 進行遠程管理。

安裝 Docker

有關最新說明,您應該始終參考官方文檔。

Docker 在 Linux 上本地運行,因此根據目標發行版,它可能像sudo apt-get install docker.io一樣簡單。 有關詳細信息,請參閱文檔。 通常在 Linux 中,您會在 Docker 命令前加上sudo ,但為了清楚起見,我們將在本文中跳過它。

由於 Docker 守護程序使用 Linux 特定的內核功能,因此無法在 Mac OS 或 Windows 中本地運行 Docker。 相反,您應該安裝一個名為 Boot2Docker 的應用程序。 該應用程序由 VirtualBox 虛擬機、Docker 本身和 Boot2Docker 管理實用程序組成。 您可以按照 MacOS 和 Windows 的官方安裝說明在這些平台上安裝 Docker。

使用 Docker

讓我們以一個簡單的示例開始本節:

 docker run phusion/baseimage echo "Hello Moby Dock. Hello Molly."

我們應該看到這個輸出:

 Hello Moby Dock. Hello Molly.

然而,幕後發生的事情比你想像的要多得多:

  • 圖像“phusion/baseimage”是從 Docker Hub 下載的(如果它還沒有在本地緩存中)
  • 已啟動基於此映像的容器
  • 命令echo在容器內執行
  • 命令退出時容器已停止

首次運行時,您可能會注意到文本在屏幕上打印之前的延遲。 如果圖像已在本地緩存,則一切都將花費不到一秒鐘的時間。 可以通過運行docker ps -l來檢索有關最後一個容器的詳細信息:

 CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES af14bec37930 phusion/baseimage:latest "echo 'Hello Moby Do 2 minutes ago Exited (0) 3 seconds ago stoic_bardeen

進行下一次潛水

如您所知,在 Docker 中運行一個簡單的命令就像直接在標準終端上運行一樣簡單。 為了說明一個更實際的用例,在本文的其餘部分,我們將了解如何利用 Docker 部署一個簡單的 Web 服務器應用程序。 為簡單起見,我們將編寫一個 Java 程序來處理對 '/ping' 的 HTTP GET 請求並以字符串 'pong\n' 進行響應。

 import java.io.IOException; import java.io.OutputStream; import java.net.InetSocketAddress; import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; import com.sun.net.httpserver.HttpServer; public class PingPong { public static void main(String[] args) throws Exception { HttpServer server = HttpServer.create(new InetSocketAddress(8080), 0); server.createContext("/ping", new MyHandler()); server.setExecutor(null); server.start(); } static class MyHandler implements HttpHandler { @Override public void handle(HttpExchange t) throws IOException { String response = "pong\n"; t.sendResponseHeaders(200, response.length()); OutputStream os = t.getResponseBody(); os.write(response.getBytes()); os.close(); } } }

Dockerfile

在開始構建自己的 Docker 映像之前,最好先檢查 Docker Hub 中是否存在現有映像或您有權訪問的任何私有註冊表。 例如,我們不會自己安裝 Java,而是使用官方鏡像: java:8

要構建映像,首先我們需要決定要使用的基礎映像。 它由FROM指令表示。 在這裡,它是來自 Docker Hub 的 Java 8 官方鏡像。 我們將通過發出COPY指令將其複製到我們的 Java 文件中。 接下來,我們將使用RUN編譯它。 EXPOSE指令表示圖像將在特定端口上提供服務。 ENTRYPOINT是我們希望在啟動基於此映像的容器時執行的指令,並且CMD指示我們將傳遞給它的默認參數。

 FROM java:8 COPY PingPong.java / RUN javac PingPong.java EXPOSE 8080 ENTRYPOINT ["java"] CMD ["PingPong"]

將這些指令保存在一個名為“Dockerfile”的文件中後,我們可以通過執行以下命令來構建相應的 Docker 鏡像:

 docker build -t toptal/pingpong .

Docker 的官方文檔有一節專門介紹有關編寫 Dockerfile 的最佳實踐。

運行容器

鏡像構建完成後,我們可以將其作為容器賦予生命。 我們可以通過多種方式運行容器,但讓我們從一種簡單的方式開始:

 docker run -d -p 8080:8080 toptal/pingpong

其中-p [port-on-the-host]:[port-in-the-container]分別表示主機和容器上的端口映射。 此外,我們通過指定-d告訴 Docker 在後台將容器作為守護進程運行。 您可以通過嘗試訪問“http://localhost:8080/ping”來測試 Web 服務器應用程序是否正在運行。 請注意,在使用 Boot2docker 的平台上,您需要將“localhost”替換為運行 Docker 的虛擬機的 IP 地址。

在 Linux 上:

 curl http://localhost:8080/ping

在需要 Boot2Docker 的平台上:

 curl $(boot2docker ip):8080/ping

如果一切順利,您應該會看到響應:

 pong

萬歲,我們的第一個自定義 Docker 容器是活生生的! 我們還可以以交互模式-i -t啟動容器。 在我們的例子中,我們將覆蓋入口點命令,因此我們會看到一個 bash 終端。 現在我們可以執行我們想要的任何命令,但是退出容器會停止它:

 docker run -i -t --entrypoint="bash" toptal/pingpong

還有更多選項可用於啟動容器。 讓我們再介紹幾個。 例如,如果我們想在容器外持久化數據,我們可以使用-v與容器共享主機文件系統。 默認情況下,訪問模式是讀寫,但可以通過將:ro附加到容器內捲路徑來更改為只讀模式。 當我們需要在容器內使用任何安全信息(如憑證和私鑰)時,卷尤其重要,這些信息不應存儲在映像中。 此外,它還可以防止數據重複,例如通過將本地 Maven 存儲庫映射到容器來避免您兩次下載 Internet。

Docker 還具有將容器鏈接在一起的能力。 即使沒有任何端口暴露,鏈接的容器也可以相互通信。 它可以通過–link other-container-name來實現。 以下是結合上述參數的示例:

 docker run -p 9999:8080 --link otherContainerA --link otherContainerB -v /Users/$USER/.m2/repository:/home/user/.m2/repository toptal/pingpong

其他容器和鏡像操作

毫不奇怪,可以應用於容器和圖像的操作列表相當長。 為簡潔起見,讓我們看一下其中的幾個:

  • stop - 停止正在運行的容器。
  • start - 啟動一個停止的容器。
  • commit - 根據容器的更改創建新圖像。
  • rm - 移除一個或多個容器。
  • rmi - 刪除一個或多個圖像。
  • ps - 列出容器。
  • 圖像 - 列出圖像。
  • exec - 在正在運行的容器中運行命令。

最後一個命令對於調試目的可能特別有用,因為它允許您連接到正在運行的容器的終端:

 docker exec -i -t <container-id> bash

面向微服務世界的 Docker Compose

如果您擁有的不僅僅是幾個相互連接的容器,那麼使用像 docker-compose 這樣的工具是有意義的。 在配置文件中,您描述瞭如何啟動容器以及它們應該如何相互鏈接。 無論涉及的容器數量及其依賴關係如何,您都可以使用一個命令啟動並運行所有容器: docker-compose up

碼頭工人在野外

讓我們看看項目生命週期的三個階段,看看我們友好的鯨魚如何提供幫助。

發展

Docker 可幫助您保持本地開發環境的清潔。 無需安裝多個版本的不同服務,例如 Java、Kafka、Spark、Cassandra 等,您可以在必要時啟動和停止所需的容器。 您可以更進一步,並排運行多個軟件堆棧,避免混淆依賴版本。

使用 Docker,您可以節省時間、精力和金錢。 如果您的項目設置起來非常複雜,請“dockerise”它。 經歷一次創建 Docker 鏡像的痛苦,從這一點開始,每個人都可以快速啟動一個容器。

您還可以在本地(或在 CI)上運行“集成環境”,並將存根替換為在 Docker 容器中運行的真實服務。

測試/持續集成

使用 Dockerfile,很容易實現可重現的構建。 Jenkins 或其他 CI 解決方案可以配置為為每個構建創建一個 Docker 映像。 您可以將部分或全部圖像存儲在私有 Docker 註冊表中以供將來參考。

使用 Docker,您只需測試需要測試的內容並將環境排除在外。 在正在運行的容器上執行測試可以幫助保持事情的可預測性。

擁有軟件容器的另一個有趣的特性是,很容易使用相同的開發設置來分拆從機。 它對於集群部署的負載測試特別有用。

生產

Docker 可以成為開發人員和運維人員之間的通用接口,消除了摩擦源。 它還鼓勵在管道的每個步驟中使用相同的圖像/二進製文件。 此外,能夠在沒有環境差異的情況下部署經過全面測試的容器有助於確保在構建過程中不會引入錯誤。

您可以將應用程序無縫遷移到生產環境中。 曾經是一個乏味且不穩定的過程現在可以很簡單:

 docker stop container-id; docker run new-image

如果在部署新版本時出現問題,您可以隨時快速回滾或更改到其他容器:

 docker stop container-id; docker start other-container-id

…保證不會留下任何混亂或使事情處於不一致的狀態。

概括

Docker 所做工作的一個很好的總結包含在它自己的座右銘中:構建、交付、運行。

  • 構建 - Docker 允許您從微服務構建應用程序,無需擔心開發和生產環境之間的不一致,也無需鎖定任何平台或語言。
  • Ship - Docker 允許您設計應用程序開發、測試和分發的整個週期,並使用一致的用戶界面對其進行管理。
  • 運行 - Docker 使您能夠在各種平台上安全可靠地部署可擴展服務。

和鯨魚一起游泳,玩得開心!

這項工作的一部分靈感來自 Adrian Mouat 所著的《Using Docker》一書。