Docker 入門教程
紅帽(Red Hat)宣布了在 Docker 技術上和 dotCloud 建立合作關系。在那時候,我并沒有時間去學習關于 Docker 的知識,所以在今天,趁著這個 30 天的挑戰,我決定去學習一下 Docker 究竟是怎樣的。這篇博文并不是說以后怎么在 OpenShift 上用 Docker 的。請閱讀由 Mike McGrath 撰寫的 "關于 OpenShift 和 Docker 的技術思考"。也可以看看這個 Stackoverflow 的問題,了解一下 Docker 和 OpenShift 的差別。
什么是 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
上面的命令會從 https://index.docker.io/ 上下載 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
這就是今天的內容。保持反饋!