Docker 概念與小實作

在本文中,我深入介紹了 Docker 的核心概念與其與傳統虛擬機的不同。透過 Docker,我們可以更高效地管理應用程式與其依賴,實現快速部署與擴展。我探討了 Docker 如何透過容器技術改進資源利用率和環境一致性,並且解釋了如何快速安裝和使用 Docker 進行開發。

Docker 概念與小實作
Photo by Rubaitul Azad / Unsplash
本文會撰寫 Docker 的概念原理,以及如何快速用 Docker 小小實作。

Docker 是在虛擬機之後衍生的新的解決方案,因此要了解 Docker 必須先了解虛擬機是甚麼,虛擬機又解決甚麼問題。


一、虛擬機是什麼

虛擬機是在現有的作業系統中再建立一個新的虛擬的作業系統,並用其來處理事情

我們在使用 VirtualBox 或 Vmware 等虛擬機的服務時,都必須要先設定 CPU 以及記憶體的大小,就像下圖這樣。

圖片來源: Day02-容器化管理工具(Docker)

那這些虛擬化 CPU 跟 記憶體 是從那裡來呢?

就是從電腦的 CPU 跟記憶體來,所以我們可以知道虛擬機就是要把整個硬體都虛擬化,最後再藉由這些虛擬化的硬體去安裝系統,但這樣就會非常吃電腦自身的資源。

使用這些虛擬機時有沒有發現一點,每次要啟動這些系統時都會耗時非常久,這都是因為要把整個硬體層都虛擬化的原因,接下來我們可以簡單的看一下虛擬機的架構:

圖片來源: Day02-容器化管理工具(Docker)

上面的架構圖我們可以很輕鬆地看到每個應用程式都必須要先依附在一個系統上

所以假如今天有三個應用程式每一種都要依附在不同的系統上的話,就必須要虛擬化三個硬體層跑三個系統了,這也會造成虛擬機非常吃電腦自身的資源。

所以虛擬機的作用通常都是用來跑一個全新的作業系統來做事情,不會拿來當作是伺服器用來跑應用程式的工具。


二、虛擬機解決了什麼問題

1. 不同硬體上創造同樣環境成功運行同一支程式

虛擬化要做的就是模擬出一個環境,讓程式可以在不同硬體上執行時都以為自己在同一個環境中執行

以往「我寫好了一支程式,在我的電腦上可以正常運作,但搬到你的電腦上可能就爆掉」。會有這樣的問題是因為:每台電腦的作業系統與硬體配置不盡相同,我的程式可能剛好只跟我電腦上的環境相容。

而虛擬化要做的就是模擬出一個環境,讓程式可以在不同硬體上執行時,都以為自己在同一個環境中執行。

2. 有效的分配與管理硬體資源

如果你有一堆 CPU、RAM 和 Disk Storage,如何有效地管理與分配硬體資源

當你只有 10 台電腦時你根本不用煩惱這個問題,但如果你有 1000 台電腦時鐵定會衍生出很多問題。這是虛擬化技術想解決的核心問題之一 。

而作為此類虛擬化技術的主角就是所謂的**虛擬機(Virutal Machine,VM)**,虛擬機操作起來就跟一般電腦一樣。以作業系統為單位的虛擬化技術強調將硬體資源抽象化後可自由分配給上層的虛擬機使用,使用者可以自由決定虛擬機要使用那種作業系統?分多少的 CPU 與RAM? 而作業系統上運行各種應用程式 (App) 。

作業系統虛擬化技術會有一個 Hypervisor 的角色負責管理與分配硬體資源,我們根據管理硬體資源的規模可以概分成以下

I. 雲級別的 Hypervisor

硬體通常是由機架式伺服器組成,其管理的硬體資源包含處理器、記憶體、存儲設備與網路卡等各種硬體,Hypervisor 負責將其抽象化或邏輯化供上層的 VM 使用。

一般科技公司由於研發與業務需求,需要大量的硬體資源,於是便可以建構一台私有雲,以便管理與分配這些硬體資源。

而全球性的科技巨頭其規模更大,像是 Amazon 的 AWS、Google 的GCP、Microsoft 的 Azure 除了把硬體資源分給自己員工使用之外,還可以將其分享給其他人使用,也就成為了所謂的公有雲了。

II. 作業系統級別的 Hypervisor

例如 VirtualBox,有些 Hypervisor 可以在 host OS 級別的機器上運行,不需要大量的 CPU 或 RAM 即可運行,這種解決方案通常是給有特殊需求的使用者,例如:

  • 開發人員同時需要測試多個版本的 Android 系統
  • MacOS 可以用 Parallels Desktop 灌 Windows 系統,以便使用 PowerPoint 之類的 Windows 應用程式
  • 電玩遊戲的 Youtuber 會用 Genymotion 之類的 Android 模擬器,邊玩遊戲邊錄製視頻 (Genymotion 背後也是使用 VirtualBox 來模擬 Linux 環境)

三、Docker 跟虛擬機的差別

1. 虛擬機

  • 讓你在作業系統(Host OS)上面再裝一個作業系統(Guest OS),然後讓兩個作業系統彼此不會打架的平台
  • 在系統層級的虛擬化技術,在這我們叫它稱虛擬機器(Virtual machine) 代表如 Virtual Box

圖片來源:Docker 基礎教學與介紹101. 何謂容器虛擬化

2. Docker

  • 在作業系統層上虛擬化,透過 Container Manager 直接將一個應用程式所需的程式碼、函式庫打包,建立資源控管機制隔離各個容器,並分配 Host OS 上的系統資源
  • 透過容器,應用程式不需要再另外安裝作業系統(Guest OS)也可以執行
  • 是在作業系統層級的虛擬化技術,此稱容器(Container) 代表如 Docker。

圖片來源:Docker 基礎教學與介紹101. 何謂容器虛擬化


四、Docker 是什麼

容器技術 Container 技術則是一種以應用程式為中心的虛擬化技術。

本質上沒什麼變,指的是將應用程式 (application)、運行環境 (running environment)、函式庫 (library),這些 run 你的 application 必要、缺一不可的東西,全部包在一起。類似 android studio 將開發環境打包成 apk 的概念。

Docker 的思想來自於集裝箱,集裝箱解決了什麼問題?

在一艘大船上,可以把貨物規整的擺放起來。並且各種各樣的貨物被集裝箱標準化了,集裝箱和集裝箱之間不會互相影響。那麼我就不需要專門運送水果的船和專門運送化學品的船了。只要這些貨物在集裝箱裡封裝的好好的,那我就可以用一艘大船把他們都運走。

沒有獨立的操作系統,那還能起到VM的作用嗎?

這個問題可以反過來想:真的有必要隔離出一個完整的操作系統嗎?

很多時候其實我們只是想減輕運維的負擔,為程序提供一個統一的「運行環境」。這所謂的「運行環境」具體來說是系統庫、運行時、第三方庫等等的文件。

如果我們僅僅想保持文件環境的一致,只需要提供一份獨立的磁盤鏡像即可並不需要替換操作系統

當然,一個程序也不只是看到文件,他還看到當前所有進程、網絡端口使用等等的一系列系統信息,我們要同時能夠隔離這些系統信息,保證每個進程都看到、以為自己是獨立運行的。

所有這些,其實都不至於非得另起一個操作系統,因為內核本身就提供一些基礎設施(namespace、cgroup等)來達到這一效果,這也是 docker 得以實現的基礎。


五、Docker 的原理

使用 Docker 時最重要的三個元素:映像檔、容器、倉庫
  • 用一個簡單的比喻來解釋:
  1. 如果映像檔是一個做蛋糕的模具
  2. 容器則是用該模具烤出來的蛋糕
  3. 而倉庫是用來集中放置模具們的收納櫃

1. 映像檔 Image

Docker 映像檔是一個模板,用來重複產生容器實體。

例如:一個映像檔裡可以包含一個完整的 MySQL 服務、一個 Golang 的編譯環境、或是一個 Ubuntu 作業系統。

透過 Docker 映像檔,我們可以快速的產生可以執行應用程式的容器

而 Docker 映像檔可以透過撰寫由命令行構成的 Dockerfile 輕鬆建立,或甚至可以從公開的地方下載已經做好的映像檔來使用。

舉例來說,如果我今天想要一個 node.js 的執行環境跑我寫好的程式,我可以直接到上 DockerHub 找到相對應的 node.js 映像檔 ,而不需要自己想辦法打包一個執行環境。

這邊的映像檔就可以想成是 VM 上的 Guest OS

差別在於映像檔僅包含最小可運行的系統,而且更重要的是映像檔本身是唯讀不可修改。

這邊可能會有疑惑,既然不能修改映像檔,那不就意味著不能修改環境?

事實上還是可以,那是因為 Docker 本身提供了容器的架構讓使用者可以自行設定並修改,如果有需要,還可以自行建構成新的映像檔放在私有倉庫。

而為了避免映像檔衝突,公有雲端為每個映像檔提供了獨有的 ID (例如 Ubuntu 14.04 的 ID = 8251da35e7a7),只有是同樣的 ID 就可以確保所下載的映像檔是官方所發行的,而不會跟私有的映像檔有所以衝突。

2. 容器 Container

容器是用映像檔建立出來的執行實例
  • 它可以被啟動、開始、停止、刪除
  • 每個容器都是相互隔離、保證安全的平台
  • 可以把容器看做是一個執行的應用程式加上執行它的簡易版 Linux 環境
  • 包括 root 使用者權限、程式空間、使用者空間和網路空間等

3. 倉庫 Repository

倉庫(Repository)是集中存放映像檔檔案的場所
  • 也可以想像成存放蛋糕模具的大本營
  • 倉庫註冊伺服器(Registry)上則存放著多個倉庫
  • 最大的公開倉庫註冊伺服器是上面提到過的 Docker Hub
    • 存放了數量龐大的映像檔供使用者下載,我們可以輕鬆在上面找到各式各樣現成實用的映像檔
  • 而 Docker 倉庫註冊伺服器的概念就跟 Github 類似
    • 你可以在上面建立多個倉庫,然後透過 push、pull 的方式上傳、存取

六、Docker 相較虛擬機解決了甚麼問題

1. 容器技術與虛擬化技術的比較

以代表性服務為例,Docker 是以 App 為單位的虛擬化技術。VMWare 是以作業系統為單位的虛擬化技術。

I. 容器虛擬化技術不是用來取代作業系統虛擬化技術的新技術
  • 作業系統虛擬化技術可以很容易地部署好一台 VM,但仍需安裝各種執行環境所需要的程式並設定正確的環境參數才能執行 App
  • 也就是說,在安裝作業系統之後與執行 App 之前仍有需多環境建置工作。

Docker 的主要優勢在於透過 Image 和 Container 大幅簡化並自動化這些工作。

II. 容器並不是 VM
  • 容器是一個封裝了相依性資源與 App 的執行環境
  • VM 則是一個配置好 CPU、RAM 與 Storage 的作業系統。
III. 容器虛擬化技術以共享 Host OS Kernel 的方式來執行 App
  • 容器依賴 Host OS的 核心 (kernel) 來運行容器
    • 因此 Windows 容器必須在 Windows OS 上運行
    • Linux 容器必須在 Linux-base OS 上運行。
IV. 實例 (instance)
  • 容器 (container) 是執行環境的實例 (instance)
  • VM 是作業系統的實例 (instance)
V. 容器化技術更面向 DevOps 的需求

容器化技術通常會與 Kubernetes 或 Docker Swarm 之類的容器調度技術整合,再配合 Drone、Jenkins 之類的 CI/CD 工具,使其可以將系統的部署工作完全自動化處理,有效降低後端維運的成本

傳統的作業系統虛擬化技術並不是處理這種議題的主要技術,雖然像 VMware 這類的工具也會有附載平衡、故障轉移、復電重啟之類的自動化維運機制,但其保障的是作業系統層級的維運需求。

VI. 硬體資源的分配
  • Container 因為是以 App 為單位,需要的硬體資源更少可以更細緻地使用硬體資源
  • 沒有 Docker 之前,我們可能為了部署一個 App 而為其配置了一台 VM,其作業系統又佔用了過多的 CPU、Storage與 RAM
  • 有了 Docker 之後,我們只要為一個 App 配置一個 Container 即可
VII. 應用程式的獨立性
  • Container 間是彼此隔離的,所以我們可以在一台 VM 下同時執行 Nodejs 5, Nodejs 6, Nodejs 7 等各種版本的 Nodejs container 卻不會產生衝突
  • 在沒有 Docker 之前,我們會為了避免衝突為不同版本的 Nodejs 建置一台獨立的 VM,這會造成不少浪費
VIII. VM 簡化了硬體資源配置與作業系統安裝的工作
  • 既使如此 VM 還有許多執行環境建置的工作要處理,才能順利部署與執行應用程式 (App)
  • Container 幫我們自動化地走完這最後一哩路
  • 也就是說,Container 簡化了介於作業系統與應用程式 (App) 之間的環境建置工作

2. 容器技術的相對優勢

改善虛擬機器因為需要裝 Guest OS 導致啟動慢、佔較大記憶體的問題
  • 一台主機能開更多個 Docker 產生的虛擬環境
  • 複製一台 VM 的話 ,大約要花 二個小時
  • 開啟一台 VM 也要花個 30 秒以上
  • 改用 Docker 之後,重製一個 Image 大約也只要 20 分鐘
  • 開啟 container 不到 3 秒就完成了
容器虛擬化技術想解決的核心問題簡言之是環境建置的問題

我們可能使用 Matlab 或 Python 來開發機器學習或人工智慧演算法,再用 C# 或 Golang 或 Node.js 去實作後端的 API 與邏輯,資料庫可能是 Mongo、MySQL、Oracle 或 Reids。

正所謂一沙一世界,每個技術雖然在整個專案裡只扮演一部分的角色,卻都有其生態性與版本相容性問題,貿然地升級版本都可能導致系統出錯,就像大多數的問題一樣,很多時候分開處理都好好的,合再一起就壞掉了,工程師們戒慎慌恐地處理這些交互影響的執行環境建置問題,直到容器化技術的出現才讓他們解脫。

與其為每一個軟體系統建置執行環境,倒不如讓整個軟體系統的執行環境是可以搬遷與重複利用的

這是容器化技術解決問題的方式。因此容器(Container)就是一種可以搬遷與重複利用的執行環境。

下圖為一個以Docker作為容器虛擬化技術的示意圖:

圖片來源: 虛擬機(VM)與容器(Container)之技術價值與比較分析

I. 容器(Container)
  • 以應用程式(App)為單位的虛擬化技術,應用程式與其相依性資源(Dependency) 會被封裝在容器(Container)中
  • 使其可以重複利用與搬遷,容器間彼此獨立運行,互不干擾
II. 相依性資源(Dependency)
  • 官方是以 bins/libs 稱之也就是二進位執行檔 (binaries) 與函數庫 (libraries)
  • 它們可能是MySQL、Nodejs、.Net Framework、程式庫、DLL、編譯器等運行App所需要的執行環境
  • 相依性資源大抵上可以說是我們前面提到的解決方案堆疊 (solution stack)或軟體棧 (software stack)
III. Docker Engine
  • 類比 Hypervisor 在硬體的上層建置一個可以運行虛擬機的環境,Docker 也同樣需要在 Host OS 上建置一個可以運行容器的環境
  • Docker Engine 就是這樣的角色,其可將 Docker Image 轉換成Container
  • Docker Image 就如同傳統虛擬化技術將 OS 封裝成 *.iso 映像檔(image)
  • Docker 也將 Dependency 封裝成 Docker Image 使其可重複利用與移植。

Docker 稱這是一種 Microservices(微服務)的新軟體架構,將組成一個應用系統的每一個 Stack,拆解成許多小型服務,例如 Apache 服務、 MySQL 服務、Node.js 服務、Ruby 服務,每一個服務都是包在Container 裡的一隻程式,例如 MySQL 服務就是部署在 Container 內的 MySQL。

這麼做的好處是可以建立一個鬆散耦合的彈性應用程式架構,也能輕易地抽換其中一個 Container,例如要升級 MySQL,只需要重新載入新版 MySQL 的 Container 映象檔,就可以完成資料庫升級,不用將整套應用系統停機。


七、Docker 的應用場景

建構一個典型的 LAMP (Linux + Apache + MySQL + PHP) 伺服器架構,不用不同環境設定一堆
  • 一般作法就是分別安裝各自軟體和其依賴程式庫,安裝後再進行繁瑣的環境設定,調整其相容性,並進行聯合除錯,一大堆。
  • 而 Docker 就是為了簡化這些服務的建構和設定,開發人員可建構一套用來開發的容器集合,開發完成後再透過 Docker 在任何實體、虛擬機中輕鬆移植部屬,提高整體效率
在不同電腦上想要安裝使用相同的工具
  • 使用 VM 就可以解決了,做好第一次安裝苦工,做成映像檔,以後就是利用映像檔複製出新的 VM
  • 過往會遇到的麻煩
    • 想要玩個新技術,但要先裝環境和函式庫,都弄好半天又過去了,還沒玩到新技術心就涼了。
    • 上述環境在公司弄好了,回家也想要玩,又要再弄一次。
    • 上述環境不小心裝壞了,比如說 mac 上同時裝 python 2 和 python 3,搞到自己原本的環境都爛了
    • 整個專案要在自己的電腦,測試環境跑過,在上正式環境,部署之前把環境都弄成一模一樣就飽了
    • 安裝時都有乖乖寫安裝手冊,過了半年要裝新的環境,卻發現半年前的函式庫抓不到了
    • 設備移機…...

八、Docker 快速安裝

  1. Mac 安裝
  2. docker pull node
  3. docker run -it node

簡單地說,以上指令就是我們「從 image node:12.19 啟動了一個 container,並且開啟了它的輸入/輸出,然後請它執行 /bin/bash 這個命令」。


圖片來源: Docker Container 基礎入門篇 1


九、延伸議題 K8s - Kubernetes

microservices 概念的導入,改善了我們過去所面臨到的問題

大型專案開發,上線產品、除錯、與測試功能都包在一起。每次發布新功能、修改代碼都非常膽戰心驚,哪怕是一個 bug 也會影響整個系統效能。

而相較於這樣單體架構(Monolithic Architecture) 的服務,微服務(microservices)架構 大大減少程式複雜度,將每個服務依照各自業務需求獨立出來,以 Rest API 互相構通。

  • 將龐大的專案拆成幾個不同面向的小專案,當代碼夠小、容易理解、開發效率能被提高
  • 各個服務之間也可獨立部署,不因一個服務癱瘓而癱瘓整個系統
  • 各團隊可以依照自己的需求使用適合自己的語言、資料庫開發
  • 每個服務也可以依照自己的需求,選擇在不同機器上部署
Kubernetes 提供一個平台以較高層次的抽象化去自動化操作與管理容器們
  • 然而當系統中的微服務越來越多時,管理上也會面臨到很大的挑戰
  • Kubenetes 的出現讓我們管理這些微服務程式更加方便
  • Kubernetes 想解決「手動部署多個容器到多台機器上並監測管理這些容器的狀態非常麻煩」的問題
  • 而 Kubernetes 要提供的解法,提供一個平台以較高層次的抽象化去自動化操作與管理容器們
Kubernetes 的優點
  1. 可以跑在任何地方 Can run anywhere
    • Kubernetes 可以運行在任何地方:不論是私有雲、公有雲(像是 AWS, Google Cloud Platform )、或是混合雲。
  2. 高度模組化 High modular
    • 每個服務都被切成一個 container ,不論是要做修改、擴張、甚至將服務遷移到另外一台機器,都可以快速被部署。
  3. 活躍的社群 Open source & active community
    • Kubernetes 是 開源的 ,受到社群的關注度也非常高。
  4. Google的背書 Backed by Google
    • 最初版的 Kubernetes 是由 Google 內部 Borg team 的成員撰寫且現在仍在持續維護。Google 使用他們自身的系統 Borg 管理容器化應用長達十年多。Kubernetes 的目的即是將 Borg 最精華的部分取出來,使得開發者能夠更簡單、直接應用。
參考資料Docker與Virtual Machine的差異如何通俗解释Docker是什么?其實我真的沒想過在美國上班也被拉來參加30天分享那些年我怎麼理解 kubernetes 的運作Docker 更有效解決了軟體開發的難題,它比虛擬機更好的地方是,不需要犧牲軟體密集度,就能隔離不同的應用程式前端工程師學習 DevOps 之路Docker 從入門到實踐用30天來介紹和使用 DockerDocker 基礎教學與介紹 101