標籤:

每天5分鐘玩轉Docker容器技術(二)

每天5分鐘玩轉Docker容器技術(一)

容器核心知識

本篇通過 Docker 討論容器的核心知識。

概述

容器核心知識主要回答有關容器 What、Why 和 How 三個問題。其中 How 是重點,將從架構、鏡像、容器、網路和存儲幾個方面進行講解。

What - 什麼是容器?

容器是一種輕量級、可移植、自包含的軟體打包技術,使應用程序可以在幾乎任何地方以相同的方式運行。開發人員在自己筆記本上創建並測試好的容器,無需任何修改就能夠在生產系統的虛擬機、物理伺服器或公有雲主機上運行。

容器與虛擬機

談到容器,就不得不將它與虛擬機進行對比,因為兩者都是為應用提供封裝和隔離。

容器由兩部分組成:

  1. 應用程序本身
  2. 依賴:比如應用程序需要的庫或其他軟體

容器在 Host 操作系統的用戶空間中運行,與操作系統的其他進程隔離。這一點顯著區別於的虛擬機。

傳統的虛擬化技術,比如 VMWare, KVM, Xen,目標是創建完整的虛擬機。為了運行應用,除了部署應用本身及其依賴(通常幾十 MB),還得安裝整個操作系統(幾十 GB)。

下圖展示了二者的區別。

如圖所示,由於所有的容器共享同一個 Host OS,這使得容器在體積上要比虛擬機小很多。另外,啟動容器不需要啟動整個操作系統,所以容器部署和啟動速度更快,開銷更小,也更容易遷移。

Why - 為什麼需要容器?

為什麼需要容器?容器到底解決的是什麼問題?

簡要的答案是:容器使軟體具備了超強的可移植能力

容器解決的問題

我們來看看今天的軟體開發面臨著怎樣的挑戰?

如今的系統在架構上較十年前已經變得非常複雜了。以前幾乎所有的應用都採用三層架構(Presentation/Application/Data),系統部署到有限的幾台物理伺服器上(Web Server/Application Server/Database Server)。

而今天,開發人員通常使用多種服務(比如 MQ,Cache,DB)構建和組裝應用,而且應用很可能會部署到不同的環境,比如虛擬伺服器,私有雲和公有雲。

一方面應用包含多種服務,這些服務有自己所依賴的庫和軟體包;另一方面存在多種部署環境,服務在運行時可能需要動態遷移到不同的環境中。這就產生了一個問題:

如何讓每種服務能夠在所有的部署環境中順利運行?

於是我們得到了下面這個矩陣:

各種服務和環境通過排列組合產生了一個大矩陣。開發人員在編寫代碼時需要考慮不同的運行環境,運維人員則需要為不同的服務和平台配置環境。對他們雙方來說,這都是一項困難而艱巨的任務。

如何解決這個問題呢?

聰明的技術人員從傳統的運輸行業找到了答案。

幾十年前,運輸業面臨著類似的問題。

每一次運輸,貨主與承運方都會擔心因貨物類型的不同而導致損失,比如幾個鐵桶錯誤地壓在了一堆香蕉上。另一方面,運輸過程中需要使用不同的交通工具也讓整個過程痛苦不堪:貨物先裝上車運到碼頭,卸貨,然後裝上船,到岸後又卸下船,再裝上火車,到達目的地,最後卸貨。一半以上的時間花費在裝、卸貨上,而且搬上搬下還容易損壞貨物。

這同樣也是一個 NxM 的矩陣。

幸運的是,集裝箱的發明解決這個難題。

任何貨物,無論鋼琴還是保時捷,都被放到各自的集裝箱中。集裝箱在整個運輸過程中都是密封的,只有到達最終目的地才被打開。標準集裝箱可以被高效地裝卸、重疊和長途運輸。現代化的起重機可以自動在卡車、輪船和火車之間移動集裝箱。集裝箱被譽為運輸業與世界貿易最重要的發明。

Docker 將集裝箱思想運用到軟體打包上,為代碼提供了一個基於容器的標準化運輸系統。Docker 可以將任何應用及其依賴打包成一個輕量級、可移植、自包含的容器。容器可以運行在幾乎所有的操作系統上。

其實,「集裝箱」 和 「容器」 對應的英文單詞都是 「Container」。

「容器」 是國內約定俗成的叫法,可能是因為容器比集裝箱更抽象,更適合軟體領域的原故吧。

我個人認為:在老外的思維中,「Container」 只用到了集裝箱這一個意思,Docker 的 Logo 不就是一堆集裝箱嗎?

Docker 的特性

我們可以看看集裝箱思想是如何與 Docker 各種特性相對應的。

容器的優勢

對於開發人員 - Build Once, Run Anywhere

容器意味著環境隔離和可重複性。開發人員只需為應用創建一次運行環境,然後打包成容器便可在其他機器上運行。另外,容器環境與所在的 Host 環境是隔離的,就像虛擬機一樣,但更快更簡單。

對於運維人員 - Configure Once, Run Anything

只需要配置好標準的 runtime 環境,伺服器就可以運行任何容器。這使得運維人員的工作變得更高效,一致和可重複。容器消除了開發、測試、生產環境的不一致性。

How - 容器是如何工作的?

接下來學習容器核心知識的最主要部分。

我們首先會介紹 Docker 的架構,然後分章節詳細討論 Docker 的鏡像、容器、網路和存儲。

Docker 架構詳解

Docker 的核心組件包括:

  1. Docker 客戶端 - Client
  2. Docker 伺服器 - Docker daemon
  3. Docker 鏡像 - Image
  4. Registry
  5. Docker 容器 - Container

Docker 架構如下圖所示:

Docker 採用的是 Client/Server 架構。客戶端向伺服器發送請求,伺服器負責構建、運行和分發容器。客戶端和伺服器可以運行在同一個 Host 上,客戶端也可以通過 socket 或 REST API 與遠程的伺服器通信。

Docker 客戶端

最常用的 Docker 客戶端是 docker 命令。通過 docker 我們可以方便地在 Host 上構建和運行容器。

docker 支持很多操作(子命令),後面會逐步用到。

除了 docker 命令行工具,用戶也可以通過 REST API 與伺服器通信。

Docker 伺服器

Docker daemon 是伺服器組件,以 Linux 後台服務的方式運行。

Docker daemon 運行在 Docker host 上,負責創建、運行、監控容器,構建、存儲鏡像。

默認配置下,Docker daemon 只能響應來自本地 Host 的客戶端請求。如果要允許遠程客戶端請求,需要在配置文件中打開 TCP 監聽,步驟如下:

1.編輯配置文件 /etc/systemd/system/multi-user.target.wants/docker.service,在環境變數 ExecStart 後面添加 -H tcp://0.0.0.0,允許來自任意 IP 的客戶端連接。

如果使用的是其他操作系統,配置文件的位置可能會不一樣。

2.重啟 Docker daemon。

3.伺服器 IP 為 192.168.56.102,客戶端在命令行里加上 -H 參數,即可與遠程伺服器通信。

info 子命令用於查看 Docker 伺服器的信息。

Docker 鏡像

可將 Docker 鏡像看成只讀模板,通過它可以創建 Docker 容器。

例如某個鏡像可能包含一個 Ubuntu 操作系統、一個 Apache HTTP Server 以及用戶開發的 Web 應用。

鏡像有多種生成方法:

  1. 可以從無到有開始創建鏡像
  2. 也可以下載並使用別人創建好的現成的鏡像
  3. 還可以在現有鏡像上創建新的鏡像

我們可以將鏡像的內容和創建步驟描述在一個文本文件中,這個文件被稱作 Dockerfile,通過執行 docker build <docker-file> 命令可以構建出 Docker 鏡像,後面我們會討論。

Docker 容器

Docker 容器就是 Docker 鏡像的運行實例。

用戶可以通過 CLI(docker)或是 API 啟動、停止、移動或刪除容器。可以這麼認為,對於應用軟體,鏡像是軟體生命周期的構建和打包階段,而容器則是啟動和運行階段。

Registry

Registry 是存放 Docker 鏡像的倉庫,Registry 分私有和公有兩種。

Docker Hub(hub.docker.com/) 是默認的 Registry,由 Docker 公司維護,上面有數以萬計的鏡像,用戶可以自由下載和使用。

出於對速度或安全的考慮,用戶也可以創建自己的私有 Registry。後面我們會學習如何搭建私有 Registry。

docker pull 命令可以從 Registry 下載鏡像。 docker run 命令則是先下載鏡像(如果本地沒有),然後再啟動容器。

Docker 組件如何協作?

一個完整的例子

還記得我們運行的第一個容器嗎?現在通過它來體會一下 Docker 各個組件是如何協作的。

容器啟動過程如下:

  1. Docker 客戶端執行 docker run 命令。
  2. Docker daemon 發現本地沒有 httpd 鏡像。
  3. daemon 從 Docker Hub 下載鏡像。
  4. 下載完成,鏡像 httpd 被保存到本地。
  5. Docker daemon 啟動容器。

docker images 可以查看到 httpd 已經下載到本地。

docker ps 或者 docker container ls 顯示容器正在運行。

小結

Docker 借鑒了集裝箱的概念。標準集裝箱將貨物運往世界各地,Docker 將這個模型運用到自己的設計哲學中,唯一不同的是:集裝箱運輸貨物,而 Docker 運輸軟體。

每個容器都有一個軟體鏡像,相當於集裝箱中的貨物。容器可以被創建、啟動、關閉和銷毀。和集裝箱一樣,Docker 在執行這些操作時,並不關心容器里到底裝的什麼,它不管裡面是 Web Server,還是 Database。

用戶不需要關心容器最終會在哪裡運行,因為哪裡都可以運行。

開發人員可以在筆記本上構建鏡像並上傳到 Registry,然後 QA 人員將鏡像下載到物理或虛擬機做測試,最終容器會部署到生產環境。

使用 Docker 以及容器技術,我們可以快速構建一個應用伺服器、一個消息中間件、一個資料庫、一個持續集成環境。因為 Docker Hub 上有我們能想到的幾乎所有的鏡像。

不知大家是否意識到,潘多拉盒子已經被打開。容器不但降低了我們學習新技術的門檻,更提高了效率。

如果你是一個運維人員,想研究負載均衡軟體 HAProxy,只需要執行 docker run haproxy,無需繁瑣的手工安裝和配置既可以直接進入實戰。

如果你是一個開發人員,想學習怎麼用 django 開發 Python Web 應用,執行 docker run django,在容器里隨便折騰吧,不用擔心會搞亂 Host 的環境。

不誇張的說:容器大大提升了 IT 人員的幸福指數。

最小的鏡像

鏡像是 Docker 容器的基石,容器是鏡像的運行實例,有了鏡像才能啟動容器。

本章內容安排如下:

  1. 首先通過研究幾個典型的鏡像,分析鏡像的內部結構。
  2. 然後學習如何構建自己的鏡像。
  3. 最後介紹怎樣管理和分發鏡像。

鏡像的內部結構

為什麼我們要討論鏡像的內部結構?

如果只是使用鏡像,當然不需要了解,直接通過 docker 命令下載和運行就可以了。

但如果我們想創建自己的鏡像,或者想理解 Docker 為什麼是輕量級的,就非常有必要學習這部分知識了。

我們從一個最小的鏡像開始吧。

hello-world - 最小的鏡像

hello-world 是 Docker 官方提供的一個鏡像,通常用來驗證 Docker 是否安裝成功。

我們先通過 docker pull 從 Docker Hub 下載它。

docker images 命令查看鏡像的信息。

hello-world 鏡像竟然還不到 2KB!

通過 docker run 運行。

其實我們更關心 hello-world 鏡像包含哪些內容。

Dockerfile 是鏡像的描述文件,定義了如何構建 Docker 鏡像。Dockerfile 的語法簡潔且可讀性強,後面我們會專門討論如何編寫 Dockerfile。

hello-world 的 Dockerfile 內容如下:

只有短短三條指令。

  1. FROM scratch

    此鏡像是從白手起家,從 0 開始構建。
  2. COPY hello /

    將文件「hello」複製到鏡像的根目錄。
  3. CMD ["/hello"]

    容器啟動時,執行 /hello

鏡像 hello-world 中就只有一個可執行文件 「hello」,其功能就是列印出 「Hello from Docker ......」 等信息。

/hello 就是文件系統的全部內容,連最基本的 /bin,/usr, /lib, /dev 都沒有。

hello-world 雖然是一個完整的鏡像,但它並沒有什麼實際用途。通常來說,我們希望鏡像能提供一個基本的操作系統環境,用戶可以根據需要安裝和配置軟體。

這樣的鏡像我們稱作 base 鏡像。

作者:cloudman6

原文

更多技術乾貨敬請關注云棲社區知乎機構號:阿里云云棲社區 - 知乎


推薦閱讀:

Docker的一個簡單示例
現在國內、國際市場上有哪些docker的容器管理平台?
區塊鏈日報:Golang | 一個go語言實現的短鏈接服務;Docker | 搭建一個私有Docker Registry服務
Azure Container Service(ACS)簡介
【技術總結】一起聊聊Kubernetes

TAG:Docker | 容器 |