第213期 / July 5, 2015

研發新視界

分享到臉書!分享到維特!分享到噗浪!分享到Google+!分享到微博!轉寄友人友善列印

新一代虛擬化技術-Docker淺析

作者/林憲良

[發表日期:2015/7/5]

前言

虛擬化技術已問世多年,直到雲端技術的崛起,虛擬化技術才被廣泛的被應用與發揚光大。虛擬化技術原理簡單來說就是在本機電腦上模擬出一台或多台獨立運作的機器,其作業系統可與本機電腦相異,如此一來可以充分利用設備資源並減少設備成本。然而,由於每台虛擬機器都需要有各自的作業系統,造成建置虛擬機器時間冗長,且因為虛擬機器的檔案實在太大,在移動虛擬機器也較麻煩。為了改善以上虛擬化技術的種種缺點,Docker便誕生了。

2013年年初,一間開發PaaS服務的公司 – dotCloud,開始了Docker專案,原本dotCloud是一間名不經傳的小公司,但自從dotCloud將Docker當作OpenSource專案開放出去後,引起了熱烈的迴響,dotCloud也更名為Docker,藉此聲名大噪。那究竟Docker為什麼那麼火紅呢,簡單來說,Docker是一種輕量化的虛擬機器,它之所以輕量是因為它沒有GuestOS,而且它製作Image的方式就像蓋房子一樣,先從一個基本的Image開始,然後一個一個應用程式疊加上去,每一次疊加後的Image可以單獨存在,所以抽換的彈性很高。

Docker架構

如前言所述,Docker是一個套比一般虛擬機器還要輕量簡單的虛擬化平台,使Docker輕量化的技術稱為Docker Container,為什麼Container會比一般虛擬機器還要輕量呢?在接下來我們將探討Docker的架構,就可以了解Container的核心概念。

一.Docker vs Virtual Machine

Docker究竟和虛擬機器差在哪了?下圖說明了Docker與虛擬機器的差異。先說明虛擬機器。虛擬機器運作在本機電腦上,在本機OS上利用Hypervisor模擬出Guest OS執行,所以每台虛擬機器都有一個Guest OS,使用者在基於這個Guest OS安裝其他應用程式,對於每台虛擬機器而言,彼此都是獨立的個體,所以在圖中A與B是各自獨立的。再來看看Docker,與虛擬機器不同的是,Docker使用的是一種名為Container的概念,透過在本機電腦上運行Docker Engine,Docker Engine模擬每個Container,每個Container也彼此獨立,但Container是共用相同的核心,圖中C跟D彼此為獨立的個體,但C只是基於D的Image上在加裝App A,Docker Engine只要記錄C與D的關係即可,這樣減少核心重複複製的問題。



往更上層一點來看,Docker是一套Client/Server的架構,所以主要有Docker Client和Docker Daemon兩個元件。Docker Client也就是使用者操作的介面,透過一些Docker指令可以與Docker Daemon溝通,因為是Client/Server架構,所以可以使用Docker Client與遠端的Docker Daemon連接;Docker Daemon為主要核心服務,提供Build Image, 執行Docker指令, 執行Container…等核心作業。

Docker Hub

在前面我們有說到Docker是個OpenSource專案,所以有興趣的參與者可以透過註冊Docker帳號,申請自己一個Docker Hub的空間。在Docker Hub裡,你可以在自己的Repository裡建立儲存自己的Docker Image,並分享跟其他人。你可以直接從Docker Hub直接關鍵字搜尋想要的Image,或進入別人公開的Repository選擇。



此外,Docker Hub可掛載上GitHub Service進行AutoBuild,只要在Docker Hub上綁定GitHub帳號或Bitbucket帳號,之後進行相關設定就可以根據Repository上的DockerFile來Build Image。

DockerFile

Docker File是Docker專用的Script,使用DockerFile可以建置客製化Image,DockerFile裏頭紀錄了從Base Image到客製化Image的安裝步驟,即利用DockerFile的指令將安裝步驟串連起來。DockerFile常用的指令有FROM, RUN, ADD, CMD, EXPOSE, ENV, COPY, VOLUMN, USER…等,以下將簡單說明各指令的說明:
  • FROM:設定Base Image。因為要先決定用哪個Base Image才能客製化Image,故FROM必須為DockerFile的第一個指令。
  • RUN:即執行Shell指令,例如RUN apt-get ….就是在Image上執行apt-get安裝應用程式。此外,每當RUN一個Shell指令就會將此Image Commit。
  • ADD:在Image裡加入指定路徑的資料夾或檔案。
  • CMD:主要目的為提供執行Container的預設值參數,一個DockerFile只能有一個CMD指令,若有多個CMD指令則會取最後一個CMD指令。
  • EXPOSE:設定Container監聽網路port,藉此可與其他Container進行溝通。
  • ENV:設定Image上的環境變數。
  • COPY:與ADD類似,在Image裡加入指定路徑的資料夾或檔案。
  • VOLUMN:建立額外的掛載目錄空間。
  • USER:設定Image的使用者ID與名稱。
  • MAINTAINER:註記Build 此Image的作者。


Docker For Windows & Mac

Docker為一OpenSource專案,其Docker Engine核心為同為OpenSource的Linux Kernel,所以在對於市場上普遍的Windows與Mac是無法相容的。但是就有如Cygwin可以在Windows上模擬Linux架構一樣,Docker Engine可以透過Boot2Docker這套軟體來安裝執行Docker Engine。Boot2Docker主要是在Windows或Mac上安裝一個輕量型的虛擬機器來執行Docker Daemon,接著使用者就可以透過使用Windows或Mac的Docker Client來對虛擬機器上的Docker Daemon進行操作。

範例操作

本章節將會進行Docker的一些簡單操作,讓使用者能夠大概了解Docker的操作方式,在使用Docker之前要先安裝Docker Service,各作業系統安裝Docker的教學可在Docker官方網頁找到。

操作一:Docker基本操作

在Docker中,Image是佔有非常重要的角色,所以在這次操作中,我們會從簡單的command line進行Build Image,並操作一些Docker的基本指令,首先來Build Image:
1.首先使用sudo docker images搜尋目前repository上有的Image檔。



目前有可用的Image有ubuntu與centos的Image。
2.執行sudo docker pull Ubuntu取得ubuntu的Image。



3.接著來試試如何啟動並使用剛剛載下來的ubuntu Image,執行sudo docker run ubuntu ping www.google.com



4.再來我們要來Base on ubuntu的Image來安裝Java,執行sudo docker run ubuntu apt-get update更新ubuntu套件來源,再來執行sudo docker ps -l來看看最新的Container的資訊。



5.執行sudo docker commit -m "Update repository" -a "Author" 將剛剛的修改另存成獨立的Image,-m參數是增加註解,-a則是增加修改的作者。



6.再來就依序執行安裝Java的步驟:
sudo docker run sudo apt-get install software-properties-common
sudo docker commit
sudo docker run sudo add-apt-repository ppa:webupd8team/java
sudo docker commit
sudo docker run sudo apt-get update
sudo docker commit
sudo docker run sudo apt-get install install oracle-java8-installer
sudo docker commit

7.經過一連串的run和commit就得到一個Base on ubuntu安裝Java的Image檔。
OPTION:執行sudo docker inspect 可以查看該container的資訊,包含修改的Log, 修改的作者, CPU架構, 記憶體…等虛擬機器資訊,Docker會將這些資訊以JSON格式的方式表示。

上述的操作方式是直接使用Command Line執行,可以發現建立Image時,每執行一道命令就要用docker commit來記錄下來,這樣實在是很消耗時間,所以接下來的操作範例將說明如何使用DockerFile快速Build Image。

操作二:使用DockerFile進行Build Image

前面章節我們有提到,Build Docker Image可直接下Docker指令一個個步驟逐步安裝,或者可直接執行DockerFile。我們將使用DockerFile方式進行操作說明,接著來實際操作如何以DockerFile Build出一個Image。下列為Base在CentOS上安裝Java的DockerFile內容:



先來逐步說明這個DockerFile:
1.第5行:FROM centos設定Base Image為CentOS的Image。
2.第6行:MAINTAINER Marco Palladino, marco@mashape.com 標記此DockerFile的作者資訊。
3.第7, 8行:設定環境變數JAVA_VERSION與BUILD_VERSION的值為8u31與b13,這邊設定的環境變數值會在後面(第13行)動態修改安裝的目錄名稱。
4.第10行:執行CentOS的yum update指令,更新所有CentOS Repository的所以套件包。
5.第11行:使用yum install指令安裝wget套件(Linux上可透過此套件到指令URL抓取檔案)。
6.第13行:使用wget套件到Oracle網站下載Java套件包至/temp目錄。
7.第14行:使用yum install安裝剛剛下載的Java套件包
8.第15, 16, 17行:使用alternatives指令管理同時存在的多個不同版本的JDK。
9.第18行:設定Java安裝目錄的環境變數。

看完了DockerFile的解說後就可以開始來使用DockerFile安裝了,以下為執行DockerFile的步驟:
1.先使用文字編輯器編輯DockerFile或直接下載DockerFile範本來修改。
2.在放置DockerFile的目錄下執行sudo docker build --tag="docker/test" .,Docker就會開始執行此目錄下的DockerFile,tag值為Repository的位置(<帳號/Repository>),注意在tag值可不能亂設定,因為會影響到要將此Image上傳至Repository時的情況,在這裡需要設定你有權限的Repository值。
3.Docker Engine逐步執行DockFile裡的命令,下圖為Build DockerFile時所顯示的各步驟Log:



4.等待執行完成後,可輸入sudo docker images指令來看看剛剛Build的Image:



OPTION:如果要將Build好的Image上傳到自己的Repository裡可按照下列步驟:
1.執行sudo docker login指令,並輸入帳號, 密碼, 電子郵件信箱進行登入。
2.執行sudo docker push docker/test,Docker Engine就會將剛剛Build的Image上傳至自己的Repository上。

結論

Docker的出現對開發人對帶來相當大的衝擊,以往開發人員在佈署應用程式時,需要重頭在一個作業系統上將需要的安裝套件逐一安裝,如果數量非常多時,這實在是一件非常龐大的工程,且不同作業系統安裝步驟又有可能不同。使用Docker,開發人員可以將自己安裝過的環境打包起來,再到其他機器上使用Docker執行打包起來的環境,省了許多工。除此之外,Docker也可以利用在PaaS上,在Docker Container裡建立服務,然後再透過Docker Container可互相Link的特性,將需要的服務拉進來組合成新的服務。知名音樂網站Spotfy擁有大量的音樂資料,使用者人數高達上千萬,每當他們要更新應用程式時,就利用Docker Container進行測試與上線的佈署來確保安全迅速的上線。

Docker的上手程度非常簡單,除了Docker官方網站提供初學者相當多的教學範例與文件之外,在許多論壇上也可以看到許多Docker的使用者的討論串,許多Docker使用者不吝的開放出他們的Repository供其他使用者參考使用,在台灣,雖然Docker在台灣尚未設點,但在台灣也有許多熱衷於Docker的開發者們建立了Docker Taipei的社群,致力於在台灣推動Docker。