1. 程式人生 > >Docker容器技術與應用(專案5 Docker叢集)

Docker容器技術與應用(專案5 Docker叢集)

專案5 容器相關技術

任務5.1 Docker底層技術

Docker 底層使用的核心技術包括 Linux 上的名稱空間(Namespaces)控制組(Control groups)聯合檔案系統(Union file systems)和容器格式(Container format)。

傳統虛擬機器(VM)通過在宿主主機中執行hypervisor 來模擬一整套完整的硬體環境,提供給虛擬機器的作業系統。容器是藉助Linux的名稱空間許可權隔離、控制組的資源分配控制、虛擬網路等技術實現程序之間的隔離,容器和宿主主機共享Linux核心。差別如下圖:


圖5.1虛擬機器技術與容器技術的對比

在Linux作業系統中,包括核心、檔案系統、網路、PID、UID、IPC、記憶體、硬碟、CPU 等等,所有的資源都是應用程序直接共享的。要實現虛擬化,除了要實現對記憶體、CPU、網路IO、硬碟IO、儲存空間等限制外,還要實現檔案系統、網路、PID、UID、IPC等等的相互隔離。

5.1.1名稱空間nameSpace

名稱空間是 Linux 核心一個強大的特性。每個容器都有自己單獨的名稱空間,執行在其中的應用都像獨立的作業系統中執行一樣。名稱空間保證了容器之間彼此互不影響。Linux核心提供了六種namespace隔離的系統呼叫,如下表所示。

Namespace

系統呼叫引數

隔離內容

UTS

CLONE_NEWUTS

主機名與域名

IPC

CLONE_NEWIPC

訊號量、訊息佇列和共享記憶體

PID

CLONE_NEWPID

程序編號

Network

CLONE_NEWNET

網路裝置、網路棧、埠等等

Mount

CLONE_NEWNS

掛載點(檔案系統)

User

CLONE_NEWUSER

使用者和使用者組

表5.1namespace六項隔離

Linux核心實現namespace的主要目的就是為了實現輕量級虛擬化(容器)服務,構建一個相對隔離的shell環境。在同一個namespace下的程序可以感知彼此的變化,而對外界的程序一無所知。這樣讓容器內的程序執行在一個獨立的系統環境中,以此達到隔離的目的。

5.1.2控制組cgroup

cgroups是Linux核心提供的一種機制,cgroup可以根據特定的行為,把一系列系統任務及其子任務整合或分隔到不同的資源等級分組中,從而為系統資源管理提供一個統一的框架。主要的功能包括:

資源限制(Resource Limitation):cgroups可以對程序組使用的資源總額進行限制。如設定應用執行時使用記憶體的上限,一旦超過這個配額就發出OOM(Out of Memory)。

優先順序分配(Prioritization):通過分配的CPU時間片數量及硬碟IO頻寬大小,實際上就相當於控制了程序執行的優先順序。

資源統計(Accounting): cgroups可以統計系統的資源使用量,如CPU使用時長、記憶體用量等等,這個功能非常適用於計費。

程序控制(Control):cgroups可以對程序組執行掛起、恢復等操作。

通俗的來說,cgroups可以限制、記錄、隔離程序組所使用的物理資源(包括:CPU、memory、IO等),為容器實現虛擬化提供了基本保證,是構建Docker等一系列虛擬化管理工具的基礎。Cgroup功能實現特點:

(1)cgroups的API以一個偽檔案系統的方式實現,即使用者可以通過檔案操作實現cgroups的組織管理。

(2)cgroups的組織管理操作單元可以細粒度到執行緒級別,使用者態程式碼也可以針對系統分配的資源建立和銷燬cgroups,從而實現資源再分配和管理。

(3)所有資源管理的功能都以subsystem(子系統)的方式實現,介面統一。

(4)子程序建立之初與其父程序處於同一個cgroups的控制組。

cgroups的實現本質上是給系統程序掛上鉤子(hooks),當task執行的過程中涉及到某個資源時就會觸發鉤子上所附帶的subsystem進行檢測,最終根據資源類別的不同使用對應的技術進行資源限制和優先順序分配。

5.1.3聯合檔案系統UnionFS

聯合檔案系統(UnionFS)是一種分層、輕量級並且高效能的檔案系統,它支援對檔案系統的修改按層(Layer)疊加,同時可以將不同目錄掛載到同一個虛擬檔案系統下。聯合檔案系統是Docker 映象的基礎。映象可以通過分層來進行繼承,基於基礎映象,可以製作各種具體的應用映象。Aufs是Docker最初採用的檔案系統,由於Aufs未能加入到Linux核心,考慮到相容性問題,加入了Devicemapper的支援。Docker 目前支援的聯合檔案系統種類包括 Aufs、btrfs、vfs和DeviceMapper。

典型的Linux檔案系統由bootfs和rootfs兩部分組成,bootfs(boot file system)主要包含bootloader和kernel,bootloader主要是引導載入kernel,當kernel被載入到記憶體中後bootfs就被umount了。rootfs (root filesystem)包含的就是典型 Linux 系統中的/dev,/proc,/bin,/etc等標準目錄和檔案。

圖5.2Linux載入結構

Docker容器建立在Aufs基礎上的,Aufs是一種Union FS, 簡單來說就是支援將不同的目錄掛載到同一個虛擬檔案系統下,並實現一種layer的概念。Aufs將掛載到同一虛擬檔案系統下的多個目錄分別設定成read-only,read-write以及whiteout-able許可權,對read-only目錄只能讀,而寫操作只能實施在read-write目錄中。寫操作是在read-only上的一種增量操作,不影響read-only目錄。當掛載目錄的時候要嚴格按照各目錄之間的這種增量關係,將被增量操作的目錄優先於在它基礎上增量操作的目錄掛載,待所有目錄掛載結束了,繼續掛載一個read-write目錄,如此便形成了一種層次結構。

Docker映象的典型結構如下圖。傳統的Linux載入bootfs時會先將rootfs設為read-only,然後在系統自檢之後將rootfs從read-only改為read-write,然後就可以在rootfs上進行寫和讀的操作了。

但Docker的映象卻不是這樣,它在bootfs自檢完畢之後並不會把rootfs的read-only改為read-write。而是利用union mount(UnionFS的一種掛載機制)將一個或多個read-only的rootfs載入到之前的read-only的rootfs層之上。在載入了這麼多層的rootfs之後,仍然讓它看起來只像是一個檔案系統,在Docker的體系裡把union mount的這些read-only的rootfs叫做Docker的映象。但是,此時的每一層rootfs都是read-only的,此時還不能對其進行操作。當建立一個容器,也就是將Docker映象進行例項化,系統會在一層或是多層read-only的rootfs之上分配一層空的read-write的rootfs。

圖5.3Docker 映象結構

為了形象化Docker的映象結構,docker pull一個ubuntu:14.04的映象,使用docker images -tree檢視結果如下:

[[email protected] qingze]#docker images -tree

Warning: '-tree' isdeprecated, it will be removed soon. See usage.

└─511136ea3c5a VirtualSize: 0 B

  └─3b363fd9d7da Virtual Size: 192.5 MB

   └─607c5d1cca71 Virtual Size: 192.7 MB

     └─f62feddc05dc Virtual Size: 192.7 MB

       └─8eaa4ff06b53 Virtual Size: 192.7 MBTags: ubuntu:14.04,

因為如果高Docker版本,docker image不再使用,可以使用“docker history 映象ID”來檢視。

可以看到Ubuntu的映象中有多個長ID的layer,且以一種樹狀結構繼承下來,如下圖。其中,第n+1層繼承了第n層,並在此基礎上有了自己的內容,直觀上的表現就是第n+1層佔用磁碟空間增大。並且,不同的映象可能會有相同的父映象。例如,圖中Tomcat和Nginx 繼承於同一個Vim 映象,這種組織方式起到共享的作用,節約了映象在物理機上佔用的空間。

圖5.4映象繼承關係

使用docker save命令儲存映象tar,查詢其結構。

[[email protected] qingze]# docker save -o ubuntu.tar ubuntu:14.04

[[email protected] qingze]#  tar -tf ubuntu.tar

3b363fd9d7dab4db9591058a3f43e806f6fa6f7e2744b63b2df4b84eadb0685a/

3b363fd9d7dab4db9591058a3f43e806f6fa6f7e2744b63b2df4b84eadb0685a/VERSION

3b363fd9d7dab4db9591058a3f43e806f6fa6f7e2744b63b2df4b84eadb0685a/json

3b363fd9d7dab4db9591058a3f43e806f6fa6f7e2744b63b2df4b84eadb0685a/layer.tar

511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158/

511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158/VERSION

511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158/json

511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158/layer.tar

607c5d1cca71dd3b6c04327c3903363079b72ab3e5e4289d74fb00a9ac7ec2aa/

607c5d1cca71dd3b6c04327c3903363079b72ab3e5e4289d74fb00a9ac7ec2aa/VERSION

607c5d1cca71dd3b6c04327c3903363079b72ab3e5e4289d74fb00a9ac7ec2aa/json

607c5d1cca71dd3b6c04327c3903363079b72ab3e5e4289d74fb00a9ac7ec2aa/layer.tar

8eaa4ff06b53ff7730c4d7a7e21b4426a4b46dee064ca2d5d90d757dc7ea040a/

8eaa4ff06b53ff7730c4d7a7e21b4426a4b46dee064ca2d5d90d757dc7ea040a/VERSION

8eaa4ff06b53ff7730c4d7a7e21b4426a4b46dee064ca2d5d90d757dc7ea040a/json

8eaa4ff06b53ff7730c4d7a7e21b4426a4b46dee064ca2d5d90d757dc7ea040a/layer.tar

f62feddc05dc67da9b725361f97d7ae72a32e355ce1585f9a60d090289120f73/

f62feddc05dc67da9b725361f97d7ae72a32e355ce1585f9a60d090289120f73/VERSION

f62feddc05dc67da9b725361f97d7ae72a32e355ce1585f9a60d090289120f73/json

f62feddc05dc67da9b725361f97d7ae72a32e355ce1585f9a60d090289120f73/layer.tar

repositories

每一個layer都有一個資料夾存在,且每個資料夾中包含VERSION,json,layer.tar三個檔案,另外還有一個repositories檔案。長ID為511136ea3c5a的layer沒有繼承任何layer,因此被稱為base映象,一般來說映象都是以這個layer開始的,其內容也為空。

json檔案包含了映象以及其對應的容器的配置資訊,其中有docker run時指定的,如CpuSharesCpuset,也有系統生成的如parent,正是這個屬性記錄了繼承結構,從而實現了layer的層次關係。每個資料夾下都有一個layer.tar的檔案,這個壓縮檔案存放的正是rootfs的內容,不過是增量存放的而已

5.1.4 容器管理

1)Libcontainer

在2013年Docker剛釋出的時候,它是一款基於LXC的開源容器管理引擎。隨著Docker的不斷髮展,它開始有了更為遠大的目標,將底層實現都抽象化到Libcontainer的介面。這就意味著,底層容器的實現方式變成了一種可變的方案,無論是使用namespace、cgroups技術或是使用systemd等其他方案,只要實現了Libcontainer定義的一組介面,Docker都可以執行。這也為Docker實現全面的跨平臺帶來了可能。

Libcontainer功能實現上涵蓋了包括namespaces使用、cgroups管理、Rootfs的配置啟動、預設的Linux capability許可權集、以及程序執行的環境變數配置。本身主要分為三大塊工作內容,一是容器的建立及初始化,二是容器生命週期管理,三則是程序管理,呼叫方為Docker的execdriver。容器的監控主要通過cgroups的狀態統計資訊,未來會加入程序追蹤等更豐富的功能。另一方面,Libcontainer在安全支援方面也為使用者儘可能多的提供了支援和選擇。

2)runC

Linux基金會於2015年6月成立OCI(Open Container Initiative)組織,旨在圍繞容器格式和執行時制定一個開放的工業化標準。OCI的目標是為了避免容器的生態分裂為“小生態王國”,確保一個引擎上構建的容器可以執行在其他引擎之上。這是實現容器可移植性至關重要的部分。該組織一成立便得到了包括谷歌、微軟、亞馬遜、華為等一系列雲端計算廠商的支援。

OCI推進容器標準化具體完成:

(1)操作標準化:容器的標準化操作包括使用標準容器感覺建立、啟動、停止容器,使用標準檔案系統工具複製和建立容器快照,使用標準化網路工具進行下載和上傳。

(2)內容無關:內容無關指不管針對的具體容器內容是什麼,容器標準操作執行後都能產生同樣的效果。如容器可以用同樣的方式上傳、啟動,不管是php應用還是mysql資料庫服務。

(3)基礎設施無關:無論是個人的膝上型電腦還是AWS S3,亦或是Openstack,或者其他基礎設施,都應該對支援容器的各項操作。

(4)為自動化量身定製:制定容器統一標準,是的操作內容無關化、平臺無關化的根本目的之一,就是為了可以使容器操作全平臺自動化。

(5)工業級交付:制定容器標準一大目標,就是使軟體分發可以達到工業級交付成為現實。

runC是Docker貢獻一個CLI工具,通過對Libcontainer的封裝,按照開放容器格式標準(OCF, Open Container Format)。2016年6月份釋出runC1.0版本。

3)containerd

2016年12月Docker 將Docker Engine 中的核心元件Containerd開源,作為一個獨立的開源專案獨立發展,目標是提供一個更加開放、穩定的容器執行基礎設施。Containerd可以說是Docker 引擎的引擎(Runtime)。和包含在DockerEngine裡containerd相比,獨立的containerd將具有更多的功能,可以涵蓋整個容器執行時管理的所有需求。

圖5.5映象、容器、runC、containerd自己的呼叫關係

Containerd面向運維人員而構建,目的構建工業級規模的Docker系統,在效能上進行了優化,Containerd利用runC來提供高階功能,比如熱遷移(checkpoint &restore)seccomp以及使用者名稱空間支援,這將為Docker引入這些功能敞開大門。containerd的功能和架構如下:

圖5.6Containerd架構圖

Containerd分三層,最上層為API,包括GRPC API(Go RPC)和Metrics API。

中間層為內部子系統,包括三個:

(1)Distribution: 和DockerRegistry打交道,拉取映象

(2)Bundle: 管理本地磁碟上面映象的子系統。

(3)Runtime:建立容器、管理容器的子系統。

最下面為功能元件包括內容、元資料、快照、執行器和監控器。

任務5.2 儲存

下面介紹Docker 內部以及容器之間管理資料。在容器中管理資料主要有兩種方式。

5.2.1 資料卷

1)資料卷(Data volumes)

資料卷是一個可供一個或多個容器使用的特殊目錄,它繞過UFS,可以提供很多有用的特性:

(1)資料卷可以在容器之間共享和重用。

(2)對資料卷的修改會立馬生效。

(3)對資料卷的更新,不會影響映象

(4)資料卷預設會一直存在,即使容器被刪除。

資料卷的使用,類似於Linux下對目錄或檔案進行mount,映象中的被指定為掛載點的目錄中的檔案會隱藏掉,能顯示看到的是掛載的資料卷。

2)建立一個數據卷

在用 docker run 命令的時候,使用 -v 標記來建立一個數據卷並掛載到容器裡。在一次 run 中多次使用可以掛載多個數據卷。下面建立一個名為 web 的容器,並載入一個數據捲到容器的/webapp 目錄。

$ sudo docker run -d -P--name web -v /webapp training/webapp python app.py

可以在Dockerfile中使用 VOLUME 來新增一個或者多個新的捲到由該映象建立的任意容器。

3)刪除資料卷

資料卷是被設計用來持久化資料的,它的生命週期獨立於容器,Docker不會在容器被刪除後自動刪除資料卷,並且也不存在垃圾回收這樣的機制來處理沒有任何容器引用的資料卷。如果需要在刪除容器的同時移除資料卷。可以在刪除容器的時候使用 docker rm -v 這個命令。

4)掛載一個主機目錄作為資料卷

使用-v標記也可以指定掛載一個本地主機的目錄到容器中去。

$ sudo docker run -d -P--name web -v /src/webapp:/opt/webapp training/webapp python app.py

上面的命令載入主機的/src/webapp目錄到容器的/opt/webapp 目錄。這個功能在進行測試的時候十分方便,比如使用者可以放置一些程式到本地目錄中,來檢視容器是否正常工作。本地目錄的路徑必須是絕對路徑,如果目錄不存在Docker 會自動為你建立它。

Docker掛載資料卷的預設許可權是讀寫,使用者也可以通過:ro指定為只讀。

$ sudo docker run -d -P--name web -v /src/webapp:/opt/webapp:ro

training/webapp pythonapp.py

5)檢視資料卷的具體資訊

在主機裡使用以下命令可以檢視指定容器的資訊,在輸出的內容中找到其中和資料卷相關的部分,可以看到所有的資料卷都是建立在主機的/var/lib/docker/volumes/下面的

$ docker inspect web

...

"Volumes": {

    "/webapp":"/var/lib/docker/volumes/fac362...80535"

},

"VolumesRW":{

    "/webapp": true

}

...

6)掛載一個本地主機檔案作為資料卷

-v標記也可以從主機掛載單個檔案到容器中

$ sudo docker run --rm-it -v ~/.bash_history:/.bash_history ubuntu /bin/bash

這樣就可以記錄在容器輸入過的命令了。如果直接掛載一個檔案,很多檔案編輯工具,包括 vi 或者 sed --in-place,可能會造成檔案 inode 的改變,所以最簡單的辦法就直接掛載檔案的父目錄。

5.2.2 資料卷容器

資料卷容器(Datavolume containers)涉及容器間共享的持久化、序列化的資料永續性的資料,最好建立資料卷容器。資料卷容器,其實就是一個正常的容器,專門用來提供資料卷供其它容器掛載的。

1)建立資料卷容器。

(1)首先,建立一個名為 dbdata 的資料卷容器:

$ sudo docker run -d -v/dbdata --name dbdata training/postgres echo Data-only container for postgres

2)然後,在其他容器中使用--volumes-from 來掛載 dbdata 容器中的資料卷。

$ sudo docker run -d--volumes-from dbdata --name db1 training/postgres

$ sudo docker run -d--volumes-from dbdata --name db2 training/postgres

3)可以使用超過一個的 --volumes-from 引數來指定從多個容器掛載不同的資料卷。也可以從其他已經掛載了資料卷的容器來級聯掛載資料卷。

$ sudo docker run -d--name db3 --volumes-from db1 training/postgres

注意:使用--volumes-from 引數所掛載資料卷的容器自己並不需要保持在執行狀態。

如果刪除了掛載的容器(包括dbdata、db1 和 db2),資料卷並不會被自動刪除。如果要刪除一個數據卷,必須在刪除最後一個還掛載著它的容器時使用 docker rm -v 命令來指定同時刪除關聯的容器。這可以讓使用者在容器之間升級和移動資料卷。

2)利用資料卷容器來備份、恢復、遷移資料卷。

可以利用資料卷對其中的資料進行進行備份、恢復和遷移。

1)備份:首先使用--volumes-from 標記來建立一個載入 dbdata 容器卷的容器,並從主機掛載當前目錄到容器的 /backup 目錄。命令如下:

$ sudo docker run--volumes-from dbdata -v $(pwd):/backup ubuntu tar cvf /backup/backup.tar /dbdata

容器啟動後,使用了tar 命令來將dbdata 卷備份為容器中/backup/backup.tar 檔案,也就是主機當前目錄下的名為 backup.tar 的檔案。

(2)恢復:如果要恢復資料到一個容器,首先建立一個帶有空資料卷的容器dbdata2

$ sudo docker run -v/dbdata --name dbdata2 ubuntu /bin/bash

然後建立另一個容器,掛載 dbdata2 容器卷中的資料卷,並使用untar解壓備份檔案到掛載的容器卷中。

$ sudo docker run--volumes-from dbdata2 -v $(pwd):/backup busybox tar xvf

/backup/backup.tar

為了檢視/驗證恢復的資料,可以再啟動一個容器掛載同樣的容器捲來檢視

$ sudo docker run--volumes-from dbdata2 busybox /bin/ls /dbdata

任務5.3 網路

5.3.1 Docker網路功能介紹

1)容器網路

Docker 的網路實現其實就是利用了 Linux 上的網路名稱空間、網橋和虛擬網路裝置(VETH)等實現。預設Docker安裝完成後會建立一個網橋docker0。Docker中的網路介面預設都是虛擬的網路介面。Docker 容器網路在本地主機和容器內分別建立一個虛擬介面,並讓它們彼此連通。

Docker 建立一個容器執行如下操作:

(1)建立一對虛擬介面,分別放到本地主機和新容器中;

(2)本地主機一端橋接到預設的docker0或指定網橋上,並具有一個唯一的名字,如veth65f9;

(3)容器一端放到新容器中,並修改名字作為eth0,這個介面只在容器的名稱空間可見;

(4)從網橋可用地址段中獲取一個空閒地址IP分配給容器的 eth0,並配置預設路由到橋接網絡卡veth65f9。

(5)完成這些之後,容器就可以使用eth0虛擬網絡卡來連線其他容器和其他網路。

另外,可以在dockerrun的時候通過--net引數來指定容器的網路配置,有4個可選值:

--net=bridge 這個是預設值,連線到預設的網橋。

--net=host 告訴 Docker 不要將容器網路放到隔離的名稱空間中,使用本地主機的網路,它擁有完全的本地主機介面訪問許可權。容器程序可以跟主機其它root程序一樣可以開啟低範圍的埠機。因此使用這個選項的時候要非常小心。如果進一步的使用 --privileged=true,容器會被允許直接配置主機的網路堆疊。

--net=container:NAME_or_ID讓 Docker 將新建容器的程序放到一個已存在容器的網路棧中,新容器程序有自己的檔案系統、程序列表和資源限制,但會和已存在的容器共享 IP 地址和埠等網路資源,兩者程序可以直接通過 lo 環回介面通訊。

--net=none 讓 Docker 將新容器放到隔離的網路棧中,但是不進行網路配置。之後,使用者可以自己進行配置。

當容器結束後,Docker 會清空容器,容器內的 eth0 會隨網路名稱空間一起被清除,A 介面也被自動從 docker0 解除安裝。

圖5.7 Docker 容器網路示意圖

2)網路配置細節

使用者使用--net=none 後,可以自行配置網路,讓容器達到跟平常一樣具有訪問網路的許可權。通過這個過程,可以瞭解 Docker 配置網路的細節。

(1)首先,啟動一個 /bin/bash 容器,指定--net=none 引數。

$ sudo docker run -i -t--rm --net=none base /bin/bash

[email protected]:/#

(2)在本地主機查詢容器的程序 id,併為它建立網路名稱空間。

$ sudo docker inspect-f '{{.State.Pid}}' 63f36fc01b5f

2778

$ pid=2778

$ sudo mkdir -p/var/run/netns

$ sudo ln -s/proc/$pid/ns/net /var/run/netns/$pid

(3)檢查橋接網絡卡的 IP 和子網掩碼資訊。

$ ip addr show docker0

21: docker0: ...

inet 172.17.42.1/16scope global docker0

...

(4)建立一對 “veth pair” 介面 A 和 B,繫結 A 到網橋 docker0,並啟用它

$ sudo ip link add Atype veth peer name B

$ sudo brctl addifdocker0 A

$ sudo ip link set A up

(5)將B放到容器的網路名稱空間,命名為 eth0,啟動它並配置一個可用 IP(橋接網段)和預設閘道器。

$ sudo ip link set Bnetns $pid

$ sudo ip netns exec$pid ip link set dev B name eth0

$ sudo ip netns exec$pid ip link set eth0 up

$ sudo ip netns exec$pid ip addr add 172.17.42.99/16 dev eth0

$ sudo ip netns exec$pid ip route add default via 172.17.42.1

以上,就是 Docker 配置網路的具體過程。

3外部訪問容器,埠對映

容器中可以執行一些網路應用,要讓外部也可以訪問這些應用,可以通過 -P 或 -p 引數來指定埠對映。

(1)檢視埠資訊

當使用 -P 標記時,Docker 會隨機對映一個 49000~49900 的埠到內部容器開放的網路埠。

使用 docker ps 可以看到,本地主機的 49155 被對映到了容器的 5000 埠。此時訪問本機的 49155 埠即可訪問容器內 web 應用提供的介面。

$ sudo docker run -d -Ptraining/webapp python app.py

$ sudo docker ps -l

CONTAINER ID  IMAGE                   COMMAND       CREATED        STATUS        PORTS                    NAMES

bc533791f3f5  training/webapp:latest  python app.py 5 seconds ago  Up 2 seconds 0.0.0.0:49155->5000/tcp nostalgic_morse

同樣的,可以通過 docker logs 命令來檢視應用的資訊。

$ sudo docker logs -fnostalgic_morse

* Running onhttp://0.0.0.0:5000/

10.0.2.2 - -[23/May/2014 20:16:31] "GET / HTTP/1.1" 200 -

10.0.2.2 - -[23/May/2014 20:16:31] "GET /favicon.ico HTTP/1.1" 404 -

-p(小寫的)則可以指定要對映的埠,並且,在一個指定埠上只可以繫結一個容器。支援的格式有

ip:hostPort:containerPort| ip::containerPort | hostPort:containerPort。

(2)對映所有介面地址

使用 hostPort:containerPort 格式本地的 5000 埠對映到容器的 5000 埠,可以執行

$ sudo docker run -d -p5000:5000 training/webapp python app.py

此時預設會繫結本地所有介面上的所有地址。

(3)對映到指定地址的指定埠

可以使用 ip:hostPort:containerPort 格式指定對映使用一個特定地址,比如 localhost 地址 127.0.0.1

$ sudo docker run -d -p127.0.0.1:5000:5000 training/webapp python app.py

(4)對映到指定地址的任意埠

使用 ip::containerPort 繫結localhost 的任意埠到容器的 5000 埠,本地主機會自動分配一個埠。

$ sudo docker run -d -p127.0.0.1::5000 training/webapp python app.py

還可以使用 udp 標記來指定 udp 埠

$ sudo docker run -d -p127.0.0.1:5000:5000/udp training/webapp python app.py

(5)檢視對映埠配置

使用 docker port來檢視當前對映的埠配置,也可以檢視到繫結的地址

$ docker portnostalgic_morse 5000

127.0.0.1:49155.

容器有自己的內部網路和 ip 地址,-p 標記可以多次使用來繫結多個埠,例如:

$ sudo docker run -d -p5000:5000  -p 3000:80 training/webapppython app.py

5.3.2 容器互聯

容器的連線(linking)系統是除了埠對映外,另一種跟容器中應用互動的方式。該系統會在源和接收容器之間建立一個隧道,接收容器可以看到源容器指定的資訊。

1)自定義容器命名

連線系統依據容器的名稱來執行。因此,首先需要自定義一個好記的容器命名。使用 --name 標記可以為容器自定義命名。

$ sudo docker run -d -P--name web training/webapp python app.py

使用 docker ps 來驗證設定的命名。

$ sudo docker ps -l

CONTAINER ID  IMAGE                  COMMAND        CREATED       STATUS       PORTS                    NAMES

aed84ee21bde  training/webapp:latest python app.py  12 hours ago Up 2 seconds 0.0.0.0:49154->5000/tcp web

也可以使用 docker inspect 來檢視容器的名字。

$ sudo docker inspect-f "{{ .Name }}" aed84ee21bde

/web

注意:容器的名稱是唯一的。如果已經命名了一個叫 web 的容器,當你要再次使用 web 這個名稱的時候,需要先用docker rm 來刪除之前建立的同名容器。

在執行 docker run 的時候如果新增 --rm 標記,則容器在終止後會立刻刪除。注意,--rm 和 -d 引數不能同時使用。

2 )容器互聯

使用 --link 引數可以讓容器之間安全的進行互動。

下面先建立一個新的資料庫容器。

$ sudo docker run -d--name db training/postgres

刪除之前建立的 web 容器

$ docker rm -f web

然後建立一個新的 web 容器,並將它連線到 db 容器

$ sudo docker run -d -P--name web --link db:db training/webapp python app.py

此時,db 容器和 web 容器建立互聯關係。

--link 引數的格式為 --link name:alias,其中 name 是要連結的容器的名稱,alias是這個連線的別名。

使用 docker ps 來檢視容器的連線

$ docker ps

CONTAINER ID  IMAGE                     COMMAND               CREATED             STATUS             PORTS                    NAMES

349169744e49  training/postgres:latest  su postgres -c '/usr  About a minute ago  Up About a minute  5432/tcp                 db, web/db

aed84ee21bde  training/webapp:latest    python app.py         16 hours ago        Up 2 minutes       0.0.0.0:49154->5000/tcp  web

可以看到自定義命名的容器db和 web,db 容器的 names 列有 db 也有 web/db。這表示 web 容器連結到 db 容器,web 容器將被允許訪問 db 容器的資訊。

Docker 在兩個互聯的容器之間建立了一個安全隧道,而且不用對映它們的埠到宿主主機上。在啟動 db 容器的時候並沒有使用 -p-P標記,從而避免了暴露資料庫埠到外部網路上。

Docker 通過 2 種方式為容器公開連線資訊:

(1).   環境變數

使用 env 命令來檢視 web 容器的環境變數

$ sudo docker run --rm--name web2 --link db:db training/webapp env

. . .

DB_NAME=/web2/db

DB_PORT=tcp://172.17.0.5:5432

DB_PORT_5000_TCP=tcp://172.17.0.5:5432

DB_PORT_5000_TCP_PROTO=tcp

DB_PORT_5000_TCP_PORT=5432

DB_PORT_5000_TCP_ADDR=172.17.0.5

. . .

其中 DB_ 開頭的環境變數是供 web 容器連線 db 容器使用,字首採用大寫的連線別名。

(2).   除了環境變數,Docker 還新增 host 資訊到父容器的 /etc/hosts 的檔案。下面是父容器 web 的 hosts 檔案

這裡有 2 個 hosts,第一個是 web 容器,web 容器用 id 作為他的主機名,第二個是 db 容器的 ip 和主機名。可以在 web 容器中安裝 ping 命令來測試跟db容器的連通。

$ sudo docker run -t -i--rm --link db:db training/webapp /bin/bash

[email protected]:/opt/webapp#cat /etc/hosts

172.17.0.7  aed84ee21bde

. . .

172.17.0.5  db

[email protected]:/opt/webapp#apt-get install -yqq inetutils-ping

[email protected]:/opt/webapp#ping db

PING db (172.17.0.5): 48 data bytes

56 bytes from172.17.0.5: icmp_seq=0 ttl=64 time=0.267 ms

56 bytes from172.17.0.5: icmp_seq=1 ttl=64 time=0.250 ms

56 bytes from172.17.0.5: icmp_seq=2 ttl=64 time=0.256 ms

用 ping 來測試db容器,它會解析成 172.17.0.5。注意:官方的 ubuntu映象預設沒有安裝 ping,需要自行安裝。

使用者可以連結多個父容器到子容器,比如可以連結多個 web 到 db 容器上。

5.3.3 高階網路配置

本章將介紹 Docker 的一些高階網路配置和選項。

當 Docker 啟動時,會自動在主機上建立一個docker0 虛擬網橋,實際上是 Linux 的一個 bridge,可以理解為一個軟體交換機。它會在掛載到它的網口之間進行轉發。

同時,Docker 隨機分配一個本地未佔用的私有網段(在 RFC1918 中定義)中的一個地址給 docker0 介面。比如典型的 172.17.42.1,掩碼為 255.255.0.0。此後啟動的容器內的網口也會自動分配一個同一網段(172.17.0.0/16)的地址。

當建立一個 Docker 容器的時候,同時會建立了一對 veth pair 介面(當資料包傳送到一個介面時,另外一個介面也可以收到相同的資料包)。這對介面一端在容器內,即eth0;另一端在本地並被掛載到docker0 網橋,名稱以 veth 開頭(例如vethAQI2QT)。通過這種方式,主機可以跟容器通訊,容器之間也可以相互通訊。Docker 就建立了在主機和所有容器之間一個虛擬共享網路。

圖5.8 Docker 網路

接下來的部分將介紹在一些場景中,Docker 所有的網路定製配置。以及通過Linux 命令來調整、補充、甚至替換 Docker 預設的網路配置。

1)快速配置指南

下面是一個跟 Docker 網路相關的命令列表。

其中有些命令選項只有在Docker 服務啟動的時候才能配置,而且不能馬上生效。

-b BRIDGE or--bridge=BRIDGE --指定容器掛載的網橋

--bip=CIDR --定製 docker0 的掩碼

-H SOCKET... or--host=SOCKET... --Docker 服務端接收命令的通道

--icc=true|false --是否支援容器之間進行通訊

--ip-forward=true|false --請看下文容器之間的通訊

--iptables=true|false --是否允許 Docker 新增 iptables 規則

--mtu=BYTES --容器網路中的 MTU

下面2個命令選項既可以在啟動服務時指定,也可以 Docker 容器啟動(dockerrun)時候指定。在 Docker 服務啟動的時候指定則會成為預設值,後面執行 docker run 時可以覆蓋設定的預設值。

--dns=IP_ADDRESS... --使用指定的DNS伺服器

--dns-search=DOMAIN... --指定DNS搜尋域

最後這些選項只有在 docker run 執行時使用,因為它是針對容器的特性內容。

-h HOSTNAME or--hostname=HOSTNAME --配置容器主機名

--link=CONTAINER_NAME:ALIAS--新增到另一個容器的連線

--net=bridge|none|container:NAME_or_ID|host--配置容器的橋接模式

-p SPEC or--publish=SPEC --對映容器埠到宿主主機

-P or--publish-all=true|false --對映容器所有埠到宿主主機

2)配置 DNS

Docker 沒有為每個容器專門定製映象,那麼怎麼自定義配置容器的主機名和 DNS 配置呢?祕訣就是它利用虛擬檔案來掛載到來容器的3個相關配置檔案。

在容器中使用 mount 命令可以看到掛載資訊:

$ mount

...

/dev/disk/by-uuid/1fec...ebdfon /etc/hostname type ext4 ...

/dev/disk/by-uuid/1fec...ebdfon /etc/hosts type ext4 ...

tmpfs on/etc/resolv.conf type tmpfs ...

...

這種機制可以讓宿主主機DNS 資訊發生更新後,所有 Docker 容器的 dns 配置通過 /etc/resolv.conf 檔案立刻得到更新。

如果使用者想要手動指定容器的配置,可以利用下面的選項。

-h HOSTNAME or--hostname=HOSTNAME 設定容器的主機名,它會被寫到容器內的 /etc/hostname 和 /etc/hosts。但它在容器外部看不到,既不會在 docker ps 中顯示,也不會在其他的容器的 /etc/hosts 看到。

--link=CONTAINER_NAME:ALIAS 選項會在建立容器的時候,新增一個其他容器的主機名到 /etc/hosts 檔案中,讓新容器的程序可以使用主機名ALIAS 就可以連線它。

--dns=IP_ADDRESS 新增DNS 伺服器到容器的 /etc/resolv.conf 中,讓容器用這個伺服器來解析所有不在 /etc/hosts 中的主機名。

--dns-search=DOMAIN 設定容器的搜尋域,當設定搜尋域為 .example.com 時,在搜尋一個名為 host 的主機時,DNS 不僅搜尋host,還會搜尋 host.example.com。 注意:如果沒有上述最後 2 個選項,Docker 會預設用主機上的 /etc/resolv.conf 來配置容器。

3)容器訪問控制

容器的訪問控制,主要通過Linux 上的 iptables 防火牆來進行管理和實現。iptables 是 Linux 上預設的防火牆軟體,在大部分發行版中都自帶。

(1).   容器訪問外部網路

容器要想訪問外部網路,需要本地系統的轉發支援。在Linux 系統中,檢查轉發是否開啟。

$sysctlnet.ipv4.ip_forward

net.ipv4.ip_forward = 1

如果為 0,說明沒有開啟轉發,則需要手動開啟。

$sysctl -wnet.ipv4.ip_forward=1

如果在啟動 Docker 服務的時候設定 --ip-forward=true,Docker 就會自動設定系統的 ip_forward 引數為 1。

(2).   容器之間訪問

容器之間相互訪問,需要兩方面的支援。

容器的網路拓撲是否已經互聯。預設情況下,所有容器都會被連線到 docker0 網橋上。

本地系統的防火牆軟體 -- iptables 是否允許通過。

(3).   訪問所有埠

當啟動 Docker 服務時候,預設會新增一條轉發策略到 iptables 的 FORWARD 鏈上。策略為通過(ACCEPT)還是禁止(DROP)取決於配置--icc=true(預設值)還是 --icc=false。當然,如果手動指定 --iptables=false 則不會新增 iptables 規則。

可見,預設情況下,不同容器之間是允許網路互通的。如果為了安全考慮,可以在 /etc/default/docker 檔案中配置 DOCKER_OPTS=--icc=false來禁止它。

(4).   訪問指定埠

在通過 -icc=false 關閉網路訪問後,還可以通過--link=CONTAINER_NAME:ALIAS 選項來訪問容器的開放埠。

例如,在啟動 Docker 服務時,可以同時使用 icc=false --iptables=true 引數來關閉允許相互的網路訪問,並讓 Docker 可以修改系統中的 iptables 規則。

此時,系統中的 iptables 規則可能是類似

$ sudo iptables -nL

...

Chain FORWARD (policy ACCEPT)

target     prot opt source               destination

DROP       all --  0.0.0.0/0            0.0.0.0/0

...

之後,啟動容器(dockerrun)時使用 --link=CONTAINER_NAME:ALIAS 選項。Docker 會在 iptable 中為兩個容器分別新增一條 ACCEPT 規則,允許相互訪問開放的埠(取決於 Dockerfile 中的 EXPOSE 行)。

當添加了 --link=CONTAINER_NAME:ALIAS 選項後,添加了 iptables 規則。

$ sudo iptables -nL

...

Chain FORWARD (policy ACCEPT)

target     prot opt source               destination

ACCEPT     tcp --  172.17.0.2           172.17.0.3           tcp spt:80

ACCEPT     tcp --  172.17.0.3           172.17.0.2           tcp dpt:80

DROP       all --  0.0.0.0/0            0.0.0.0/0

注意:--link=CONTAINER_NAME:ALIAS 中的 CONTAINER_NAME 目前必須是 Docker 分配的名字,或使用 --name 引數指定的名字。主機名則不會被識別。

4)對映容器埠到宿主主機的實現

預設情況下,容器可以主動訪問到外部網路的連線,但是外部網路無法訪問到容器。

(1).   容器訪問外部實現

容器所有到外部網路的連線,源地址都會被NAT成本地系統的IP地址。這是使用 iptables 的源地址偽裝操作實現的。

檢視主機的 NAT 規則。

$ sudo iptables -t nat-nL

...

Chain POSTROUTING (policy ACCEPT)

target     prot opt source               destination

MASQUERADE  all --  172.17.0.0/16       !172.17.0.0/16

...

其中,上述規則將所有源地址在 172.17.0.0/16 網段,目標地址為其他網段(外部網路)的流量動態偽裝為從系統網絡卡發出。MASQUERADE 跟傳統 SNAT 的好處是它能動態從網絡卡獲取地址。

(2).   外部訪問容器實現

容器允許外部訪問,可以在 docker run 時候通過 -p 或 -P 引數來啟用。

不管用那種辦法,其實也是在本地的 iptable 的 nat 表中新增相應的規則。

使用 -P 時:

$ iptables -t nat -nL

...

Chain DOCKER (2 references)

target     prot opt source               destination

DNAT       tcp --  0.0.0.0/0            0.0.0.0/0            tcp dpt:49153 to:172.17.0.2:80

使用 -p 80:80 時:

$ iptables -t nat -nL

Chain DOCKER (2 references)

target     prot opt source               destination

DNAT       tcp --  0.0.0.0/0            0.0.0.0/0            tcp dpt:80 to:172.17.0.2:80

注意:

這裡的規則映射了0.0.0.0,意味著將接受主機來自所有介面的流量。使用者可以通過 -p IP:host_port:container_port 或 -p IP::port 來指定允許訪問容器的主機上的IP、介面等,以制定更嚴格的規則。

配置檔案 /etc/default/docker 中指定 DOCKER_OPTS="--ip=IP_ADDRESS",之後重啟 Docker 服務即可生效。

5)配置 docker0 網橋

Docker 服務預設會建立一個 docker0 網橋(其上有一個 docker0 內部介面),它在核心層連通了其他的物理或虛擬網絡卡,這就將所有容器和本地主機都放到同一個物理網路。

Docker 預設指定了 docker0 介面的 IP 地址和子網掩碼,讓主機和容器之間可以通過網橋相互通訊,它還給出了 MTU(介面允許接收的最大傳輸單元),通常是 1500 Bytes,或宿主主機網路路由上支援的預設值。這些值都可以在服務啟動的時候進行配置。

--bip=CIDR -- IP 地址加掩碼格式,例如 192.168.1.5/24

--mtu=BYTES -- 覆蓋預設的 Docker mtu 配置

也可以在配置檔案中配置DOCKER_OPTS,然後重啟服務。 由於目前 Docker 網橋是 Linux 網橋,使用者可以使用 brctl show 來檢視網橋和埠連線資訊。

$ sudo brctl show

bridge name     bridge id               STP enabled     interfaces

docker0         8000.3a1d7362b4ee       no              veth65f9

                                             vethdda6

*注:brctl 命令在 Debian、Ubuntu 中可以使用 sudo apt-get install bridge-utils 來安裝。

每次建立一個新容器的時候,Docker從可用的地址段中選擇一個空閒的 IP 地址分配給容器的 eth0 埠。使用本地主機上 docker0 介面的 IP 作為所有容器的預設閘道器。

$ sudo docker run -i -t--rm base /bin/bash

$ ip addr show eth0

24: eth0:<BROADCAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group defaultqlen 1000

    link/ether 32:6f:e0:35:57:91 brdff:ff:ff:ff:ff:ff

    inet 172.17.0.3/16 scope global eth0

       valid_lft forever preferred_lft forever

    inet6 fe80::306f:e0ff:fe35:5791/64 scopelink

       valid_lft forever preferred_lft forever

$ ip route

default via 172.17.42.1dev eth0

172.17.0.0/16 deveth0  proto kernel  scope link src 172.17.0.3

$ exit

6)自定義網橋

除了預設的 docker0 網橋,使用者也可以指定網橋來連線各個容器。

在啟動 Docker 服務的時候,使用 -b BRIDGE或--bridge=BRIDGE 來指定使用的網橋。

如果服務已經執行,那需要先停止服務,並刪除舊的網橋。

$ sudo service dockerstop

$ sudo ip link set devdocker0 down

$ sudo brctl delbrdocker0

然後建立一個網橋 bridge0。

$ sudo brctl addbrbridge0

$ sudo ip addr add192.168.5.1/24 dev bridge0

$ sudo ip link set devbridge0 up

檢視確認網橋建立並啟動。

$ ip addr show bridge0

4: bridge0:<BROADCAST,MULTICAST> mtu 1500 qdisc noop state UP group default

    link/ether 66:38:d0:0d:76:18 brdff:ff:ff:ff:ff:ff

    inet 192.168.5.1/24 scope global bridge0

      valid_lft forever preferred_lft forever

配置 Docker 服務,預設橋接到建立的網橋上。

$ echo'DOCKER_OPTS="-b=bridge0"' >> /etc/default/docker

$ sudo service dockerstart

啟動 Docker 服務。新建一個容器,可以看到它已經橋接到了 bridge0 上。

可以繼續用 brctlshow 命令檢視橋接的資訊。另外,在容器中可以使用 ip addr 和 ip route 命令來檢視 IP 地址配置和路由資訊。

7)工具和示例

在介紹自定義網路拓撲之前,你可能會對一些外部工具和例子感興趣:

pipework

Jérôme Petazzoni 編寫了一個叫 pipework 的 shell 指令碼,可以幫助使用者在比較複雜的場景中完成容器的連線。

playground

Brandon Rhodes 建立了一個提供完整的 Docker 容器網路拓撲管理的 Python庫,包括路由、NAT 防火牆;以及一些提供 HTTP, SMTP, POP, IMAP,Telnet, SSH, FTP 的伺服器。

8)編輯網路配置檔案

Docker 1.2.0 開始支援在執行中的容器裡編輯 /etc/hosts, /etc/hostname 和 /etc/resolve.conf 檔案。

但是這些修改是臨時的,只在執行的容器中保留,容器終止或重啟後並不會被儲存下來。也不會被 docker commit 提交。

9)建立一個點到點連線

預設情況下,Docker 會將所有容器連線到由 docker0 提供的虛擬子網中。

使用者有時候需要兩個容器之間可以直連通訊,而不用通過主機網橋進行橋接。

解決辦法很簡單:建立一對 peer 介面,分別放到兩個容器中,配置成點到點鏈路型別即可。

首先啟動 2 個容器:

$ sudo docker run -i -t--rm --net=none base /bin/bash

[email protected]:/#

$ sudo docker run -i -t--rm --net=none base /bin/bash

[email protected]:/#

找到程序號,然後建立網路名稱空間的跟蹤檔案。

$ sudo docker inspect-f '{{.State.Pid}}' 1f1f4c1f931a

2989

$ sudo docker inspect-f '{{.State.Pid}}' 12e343489d2f

3004

$ sudo mkdir -p/var/run/netns

$ sudo ln -s/proc/2989/ns/net /var/run/netns/2989

$ sudo ln -s/proc/3004/ns/net /var/run/netns/3004

建立一對 peer 介面,然後配置路由

$ sudo ip link add Atype veth peer name B

$ sudo ip link set Anetns 2989

$ sudo ip netns exec2989 ip addr add 10.1.1.1/32 dev A

$ sudo ip netns exec2989 ip link set A up

$ sudo ip netns exec2989 ip route add 10.1.1.2/32 dev A

$ sudo ip link set Bnetns 3004

$ sudo ip netns exec3004 ip addr add 10.1.1.2/32 dev B

$ sudo ip netns exec3004 ip link set B up

$ sudo ip netns exec3004 ip route add 10.1.1.1/32 dev B

現在這 2 個容器就可以相互 ping 通,併成功建立連線。點到點鏈路不需要子網和子網掩碼。

此外,也可以不指定 --net=none 來建立點到點鏈路。這樣容器還可以通過原先的網路來通訊。

利用類似的辦法,可以建立一個只跟主機通訊的容器。但是一般情況下,更推薦使用 --icc=false 來關閉容器之間的通訊。

任務5.4 Docker API

5.4.1 DockerAPI介紹

API 的主要型別:RESTful,基於 HTTP 協議,也能基於 RPC 協議。

所謂 RESTful, 是指通過如HTTP協議封裝的各種請求,主要包括 GET、POST、UPDATE、DELETE、PUT等,儲存建立,修改等操作。一般 RESTful 伺服器提供這些請求的介面(地址,路徑,引數),然後客戶端可以通過過類似 Linux 命令 curl,Python 標準庫 httplib、httplib2、urllib 等訪問,需要注意的是,多數引數(資料)都是以 JSON/XML 打包。並且多數按照token 方式驗證請求許可權和安全性。 當然也支援其他型別的驗證。

Docker生態系統中一共有三種api

Registry:提供了與來儲存docker映象的docker registry 整合的功能。

Docker hub api:提供了與docker hub 整合的功能。

Docker remote api:提供與docker守護程序進行整合的功能。

所有這3種api都是restful風格的。在本章中,將會著重對remote api進行介紹,因為它是通過程式與docker進行整合和互動的核心內容。

5.4.2 初識Remote API

讓瀏覽一下dockerremote api,並看看它都提供了哪些功能。首先要牢記的是。Remote api 是由docker守護程序提供的。在預設情況下,docker守護程序會繫結到一個所在宿州機的套接字,即unix:///var/run/docker.sock. docker守護程序需要以root許可權來運,以便它有足夠的許可權去管理所需要的資源。也正如在第2章所闡述的哪樣,如果系統中存在一個名為docker的使用者組,docker會將上面所說的套接字的所有者設為該使用者組。因此任何屬於docker使用者組的使用者都可以執行docker而無需root許可權。

如果只查詢在同一臺宿主機上執行docker的Remote api,那麼上面的機制看起來沒什麼問題,但是如果想遠端訪問Remote api, 就需要將docker守護程序繫結到一個網路介面上去。只需要給docker守護程序傳遞一個-H標誌即可做到這一點。

如果使用者可以在本地使用docker api,那麼就可以使用nc命令來進行查詢,如圖所示:

在大多數作業系統上,可以通過編輯守護程序的啟動配置檔案將docker守護程序繫結到指定網路介面。需要編輯/usr/lib/system/system/docker.service檔案。

讓來看看如何在一個執行systemd的red hat 衍生版上將docker守護程序繫結到一個網路介面上。將編輯/usr/lib/system/system/docker.service檔案,將程式碼清單所示的內容修改為以下內容。

ExecStart=/usr/bin/docker-current-d --selinu-enabled -H tcp://0.0.0.0:2375

這將把docker守護程序繫結到該宿主機的所有網路介面的2375埠上。之後需要使用systemctl命令來重新載入並啟動該守護程序,如程式碼清單所示。

[[email protected] ~]# sudosystemctl --system daemon-reload

現在可以通過docker客戶端命令的-H標誌來測試一下剛才的配置是否生效。讓從一臺遠端主機來訪問docker守護程序,如程式碼清單所示。

[[email protected] ~]# dockerdaemon -H unix:///var/run/docker.sock -H 0.0.0.0:2375

WARN[0000] /!\ DON'TBIND ON ANY IP ADDRESS WITHOUT setting -tlsverify IF YOU DON'T KNOW WHAT YOU'REDOING /!\

WARN[0000] devmapper:Usage of loopback devices is strongly discouraged for production use. Pleaseuse `--storage-opt dm.thinpooldev` or use `man docker` to refer todm.thinpooldev section.

WARN[0000] devmapper:Base device already exists and has filesystem xfs on it. User specifiedfilesystem  will be ignored.

INFO[0000][graphdriver] using prior storage driver "devicemapper"

INFO[0000] Graphmigration to content-addressability took 0.00 seconds

INFO[0000] Firewalldrunning: false                    

INFO[0000] Defaultbridge (docker0)isassigned with an IP address 172.17.0.0/16. Daemon option --bip can be used toset a preferred IP address

INFO[0000] Loadingcontainers: start.                  

.

INFO[0000] Loadingcontainers: done.                   

INFO[0000] Daemon hascompleted initialization         

INFO[0000] Dockerdaemon                                 commit=3999ccb-unsupportedexecdriver=native-0.2 graphdriver=devicemapper version=1.10.3

INFO[0001] API listenon [::]:2375                     

INFO[0001] API listenon /var/run/docker.sock  

[[email protected] ~]# sudodocker -H 127.0.0.1:2375 info

Containers: 1

 Running: 1

 Paused: 0

 Stopped: 0

Images: 22

Server Version: 1.10.3

Storage Driver:devicemapper

 Pool Name: docker-253:1-285241608-pool

 Pool Blocksize: 65.54 kB

 Base Device Size: 10.74 GB

 Backing Filesystem: xfs

 Data file: /dev/loop0

 Metadata file: /dev/loop1

 Data Space Used: 5.105 GB

 Data Space Total: 107.4 GB

 Data Space Available: 90.75 GB

 Metadata Space Used: 10.23 MB

 Metadata Space Total: 2.147 GB

 Metadata Space Available: 2.137 GB

 Udev Sync Supported: true

 Deferred Removal Enabled: false

 Deferred Deletion Enabled: false

 Deferred Deleted Device Count: 0

 Data loop file:/var/lib/docker/devicemapper/devicemapper/data

 WARNING: Usage of loopback devices is stronglydiscouraged for production use. Either use `--storage-opt dm.thinpooldev` oruse `--storage-opt dm.no_warn_on_loop_devices=true` to suppress this warning.

 Metadata loop file:/var/lib/docker/devicemapper/devicemapper/metadata

 Library Version: 1.02.135-RHEL7 (2016-09-28)

Execution Driver:native-0.2

Logging Driver:json-file

Plugins:

 Volume: local

 Network: host bridge null

Kernel Version:3.10.0-229.el7.x86_64

Operating System:CentOS Linux 7 (Core)

OSType: linux

Architecture: x86_64

Number of Docker Hooks:2

CPUs: 1

Total Memory: 1.954 GiB

Name: docker

ID:HRBL:3YXE:HAAO:MRAG:NKQO:MZWC:7EVD:Q2QK:UYK6:C7NF:GOYU:ELSR

WARNING:bridge-nf-call-iptables is disabled

WARNING:bridge-nf-call-ip6tables is disabled

Registries: docker.io (secure)

這裡假定docker提供了更便捷的docker_host環境變數,這樣即省掉了每次都需要設定-H標誌的麻煩

[[email protected] ~]# exportDOCKER_HOST="tcp://127.0.0.1:2375"

5.4.3 測試Docker RemoteAPI

現在已經通過docker程式建立並確認了與docker守護程序之間的網路連通性,接著來直接連線到api。用curl命令查詢docker info 命令大致相同的資訊。

[[email protected] ~]# curlhttp://127.0.0.1:2375/info                  

{"ID":"HRBL:3YXE:HAAO:MRAG:NKQO:MZWC:7EVD:Q2QK:UYK6:C7NF:GOYU:ELSR","Containers":1,"ContainersRunning":1,"ContainersPaused":0,"ContainersStopped":0,"Images":22,"Driver":"devicemapper","DriverStatus":[["PoolName","docker-253:1-285241608-pool"],["Pool Blocksize","65.54kB"],["Base Device Size","10.74 GB"],["BackingFilesystem","xfs"],["Datafile","/dev/loop0"],["Metadatafile","/dev/loop1"],["Data Space Used","5.106GB"],["Data Space Total","107.4 GB"],["Data SpaceAvailable","90.75 GB"],["Metadata Space Used","10.23MB"],["Metadata Space Total","2.147GB"],["Metadata Space Available","2.137GB"],["Udev Sync Supported","true"],["DeferredRemoval Enabled","false"],["Deferred DeletionEnabled","false"],["Deferred Deleted DeviceCount","0"],["Data loop file","/var/lib/docker/devicemapper/devicemapper/data"],["Metadataloopfile","/var/lib/docker/devicemapper/devicemapper/metadata"],["LibraryVersion","1.02.135-RHEL7 (2016-09-28)"]],"SystemStatus":null,"Plugins":{"Volume":["local"],"Network":["host","bridge","null"],"Authorization":null},"MemoryLimit":true,"SwapLimit":true,"CpuCfsPeriod":true,"CpuCfsQuota":true,"CPUShares":true,"CPUSet":true,"IPv4Forwarding":true,"BridgeNfIptables":false,"BridgeNfIp6tables":false,"Debug":false,"NFd":21,"OomKillDisable":true,"NGoroutines":28,"SystemTime":"2016-12-30T03:24:27.654171066Z","ExecutionDriver":"native-0.2","LoggingDriver":"json-file","NEventsListener":0,"KernelVersion":"3.10.0-229.el7.x86_64","PkgVersion":"docker-common-1.10.3-59.el7.centos.x86_64","OperatingSystem":"CentOSLinux 7 (Core)","OSType":"linux","Architecture":"x86_64","IndexServerAddress":"https://index.docker.io/v1/","IndexServerName":"docker.io","RegistryConfig":{"InsecureRegistryCIDRs":["127.0.0.0/8"],"IndexConfigs":{"docker.io":{"Name":"docker.io","Mirrors":null,"Secure":true,"Official":true}},"Mirrors":null},"InitSha1":"2195bfa7012bb8ffc50f899b658b487b565336e1","InitPath":"","NCPU":1,"MemTotal":2098581504,"DockerRootDir":"/var/lib/docker","HttpProxy":"","HttpsProxy":"","NoProxy":"","Name":"docker","Labels":null,"ExperimentalBuild":false,"ServerVersion":"1.10.3","ClusterStore":"","ClusterAdvertise":"","Registries":[{"Name":"docker.io","Secure":true}]}

1)通過API來管理docker映象

讓從一些基礎的api開始:操作docker映象的api。將從獲取docker守護程序中所有程序中所有映象的列表開始

[[email protected] ~]# curlhttp://127.0.0.1:2375/images/json | python -m json.tool

  % Total   % Received % Xferd  AverageSpeed   Time    Time    Time  Curren