一 鏡像基本操作 鏡像是一個包含程式運行必要依賴環境和代碼的只讀文件,其本質是磁碟上一系列文件的集合。它採用分層的文件系統,將每一次改變以讀寫層的形式增加到原來的只讀文件上。鏡像是容器運行的基石。 1.1 搜索鏡像 docker命令必須具備root許可權,普通用戶可是用那個sudo。 提示:docke ...
一 鏡像基本操作
鏡像是一個包含程式運行必要依賴環境和代碼的只讀文件,其本質是磁碟上一系列文件的集合。它採用分層的文件系統,將每一次改變以讀寫層的形式增加到原來的只讀文件上。鏡像是容器運行的基石。1.1 搜索鏡像
1 root@docker:~# docker search centos #查詢centos共用鏡像
![01 01](https://img2018.cnblogs.com/blog/680719/201901/680719-20190112102842203-1473069134.png)
1.2 下載(拉取)鏡像
1 root@docker:~# docker pull centos:7 #使用pull下載鏡像
![02 02](https://img2018.cnblogs.com/blog/680719/201901/680719-20190112102844175-1310962825.png)
1.3 列出(查看)本地鏡像
1 root@docker:~# docker images <特定標簽> #查看本地下載的鏡像
![03 03](https://img2018.cnblogs.com/blog/680719/201901/680719-20190112102846221-1099218726.png)
- REPOSTITORY:表示鏡像的倉庫源,有以下類型:
- [namespace/centos]:由命名空間和實際的倉庫名稱組成。
- [centos]:只有倉庫名。屬於頂級命名空間,只用於官方鏡像。
- [dl.dockerpool.com:5000\centos:7]:指定URL路徑的方式。
- TAG:鏡像的標簽
- 未指定鏡像tag時,預設為latest,但latest沒有任何特殊含義,人為的將latest作為最新穩定版本的別名;
- 一個repository可以有多個tag,而多個tag也可能對應同一個鏡像。
- IMAGE ID:鏡像ID
- CREATED:鏡像創建時間
- SIZE:鏡像大小
1.4 推送鏡像
1 root@docker:~# docker push registry.cn-hangzhou.aliyuncs.com/xhy-study-01/xhy-images-01:centos-7-xhy
![04 04](https://img2018.cnblogs.com/blog/680719/201901/680719-20190112102848100-2125120714.png)
1.5 導出鏡像
1 root@docker:~# docker save -o centos-7.tar centos:7
1.6 導入鏡像
1 root@docker:~# docker load -i centos-7.tar
1.7 刪除鏡像
1 root@docker:/study# docker rmi httpd
1.8 設置鏡像標簽
1 root@docker:~# docker tag 6de222aa7640 xhy/centos7:v3 2 root@docker:~# docker images
![05 05](https://img2018.cnblogs.com/blog/680719/201901/680719-20190112102849123-1159243839.png)
二 docker文件系統
2.1 Linux文件系統簡介
linux文件系統由bootfs和rootfs組成,bootfs主要包含bootloader和kernel,bootloader主要是引導載入kernel,當kernel被載入到記憶體之後bootfs就被卸載掉了。rootfs包含的就是典型linux系統中/dev,/proc,/bin,/etc等標準目錄。2.2 docker文件系統
Docker容器是建立在Aufs基礎上的,Aufs支持將不同的目錄掛載到同一個虛擬文件系統下,並實現一種layer的概念。Aufs將掛載到同一虛擬文件系統下的多個目錄分別設置成read-only,read-write以及whiteout-able許可權。 read-only目錄只能讀,而寫操作只能在read-write目錄中實現。 寫操作是在read-only之上的一種增量操作,不影響read-only目錄。 docker 鏡像中每一層文件系統都是read-only。 提示:當掛載目錄的時候要嚴格按照各目錄之間的這種增量關係,將被增量操作的目錄優先於在它基礎上增量操作的目錄掛載,待所有目錄掛載結束了,繼續掛載一個read-write目錄,如此便形成了一種層次結構。2.3 docker鏡像原理
在構建鏡像時,從一個最基本的操作系統開始,每個構建的操作都相當於做一層修改,增加了一層文件系統,一層層往上疊加,上層的修改會覆蓋底層該位置的可見性。當使用時,只會看到一個完全的整體,總共有多少層以及每層所做的修改都是透明的。![06 06](https://img2018.cnblogs.com/blog/680719/201901/680719-20190112102851127-181909306.png)
![07 07](https://img2018.cnblogs.com/blog/680719/201901/680719-20190112102852244-440188107.png)
![08 08](https://img2018.cnblogs.com/blog/680719/201901/680719-20190112102853218-338943033.png)
三 鏡像結構
3.1 image結構
![09 09](https://img2018.cnblogs.com/blog/680719/201901/680719-20190112102853602-1000813942.png)
1 root@docker:/study# tar -xf centos-7.tar
![10 10](https://img2018.cnblogs.com/blog/680719/201901/680719-20190112102854337-2095587071.png)
1 root@docker:/study# tree
![11 11](https://img2018.cnblogs.com/blog/680719/201901/680719-20190112102854711-884250985.png)
1 root@docker:/study# cat repositories 2 {"centos":{"7":"d1ed0d8ec4ec460641430566e9a8cece698e60d4ad4afcf48759ad157d340064"}}解釋:repositories 文件,裡面是一個 JSON 定義,保存了三個信息:鏡像名字、tag、tag 對應的 layer。
1 root@docker:/study# cat d1ed0d8ec4ec460641430566e9a8cece698e60d4ad4afcf48759ad157d340064/json | jq .
![12 12](https://img2018.cnblogs.com/blog/680719/201901/680719-20190112102855095-332184506.png)
1 root@docker:/study# tar -tf d1ed0d8ec4ec460641430566e9a8cece698e60d4ad4afcf48759ad157d340064/layer.tar
![13 13](https://img2018.cnblogs.com/blog/680719/201901/680719-20190112102855458-1764995817.png)
四 Dockerfile、Docker鏡像和Docker容器
4.1 關係
Dockerfile 是軟體的原材料,Docker 鏡像是軟體的交付品,而 Docker 容器則可以認為是軟體的運行態。從應用軟體的角度來看,Dockerfile、Docker 鏡像與 Docker 容器分別代表軟體的三個不同階段,Dockerfile 面向開發,Docker 鏡像成為交付標準,Docker 容器則涉及部署與運維。![14 14](https://img2018.cnblogs.com/blog/680719/201901/680719-20190112102855818-2010560684.png)
![15 15](https://img2018.cnblogs.com/blog/680719/201901/680719-20190112102856219-141643585.png)
五 docker存儲驅動
Docker最開始採用AUFS作為文件系統,也得益於AUFS分層的概念,實現了多個Container可以共用同一個image。但由於AUFS未併入Linux內核,且只支持Ubuntu,考慮到相容性問題,在Docker 0.7版本中引入了存儲驅動, 目前,Docker支持AUFS、Btrfs、Device mapper、OverlayFS、ZFS五種存儲驅動。5.1 底層技術
- 寫時複製(CoW)
- 用時分配(allocate-on-demand)
5.2 AUFS
AUFS(AnotherUnionFS)是一種Union FS,是文件級的存儲驅動。AUFS能透明覆蓋一個或多個現有文件系統的層狀文件系統,把多層合併成文件系統的單層表示。即支持將不同目錄掛載到同一個虛擬文件系統下的文件系統。 這種文件系統可以一層一層地疊加修改文件。無論底下有多少層都是只讀的,只有最上層的文件系統是可寫的。當需要修改一個文件時,AUFS創建該文件的一個副本,使用CoW將文件從只讀層複製到可寫層進行修改,結果也保存在可寫層。 在Docker中,底下的只讀層就是image,可寫層就是Container。結構如下圖所示:![16 16](https://img2018.cnblogs.com/blog/680719/201901/680719-20190112102857111-713209600.png)
5.3 OverlayFS
Overlay是Linux內核3.18後支持的,也是一種Union FS,和AUFS的多層不同的是Overlay只有兩層:一個upper文件系統和一個lower文件系統,分別代表Docker的鏡像層和容器層。當需要修改一個文件時,使用CoW將文件從只讀的lower複製到可寫的upper進行修改,結果也保存在upper層。在Docker中,底下的只讀層就是image,可寫層就是Container。![17 17](https://img2018.cnblogs.com/blog/680719/201901/680719-20190112102858119-1539769163.png)
5.4 Device mapper
Device mapper是Linux內核2.6.9後支持的,提供的一種從邏輯設備到物理設備的映射框架機制,在該機制下,用戶可根據需要制定實現存儲資源的管理策略。 不同於AUFS和OverlayFS的文件級存儲,Device mapper是塊級存儲,所有的操作都是直接對塊進行操作,而不是文件。 Device mapper驅動會先在塊設備上創建一個資源池,然後在資源池上創建一個帶有文件系統的基本設備,所有鏡像都是這個基本設備的快照,而容器則是鏡像的快照。 所以在容器里看到文件系統是資源池上基本設備的文件系統的快照,並不有為容器分配空間。當要寫入一個新文件時,在容器的鏡像內為其分配新的塊並寫入數據,即用時分配。當要修改已有文件時,再使用CoW為容器快照分配塊空間,將要修改的數據複製到在容器快照中新的塊里再進行修改。 Device mapper 驅動預設會創建一個100G的文件包含鏡像和容器。每一個容器被限制在10G大小的捲內,大小可配置調整。![18 18](https://img2018.cnblogs.com/blog/680719/201901/680719-20190112102859272-262731789.png)
5.5 Btrfs
Btrfs被稱為下一代寫時複製文件系統,併入Linux內核,也是文件級級存儲,但可以像Device mapper直接操作底層設備。 Btrfs把文件系統的一部分配置為一個完整的子文件系統,稱之為subvolume 。那麼採用 subvolume,一個大的文件系統可以被劃分為多個子文件系統,這些子文件系統共用底層的設備空間,在需要磁碟空間時便從底層設備中分配。 為了靈活利用設備空間,Btrfs 將磁碟空間劃分為多個chunk 。每個chunk可以使用不同的磁碟空間分配策略。比如某些chunk只存放metadata,某些chunk只存放數據。這種模型有很多優點,比如Btrfs支持動態添加設備。 用戶在系統中增加新的磁碟之後,可以使用Btrfs的命令將該設備添加到文件系統中。 Btrfs把一個大的文件系統當成一個資源池,配置成多個完整的子文件系統,還可以往資源池裡加新的子文件系統,而基礎鏡像則是子文件系統的快照,每個子鏡像和容器都有自己的快照,這些快照則都是subvolume的快照。 當寫入一個新文件時,為在容器的快照里為其分配一個新的數據塊,文件寫在這個空間里,這個叫用時分配。而當要修改已有文件時,使用CoW複製分配一個新的原始數據和快照,在這個新分配的空間變更數據,變結束再更新相關的數據結構指向新子文件系統和快照,原來的原始數據和快照沒有指針指向,被覆蓋。![19 19](https://img2018.cnblogs.com/blog/680719/201901/680719-20190112102900399-1971127929.png)
5.6 ZFS
ZFS 文件系統是一個革命性的全新的文件系統,它從根本上改變了文件系統的管理方式,ZFS 完全拋棄了“捲管理”,不再創建虛擬的捲,而是把所有設備集中到一個存儲池中來進行管理,用“存儲池”的概念來管理物理存儲空間。過去,文件系統都是構建在物理設備之上的。為了管理這些物理設備,併為數據提供冗餘,“捲管理”的概念提供了一個單設備的映像。而ZFS創建在虛擬的,被稱為“zpools”的存儲池之上。每個存儲池由若幹虛擬設備(virtual devices,vdevs)組成。這些虛擬設備可以是原始磁碟,也可能是一個RAID1鏡像設備,或是非標準RAID等級的多磁碟組。於是zpool上的文件系統可以使用這些虛擬設備的總存儲容量。![20 20](https://img2018.cnblogs.com/blog/680719/201901/680719-20190112102902106-1007169040.png)
![21 21](https://img2018.cnblogs.com/blog/680719/201901/680719-20190112102902616-1808400623.png)
5.7 存儲驅動的對比及適應場景
5.8 修改docker存儲驅動類型
1 root@docker:~# vi /etc/docker/daemon.json 2 { 3 "storage-driver": "overlay2" 4 }
六 創建鏡像
從鏡像倉庫中下載的鏡像若不能滿足需求,可通過以下兩種方式對鏡像進行更改。- 從已經創建的容器中更新鏡像,並且提交這個鏡像
- 使用 Dockerfile 指令來創建一個新的鏡像
6.1 更新鏡像並提交
- 運行容器
- 修改容器
- 將容器保存為新的鏡像
1 root@docker:~# docker run --name centos-7-01 -it centos:7 /bin/bash #創建容器 2 [root@01b2b251e216 /]# yum -y install net-tools vim openssh-clients wget ntp bash-completion #安裝軟體 3 [root@01b2b251e216 /]# exit 4 root@docker:~# docker commit -m="has modify" -a="xhy" 01b2b251e216 centos-7-01 5 root@docker:~# docker images
![22 22](https://img2018.cnblogs.com/blog/680719/201901/680719-20190112102902986-885132116.png)
- -m:提交的描述信息
- -a:指定鏡像作者
- 01b2b251e216 :容器ID
- centos-7-01:指定要創建的目標鏡像名
1 root@docker:~# docker images #查看鏡像
更新現有鏡像缺陷
- 手動創建,容易出錯,效率低及可重覆性弱
- 使用者並不知道鏡像是如何創建出來的,裡面是否有惡意程式,可能存在案例隱患
6.2 Dockerfile構建鏡像舉例
1 root@docker:~# mkdir /dockerfiles 2 root@docker:~# cd /dockerfiles/ 3 root@docker:/dockerfiles# vi Dockerfile 4 FROM centos:7 5 MAINTAINER Fisher "[email protected]" 6 7 RUN /bin/echo 'root:x123456' |chpasswd 8 RUN useradd xhy 9 RUN /bin/echo 'xhy:x123456' |chpasswd 10 RUN /bin/echo -e "LANG=\"en_US.UTF-8\"" >/etc/default/local 11 EXPOSE 22 12 EXPOSE 80 13 CMD /usr/sbin/sshd -D語句說明: 第一條FROM,指定所採用的鏡像源,每一個指令的首碼都必須是大寫的; RUN 指令表示docker在鏡像內執行的命令,更多詳見七Dockerfile詳解。
1 root@docker:/dockerfiles# docker build -t xhy/centos7 /dockerfiles/
參數說明:
- -t :指定要創建的目標鏡像名
- /dockerfiles/:Dockerfile 文件所在目錄
1 root@docker:~# docker images #查看鏡像
![23 23](https://img2018.cnblogs.com/blog/680719/201901/680719-20190112102903174-961140970.png)
1 root@docker:/dockerfiles# docker run -t -i xhy/centos7 /bin/bash #創建容器
![24 24](https://img2018.cnblogs.com/blog/680719/201901/680719-20190112102903493-825741580.png)
七 Dockerfile詳解
7.1 Dockerfile典型結構
1 From ubutu #第一行必須指令基於的基礎鏡像 2 MAINTAINER docker_user [email protected] #維護者信息 3 apt/sourcelist.list #鏡像的操作指令 4 RUN apt-get update && apt-get install -y ngnix #鏡像的操作指令 5 RUN echo "\ndaemon off;">>/etc/ngnix/nignix.conf #鏡像的操作指令 6 CMD /usr/sbin/ngnix #容器啟動時執行指令
7.2 Dockerfile相關指令
- 指令:From
1 FROM <image> 2 FROM <image>:<tag> 3 FROM <image>:<digest>
含義:FROM命令定義構建鏡像的基礎鏡像,該條必須是dockerfile的首個命令。若同一個DockerFile創建多個鏡像時,可使用多個From指令(每個鏡像一次),FROM 是必備且必須是第一條指令。在FROM指定構建鏡像的基礎源鏡像時,若本地沒有指定的該鏡像,則會自動從 Docker 的公共庫 pull 鏡像下來。 提示:
- FROM必須是 Dockerfile 中非註釋行的第一個指令,即一個 Dockerfile 從FROM語句開始。
- 如果有需求在一個 Dockerfile 中創建多個鏡像,則FROM可以在一個 Dockerfile 中出現多次。
- 如果FROM語句沒有指定鏡像標簽,則預設使用latest標簽。
- 指令:MAINTAINER
1 MAINTAINER <name>含義:聲明作者信息,可以放在文件任何位置,建議放在FROM後面。 舉例:
1 MAINTAINER xhy
- 指令:RUN
1 RUN <commands> 2 RUN "executable", "param1", "param2"
含義:RUN 指令是用來執行命令行命令的,每條RUN指令將在當前鏡像基礎上執行指定命令,並提交為新的鏡像,後續RUN都在之前RUN提交後的鏡像為基礎. exec 方式會被解析為一個 JSON 數組,所以必須使用雙引號而不是單引號。exec 方式不會調用一個命令 shell,所以也就不會繼承相應的變數,RUN產生的緩存在下一次構建的時依舊有效,且會被重用,可以使用--no-cache選項,即docker build --no-cache,如此便不會緩存。 舉例:
1 RUN echo 'Hello, Docker!' 2 RUN ["/bin/bash", "-c","echo hello"]
提示:對於處理同一事件的多個命令,建議採用&&連接為一個命令,即構建一層即可。命令過長可使用\的換行方式。
- 指令:CMD