2014/10/29

使用 Docker


Docker 是基於 LXC(Linux Container)的一個工具,
Docker 妥善運用了 LXC,並提供了一個友善的操作介面(Command Line)以及額外的功能。

---

# LXC

先了解一下 LXC:
LXC is a userspace interface for the Linux kernel containment features.
Through a powerful API and simple tools, it lets Linux users easily create and manage system or application containers.
LXC is often considered as something in the middle between a chroot on steroids and a full fledged virtual machine.
The goal of LXC is to create an environment as close as possible as a standard Linux installation but without the need for a separate kernel.

LXC 是一個讓你可以輕鬆操作 userspace 的工具,只要你的 Linux kernel 支援 LXC,就可以透過 LXC 封裝 kernel 層以外的任何東西。

我舉一個比較糟糕的例子來說明:

想像 Linux 作業系統就是一個煮東西的大鍋子,你想要用鍋子煮出什麼東西,就要往鍋子裡加什麼料。
你加了 Apache,加了 MySQL,加了 PHP;接著又加了 Ruby,加了各式 Ruby gems;加了 Python,加了各種 Python eggs …
於是大鍋子漸漸開始變成了大雜燴,各種食材的味道開始互相影響。

LXC 就像是在大鍋子上面加了一個大蒸架(LXC API),讓你可以放置各種容器(Container)盛煮各種料理(Packages,Programs)。
Docker 就是讓你可以非常簡單地使用這個蒸架,放置這些各別的料理容器,以及其他一些額外的好用功能(例如 docker pull)。



Reference:
https://linuxcontainers.org/
http://zh.wikipedia.org/wiki/LXC
http://en.wikipedia.org/wiki/UnionFS

---

# Docker 基礎

Docker 有 Server 端跟 Client 端。

Docker Server 端的主機也叫做 Docker Host;
Docker Server 預設透過 2375 跟 2376 port 提供 Docker REST API。
Docker Client 可以透過 Docker REST API 操作 Docker Server 上的 Docker images 或 containers。

image 跟 container 可以想像成這樣:

image 就是事先準備好的料理容器,這些容器是五花八門的。
它可以是乾乾淨淨的料理容器(精簡安裝的 Ubuntu、CentOS、FreeBSD 等),
它也可以事先放了幾杯水、加了幾勺鹽巴(安裝了 Apache、MySQL 等)。
這些料理容器(image)都可以直接拿來放到架上蒸煮(執行),
image 每次被執行時,會將它自己當成藍本,複製產生一個 container,
執行中的 container 可以持續改變(被料理),而 image 則一直以本來的樣子存在著。

container 是 Docker 執行(docker run 指令)時,以指定的 image 為藍本,產生出來的。
image 可以看成是虛擬機的硬碟檔(例如 VirtualBox 的 vdi 檔,或 Vagrant 的 box 檔),
container 就是根據某個指定的硬碟檔複製產生的虛擬機,產生這個虛擬機的成本是很低的。
執行中的 container 可以看成是開機運行中的虛擬機,可以使用 docker ps 指令查看;
執行完畢的 container 就是已經關機的虛擬機,可以使用 docker ps -a 指令查看。

container 可以透過 docker commit 指令轉換成 image,
相當於將運行到某個階段虛擬機 snapshot 起來,並匯出變成一個虛擬機硬碟檔。

剛開始使用時,Docker Client 跟 Docker Server 通常會在同一臺主機上。
在 Ubuntu 中安裝 Docker Client(docker.io)跟 Docker Server(lxc-docker)是非常簡單的:

1. sudo apt-get update
2. sudo apt-get install docker.io
3. sudo ln -sf /usr/bin/docker.io /usr/local/bin/docker
4. sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 36A1D7869245C8950F966E92D8576A8BA88D21E9
5. sudo sh -c "echo deb https://get.docker.com/ubuntu docker main > /etc/apt/sources.list.d/docker.list”
6. sudo apt-get update
7. sudo apt-get install lxc-docker

正常來說,安裝完 lxc-docker,就會自動啟動 Docker Server,可以執行 sudo docker info 指令來確認。

因為 docker daemon(Docker Server)預設使用 root 權限啟動的,
所以透過 Docker Client 對它進行操作時,通常都要加上 sudo 命令。
http://askubuntu.com/questions/477551/how-can-i-use-docker-without-sudo

先檢查本機有哪些可用的 image:
sudo docker image

搜尋遠端是否有自己感興趣的 image:
sudo docker search ubuntu

將遠端的 image 複製到本地端:
sudo docker pull ubuntu

以 ubuntu image 為基礎,創建一個 container,並進入這個 container 的 shell;
相當於使用 ubuntu image 創建一台虛擬機,並登入這台虛擬機的 console:
sudo docker run -i -t ubuntu

接著在 container 的 shell 中,就可以跟平常操作 Ubuntu 一樣進行使用了。
使用告一段落後,如果使用 exit 指令離開,這個 container 就會結束執行(相當於虛擬機關機),
想要離開 container 的 shell,但是讓它保持執行,可以先按 Ctrl + P,再按 Ctrl + Q 離開。

顯示執行中的 container(container 對於 Docker 而言就像是 process):
sudo docker ps

顯示全部的 container:
sudo docker ps -a

啟動沒有執行的 container:
sudo docker start {container id}

接續回到執行中的 container 的畫面:
sudo docker attach {container id}

將進行到某個階段的 container 轉成 image:
sudo docker commit {container id} {image name}

移除 container:
sudo docker rm {container id}

移除 image:
sudo docker rmi {image name}

執行一個 container,將它的 80 port 對應到 Docker Host 主機的 8080 port,並將 Docker Host 的 /www 共享到 container 的 /var/www/ 目錄:
sudo docker run -i -t -p 8080:80 -v /www:/var/www ubuntu

Reference:
https://docs.docker.com/articles/basics/
https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-getting-started
http://slopjong.de/2014/09/17/install-and-run-a-web-server-in-a-docker-container/

---

# Docker Best Practice