主題: Docker 實作與應用

分享者:張明泰 mtchang.tw@gmail.com

講者BLOG: http://blog.jangmt.com/

日期: 2015.3. 10

地點:管CM2016 教室

時間 19:00 ~ 21:00

19:00 ~ 19:30 報到

19:30 ~ 21:00 活動開始

21:00 ~ 21:30 討論

摘要:

本次分享的主題,主要介紹 Docker 的實作與應用。

Docker 是一個類似虛擬化主機功能的容器,但他少了很多虛擬化主機的層層堆疊。

他讓 Linux 系統上的應用程式的分派、部署和管理都變得有效率和輕鬆。

使用 Docker 需要有一些 Linux 的系統概念,但不論你的 Linux 作業系統是 Ubuntu 或是 CentOS 都可以方便快速的佈署 Docker 系統。

此分享將示範如何建立、管理與應用,並將以常見的 Apache + MySQL + PHP 服務的應用情境,說明如何透過 Docker 來使用協助網站的開發。

--------------------------------

以下正文分隔線

--------------------------------

(1) 簡介:

Docker是一個開放原始碼軟體專案,在軟體容器下自動布署應用程式,藉此在Linux作業系統上,提供了一個額外的軟體抽象層,以及作業系統層虛擬化的自動管理機制。Docker利用Linux內核中的資源分離機制,例如cgroups 及Linux 內核名稱空間 (name space),來建立獨立的軟體容器(containers)。這可以在單一 Linux 實體下運作,不用啟動一個完整的虛擬機器。

(引用:維基百科:http://zh.wikipedia.org/wiki/Docker_%28%E8%BB%9F%E9%AB%94%29 )

也可以說,透過 Docker 建立的容器跑起來像是一台虛擬機器的功能,但是又沒有虛擬機器的層層堆疊。底下示意圖可以顯示 VMs 和 Container 兩者的差異:

ref: http://www.logitrain.com.au/blog/wp-content/uploads/2014/09/docker.png 

如果把 Containers 和 Linux 上面的 Processes 比較,差別在於 container 有對於所執行的程式的資源使用限制。也因為 Linux 可以支援對於各種系統資源的使用限制,所以可以跑起來類似虛擬機器一樣的具有資源的獨立性。

ref: http://www.rightscale.com/blog/cloud-management-best-practices/docker-vs-vms-combining-both-cloud-portability-nirvana 

底下為 Docker 透過 Linux 核心提供的資源限制的功能示意圖。

ref: http://lab.howie.tw/2014/08/docker-docker-lxc-hypervisor.html 

ref:http://en.wikipedia.org/wiki/Docker_(software) 

CGroups

cgroups 是一個 linux 核心的功能一個設計目標是為不同的應用情況提供統一的介面,從控制單一行程(像nice)到系統級虛擬化(像opeNVZ,Linux-VServer,LXC)。

cgroups提供:

資源限制:組可以被設定不超過設定的記憶體限制;這也包括虛擬記憶體。

優先化:一些組可能會得到大量的CPU 或磁碟輸入輸出通量。

報告:用來衡量系統確實把多少資源用到適合的目的上。

分離:為組分離命名空間,這樣一個組不會看到另一個組的行程、網路連線和檔案。

控制:凍結組或檢查點和重新開機動。

ref:https://mairin.wordpress.com/2011/05/13/ideas-for-a-cgroups-ui/ 

UnionFS

可合併指定的所有實體目錄(branch),並建立一個單一的目錄(ex. union )集合去堆疊所有目錄來使用,並不會真正去變更到指定的所有目錄資料,全部的變更資料均會儲存在建立的目錄資料夾內(union)。(ref:http://gis.nchc.org.tw/lsi/Linux_Basic/discuss/look.asp?id=875&Page=7&ADMIN=1 )

ref: http://hondou.homedns.org/pukiwiki/pukiwiki.php?Docker%20%A4%B6%A4%C3%A4%AF%A4%EA%B8%C0%A4%A6%A4%C8%B2%BF%3F 

Docker 的架構:

Docker client 負責與 server  端的 docker deamon 溝通,下達 docker 的操作指令 (ex: docker pull , docker run 等...)。一般而言 Docker client 與 Docker deamon 都在同一台機器上面。架構圖如下:

ref: http://www.slideshare.net/winggundamth/docker-cd-workshop 

Docker 的元件:

Docker 有幾個重要的元件

Docker images & Containers: Docker images 是用來產生 container 的樣板檔案,他會以一公版的 linux 影像檔當成基礎,且使用者可透過 docker commit 擴展修改成為一個適合自己用的 docker images ,並且可以透過 docker registries 來分享。

Docker registries:是用來存放 images 的倉庫,預設的公用 Registry 就是 Docker Hub (https://hub.docker.com),提供類似套件儲存庫的功能。你可以透過 Docker Hub 下載及分享影像檔案,他類似 github 是一個有社交功能的公用倉庫。

ref: http://owaaa.github.io/docker/amazon/aws/devops/continuous/delivery/2014/10/10/docker_continous_delivery.html 

(2) Docker 安裝:

Docker 的運作是在 Linux kernel 的基礎上,在非 Linux 的平台如 Windows 他是透過 輕量級的 VM 元件產生一個虛擬機器在系統上執行,這個元件叫做 Boot2Docker (https://docs.docker.com/installation/windows/),所以跑起來和 Linux 不太一樣。所以在 MAC OS X 上面的 Docker 用的 Boot2Docker(https://docs.docker.com/installation/mac/ ) 也是用類似的方式達成的。

ref: https://docs.docker.com/installation/mac/ 

我不建議在非 Linux 平台上面使用 Docker ,使用一個完整的 Linux 來使用 Docker 才是較為正確的方式。

ref: https://docs.docker.com/installation/mac/ 

目前在 ubuntu 及 centos 可以用的的維護套件名稱為 docker.io ,ubuntu 由 http://www.ubuntuupdates.org/ppa/docker 這裡在維護提供。 Centos 7的 Docker 從 RHEL7 重新編譯,目前收錄在 CentOS-Extras 套件庫中( http://wiki.centos.org/zh-tw/Cloud/Docker )。

如果可以建議你使用 ubuntu 最新的14.04 LTS 版本

http://www.ubuntu-tw.org/modules/tinyd0/ 

Linux  mint 對應 Ubuntu 14.04 的版本為 Linux Mint 17.1 Rebecca

http://www.linuxmint.com/download.php 

使用 CnetOS 7 最新的版本來安裝

http://www.centos.org/download/ 

如果你不是用這些新的版本的 Linux,請你參考 docker 官方網站的說明來解決你安裝上的問題。

https://docs.docker.com/installation/ 

(2.1) CentOS 7 的 Docker 服務安裝:

# Install Docker in CentOS 7 , lsb_release 確定一下目前的 linux 版本

[mtchang@mtchang ~]$ sudo lsb_release -a

LSB Version:        :core-4.1-amd64:core-4.1-noarch:cxx-4.1-amd64:cxx-4.1-noarch:desktop-4.1-amd64:desktop-4.1-noarch:languages-4.1-amd64:languages-4.1-noarch:printing-4.1-amd64:printing-4.1-noarch

Distributor ID:        CentOS

Description:        CentOS Linux release 7.0.1406 (Core)

Release:        7.0.1406

Codename:        Core

# 直接安裝 docker 和 docker-registry

[mtchang@mtchang ~]$ sudo yum -y install docker docker-registry

# 在 centos 7 使用 systemctl 管控 docker.service ,這裡是把服務預設開機啟動

[mtchang@mtchang ~]$ sudo systemctl enable docker.service

ln -s '/usr/lib/systemd/system/docker.service' '/etc/systemd/system/multi-user.target.wants/docker.service'

# 手動啟用 docker service

[mtchang@mtchang ~]$ sudo systemctl start docker.service

# 驗證是否已經啟動

[mtchang@mtchang ~]$ sudo systemctl status docker.service

docker.service - Docker Application Container Engine

   Loaded: loaded (/usr/lib/systemd/system/docker.service; enabled)

   Active: active (running) since Sat 2015-02-21 15:22:01 CST; 15s ago

     Docs: http://docs.docker.com

 Main PID: 4346 (docker)

   CGroup: /system.slice/docker.service

           └─4346 /usr/bin/docker -d --selinux-enabled -H fd://

Feb 21 15:21:51 mtchang docker[4346]: 2015/02/21 15:21:51 docker daemon: 1.3.2 39fa2fa/1.3.2; execdriver: nat...iver:

Feb 21 15:21:51 mtchang docker[4346]: [aec76134] +job serveapi(fd://)

Feb 21 15:21:51 mtchang docker[4346]: [info] Listening for HTTP on fd ()

Feb 21 15:22:00 mtchang docker[4346]: [aec76134] +job init_networkdriver()

Feb 21 15:22:00 mtchang docker[4346]: [aec76134] -job init_networkdriver() = OK (0)

Feb 21 15:22:01 mtchang docker[4346]: [info] Loading containers:

Feb 21 15:22:01 mtchang docker[4346]: [info] : done.

Feb 21 15:22:01 mtchang docker[4346]: [aec76134] +job acceptconnections()

Feb 21 15:22:01 mtchang docker[4346]: [aec76134] -job acceptconnections() = OK (0)

Feb 21 15:22:01 mtchang systemd[1]: Started Docker Application Container Engine.

Hint: Some lines were ellipsized, use -l to show in full.

# 從 docker registry 抓取 ubuntu 的影像檔案

[mtchang@mtchang ~]$ sudo docker pull ubuntu

Pulling repository ubuntu

2d24f826cb16: Download complete

511136ea3c5a: Download complete

fa4fd76b09ce: Download complete

1c8294cc5160: Download complete

117ee323aaa9: Download complete

Status: Downloaded newer image for ubuntu:latest

# docker run 指令執行以 ubuntu 影像檔為基礎的一個 container

# mtchang@mt ~ $ sudo docker run --help

# 語法: docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

# -i 可以保持 STDIN 輸出訊息打開

# -t 可以取得一個 pseudo-TTY (虛擬終端機界面)

[mtchang@mtchang ~]$ sudo docker run -i -t ubuntu /bin/bash

# 已經切換到docker container 內, ip 也變換成為虛擬網段 172.17.0.xx。

root@bc44ac88d7a4:/# ifconfig

eth0      Link encap:Ethernet  HWaddr 02:42:ac:11:00:02

          inet addr:172.17.0.2  Bcast:0.0.0.0  Mask:255.255.0.0

          inet6 addr: fe80::42:acff:fe11:2/64 Scope:Link

          UP BROADCAST RUNNING  MTU:1500  Metric:1

          RX packets:19 errors:0 dropped:0 overruns:0 frame:0

          TX packets:6 errors:0 dropped:0 overruns:0 carrier:0

          collisions:0 txqueuelen:1000

          RX bytes:2173 (2.1 KB)  TX bytes:508 (508.0 B)

lo        Link encap:Local Loopback

          inet addr:127.0.0.1  Mask:255.0.0.0

          inet6 addr: ::1/128 Scope:Host

          UP LOOPBACK RUNNING  MTU:65536  Metric:1

          RX packets:0 errors:0 dropped:0 overruns:0 frame:0

          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0

          collisions:0 txqueuelen:0

          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

root@bc44ac88d7a4:/#  exit

exit

(2.2) Linux Mint 17 OR Ubuntu 的 Docker 服務安裝:

# Linux mint 安裝 docker

mtchang@mt ~ $ lsb_release -a

No LSB modules are available.

Distributor ID: LinuxMint

Description: Linux Mint 17 Qiana

Release: 17

Codename: qiana

# ubuntu 因為安裝過程很煩,所以它把安裝過程寫成了script 放在 https://get.docker.com/ubuntu/ ,所以底下的安裝需要先透過 curl 抓回 script ,然後透過 shell 執行安裝。

mtchang@mt ~ $ sudo apt-get install curl

# 它需要有 apparmor ,這是一個應用程式安全性的控管機制

mtchang@mt ~ $ sudo apt-get install apparmor

# 安裝由 ubuntu 維護的 docker.io 套件,不要安裝原本 ubuntu 提供的 docker 套件

mtchang@mt ~ $ sudo apt-get install docker.io

# 載入 bash 環境變數

mtchang@mt ~ $ source /etc/bash_completion.d/docker.io

# 抓取安裝 script 並執行

mtchang@mt ~ $ curl -sSL https://get.docker.com/ubuntu/ | sudo sh

# 直接執行 ubuntu 的影像檔

mtchang@mt ~ $ sudo docker run -i -t ubuntu /bin/bash

# 第一次執行會發現還沒有 ubuntu 這個影像檔,會直接從網路上抓取

Unable to find image 'ubuntu' locally

Pulling repository ubuntu

5ba9dab47459: Download complete

511136ea3c5a: Download complete

27d47432a69b: Download complete

5f92234dcf1e: Download complete

51a9c7c1f8bb: Download complete

# 然後就直接進入 container

root@6bcf5474cbf3:/# ifconfig

eth0      Link encap:Ethernet  HWaddr 02:42:ac:11:00:02

          inet addr:172.17.0.2  Bcast:0.0.0.0  Mask:255.255.0.0

          inet6 addr: fe80::42:acff:fe11:2/64 Scope:Link

          UP BROADCAST RUNNING  MTU:1500  Metric:1

          RX packets:43 errors:0 dropped:0 overruns:0 frame:0

          TX packets:8 errors:0 dropped:0 overruns:0 carrier:0

          collisions:0 txqueuelen:0

          RX bytes:7262 (7.2 KB)  TX bytes:648 (648.0 B)

lo        Link encap:Local Loopback

          inet addr:127.0.0.1  Mask:255.0.0.0

          inet6 addr: ::1/128 Scope:Host

          UP LOOPBACK RUNNING  MTU:65536  Metric:1

          RX packets:0 errors:0 dropped:0 overruns:0 frame:0

          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0

          collisions:0 txqueuelen:0

          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

root@6bcf5474cbf3:/# df -lh

Filesystem                                              Size  Used Avail Use% Mounted on

rootfs                                                  451G   28G  401G   7% /

none                                                    451G   28G  401G   7% /

tmpfs                                                   1.9G     0  1.9G   0% /dev

shm                                                      64M     0   64M   0% /dev/shm

/dev/disk/by-uuid/600e3388-c76f-4b56-ba18-14b58274f430  451G   28G  401G   7% /etc/hosts

tmpfs                                                   1.9G     0  1.9G   0% /proc/kcore

root@6bcf5474cbf3:/# exit

exit

mtchang@mt ~ $ sudo docker images

REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE

ubuntu              trusty              5ba9dab47459        13 days ago         188.3 MB

ubuntu              14.04               5ba9dab47459        13 days ago         188.3 MB

ubuntu              14.04.1             5ba9dab47459        13 days ago         188.3 MB

ubuntu              latest              5ba9dab47459        13 days ago         188.3 MB

安裝參考:https://docs.docker.com/installation/ubuntulinux/#ubuntu-trusty-1404-lts-64-bit 

Docker 的網路:

docker 安裝好後會在系統產生一個 docker0 的虛擬網卡,通常 ip 會是 172.17.42.1 ,內部的 container 會自動取得 172.17.0.0/24 的 ip ,並且預設就可 nat 連接到 eth0 出去。

外界如果需要連接到 container 內的網路,需要透過docker -p 外部 port : 內部 port 的 DNAT port 對應方式,來指定允許存取容器的主機上的 IP、界面。

例如:

$ sudo docker run --name="jangmt0305" -p 8080:80 -i -t ubuntu /bin/bash

這會讓本地端的 8080 port 對應到 container 內的 80 port

Docker 的儲存裝置:

資料卷 docker volume ,在 docker container 內如果需要存取外部的儲存裝置,可以透過建立 docker volume 和 docker host 產生目錄的對應。 當然也可以透過 mount  之類的方式掛載外界的資源,但 docker container 內部是一個非常精簡的 linux 這會需要多增加安裝更多的程式。

使用的方法為在 docker run 的時候加入 -v  指定一個本地端主機到 docker container 內。

例如:

$ sudo docker run -i -t  --name web -v /home/webapp:/var/www/html/webapp  /bin/bash

這會把本地端的 /home/webapp 對應到 container 內的 /var/www/html/webapp 目錄內。

ref: http://jam.sg/blog/mongodb-docker-part-2/ 

(3) Docker 常用指令:

docker search  搜尋 docker hub 上面的 images 檔案

docker pull   抓取影像檔

docker login  登入 docker hub

docker push  將影像檔上傳道 docker hub

docker commit  將修正的 container 資料提交成為新的影像檔

docker run  以某個 image 執行 container

docker ps  觀看目前系統正在執行的 container

docker images  觀看系統擁有的影像檔

docker build  依據 docker file 的描述,建立一個 docker images

# 詳細可以觀看 docker help 的說明

# docker help

Usage: docker [OPTIONS] COMMAND [arg...]

A self-sufficient runtime for linux containers.

.. 略...

Commands:

    attach    Attach to a running container

    build     Build an image from a Dockerfile

    commit    Create a new image from a container's changes

    cp        Copy files/folders from a container's filesystem to the host path

    create    Create a new container

    diff      Inspect changes on a container's filesystem

    events    Get real time events from the server

    exec      Run a command in a running container

    export    Stream the contents of a container as a tar archive

    history   Show the history of an image

    images    List images

    import    Create a new filesystem image from the contents of a tarball

    info      Display system-wide information

    inspect   Return low-level information on a container or image

    kill      Kill a running container

    load      Load an image from a tar archive

    login     Register or log in to a Docker registry server

    logout    Log out from a Docker registry server

    logs      Fetch the logs of a container

    port      Lookup the public-facing port that is NAT-ed to PRIVATE_PORT

    pause     Pause all processes within a container

    ps        List containers

    pull      Pull an image or a repository from a Docker registry server

    push      Push an image or a repository to a Docker registry server

    rename    Rename an existing container

    restart   Restart a running container

    rm        Remove one or more containers

    rmi       Remove one or more images

    run       Run a command in a new container

    save      Save an image to a tar archive

    search    Search for an image on the Docker Hub

    start     Start a stopped container

    stats     Display a live stream of one or more containers' resource usage statistics

    stop      Stop a running container

    tag       Tag an image into a repository

    top       Lookup the running processes of a container

    unpause   Unpause a paused container

    version   Show the Docker version information

    wait      Block until a container stops, then print its exit code

Run 'docker COMMAND --help' for more information on a command.

(4) 應用情境:( 以 ubuntu 的 docker 影像檔基礎為範例)

目前 docker 的應用都是透過網路上 docker hub 這種發布的平台,發布分享影像檔案。開發者透過釋放出來的影像檔,提交 commit 自己修改過的影像檔案。 docker 有各教學的連結,教你如何使用 docker 來使用別人提交的現成 images https://www.docker.com/tryit/ ,你可以花各 10 min 試試看這個互動式教學文件。

ref: http://developer-blog.cloudbees.com/2014/07/announcing-dockerhub-jenkins-plugin.html 

ref: http://blog2dev.blogspot.fr/2014/06/docker-mise-en-pratique.html 

https://www.docker.com/tryit/  線上互動教學

應用情境案例(1):一個 Apache2 + PHP 服務安裝為例

# 啟動一個以 ubuntu image為主 的 container , 名稱命名為 jangmt0305 ,並將本地端的 tcp port 8080 對應到 container  80 ,並且 -i 將 STDIN 保留, -t 取得一個虛擬終端機,並執行 /bin/bash  的程序。

mtchang@mt ~ $ sudo docker run --name="jangmt0305" -p 8080:80 -i -t ubuntu /bin/bash

# 底下為在 docker container 內的 /bin/bash 執行

root@b29f95d30b68:/# ifconfig

eth0      Link encap:Ethernet  HWaddr 02:42:ac:11:00:09  

          inet addr:172.17.0.9  Bcast:0.0.0.0  Mask:255.255.0.0

          inet6 addr: fe80::42:acff:fe11:9/64 Scope:Link

          UP BROADCAST RUNNING  MTU:1500  Metric:1

          RX packets:6 errors:0 dropped:0 overruns:0 frame:0

          TX packets:6 errors:0 dropped:0 overruns:0 carrier:0

          collisions:0 txqueuelen:0

          RX bytes:508 (508.0 B)  TX bytes:508 (508.0 B)

lo        Link encap:Local Loopback  

          inet addr:127.0.0.1  Mask:255.0.0.0

          inet6 addr: ::1/128 Scope:Host

          UP LOOPBACK RUNNING  MTU:65536  Metric:1

          RX packets:0 errors:0 dropped:0 overruns:0 frame:0

          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0

          collisions:0 txqueuelen:0

          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

# docker host 另開一個新視窗,從外部來看目前的 container 執行狀況

mtchang@mt ~ $ sudo docker ps

CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                  NAMES

b29f95d30b68        ubuntu:14.04        "/bin/bash"         36 seconds ago      Up 35 seconds       0.0.0.0:8080->80/tcp   jangmt0305

# 可以透過 Linux 的 iptables 看到系統開了一個 DNAT 對應  tcp dpt:8080 to:172.17.0.9:80

mtchang@mt ~ $ sudo iptables -L -n -t nat

Chain PREROUTING (policy ACCEPT)

target     prot opt source               destination        

DOCKER     all  --  0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCAL

Chain INPUT (policy ACCEPT)

target     prot opt source               destination        

Chain OUTPUT (policy ACCEPT)

target     prot opt source               destination        

DOCKER     all  --  0.0.0.0/0           !127.0.0.0/8          ADDRTYPE match dst-type LOCAL

Chain POSTROUTING (policy ACCEPT)

target     prot opt source               destination        

MASQUERADE  all  --  172.17.0.0/16        0.0.0.0/0          

MASQUERADE  tcp  --  172.17.0.9           172.17.0.9           tcp dpt:80

Chain DOCKER (2 references)

target     prot opt source               destination        

DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:8080 to:172.17.0.9:80

# 回到 docker container 內,可以執行安裝程序。

root@b29f95d30b68:/# apt-get install apache2 php5-cli  libapache2-mod-php5

# 啟動服務

root@b29f95d30b68:/# /etc/init.d/apache2 restart

 * Restarting web server apache2                                                                                                                                AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.17.0.9. Set the 'ServerName' directive globally to suppress this message          [ OK ]

root@b29f95d30b68:/# netstat -anp

Active Internet connections (servers and established)

Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name

tcp6       0      0 :::80                   :::*                    LISTEN      -              

Active UNIX domain sockets (servers and established)

Proto RefCnt Flags       Type       State         I-Node   PID/Program name    Path

# 用瀏覽器測試看看觀看網址  http://<docker host IP>:8080/

# 把剛剛的 container 重新載入啟動,需要記住 container ID 號碼,可以使用 docker ps -a 來查詢。

mtchang@mt ~ $ sudo docker start b29f95d30b68

b29f95d30b68

mtchang@mt ~ $ sudo docker ps

CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                  NAMES

b29f95d30b68        ubuntu:14.04        "/bin/bash"         19 minutes ago      Up 6 seconds        0.0.0.0:8080->80/tcp   jangmt0305

# 可以透過 docker attach 取回 container ,重新取得 /bin/bash

mtchang@mt ~ $ sudo docker attach b29f95d30b68

root@b29f95d30b68:/# ifconfig

eth0      Link encap:Ethernet  HWaddr 02:42:ac:11:00:0a  

          inet addr:172.17.0.10  Bcast:0.0.0.0  Mask:255.255.0.0

          inet6 addr: fe80::42:acff:fe11:a/64 Scope:Link

          UP BROADCAST RUNNING  MTU:1500  Metric:1

          RX packets:8 errors:0 dropped:0 overruns:0 frame:0

          TX packets:8 errors:0 dropped:0 overruns:0 carrier:0

          collisions:0 txqueuelen:0

          RX bytes:648 (648.0 B)  TX bytes:648 (648.0 B)

lo        Link encap:Local Loopback  

          inet addr:127.0.0.1  Mask:255.0.0.0

          inet6 addr: ::1/128 Scope:Host

          UP LOOPBACK RUNNING  MTU:65536  Metric:1

          RX packets:0 errors:0 dropped:0 overruns:0 frame:0

          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0

          collisions:0 txqueuelen:0

          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

應用情境案例(2):把這個 container 提交並且上傳到 docker hub:

# 把系統中最後狀態的 container commit ,並且上傳道 docker hub 提供分享。

# 先使用 docker ps -a 觀看 container ID

mtchang@mt ~ $ sudo docker ps -a

CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                      PORTS               NAMES

…(skip) ...

b29f95d30b68        ubuntu:14.04        "/bin/bash"         20 hours ago        Exited (0) 17 minutes ago  

# 使用 docker commit  提交 -m 為提交的說明 -a 為作者資訊

#  b29f95d30b68 為提交的 container ID

#  mtchang/lamp 為 REPOSITORY[:TAG]  ,在本機提交後顯示成為 docker images 的 REPOSITORY 及 TAG ,並且產生一個新的 hash code

mtchang@mt ~ $ sudo docker commit -m="jangmt/lamp v1" -a="mtchang" b29f95d30b68 mtchang/lamp

cfa9495f5d8f62278ff235a6124309b81aff48afdec74adb625d118a39b36cbf

# 檢查看看提交後的 docker images

mtchang@mt ~ $ sudo docker images 

REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE

mtchang/lamp        latest              cfa9495f5d8f        29 seconds ago      248.9 MB

Docker HUB 提交 push

# 版本更新,在提交一次。

$ docker commit -m="jangmt/lamp v4" -a="mtchang" 0b65d5ceae03 mtchang/lamp

59480b898c911ed8551eb18c24bf35992d2561714be15c0919f9c5a15008290d

# 登入 docker hub ,先確定你在 docker hub 已經有帳號了

mtchang@mt ~ $ sudo docker login

Username: mtchang

Password: oooxxx

Email: mtchang.tw@gmail.com

Login Succeeded

# 檢查一下最後要提交的 images

mtchang@mt ~ $ sudo docker images

REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE

mtchang/lamp        latest              cfa9495f5d8f        43 minutes ago      248.9 MB

# docker push 提交 mtchang/lamp ,系統會檢查 hash code 如果影像檔有提交過了,會跳過不重複提交。基本上影像檔都是由很多小的影像檔組合成的。

mtchang@mt ~ $ sudo docker push mtchang/lamp

The push refers to a repository [mtchang/lamp] (len: 1)

Sending image list

Pushing repository mtchang/lamp (1 tags)

511136ea3c5a: Image already pushed, skipping

27d47432a69b: Image already pushed, skipping

5f92234dcf1e: Image already pushed, skipping

51a9c7c1f8bb: Image already pushed, skipping

5ba9dab47459: Image already pushed, skipping

cfa9495f5d8f: Image successfully pushed

Pushing tag for rev [cfa9495f5d8f] on {https://cdn-registry-1.docker.io/v1/repositories/mtchang/lamp/tags/latest}

(5) 其他 Docker 主題

(5.1)讓 Docker 程式可以持續工作

當我們要啟動一個 container 後,並且讓它執行一些服務又要可以讓服務成為背景以服務的型態工作,這時候需要透過 supervisord 當成 startup 的啟動程式,呼叫啟動我們需要的 service,並且讓他在系統中可以持續的工作。

ref: http://blog.trifork.com/2014/03/11/using-supervisor-with-docker-to-manage-processes-supporting-image-inheritance/ 

說明文件:

https://docs.docker.com/articles/using_supervisord/   Using Supervisor with Docker

http://supervisord.org/  Supervisord

(5.2) Docker API

應用案例:

https://github.com/crosbymichael/dockerui 

官方API文件:

https://docs.docker.com/reference/api/docker_remote_api/ 

(6) 使用現成的 docker images ,以 mtchang/lamp 為例

如何使用 mtchang/lamp 這個 docker images

https://registry.hub.docker.com/u/mtchang/lamp/ 

1. 使用這個 docker images

# 從 docker hub 抓取這個版本的 lamp

$ sudo docker pull mtchang/lamp

# 看看本地端的 images 是否抓好了

$ sudo docker images

REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE

mtchang/lamp        latest              59480b898c91        7 minutes ago       578.1 MB

...(skip)...

# 以 mtchang/lamp 的 images 啟動一個 container ,動作是本地端的 tcp 8080:對應到 container 中的 tcp 80 port

# 將本地端指定的目錄 對應到 伺服器端目錄 ,並且啟動 /usr/bin/supervisord 讓 container 可以停在系統內

# sudo docker run -d -p 8080:80 -v 本地端目錄:伺服器端目錄 mtchang/lamp /usr/bin/supervisord

# example:

$ sudo docker run -d -p 8080:80 -v /home/mtchang/app:/var/www/html/test mtchang/lamp /usr/bin/supervisord

# 觀看是否常駐

$ sudo docker ps

CONTAINER ID        IMAGE                 COMMAND                CREATED              STATUS              PORTS                  NAMES

0b65d5ceae03        mtchang/lamp:latest   "/usr/bin/supervisor   About a minute ago   Up About a minute   0.0.0.0:8080->80/tcp   jolly_brattain      

2. LAMP 功能測試:

(1) http://<your host>:8080/

LAMP server

https://registry.hub.docker.com/u/mtchang/lamp/

by mtchang.tw@gmail.com

(2) http://<your host>:8080/test/

會出現對應到本地端目錄 /home/mtchang/app 目錄的內容

(3)phpmyadmin http://192.168.123.59:8080/phpmyadmin/

mysql root password is "dockermysql"

(4)sqlbuddy http://192.168.123.59:8080/sqlbuddy

3. 結束這個 container 的程式

# 使用 docker attach 進入 container 的 console 使用 ctrl + c 中斷程式。

$ docker attach 0b65d5ceae03

^C2015-03-07 15:33:10,571 WARN received SIGINT indicating exit request

(7) 使用 dockerfile 建立 images:

透過用 dockerfile 配置可以快速生成 docker image 並實現 container 部署 。

ref: http://dockerone.com/article/101 

範例:

https://registry.hub.docker.com/u/tutum/lamp/dockerfile/ 

官方說明文件:

https://docs.docker.com/articles/dockerfile_best-practices/ 

7.1 本機 dockerfile 建立

# 在本地端的目錄下,建立一個檔案名稱為 Dockerfile

#

# FROM:你的 base image 為基底

# MAINTAINER:維護 images 的人

# RUN:在 images 建立過程執行的指令

# ADD:將本機的檔案或遠端的檔案加入到 image 內的目錄

# 語法請參考:https://docs.docker.com/reference/builder/

# 底下 Dockerfile 參考 https://registry.hub.docker.com/u/tutum/lamp/dockerfile/ 

mtchang@mt ~/SCM_code/docker/apdemo $ vim Dockerfile

FROM ubuntu:latest

MAINTAINER mtchang <mtchang.tw@gmail.com>

# Install packages

ENV DEBIAN_FRONTEND noninteractive

RUN apt-get update && \

  apt-get -y install supervisor git apache2 libapache2-mod-php5 mysql-server php5-mysql pwgen php-apc php5-mcrypt && \

  echo "ServerName localhost" >> /etc/apache2/apache2.conf

#Enviornment variables to configure php

ENV PHP_UPLOAD_MAX_FILESIZE 10M

ENV PHP_POST_MAX_SIZE 10M

# 執行 docker build 會直接依據 dockerfile 內容編譯 image

mtchang@mt ~/SCM_code/docker/apdemo $ sudo docker build -t mtchang/apdemo   .  (<--  點)

# 注意每個過程都會有各 hash code

Sending build context to Docker daemon  2.56 kB

Sending build context to Docker daemon

Step 0 : FROM ubuntu:latest

 ---> 5ba9dab47459

Step 1 : MAINTAINER mtchang <mtchang.tw@gmail.com>

 ---> Running in 584aa4bb3e1c

 ---> 6c304964c942

Removing intermediate container 584aa4bb3e1c

Step 2 : ENV DEBIAN_FRONTEND noninteractive

 ---> Running in 9522aec6d092

 ---> 4eb8188f88d7

Removing intermediate container 9522aec6d092

Step 3 : RUN apt-get update &&   apt-get -y install supervisor git apache2 libapache2-mod-php5 mysql-server php5-mysql pwgen php-apc php5-mcrypt &&   echo "ServerName localhost" >> /etc/apache2/apache2.conf

 ---> Running in b7c3e263758c

...(省略數百行)...

Removing intermediate container cd49243be07b

Step 6 : EXPOSE 8080

 ---> Running in a4843a5a0c8e

 ---> c31129378fe8

Removing intermediate container a4843a5a0c8e

Successfully built c31129378fe8

# 第二次編譯速度會比較快,因為使用了 cache

mtchang@mt ~/SCM_code/docker/apdemo $ vim Dockerfile

mtchang@mt ~/SCM_code/docker/apdemo $ sudo docker build -t mtchang/apdemo .

Sending build context to Docker daemon 2.048 kB

Sending build context to Docker daemon

Step 0 : FROM ubuntu:latest

 ---> 5ba9dab47459

Step 1 : MAINTAINER mtchang <mtchang.tw@gmail.com>

 ---> Using cache

 ---> 6c304964c942

Step 2 : ENV DEBIAN_FRONTEND noninteractive

 ---> Using cache

 ---> 4eb8188f88d7

Step 3 : RUN apt-get update &&   apt-get -y install supervisor git apache2 libapache2-mod-php5 mysql-server php5-mysql pwgen php-apc php5-mcrypt &&   echo "ServerName localhost" >> /etc/apache2/apache2.conf

 ---> Using cache

 ---> b0d088b36fe3

Step 4 : ENV PHP_UPLOAD_MAX_FILESIZE 10M

 ---> Using cache

 ---> 61e966ed8a2d

Step 5 : ENV PHP_POST_MAX_SIZE 10M

 ---> Using cache

 ---> 431d2a1cc310

Successfully built 431d2a1cc310

# 建立的影像檔案 mtchang/apdemo

mtchang@mt ~/SCM_code/docker/apdemo $ sudo docker images

REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE

mtchang/apdemo      latest              431d2a1cc310        14 minutes ago      426 MB

mtchang@mt ~/SCM_code/docker/apdemo $ sudo docker login

Username (mtchang):

Login Succeeded

# 可以單獨將這個檔案 push 到 docker hub 上面

mtchang@mt ~/SCM_code/docker/apdemo $ sudo docker push mtchang/apdemo

The push refers to a repository [mtchang/apdemo] (len: 1)

Sending image list

Pushing repository mtchang/apdemo (1 tags)

511136ea3c5a: Image already pushed, skipping

27d47432a69b: Image already pushed, skipping

5f92234dcf1e: Image already pushed, skipping

51a9c7c1f8bb: Image already pushed, skipping

5ba9dab47459: Image already pushed, skipping

6c304964c942: Image already pushed, skipping

4eb8188f88d7: Image already pushed, skipping

b0d088b36fe3: Image already pushed, skipping

61e966ed8a2d: Image already pushed, skipping

431d2a1cc310: Image already pushed, skipping

Pushing tag for rev [431d2a1cc310] on {https://cdn-registry-1.docker.io/v1/repositories/mtchang/apdemo/tags/latest}

# 以上為依據 dockerfile 的建立方法,但是產生的檔案只有本機可以使用。 push 到 docker hub 仍是影像檔案型態,使用者看不到你的 dockerfile 。

7.2 配合 github 的 dockerfile 建立

Docker hub 可以從 github 的儲存庫中,依據 Dockerfile 的內容自動建立影像檔案。

所以請先在 github 中建立一個 Dockerfile 檔案, README 有則是最好。

dockerfile_1_github.jpg

在 Docker HUB 內建立一個 REPOS 選擇 Github 的儲存庫。

dockerfile_1_repo.jpg

在 docker hub 內選擇 automated Build 選項。

dockerfile_2_start_build.jpg

把 Active 打勾,並確認路徑是否正確。

dockerfile_3_trigger_build.jpg

按下 save and trigger build 就會自動建立 dockerfile 檔案了。

dockerfile_4_finish.jpg

7.3 使用及測試

mtchang@mt ~/SCM_code/docker/apdemo $ sudo docker pull mtchang/apdemo

Pulling repository mtchang/apdemo

d0611a67283c: Download complete

d0611a67283c: Pulling image (latest) from mtchang/apdemo

fa4fd76b09ce: Download complete

1c8294cc5160: Download complete

117ee323aaa9: Download complete

2d24f826cb16: Download complete

d5f32e0f2638: Download complete

f6b232724428: Download complete

a392b7a15278: Download complete

ad48e990d540: Download complete

Status: Downloaded newer image for mtchang/apdemo:latest

mtchang@mt ~/SCM_code/docker/apdemo $ sudo docker images

REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE

mtchang/apdemo      latest              d0611a67283c        17 minutes ago      425.9 MB

mtchang@mt ~/SCM_code/docker/apdemo $ sudo docker run -i -t -p 8080:80 mtchang/apdemo /bin/bash

root@c88dac59dbab:/# ifconfig

eth0      Link encap:Ethernet  HWaddr 02:42:ac:11:00:08  

          inet addr:172.17.0.8  Bcast:0.0.0.0  Mask:255.255.0.0

          inet6 addr: fe80::42:acff:fe11:8/64 Scope:Link

          UP BROADCAST RUNNING  MTU:1500  Metric:1

          RX packets:8 errors:0 dropped:0 overruns:0 frame:0

          TX packets:8 errors:0 dropped:0 overruns:0 carrier:0

          collisions:0 txqueuelen:0

          RX bytes:648 (648.0 B)  TX bytes:648 (648.0 B)

lo        Link encap:Local Loopback  

          inet addr:127.0.0.1  Mask:255.0.0.0

          inet6 addr: ::1/128 Scope:Host

          UP LOOPBACK RUNNING  MTU:65536  Metric:1

          RX packets:0 errors:0 dropped:0 overruns:0 frame:0

          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0

          collisions:0 txqueuelen:0

          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

root@c88dac59dbab:/# /etc/init.d/apache2 restart

 * Restarting web server apache2

 

# Docker HOST 上面看到的 iptables 狀況

mt ~ # iptables -L -n -t nat

Chain PREROUTING (policy ACCEPT)

target     prot opt source               destination        

DOCKER     all  --  0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCAL

Chain INPUT (policy ACCEPT)

target     prot opt source               destination        

Chain OUTPUT (policy ACCEPT)

target     prot opt source               destination        

DOCKER     all  --  0.0.0.0/0           !127.0.0.0/8          ADDRTYPE match dst-type LOCAL

Chain POSTROUTING (policy ACCEPT)

target     prot opt source               destination        

MASQUERADE  all  --  172.17.0.0/16        0.0.0.0/0          

MASQUERADE  tcp  --  172.17.0.8           172.17.0.8           tcp dpt:80

Chain DOCKER (2 references)

target     prot opt source               destination        

DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:8080 to:172.17.0.8:80

 

# 測試網頁

http://<Docker HOST IP>:8080/

test_ok_page.jpg

(8) QA討論:

1. DockerFile  類似 Redhat 上面的 kickstart 功能,可以預先指定所需安裝設定的資訊。但這樣兩者只差別在於 docker images 下載並產生 container 和 OS 安裝速度的差別。

Docker 的特色 佈署快 、版本控制、Isolation。但我用 kickstart 自動化安裝一個精簡版的 Linux 也很快,只比 Docker 慢一點點而已。所以他的特點到底適合哪種應用?

(9) Learn More: