鏡像
Image的生命周期
常用操作
- 列出本地存儲的鏡像:
docker images - 列出完整的image ID:
docker images --no-trunk - 只列出image ID:
docker images -q - 刪除“懸掛”的Image:
docker images --filter "dangling=true" -q | xargs docker rmi - 鏡像分析Dive:
dive {image id} - 下載鏡像:
docker pull busybox - 保存和導(dǎo)入鏡像:
docker save -o busybox.tar busybox
docker load -i busybox.tar
docker load一般只用于導(dǎo)入由docker save導(dǎo)出的鏡像,導(dǎo)入后的鏡像跟原鏡像完全一樣,包括擁有相同的鏡像ID和分層等內(nèi)容.
Docker image的組織結(jié)構(gòu)
Docker image包含著數(shù)據(jù)及必要的元數(shù)據(jù)。數(shù)據(jù)由一層層的image layer組成,元數(shù)據(jù)則是一些JSON文件,用來描述數(shù)據(jù)(image layer)之間的關(guān)系以及容器的一些配置信息
查看鏡像的歷史:
docker history victor0217/numberone
IMAGE CREATED CREATED BY SIZE COMMENT
51b41265c9d9 25 hours ago /bin/sh -c #(nop) ENTRYPOINT ["java" "-jar"… 0B
0724e6967b63 25 hours ago /bin/sh -c #(nop) COPY multi:9f7f512ecc1933e… 63.4MB
cdf26cc71b50 7 days ago /bin/sh -c set -eux; dpkgArch="$(dpkg --pr… 205MB
<missing> 7 days ago /bin/sh -c #(nop) ENV JAVA_URL_VERSION=8u24… 0B
<missing> 7 days ago /bin/sh -c #(nop) ENV JAVA_BASE_URL=https:/… 0B
<missing> 7 days ago /bin/sh -c #(nop) ENV JAVA_VERSION=8u242 0B
<missing> 7 days ago /bin/sh -c { echo '#/bin/sh'; echo 'echo "$J… 27B
<missing> 7 days ago /bin/sh -c #(nop) ENV PATH=/usr/local/openj… 0B
<missing> 7 days ago /bin/sh -c #(nop) ENV JAVA_HOME=/usr/local/… 0B
<missing> 7 days ago /bin/sh -c #(nop) ENV LANG=C.UTF-8 0B
<missing> 7 days ago /bin/sh -c set -eux; apt-get update; apt-g… 11.1MB
<missing> 8 days ago /bin/sh -c apt-get update && apt-get install… 145MB
<missing> 8 days ago /bin/sh -c set -ex; if ! command -v gpg > /… 17.5MB
<missing> 8 days ago /bin/sh -c apt-get update && apt-get install… 16.5MB
<missing> 8 days ago /bin/sh -c #(nop) CMD ["bash"] 0B
<missing> 8 days ago /bin/sh -c #(nop) ADD file:e05e45c33042db4ec… 114MB
鏡像被本地存儲在:/var/lib/docker
查看鏡像的元數(shù)據(jù)信息: docker inspect busybox
倉庫
Hub和Repository以及Image的關(guān)系如下圖:

倉庫的名字通常由兩部分組成,中間以斜線分開。斜線之前是用戶名,斜線之后是鏡像名。如tom/ubuntu表示屬于用戶tom的Ubuntu鏡像。這也是社區(qū)上區(qū)分公有倉庫和私有倉庫的方法.
- 登錄倉庫:
docker login -u <user name> -p <password> - 上傳鏡像:
docker push localhost:5000/official/ubuntu:14.04
上面的示例中是向本地私有倉庫上傳鏡像。如果不寫服務(wù)器地址,則默認(rèn)上傳到官方DockerHub(https://hub.docker.com)
- 下載鏡像:
docker pull ubuntu:14.04 - 查詢鏡像:
docker search localhost:5000/ubuntu
可以通過Docker Private Registry搭建一個本地的鏡像倉庫:
docker run -d --hostname localhost --name registry-v2 \
-v /opt/data/distribution:/var/lib/registry/docker/registry/v2 \
-p 5000:5000 registry:2.0
網(wǎng)絡(luò)
CNM概念模型
Libnetwork提出了新的容器網(wǎng)絡(luò)模型(Container Network Model,簡稱CNM),定義了標(biāo)準(zhǔn)的API用于為容器配置網(wǎng)絡(luò),其底層可以適配各種網(wǎng)絡(luò)驅(qū)動
- 沙盒。沙盒是一個隔離的網(wǎng)絡(luò)運行環(huán)境,保存了容器網(wǎng)絡(luò)棧的配置,包括了對網(wǎng)絡(luò)接口、路由表和DNS配置的管理。在Linux平臺上,沙盒是用Linux Network Namespace實現(xiàn)的,在其他平臺上可能是不同的概念,如FreeBSD Jail。一個沙盒可以包括來自多個網(wǎng)絡(luò)的多個Endpoint(端點)
- Endpoint。Endpoint將沙盒加入一個網(wǎng)絡(luò),Endpoint的實現(xiàn)可以是一對veth pair或者OVS內(nèi)部端口,當(dāng)前的Libnetwork使用的是veth pair。一個Endpoint只能隸屬于一個沙盒及一個網(wǎng)絡(luò)。通過給沙盒增加多個Endpoint可以將一個沙盒加入多個網(wǎng)絡(luò)。
- 網(wǎng)絡(luò)。網(wǎng)絡(luò)包括一組能互相通信的Endpoint。網(wǎng)絡(luò)的實現(xiàn)可以是Linux bridge、vlan等。
Libnetwork已經(jīng)實現(xiàn)了五種驅(qū)動(driver):
- bridge:Docker默認(rèn)的容器網(wǎng)絡(luò)驅(qū)動。Container通過一對veth pair連接到docker0網(wǎng)橋上,由Docker為容器動態(tài)分配IP及配置路由、防火墻規(guī)則等。
- host:容器與主機共享同一Network Namespace,共享同一套網(wǎng)絡(luò)協(xié)議棧、路由表及iptables規(guī)則等。容器與主機看到的是相同的網(wǎng)絡(luò)視圖。
- null:容器內(nèi)網(wǎng)絡(luò)配置為空,需要用戶手動為容器配置網(wǎng)絡(luò)接口及路由等。
- remote:Docker網(wǎng)絡(luò)插件的實現(xiàn)。Remote driver使得Libnetwork可以通過HTTPRESTful API對接第三方的網(wǎng)絡(luò)方案,類似SocketPlane的SDN方案只要實現(xiàn)了約定的HTTP URL處理函數(shù)及底層的網(wǎng)絡(luò)接口配置方法,就可以替換Docker原生的網(wǎng)絡(luò)實現(xiàn)。
- overlay:Docker原生的跨主機多子網(wǎng)網(wǎng)絡(luò)方案。主要通過使用Linux bridge和vxlan隧道實現(xiàn),底層通過類似于etcd或consul的KV存儲系統(tǒng)實現(xiàn)多機的信息同步。
常用命令
- 創(chuàng)建網(wǎng)絡(luò):
docker network create --driver bridge numberone-net - 啟動時加入網(wǎng)絡(luò):
docker run -p 3306:3306 --name mysql -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7.29 --network=numberone-net - 動態(tài)改成容器網(wǎng)絡(luò)
docker network disconnect bridge mysql
docker network connect numberone-net mysql
5種容器網(wǎng)絡(luò)模式
- none:不為容器配置任何網(wǎng)絡(luò)功能
docker run --net=none -it ubuntu ip addr show
- container:與另一個運行中的容器共享Network Namespace,共享相同的網(wǎng)絡(luò)視圖
docker run -h dockernet --dns 8.8.4.4 -itd ubuntu bash
docker run --net=container:{target container id} -it ubuntu bash
- host:與主機共享Root Network Namespace,容器有完整的權(quán)限可以操縱主機的協(xié)議棧、路由表和防火墻等,所以被認(rèn)為是不安全的
docker run -it --net=host ubuntu bash
- bridge:Docker設(shè)計的NAT網(wǎng)絡(luò)模型
Docker daemon啟動時會在主機創(chuàng)建一個Linux網(wǎng)橋(默認(rèn)為docker0,可通過-b參數(shù)手動指定)。容器啟動時,Docker會創(chuàng)建一對veth pair(虛擬網(wǎng)絡(luò)接口)設(shè)備,veth設(shè)備的特點是成對存在,從一端進入的數(shù)據(jù)會同時出現(xiàn)在另一端。Docker會將一端掛載到docker0網(wǎng)橋上,另一端放入容器的Network Namespace內(nèi),從而實現(xiàn)容器與主機通信的目的
Bridge
在橋接模式下,Docker容器與Internet的通信,以及不同容器之間的通信,都是通過iptables規(guī)則控制的
總之,Docker網(wǎng)絡(luò)的初始化動作包括:創(chuàng)建docker0網(wǎng)橋、為docker0網(wǎng)橋新建子網(wǎng)及路由、創(chuàng)建相應(yīng)的iptables規(guī)則等
-
overlay:Docker原生的跨主機多子網(wǎng)模型
overlay網(wǎng)絡(luò)模型比較復(fù)雜,底層需要類似consul或etcd的KV存儲系統(tǒng)進行消息同步,核心是通過Linux網(wǎng)橋與vxlan隧道實現(xiàn)跨主機劃分子網(wǎng)
Capture.PNG
如圖5-3所示,每創(chuàng)建一個網(wǎng)絡(luò),Docker會在主機上創(chuàng)建一個單獨的沙盒,沙盒的實現(xiàn)實質(zhì)上是一個Network Namespace。在沙盒中,Docker會創(chuàng)建名為br0的網(wǎng)橋,并在網(wǎng)橋上增加一個vxlan接口,每個網(wǎng)絡(luò)占用一個vxlan ID,當(dāng)前Docker創(chuàng)建vxlan隧道的ID范圍為256~1000,因而最多可以創(chuàng)建745個網(wǎng)絡(luò)。當(dāng)添加一個容器到某一個網(wǎng)絡(luò)上時,Docker會創(chuàng)建一對veth網(wǎng)卡設(shè)備,一端連接到此網(wǎng)絡(luò)相關(guān)沙盒內(nèi)的br0網(wǎng)橋上,另一端放入容器的沙盒內(nèi),并設(shè)置br0的IP地址作為容器內(nèi)路由默認(rèn)的網(wǎng)關(guān)地址,從而實現(xiàn)容器加入網(wǎng)絡(luò)的目的
以圖5-3為例,容器1和容器4同屬一個網(wǎng)絡(luò),容器1需要通過256號vxlan隧道訪問另一臺主機的容器4。Docker通過vxlan和Linux網(wǎng)橋?qū)崿F(xiàn)了跨主機的虛擬子網(wǎng)功能。
容器卷
Docker容器里產(chǎn)生的數(shù)據(jù),如果不通過docker commit生成新的鏡像,使數(shù)據(jù)作為鏡像的一部分保存下來,就會在容器刪除后丟失。
為了能夠持久化保存和共享容器的數(shù)據(jù),Docker提出了卷(volume)的概念。簡單來講,卷就是目錄或文件,由Docker daemon掛載到容器中,因此不屬于聯(lián)合文件系統(tǒng),卷中的數(shù)據(jù)在容器被刪除后仍然可以訪問
數(shù)據(jù)卷
- 增加新數(shù)據(jù)卷
docker run -d -v /tmp/data --name busyboxtest busybox
其中,-v參數(shù)會在容器的/tmp/data目錄下創(chuàng)建一個新的數(shù)據(jù)卷
用戶可以通過docker inspect命令查看數(shù)據(jù)卷在主機中的位置:docker inspect busyboxtest
-
將主機目錄掛載為數(shù)據(jù)卷
-v參數(shù)除了可以用于創(chuàng)建數(shù)據(jù)卷外,還可以用來將Docker daemon所在主機上的文件或文件夾掛載到容器中
docker run -d -v /host/data:/data --name busyboxtest busybox
上述命令可以將Docker daemon所在主機的/host/data目錄掛載到容器的/data路徑下
-v參數(shù)的主機目錄必須使用絕對路徑,如果指定路徑不存在,Docker會自動創(chuàng)建該目錄。
以只讀的方式掛載一個數(shù)據(jù)卷:docker run -it -v /host/data:/data:ro --name busyboxtest busybox
數(shù)據(jù)卷容器
如果用戶需要在容器之間共享一些需要永久存儲的數(shù)據(jù),或者想要使用一個臨時容器中的相關(guān)數(shù)據(jù),可以創(chuàng)建一個數(shù)據(jù)卷容器,然后使用該容器進行數(shù)據(jù)共享。
docker create -v /dbdata --name dbdata training/postgress /bin/true
docker run -d --volumes-from dbdata --name db1 training/postgress
docker run -d --volumes-from dbdata --name db2 training/postgress
docker run -d --name db3 --volumes-from db1 training/postgress
數(shù)據(jù)卷的備份,轉(zhuǎn)儲和遷移
docker run --rm --volumes-from dbdata -v $(pwd):/backup ubuntu tar cvf /backup/backup.tar /dbdata
上述命令創(chuàng)建了一個容器,該容器掛載了dbdata數(shù)據(jù)卷,并將主機的當(dāng)前目錄掛載到了容器的/backup目錄中;然后在容器中使用tar命令將dbdata數(shù)據(jù)卷中的內(nèi)容打包存放到/backup目錄的backup.tar文件中。待容器執(zhí)行結(jié)束后,備份文件就會出現(xiàn)在主機的當(dāng)前目錄。之后可以將該備份文件恢復(fù)到當(dāng)前容器或新創(chuàng)建的容器中,完成數(shù)據(jù)的備份和遷移工作
Docker API
目前Docker提供如下三類RESTful API:
- Docker Remote API:諸如docker run等操作最終均是通過調(diào)用Docker Remote API向Docker daemon發(fā)起請求的。
- Docker Registry API:與鏡像存儲有關(guān)的操作可通過Docker Registry API來完成。
- Docker Hub API:用戶管理等操作可通過Docker Hub API來完成。
RestAPI應(yīng)用實例
如果沒有進行特殊配置,Docker會監(jiān)聽本機的一個unix socket,默認(rèn)為unix:///var/run/docker.sock
本地訪問:
echo -e "GET /images/json HTTP/1.0\r\n" | nc -U /var/run/docker.sock
遠(yuǎn)程訪問
curl -XGET localhost:5678/images/ubuntu/history
使用python格式化json輸出
curl -XGET localhost:5678/images/ubuntu/history | python -mjson.tool
啟動Docker暴露HTTP訪問接口
docker -d -H unix:///var/run/docker.sock -H tcp://0.0.0.0.:5678
安全性
Cgroup
Cgroup用于限制容器對CPU、內(nèi)存等關(guān)鍵資源的使用,防止某個容器由于過度使用資源,導(dǎo)致host或者其他容器無法正常運作
限制CPU
Docker能夠指定一個容器的CPU權(quán)重,這是一個相對權(quán)重,與實際的處理速度無關(guān)。事實上,沒有辦法限制一個容器只可以獲得1GHZ的CPU。每個容器默認(rèn)的CPU權(quán)重是1024,簡單地說,假設(shè)只有兩個容器,并且這兩個容器競爭CPU資源,那么CPU資源將在這兩個容器之間平均分配。如果其中一個容器啟動時設(shè)置的CPU權(quán)重是512,那它相對于另一個容器只能得到一半的CPU資源,因此這兩個容器可以得到的CPU資源分別是33.3%和66.6%。但如果另外一個容器是空閑的,第一個容器則會被允許使用100%的CPU。也就是說,CPU資源不是預(yù)先硬性分配好的,而是跟各個容器在運行時對CPU資源的需求有關(guān)
| 選項 | 描述 |
|---|---|
| --cpuset-cpus="" | 允許使用的 CPU 集,值可以為 0-3,0,1 |
| -c,--cpu-shares=0 | CPU 共享權(quán)值(相對權(quán)重) |
| --cpu-period=0 | 限制 CPU CFS 的周期,范圍從 100ms~1s,即[1000, 1000000] |
| --cpu-quota=0 | 限制 CPU CFS 配額,必須不小于1ms,即 >= 1000 |
| --cpuset-mems="" | 允許在上執(zhí)行的內(nèi)存節(jié)點(MEMs),只對 NUMA 系統(tǒng)有效 |
- 可以為容器設(shè)置CPU權(quán)重為100:
docker run --rm -it -c 100 ubuntu bash
- 容器在每個0.5秒里最多只能運行0.25秒:
docker run --rm -it --cpu--period=500000 --cpu-quota=250000 ubuntu /bin/bash
- 把容器的進程限定在特定的CPU上運行,例如將容器限定在0號和1號CPU上運行:
docker run --rm -it --cpuset--cpus=0,1 ubuntu /bin/bash
限制內(nèi)存
| 選項 | 描述 |
|---|---|
| -m,--memory | 內(nèi)存限制,格式是數(shù)字加單位,單位可以為 b,k,m,g。最小為 4M |
| --memory-swap | 內(nèi)存+交換分區(qū)大小總限制。格式同上。必須必-m設(shè)置的大 |
| --memory-reservation | 內(nèi)存的軟性限制。格式同上 |
| --oom-kill-disable | 是否阻止 OOM killer 殺死容器,默認(rèn)沒設(shè)置 |
| --oom-score-adj | 容器被 OOM killer 殺死的優(yōu)先級,范圍是[-1000, 1000],默認(rèn)為 0 |
| --memory-swappiness | 用于設(shè)置容器的虛擬內(nèi)存控制行為。值為 0~100 之間的整數(shù) |
| --kernel-memory | 核心內(nèi)存限制。格式同上,最小為 4M |
- 將容器可使用的內(nèi)存限制在200MB
docker run --rm -it -m 200M ubuntu /bin/bash
這個例子將容器可使用的內(nèi)存限制在200MB。不過事實上還不是這么簡單,我們知道系統(tǒng)在發(fā)現(xiàn)內(nèi)存不足時,會將部分內(nèi)存置換到swap分區(qū)里,因此如果只限制內(nèi)存使用量,可能會導(dǎo)致swap分區(qū)被用光。通過--memory-swap參數(shù)可以限制容器對內(nèi)存和swap分區(qū)的使用,如果只是指定-m而不指定--memory-swap,那么總的虛擬內(nèi)存大?。ㄒ布磎emory加上swap)是-m參數(shù)的兩倍
Dockerfile
Dockerfile的注釋都是以“#”開始的,每一行是一個指令。一般情況下,Dockerfile由4部分組成:
- 基礎(chǔ)鏡像信息
- 維護者信息
- 鏡像操作指令
- 容器啟動指令
# This Dockerfile uses the ubuntu image
# Version 2 - EDITION 1
# Author: tester
# Command format: Instruction [arguments / command] ..
# Base image to use, this must be set as the first line
From ubuntu
#Maintainer: tester tester@email.com
MAINTAINER tester tester@hotmail.com
#Commands to update the image
RUN echo "deb http://archive.ubuntu.com/ubuntu/ raring main universe" >> /etc/apt/sources.list
RUN apt-get update && apt-get install -y nginx
RUN echo "\ndaemon off;" >> /etc/nginx/nginx.conf
#Commands when creating a new container
CMD /usr/sbin/nginx
Dockerfile指令
- FROM指令格式為
FROM<image>或FROM<image>:<tag>。
Dockerfile的第一條必須是FROM指令,用來指定要制作的鏡像繼承自哪個鏡像。
需要說明的是,可以在Dockerfile中寫多個FROM指令來構(gòu)建復(fù)雜的鏡像。 - MAINTAINER
指令格式為MAINTAINER<name>
用來指定維護者信息。 - RUN指令格式為
RUN<command>或RUN["executable","param1","param2"...]
該指令是用來執(zhí)行shell命令的,當(dāng)解析Dockerfile時,遇到RUN指令,Docker會將該指令翻譯為“/bin/sh–c“xxx””,其中xxx為RUN后邊的Shell命令。 - EXPOSE指令格式為
EXPOSE<port>[<port>...]。
該指令用來將容器中的端口號暴露出來,也可以通過“docker run–p”命令實現(xiàn)和服務(wù)器端口的映射。 - CMD指令該指令有三種格式:
CMD["executable","param1","param2"]使用exec執(zhí)行,推薦方式;
CMD command param1 param2在/bin/sh中執(zhí)行,提供給需要交互的應(yīng)用;CMD["param1","param2"]提供給ENTRYPOINT的默認(rèn)參數(shù)。
指定啟動容器時執(zhí)行的命令,每個Dockerfile只能有一條CMD指令。
如果指定了多條CMD指令,只有最后一條會被執(zhí)行。值得說明的是,如果用戶啟動容器時指定了運行的命令,則會覆蓋掉CMD指定的命令。 - ENTRYPOINT指令該指令有兩種格式:
ENTRYPOINT["executable","param1","param2"]
ENTRYPOINT command param1 param2(Shell中執(zhí)行)。
每個Dockerfile中只能有一個ENTRYPOINT,當(dāng)指定多個時,只有最后一個有效。 - VOLUME指令格式為VOLUME["/data"]。
創(chuàng)建一個可以從本地主機或其他容器掛載的掛載點,一般用來存放數(shù)據(jù)庫或需要永久保存的數(shù)據(jù)。如果和host共享目錄,Dockerfile中必須先創(chuàng)建一個掛載點,然后在啟動容器的時候通過“docker run–vCONTAINERPATH”來掛載,其中CONTAINERPATH就是創(chuàng)建的掛載點。
- ENV指令格式為
ENV<key><value>。
指定一個環(huán)境變量,會被后續(xù)RUN指令使用,并在容器運行時保持。 - ADD指令格式為
ADD<src><dest>。
該指令將復(fù)制指定的<src>到容器中的<dest>。
其中<src>可以是Dockerfile所在目錄的一個相對路徑;也可以是一個URL;還可以是一個tar文件(自動解壓為目錄)。 - COPY指令格式為COPY<src><dest>。復(fù)制本地主機的<src>(為Dockerfile所在目錄的相對路徑)到容器中的<dest>。當(dāng)使用本地目錄為源目錄時,推薦使用COPY。
Docker集群管理
Compose
Compose是用來定義和運行一個或多個容器應(yīng)用的工具。使用Compose可以簡化容器鏡像的建立及容器的運行。
Compose是使用YML文件來定義多容器應(yīng)用的,它還會用docker-compose up命令把完整的應(yīng)用運行起來.
從本質(zhì)上來講,Compose把YML文件解析成docker命令的參數(shù),然后調(diào)用相應(yīng)的docker命令行接口,從而把應(yīng)用以容器化的方式管理起來。它通過解析容器間的依賴關(guān)系來順序地啟動容器。而容器間的依賴關(guān)系則可以通過在docker-compose.yml文件中使用“l(fā)inks”標(biāo)記來指定.
實例
web:
build: ./web
ports:
- "5000":"5000"
volumes:
- .:/code
links:
- redis
redis:
image: redis
- 每個定義的服務(wù)都至少要包含build或image兩個命令中的一個,其他的命令都是可選的.
- build命令指定了包含Dockerfile的目錄,可以是絕對目錄也可以是相對目錄,相對目錄指的是相對于docker-compose.yml文件所在位置的目錄
- docker-compose.yml文件中的“ports”標(biāo)記對應(yīng)docker run命令中的“-p”選項
- “volumes”標(biāo)記對應(yīng)docker run命令中的“-v”選項
- “l(fā)inks”標(biāo)記對應(yīng)docker run命令中的“--links”選項
- 通過運行docker-compose build和docker-compose up命令,上述docker-compose.yml文件中定義的Web和Redis服務(wù)都會成功運行起來