Docker 介紹與實作

李麒傑( James )
什麼是 Docker ?
Docker 誕生於 2013 年初,基於 Go 語言實作,專案後來加入了 Linux 基金會,遵從了 Apache 2.0 協議,原始碼在 GitHub 上進行維護。

所以,Docker 可以做什麼?
其實,Docker 就是一個 快速且輕量級虛擬機
Docker ? VM ?


Docker 特性
-
不可變:將作業系統、函式庫版本、應用程式...等都包裝在 Container 內,確保每次建置的 Container 都擁有同樣的行為。
-
輕量:Container 不需消耗太多記憶體,只需使用主程序所需的用量,在多加上數十 MB 記憶體就足夠。
-
快速:啟動 Container 就如同平時啟動 Linux 程序一樣快,僅需耗費幾秒鐘的時間。
Docker 基本概念
Docker 基本概念:
-
映像檔 (Image)
-
容器 (Container)
-
倉庫 (Repository)
Docker Images
Docker 映像檔就是一個唯獨的模版,其儲存系統當下的狀態。

Docker Container
利用 Image 執行後的服務就稱為一個 container,可以想成是 VM 的實例 (Instance) ,它在一個被隔離的行程中執行,這行程共享主機的核心
Docker Repository
倉庫是集中存放映像檔檔案的場所
倉庫分為:
- 公開倉庫 (Public)
- 私有倉庫 (Private)

Docker 環境建置
Linux
$ curl -fsSL https://get.docker.com/ | sh
官方提供目前最新安裝腳本(Docker 1.12.1)
記得!!!
將目前使用者加入 docker group
$ sudo usermod -aG docker <user_name>
若您使用 ssh 的話,記得要離開再重新登入!!
Windows、OSX
官方針對 Windows 與 Mac 作業系統提供兩種建置環境方式:

Docker 基本指令
Docker version and info
$ docker -v
$ docker --version
結果:Docker version 1.11.1, build 5604cbe
Version:
info:
$ docker info
結果:
Containers: 0
...
Images: 0
Server Version: 1.11.1
Storage Driver: aufs
...
再次強調!!
若使用任何指令出現如下狀況...
Cannot connect to the Docker daemon. Is the docker daemon running on this host?
請使用下列指令,將當前使用者加入 docker group
$ sudo usermod -aG docker <user_name>
Docker pull
$ docker pull <image_name>:<image_version>
使用下列指令取得你所想要的 Image :
Example:
$ docker pull ubuntu:14.04
$ docker pull hello-world
注意!!
如果沒有指定 <image_version>,預設系統取得 latest 版本
Docker images
$ docker images
$ docker images -a
結果:
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest 94df4f0ce8a4 6 hours ago 967 B
ubuntu 14.04 8fa7f61732d6 36 hours ago 188 MB
如何知道已經取得哪些 Images ?
指令中的 -a 為選擇性參數,此處 -a 表示 all 的意思
顯示所有的 images
Docker Run
有了 image 後,如何執行它?
$ docker run <image_name>
$ docker run <image_id>
$ docker run <image_name>:<image_version>
Example:
$ docker run hello-world
$ docker run 94df4f0ce8a4
$ docker run ubuntu:14.04
再次強調!! 不指定版本,預設執行 latest
Docker Ps
如何得知我當下以執行哪些 container ?
$ docker ps
結果:
ONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
此時,你一定再想...我剛剛明明有執行 container,
可是為什麼沒有東西????

其實,你的 Container 有被執行的!! 只是它執行結束了...
切記,Container 目前是處於結束狀態,可以透過啟動指令重新啟動 Container 。
Docker ps
如何檢視所有執行過與正在執行的 Container ?
$ docker ps -a
結果:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
624c80d2368f ubuntu:14.04 "/bin/bash" 22 minutes ago Exited (0) 22 minutes ago insane_mclean
819722d06baf 94df4f0ce8a4 "/hello" 29 minutes ago Exited (0) 28 minutes ago boring_hawking
c1e511d3f581 hello-world "/hello" 29 minutes ago Exited (0) 29 minutes ago happy_carson
你是否還記得如何檢視所有 images ? 沒錯,一樣的方法
只需再指令後面加入 -a 參數即可!!

此時,你一定還有一個疑問!! 如果我是執行 Ubuntu 總不能執行完就結束吧 ??
Docker Run
沒錯,其實您可以使用下列語法執行它!!
$ docker run -tid ubuntu:14.04 bash
簡單介紹下面幾個選擇性參數:
-i 表示使用互動模式,始終保持輸入串流
-t 表示分配一個偽終端,通常都與 -i 一起使用
-d 表示以背景模式執行
bash 表示分配一個偽終端執行 bash 指令,讓使用者可以與容器(container)進行互動
當您執行一個 Ubuntu Container 以後,
您就可以進入 container 中做您想要做的事了!!!
Docker Exec
如何進入 ubuntu container 呢 ?
$ docker exec -ti <container_id> bash
Example:
$ docker exec -ti 53c5dd293e65 bash
如果您不知道 container id ,
可以透過 docker ps 查詢!!
Container 操作
$ docker start <container_id>
啟動:
停止:
$ docker stop <container_id>
重新啟動:
$ docker restart <container_id>
刪除:
$ docker rm <container_id>
Images 操作
刪除:
$ docker rmi <image_id>
注意: 若該 image 正在被 container 所使用時,必須先停止且移除 container
可是,如果您有很多 Image 或 Container 要被刪除,單一刪除可能會花你很多時間...
其實你有更快的方法!!!
快速刪除的方法!!
刪除多個 Images
$ docker rmi $(docker images -a -q)
刪除多個 Containers
$ docker rm $(docker ps -a -q)
了解 -a 以後,其實可以搭配 -q 一起使用,您會發現這個 command line 會顯示您現有的所有 Images(Containers) ,在搭配 docker 刪除語法即可一次刪除全部!!
常用快速指令 #1
$ docker rmi $(docker images -q --filter="dangling=true")
刪除無標籤 Images
$ docker rm $(docker ps -a | grep Exited | awk '{print $1}')
刪除所有狀態為 Exited 的 containers
docker rm -f $(docker ps -a -q)
停止並刪除所有 containers
docker rm `docker ps -a | grep <image_name>:<image_version> | cut -f1 -d" "`
刪除指定 Image 所建立的 containers
常用快速指令 #2
$ docker rmi $(docker images -a -q)
刪除所有 Images
$ docker logs $(docker ps -lq)
檢視最近建立的容器記錄檔資訊
現在,您已經了解 如何在 Docker 上執行您要的服務了!!
Try Try It!!
您現在是否可以完成 在 docker 上執行 nginx image 呢 ?
提示:
1.如果您想將您的 container port 對應出來,可以使用下列方式
2.如果您今天使用 docker Toolbox 可使用 docker-machine ip 查看 IP
$ docker run -p <local_port>:<container_port> -tid <image_name>:<image_version>

Docker Hub
先註冊一個 Docker Hub 帳號 !!

Docker Hub
$ docker logout
登入
登出
$ docker login
結果:
Username: cijie
Password:
Login Succeeded
如何打造一個專屬自己的 Docker Image ?
嘗試打造一個簡易的網頁
$ vim /usr/share/nginx/html/index.html
<html>
<head>
</head>
<body>
<p> Hello World!! </p>
</body>
</html>
將下列 Html 語法寫入...
目錄下...
注意!!
若預設沒有 vim 編輯器,可透過 apt-get 安裝
如何打造一個專屬自己的 Docker Image ?
將目前狀態的 container 打包成 image
$ docker commit -m "first version" <container_id>
檢視新打包的 image
$ docker images
結果:
REPOSITORY TAG IMAGE ID CREATED SIZE
<none> <none> ae1539ae1f1b 2 seconds ago 221.2 MB
hello-world latest 94df4f0ce8a4 12 hours ago 967 B
eboraas/apache latest 11da4215b424 25 hours ago 263.1 MB
ubuntu 14.04 8fa7f61732d6 42 hours ago 188 MB
nginx latest eb4a127a1188 3 weeks ago 182.7 MB
php latest c47a0064b207 3 weeks ago 489.6 MB
名稱為 <none> 即為新打包的 image
如何打造一個專屬自己的 Docker Image ?
給新的 image 一個名稱與版本!!
$ docker tag <image_id> <your_name>/<new_image_name>:<image_version>
再次檢視結果...
$ docker images
結果:
REPOSITORY TAG IMAGE ID CREATED SIZE
cijie/hello-world latest ae1539ae1f1b 7 minutes ago 221.2 MB
hello-world latest 94df4f0ce8a4 12 hours ago 967 B
eboraas/apache latest 11da4215b424 25 hours ago 263.1 MB
ubuntu 14.04 8fa7f61732d6 42 hours ago 188 MB
nginx latest eb4a127a1188 3 weeks ago 182.7 MB
php latest c47a0064b207 3 weeks ago 489.6 MB
注意: 建議給 image 版本,不建議使用 latest
如何打造一個專屬自己的 Docker Image ?
上傳新的 image 至 docker hub
$ docker push <your_name>/<image_name>:<image_version>
現在,你已經完成一個專屬自己的 Docker Image
你可以到 Docker Hub 上看到它!!!
DockerFile
工程師最大的特色就是 懶
總會思考是否有更快且方便的方法!!

接下來 Dockerfile 將實現你的願望!!
如何執行 Dockerfile ?
$ docker build <dockerfile_path>
實際演練
$ docker build .
REPOSITORY TAG IMAGE ID CREATED SIZE
ci-jie/docker-tutorial latest 34f84f5a1ee3 About a minute ago 221.2 MB
執行建置指令後,
你可以透過 Image 查詢語法 (docker images) 查詢
注意,建置完只是一個 Image ,並非 container
若要啟動,可透過 docker run ...
接下來讓我們來了解 Dockerfile 如何撰寫!!
讓我們了解 Dockerfile ...
FROM nginx:1.9
MAINTAINER "James Lee <cjlee8110@gmail.com>"
USER root
RUN apt-get update && \
apt-get install -y vim
WORKDIR /usr/share/nginx/html
COPY ./web/index.html ./
COPY ./img/NUTC_cloud.png ./img/NUTC_cloud.png
我們以剛剛的 Dockerfile 為範例
我們一步一步的了解!!
FROM
FROM <Image_Name>:<Image_Version>
範例:
FROM nginx:1.9
在開發應用之前,我們先選擇一個 Image 作為基底 如此一來,我們就可以在基底上層進行二次開發 注意,FROM 一定要放在最上方!!
MAINTAINER
MAINTAINER "Your_Name <Your_Email>"
範例:
MAINTAINER "James Lee <cjlee8110@gmail.com>"
不用多說,寫下您的大名與聯絡方式 描述這支程式的開發者!! 格式不限定,推薦以上方格式撰寫!!
USER
USER <User_Name>
範例:
USER root
USER 表示執行語法的角色身分
可以隨時切換身分!!
RUN
RUN <Command>
範例:
RUN apt-get update && \
apt-get install -y vim
RUN 執行相關設定的 Command 可以使用 && \ 符號將你的 Command 切成小區塊, 增加程式可讀性
錯誤的 RUN 用法!!!
RUN cd /usr/local
RUN touch index.html
這裡要特別注意!!
RUN 之間是獨立的,不可透過 cd 指令更改目錄位置!!!
你一定在想... 我在開發一定會需要切面目錄位置 我該怎麼辦呢 ??

WORKDIR 幫你做到了!!
WORKDIR <Path>
範例:
WORKDIR /usr/share/nginx/html
只需在 WORKDIR 後面加上你要切換的目錄位置即可!!
COPY
COPY <Local_Path> <Container_Path>
範例:
COPY ./web/index.html ./
COPY ./img/NUTC_cloud.png ./img/NUTC_cloud.png
COPY 可以將你本機端的檔案複製到 Container 中!! 如此方便的設計!!
現在我們已經了解基本 Dockerfile 的撰寫了...
其實,指令不只這些...
如果你想了解更多!!
Docker Compose
在現代,一個簡單的 App 可能同時包含多個 Service!!
我們該如何快速建置複雜架構的系統?
建置 Docker Compose 環境 (Linux)
$ wget -L https://github.com/docker/compose/releases/download/1.7.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
$ chmod +x /usr/local/bin/docker-compose
使用下面的 command line 進行建置
注意:
如果您使用的是 docker toolbox 預設已經安裝完成,不需再另外手動建置!!
環境建置完成以後,我們實際執行一個範例!
version: '2'
services:
db:
build: ./database
container_name: db
ports:
- 3306:3306
crawler:
build: ./crawler
container_name: crawler
apis:
build: ./apis
container_name: apis
ports:
- 3000:3000
web:
build: ./web
container_name: web
ports:
- 80:80
Docker Compose
您只需要建立一個名為
docker-compose.yml 的檔案,並將需要建置的 dockerfile 以及對應的 port 填入即可!!
最後,執行它!!
$ docker-compose up -d
可是,您可能會注意到現在所有的服務都是啟動在同一台伺服器上!!
我們該如何將所有的 Containers 分離?
Swarm
Docker 1.12
是否覺得單一節點在服務上,效能不如預期!?
建置 Swarm 叢集
初始化叢集
$ docker swarm init
Swarm initialized: current node (9nh4v53ixfmbh88c876j5372h) is now a manager.
To add a worker to this swarm, run the following command:
docker swarm join \
--token SWMTKN-1-5l2g5ao35wsdxmj4podjpk7js6ph4pqspwk8em6 ...
172.16.99.114:2377
To add a manager to this swarm, run 'docker swarm join-token manager' ...
記得,建置 Swarm 叢集前,需先建置 Docker 1.12 環境,該指令是 1.12 版後新增的功能!!
建置 Swarm 叢集
接著,您可以對新節點使用以下指令,將它變成叢集中的 worker !!
$ docker swarm join \
> --token SWMTKN-1-5l2g5ao35wsdxmj4podjpk7js6ph4pqspwk8em6y0k...
> 172.16.99.114:2377
This node joined a swarm as a worker.
若看到如上方結果,表示該節點已加入 Swarm 叢集中。
如何查詢叢集上的所有節點!?
$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
06pojrqvb32e8pd6xtzi4i6yx * swarm-m Ready Active Leader
7oiggsh0jw6lsv9pwgzddk1zo swarm-s-2 Ready Active
b76hq9s52b0bbwbwg2k8xfse8 swarm-s-1 Ready Active
標示為 Leader 表示為該叢集的 Manager 節點,並且系統會隨機給予節點亂數 ID。
查詢目前叢集資訊!
$ docker info
Containers: 0
Running: 0
Paused: 0
Stopped: 0
Images: 0
Server Version: 1.12.1
Storage Driver: aufs
...snip...
Swarm: active
NodeID: 06pojrqvb32e8pd6xtzi4i6yx
Is Manager: true
ClusterID: dsqfi3sfj6xb3qdxbukzp45zf
Managers: 1
Nodes: 3
Orchestration:
Task History Retention Limit: 5
...snip...
將節點移除!
$ docker swarm leave
Node left the swarm.
返回 Manager node ,即可看到該節點狀態已變成 Down !!
docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
06pojrqvb32e8pd6xtzi4i6yx * swarm-m Ready Active Leader
7oiggsh0jw6lsv9pwgzddk1zo swarm-s-2 Down Active
b76hq9s52b0bbwbwg2k8xfse8 swarm-s-1 Ready Active
Docker 介紹與實作
By James
Docker 介紹與實作
- 3,847