Docker 初體驗

環境

ver: CentOS 7

觀念

只要搞懂什麼是映像檔(Image)、容器(Container)、倉庫(Respository),就會一路好走了。

什麼是映像檔?

「一份最單純環境的檔案。」

如果有經歷過那個燒錄軟體的年代,可能做過屬於自己的系統環境:

先安裝 windows、安裝驅動程式,然後將這個系統環境備份成一個 .iso 檔,燒錄成一個光碟。不管最終形式一份 .iso 檔案,還是一張光碟,代表的意義都是「最單純環境的檔案」。

那這個檔案的用途是幹嘛?當然是用來快速建立、還原自己的基礎系統環境,節省大量的重複時間。在 Docker 裡,映像檔就是這樣的東西,更棒的是,在網路上會有一群人分享他們建立的各種不同環境的映像檔,隨便你取用,讓你可以快速建立自己的測試環境(或線上環境)。

什麼是倉庫?

一堆映像檔,總要有個地方統一存放吧,不然會很散亂,要找起來也不方便啊!所以統一存放映像檔的地方就是倉庫。倉庫又分為公有和私有兩種,大家可以一起分享的叫公有,如果只有自己或者少數一群人可以使用的,就叫私有。這不是廢話嗎?!最有名的公有倉庫是 Docker Hub,可以在上面找到 centos、ubuntu、nginx 最單純的映像檔。

什麼是容器?

有了映像檔,總得安裝到某個機器上吧!但是 Docker 的觀念不是這樣,因為這樣就是傳統虛擬機器做的事,Docker 是依賴 Linux 容器技術(LXC),不太一樣,細節我也不是很清楚,但是差異上大概可以這樣理解:虛擬機器像是重啟一個 os,然後執行到想執行的程式(ex:nginx)為止。而 Docker 卻只是一個行程,這個行程構建出一個虛擬空間,這個空間可以像一般的主機安裝映像檔,之後只要啟動這個虛擬空間,就能讓想要執行的程式(ex:nginx)可以順利執行。而這個虛擬空間,就是所謂的容器。由於容器技術不用重啟一個 os,而裡面的環境又是最單純的狀況,所以容器的啟動很快速。

假設我們想要打造一個單純的 web 服務,我們可以用 Docker 建構一個容器跑 nginx、建構一個容器跑 mysql 、建構一個容器執行 php-fpm。 這樣看起來只是把服務拆分,好處在哪裡?可以參考這個影片

因為我只想讓開發環境不要全部都喇在一起而已,然後 Docker 在啟動上又很快,所以我抽空來玩看看了。至於線上環境適合不適合使用低耦合的概念來管理,我不是專業的系統人員,沒辦法給答案。

以下,我將示範如何建造一個 hhvm 環境來開發 php。

操作

安裝 docker

sudo yum install docker

sudo systemctl enable docker
sudo systemctl start docker

尋找映像檔

docker search 會去 Docker Hub 找映像檔

sudo docker search <keyword>

因為 hhvm 支援程度最高的作業系統是 ubuntu,所以我拿 ubuntu 映像檔當我的基礎環境。所以先來查看看有提供哪些 ubuntu 的

sudo docker search ubuntu

就會看到一串結果

INDEX       NAME                                     DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
docker.io   docker.io/ubuntu                         Ubuntu is a Debian-based Linux operating s...   2755      [OK]       
docker.io   docker.io/ubuntu-upstart                 Upstart is an event-based replacement for ...   47        [OK]       
docker.io   docker.io/torusware/speedus-ubuntu       Always updated official Ubuntu docker imag...   25                   [OK]
... ... ...

容器的開開關關

使用第一個映像檔,新增並進入容器

sudo docker run -it ubuntu:15.04 /bin/bash

這個 run 指令在我這邊其實做了兩個動作,因為我之前沒有下載過 ubuntu:15.04,所以他會先去網路幫我 pull 出 ubuntu:15.04,然後拿這個映像檔建立容器,並執行它。如果照上面指令執行,會看到出現這樣的畫面:

sudo docker run -it ubuntu:15.04 /bin/bash
c9caefea4a076adb394334dd5ef0d93f13309ab54074311ddc1947429616e363
root@5b0ae5548308:/#

看到「root@5b0ae5548308」就代表已經跑到容器裡(5b0ae5548308 就是所謂的 container id),並執行容器裡的 bash 程式(在 ubuntu 裡)。

離開容器

root@5b0ae5548308:/# exit

檢視目前所有容器

離開了,然後呢?原來離開了之後,會順便中止(stop)這個容器。可以使用以下的指令查看已經建立起來的所有容器。

sudo docker ps -a
CONTAINER ID    IMAGE          COMMAND       CREATED        STATUS         PORTS      NAMES
5b0ae5548308    ubuntu:15.04   "/bin/bash"   46 hours ago   Exited (0)...             sad_tesla

目前容器只有一個,所以很好認,我們會看到剛剛的容器是 Exited 的狀態。每個容器一旦被建立起來,就會配給一個 container id 和 name (如果沒有使用 –name 指定名稱的話)。大概注意一下,接下來操作最常使用的資訊就是 container id 和 name 了。

可是這樣怪怪的啊,只要我 exit ,容器就停止執行,那不就得一直呆在容器裡,想要執行的服務或程式才能運作?只要在 docker run 時,加上 -d 參數就能讓容器在背景跑:

sudo docker run -itd ubuntu:15.04

執行完這行會看到自己還停留原始環境中,而不是跑到容器裡(停留在 centos):

ueicren@nginx.pd.net:/var/www/nginx/php$ docker run -idt ubuntu:15.04
c9caefea4a076adb394334dd5ef0d93f13309ab54074311ddc1947429616e363
ueicren@nginx.pd.net:/var/www/nginx/php$

檢視運行中的容器

這時候我們來查看有沒有「運行中」的容器,很簡單,不要加上 -a 參數即可,只會列出運行中的容器:

sudo docker ps
CONTAINER ID    IMAGE          COMMAND       CREATED        STATUS         PORTS      NAMES
5b0ae5548308    ubuntu:15.04   "/bin/bash"   46 hours ago   Exited (0)...             sad_tesla

進入運行中的容器

剛剛我們讓容器跑起來了,可是總得要能夠隨心所欲地進去容器吧,不然也沒意義啊!主要有以下三種方式,我個人比較喜歡 docker exec。

使用 docker exec 指令
sudo docker exec -it <container id or name> bash
  • 執行 exit 時,不會中止容器。
使用 docker attach
sudo docker attach <container id or name>
  • 很有趣,多個窗口一起進去容器時,會互相影響。然後執行 exit 時,就會中止容器。
使用 nsenter
PID=$(sudo docker inspect --format "{{ .State.Pid }}" <container id>)
sudo nsenter --target $PID --mount --uts --ipc --net --pid 
  • 執行 exit 時,不會中止容器。

控制容器的常用操作

停止活動中的容器

sudo docker stop <container id or name>

重新啟動停止的容器

sudo docker start <container id or name>

刪除已經停止的容器

sudo docker rm <container id or name>

強制刪除活動中的容器

sudo docker rm -f <container id or name>

建立映像檔

好啦,容器的基本操作介紹完,接著我進入到新建的容器裡,開始安裝 hhvm 的環境。由於是介紹 Docker 的使用,細節就快速省略,主要就是慢慢執行以下指令:

apt-get install -y software-properties-common
apt-get install -y vim
apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 0x5a16e7281be7a449
add-apt-repository "deb http://dl.hhvm.com/ubuntu $(lsb_release -sc) main"
apt-get update
apt-get install -y hhvm

手動建立映像檔

容器裡的環境已經被我們調整成可以玩 hhvm,接下來就可以把這個環境做成新的映像檔,這樣以後就不用這樣從頭做:

sudo docker commit -m "15.04 + hhvm" -a "author_name" 0b2616b0e5a8 docker.io/ubuntu:15.04_hhvm
檢視目前有哪些映像檔
sudo docker images

就會看到新建立的映像檔

REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
docker.io/ubuntu    15.04_hhvm          8c1bf272259a        47 hours ago        481.6 MB
docker.io/ubuntu    15.04               db672630245b        13 days ago         131.3 MB

使用 Dockerfile 建立映像檔

這個是讓我最開心的功能,只要以一個映像檔為基礎,透過撰寫 Docker file,類似 shell 的執行指令稿,就能透過分享 Dockerfile 達到分享環境的方式,超方便。

先產生一個目錄,在裡面撰寫 Dockerfile,然後執行 docker build 指令即可。

# Dockerfile START
FROM ubuntu:15.04
MAINTAINER ueicren <ueicren@gmail.com>
RUN apt-get install -y software-properties-common
RUN apt-get install -y vim
RUN apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 0x5a16e7281be7a449
RUN add-apt-repository "deb http://dl.hhvm.com/ubuntu $(lsb_release -sc) main"
RUN apt-get update
RUN apt-get install -y hhvm
# Dockerfile END
建立映像檔

sudo docker build -t=”docker.io/ubuntu:hhvm” .

截至目前為止,算是大功告成,作出了可以給自己重複使用的映像檔了。只要使用 docker run 就可以建立新的可以跑 hhvm 的容器了。在開發環境中,就會體驗到這個工具有多方便,環境被玩爛了,只要重建一個新容器就好。

參考