編者注:我們發現了有趣的系列文章 《30天學習30種新技術》 ,正在翻譯,一天一篇更新,年終禮包。下面是第 21 天的内容。

什麼是 Docker?
Docker提供了一個可以運作你的應用程式的封套(envelope),或者說容器。它原本是 dotCloud 啟動的一個業餘項目,并在前些時候
開源了。它吸引了大量的關注和讨論,導緻 dotCloud 把它重命名到 Docker Inc。它最初是用 Go 語言編寫的,它就相當于是加在 LXC(LinuX Containers,linux 容器)上的管道,允許開發者在更高層次的概念上工作。
Docker 擴充了 Linux 容器(Linux Containers),或着說 LXC,通過一個高層次的 API 為程序單獨提供了一個輕量級的虛拟環境。Docker 利用了 LXC, cgroups 和 Linux 自己的核心。和傳統的虛拟機不同的是,一個 Docker 容器并不包含一個單獨的作業系統,而是基于已有的基礎設施中作業系統提供的功能來運作的。這裡有一個
Stackoverflow 的答案,裡面非常詳細清晰地描述了所有 Docker 不同于純粹的 LXC 的功能特性
Docker 會像一個可移植的容器引擎那樣工作。它把應用程式及所有程式的依賴環境打包到一個虛拟容器中,這個虛拟容器可以運作在任何一種 Linux 伺服器上。這大大地提高了程式運作的靈活性和可移植性,無論需不需要許可、是在公共雲還是私密雲、是不是裸機環境等等。
Docker 由下面這些組成:
1. Docker 伺服器守護程式(server daemon),用于管理所有的容器。
2. Docker 指令行用戶端,用于控制伺服器守護程式。
3. Docker 鏡像:查找和浏覽 docker 容器鏡像。它也通路這裡得到:
https://index.docker.io/我為什麼要關心這些?
Docker 之是以有用,是因為把代碼從一個機器遷移到另一個機器經常是困難的。它嘗試去使得軟體遷移的過程變得更加可信和自動化。Docker 容器可以移植到所有支援運作 Docker 的作業系統上。
可以看這篇文章了解更多:
how the Fedora Project is embracing Docker但是我已經在使用虛拟機(VMs)了
到現在為止,要把程式可靠地移植的唯一選擇是虛拟機(Virtual Machines,VMs)。虛拟機現在已經很常見了,但虛拟機是非常低級,它提供的是完整的作業系統環境。虛拟機的問題是,遷移的時候太大了。它們包含了大量類似硬體驅動、虛拟處理器、網絡接口等等并不需要的資訊。 虛拟機也需要比較長時間的啟動,同時也會消耗大量的記憶體、CPU 資源。
Docker 相比起來就非常輕量級了。運作起來就和一個正常程式差不多。這個容器不僅僅運作快,建立一個鏡像和制作檔案系統快照也很快。它可以在 EC2, RackSpace VMs 那樣的虛拟環境中運作。事實上,在 Mac 和 Windows 系統上使用 Docker 的更好方式是使用 Vagrant。Docker 的初衷其實是發揮類似 VM 的作用,但它啟動得更快和需要更少的資源。
它就像 Vagrant 一樣嗎?
我遇到的一個疑問是,我應該用 Vagrant 還是 Docker 去為我的下一個項目建立沙箱環境?答案再一次是一樣的。
Docker 比起 Vagrant 來說,運作起來會更加省資源。Vagrant 提供的環境其實是基于 Virtual Box 提供的虛拟機。可以閱讀 Stackoverflow 的
這個回答了解更多。
噢,不是!另一個應用程式打包系統
當第一次讀到 Docker 打包應用程式時,我困惑了。我們為什麼需要再多一個應用打包系統(packaging system)?我早已經把我的 Java 程式打包成 JAR 或 WAR 了。在花了些時間閱讀了關于 Docker 的資料後,我明白了 Docker 應用包(application package)的含義。Docker 就是虛拟機和你的像 WAR 或 JAR 那樣的應用包之間的橋梁。一方面來說,虛拟機是非常重量級的(耗資源),因為移植時要附帶些不需要的東西。另一方面來說,應用代碼包(the application code packages)是非常的輕量的,并沒有附帶足夠可靠地運作起來的資訊。Docker 很好地平衡了這兩方面。
在 Docker 中,應用程式包(application package)意味着一個包含了應用程式代碼和所需部署環境的包。例如,在 Java 中我們一般把我們的 Web 應用程式打包在一個 WAR 檔案中。這個 WAR 檔案是一個非常簡約的軟體包,它僅僅包含了應用程式的代碼。但應用程式需要特定部署的環境去高效地運作起來。有時候部署的環境和開發時的環境是不同的。例如開發者使用 Java 7 開發程式,但部署時的環境是在 OpenJDK Java 6 中;又或者是在 Mac 上開發的,但在 RHEL 上部署。情況也有可能是:有一些系統庫(system libraries)在開發環境和模拟環境(staging environment)中,在不同的應用程式上有不同的效果。Docker 通過不僅僅打包應用程式,也打包應用程式的依賴環境來解決這個問題。
開始使用 Docker
在 Fedora 機器上使用這篇
博文中的指令安裝 Docker
$ vagrant up
$ vagrant ssh
然後安裝 Docker Fedora 鏡像:
$ sudo docker pull mattdm/fedora
上面的指令會從
上下載下傳 Docker Fedora 鏡像。
安裝了 Docker Fedora 鏡像後,我們可以使用下面指令列出所有的鏡像:
$ sudo docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
shekhargulati/node_image_007 latest e12b3054d981 50 minutes ago 470.3 MB (virtual 601.8 MB)
mattdm/fedora 12.04 8dbd9e392a96 7 months ago 131.5 MB (virtual 131.5 MB)
上面清單中第一個鏡像就是我以前建立的。它打包了 NodeJS 及 Express Fremework。第二個鏡像就是存儲的 Docker Fedora 鏡像了。
現在,我們在 Docker 容器内運作一個腳本:
$ sudo docker run -t -i -p 3000 mattdm/fedora /bin/bash
在運作完上面的指令後,我們就在 Docker 的容器裡面了。我們可以通過
ls
指令列出所有的指令。
現在我們建立下面的目錄結構
/home/shekhar/dev
:
$ mkdir -p home/shekhar/dev
$ cd home/shekhar/dev
現在,我會安裝 NodeJS。運作下面的指令去在 Fedora Docker 鏡像上安裝 Node:
$ sudo yum install npm
接着,我們安裝 Express 架構:
$ npm install express -g
Express 架構安裝後,我們建立一個新的 Express 程式,然後運作它:
$ express myapp
$ cd myapp
$ npm install
$ node app.js
上面會在
3000
端口啟動 NodeJS Express 程式。
現在打開另一個指令行标簽,列出所有的 Docker 程序:
$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4a5715a915e5 mattdm/fedora /bin/bash 5 minutes ago Up 5 minutes 0.0.0.0:49157->3000/tcp red_duck
你會注意到,
3000
端口和本機上的
49157
綁定了。你可以通過下面所示的
curl
指令測試 Express 應用:
$ curl 0.0.0.0:49157
<!DOCTYPE html><html><head><title>Express</title><link rel="stylesheet" href="/stylesheets/style.css"></head><body><h1>Express</h1><p>Welcome to Express</p></body></html>
現在 commit 鏡像,然後 push 到 Docker 鏡像系統資料庫(registry)。在你做這步之前,你必須通過
https://index.docker.io/account/signup/去注冊一個 Docker 系統資料庫。
$ sudo docker commit 4a5715a915e5 shekhargulati/node_image_007
$ sudo docker push shekhargulati/node_image_007
請使用你自己的使用者名和鏡像名。
是以,我的第一個鏡像已經上傳到 Docker 系統資料庫上面了:
https://index.docker.io/u/shekhargulati/node_image_007/你可以使用
pull
指令下載下傳這個鏡像:
$ docker pull shekhargulati/node_image_007
這就是今天的内容。保持回報!