Docker 介紹與實作

李麒傑( James )

什麼是 Docker ?

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

所以,Docker 可以做什麼?

其實,Docker 就是一個 快速且輕量級虛擬機

Docker ? VM ?

Docker 特性

  1. 不可變:將作業系統、函式庫版本、應用程式...等都包裝在 Container 內,確保每次建置的 Container 都擁有同樣的行為。

  2. 輕量:Container 不需消耗太多記憶體,只需使用主程序所需的用量,在多加上數十 MB 記憶體就足夠。

  3. 快速:啟動 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