Docker鏡像原理
Docker鏡像原理
Docker 10 鏡像原理
聯(lián)合文件系統(tǒng)
聯(lián)合文件系統(tǒng)(UnionFS)是 Docker 的核心,也是 Docker 得以極致精簡的保證。
以拉取 redis 鏡像為例
先拉取最新版鏡像
[root@sail ~]# docker pull redis
Using default tag: latest # 默認最新版標簽
latest: Pulling from library/redis
e5ae68f74026: Pull complete # 分層下載,docker image的核心:聯(lián)合文件系統(tǒng)
37c4354629da: Pull complete
b065b1b1fa0f: Pull complete
6954d19bb2e5: Pull complete
6333f8baaf7c: Pull complete
f9772c8a44e7: Pull complete
Digest: sha256:2f502d27c3e9b54295f1c591b3970340d02f8a5824402c8179dcd20d4076b796 #防偽簽名
Status: Downloaded newer image for redis:latest
docker.io/library/redis:latest # 真實地址,docker pull redis 等價于 docker pull docker.io/library/redis:latest
再拉取指定版鏡像
[root@sail ~]# docker pull redis
Using default tag: latest # 默認最新版標簽
latest: Pulling from library/redis
e5ae68f74026: Pull complete # 分層下載,docker image的核心:聯(lián)合文件系統(tǒng)
37c4354629da: Pull complete
b065b1b1fa0f: Pull complete
6954d19bb2e5: Pull complete
6333f8baaf7c: Pull complete
f9772c8a44e7: Pull complete
Digest: sha256:2f502d27c3e9b54295f1c591b3970340d02f8a5824402c8179dcd20d4076b796 #防偽簽名
Status: Downloaded newer image for redis:latest
docker.io/library/redis:latest # 真實地址,docker pull redis 等價于 docker pull docker.io/library/redis:latest
由此可見,redis 鏡像一共 6 層,由于之前拉取了默認的最新版 redis 鏡像,再拉取 redis:5.0 時,有 3 層是可以復(fù)用的,所以只下載了不能復(fù)用的 3 層。
這樣既能提高下載速度,也能極大節(jié)省磁盤占用和資源消耗。
分層鏡像
Docker 使用聯(lián)合文件系統(tǒng)對鏡像做了分層,如下圖所示:

- bootfs(boot file system):啟動文件系統(tǒng)。
- rootfs:root file system:基礎(chǔ)文件系統(tǒng)。



Docker 鏡像都是只讀的,當容器啟動時,一個新的可寫層被加到鏡像的頂部。
這一層就是我們通常說的容器層,容器層之下的都叫鏡像層。

我們自己也是可以制作鏡像并提交的,使用 docker commit 命令。
Docker自定義鏡像
提交鏡像
docker commit
語法
docker commit [參數(shù)] 容器 [倉庫[:標簽]]
參數(shù)
a:作者信息。一般為 作者名字<郵箱>。c:將 Dockerfile 指令應(yīng)用于創(chuàng)建的映像。m:注釋信息。p:提交期間暫停容器(默認)。
將這個容器創(chuàng)建為一個自定義的鏡像并提交到倉庫中。
[root@sail ~]# docker commit -a="sail<yifansailing@163.com>" -m="diy tomcat by sail" fe247e0ef80d tomcat4sail:1.0
sha256:187a99503046ef1a4316221d174add0fbc92391ac534fb1926e535474491f9d2
[root@sail ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
tomcat4sail 1.0 187a99503046 5 seconds ago 684MB
tomcat latest 24207ccc9cce 4 days ago 680MB
可以看到,我們自定義的鏡像已經(jīng)在本地鏡像庫中了。
測試
停止原有容器。
[root@sail ~]# docker stop fe247e0ef80d
fe247e0ef80d
啟動自定義鏡像。
[root@sail ~]# docker run -d -p 8080:8080 --name="tomcat4sail" 187a99503046
602c3c576c1b6d13aa0d2508490220d479eaf8c52c9cfe116029c67437fac61b
由于自定義的鏡像還沒有提交到遠程庫,所以這里只能使用鏡像 ID 啟動。
如果使用鏡像名啟動,會從遠程庫中進行搜索,由于我們還沒有提交,會因為搜索不到報錯。
訪問測試

這里我們并沒有改變?nèi)萜髦?webapps 下的內(nèi)容,但依然可以直接訪問,說明我們自定義的鏡像是生效了的。
Docker數(shù)據(jù)卷 掛載
由來
Docker 是將應(yīng)用和環(huán)境打包成一個鏡像。
這樣,數(shù)據(jù)就不應(yīng)該保存在容器中,否則容器刪除,數(shù)據(jù)就會丟失,有著非常大的風險。
為此,容器和主機之間需要有一個數(shù)據(jù)共享技術(shù),使得在 Docker 容器中產(chǎn)生的數(shù)據(jù)能夠同步到本地。
這就是數(shù)據(jù)卷技術(shù)。其本質(zhì)上是一個目錄掛載,將容器內(nèi)的目錄掛載到主機上。
使用
命令方式
語法
docker run -v 主機目錄:容器目錄
查看主機 /home 目錄。
[root@sail ~]# ls /homeadmin f2 f3 sail test.java
以交互模式啟動 centos 鏡像。
[root@sail ~]# docker run -it -v /home/ceshi:/home centos /bin/bash
[root@ec95646b1a4c /]#
新開一個窗口查看容器詳情。

Mounts 下的 Source 即為設(shè)置的主機目錄、Destination 即為設(shè)置的容器目錄,他們已經(jīng)綁定在了一起。
在主機中查看 /home。
[root@sail /]# cd /home
[root@sail home]# ls
admin ceshi f2 f3 sail test.java
主機上的 /home 下已經(jīng)有了 ceshi 目錄。說明容器一經(jīng)啟動,就會在主機生成對應(yīng)的掛載目錄。
在容器中的 /home 下新建一個文件。
[root@ec95646b1a4c /]# cd /home
[root@ec95646b1a4c home]# ls
[root@ec95646b1a4c home]# touch test.java
[root@ec95646b1a4c home]# ls
test.java
查看主機的 ceshi 目錄。
[root@sail home]# cd ceshi
[root@sail ceshi]# ls
test.java
此時主機中的 ceshi 目錄下也有了這個文件。
關(guān)閉容器。
[root@ec95646b1a4c home]# exit
exit
修改主機中 /home/ceshi/test.java 文件的內(nèi)容。
[root@sail ceshi]# vim test.java
# 此處編輯文件過程省略
[root@sail ceshi]# cat test.java
hello sail
重啟容器。
[root@sail ~]# docker start ec95646b1a4c
ec95646b1a4c
[root@sail ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ec95646b1a4c centos "/bin/bash" 19 minutes ago Up 5 seconds charming_cartwright
查看 /home 下的文件。
[root@sail ~]# docker exec -it ec95646b1a4c /bin/bash
[root@ec95646b1a4c /]# cd /home
[root@ec95646b1a4c home]# ls
test.java
[root@ec95646b1a4c home]# cat test.java
hello sail
此時容器中的文件也更改了。
由此可見,數(shù)據(jù)卷技術(shù)實現(xiàn)的是雙向同步。
權(quán)限設(shè)置
在使用命令方式設(shè)置卷時,還可以指定權(quán)限,以此保證數(shù)據(jù)安全。
參數(shù)
ro(readonly):只讀。rw(readwrite):可讀可寫。
以數(shù)據(jù)卷只讀權(quán)限啟動鏡像。
[root@sail mysql]# docker run -it -v /home/sail:/home:ro centos /bin/bash
新建文件測試。
[root@02ef70c94920 home]# touch test.java
touch: cannot touch 'test.java': Read-only file system
容器內(nèi)部該目錄是沒有寫入權(quán)限的。
以數(shù)據(jù)卷可讀可寫的權(quán)限啟動鏡像。
[root@sail mysql]# docker run -it -v /home/sail:/home:rw centos /bin/bash
[root@48678e08f868 /]# cd /home
[root@48678e08f868 home]# touch test.java
[root@48678e08f868 home]# ls
apache-tomcat-9.0.55.tar.gz jdk-8u301-linux-x64.rpm test.java
新建文件測試。
[root@sail mysql]# docker run -it -v /home/sail:/home:rw centos /bin/bash
[root@48678e08f868 /]# cd /home
[root@48678e08f868 home]# touch test.java
[root@48678e08f868 home]# ls
apache-tomcat-9.0.55.tar.gz jdk-8u301-linux-x64.rpm test.java
容器內(nèi)部該目錄寫入是沒有問題的。
前面我們沒有指定權(quán)限也可以寫入,由此可見,數(shù)據(jù)卷默認是具有讀寫權(quán)限的。
具名掛載
啟動鏡像時只定義主機卷名稱,不指定掛載目錄。
[root@sail mysql]# docker run -it -v my-centos:/home centos /bin/bash
[root@3cf74e9e6973 /]#
查看目前掛載的卷。
# 使用 Ctrl + P + Q 不退出容器的情況下回到主機目錄。
[root@sail mysql]# docker volume ls
DRIVER VOLUME NAME
local my-centos
查看卷的詳情。
[root@sail mysql]# docker volume inspect my-centos
[
{
"CreatedAt": "2021-12-20T16:55:35+08:00",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/my-centos/_data",
"Name": "my-centos",
"Options": null,
"Scope": "local"
}
]
卷掛載在 /var/lib/docker/volumes/卷名/_data 目錄下。
在沒有指定主機掛載目錄的情況下,會默認掛載到該目錄。
由于指定了卷名,所以這種方式稱為具名掛載。
匿名掛載
啟動鏡像時只指定容器目錄。
[root@sail mysql]# docker run -it -v /home centos /bin/bash
查看目前掛載的卷。
[root@sail mysql]# docker volume ls
DRIVER VOLUME NAME
local 159830cf55550c9a39e845c1d96aa04cc762005bc0c64d15d5066834b47df940
查看卷的詳情。
[root@sail mysql]# docker volume inspect 159830cf55550c9a39e845c1d96aa04cc762005bc0c64d15d5066834b47df940
[
{
"CreatedAt": "2021-12-20T17:05:23+08:00",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/159830cf55550c9a39e845c1d96aa04cc762005bc0c64d15d5066834b47df940/_data",
"Name": "159830cf55550c9a39e845c1d96aa04cc762005bc0c64d15d5066834b47df940",
"Options": null,
"Scope": "local"
}
]
卷也是掛載在 /var/lib/docker/volumes/xxx/_data 目錄下。
在沒有指定主機掛載目錄的情況下,會默認掛載到該目錄。
由于沒有指定卷名,所以這種方式稱為匿名掛載。
只有指定主機目錄的情況下會掛載到指定目錄,否則都會掛載到默認目錄。
實戰(zhàn)
mysql數(shù)據(jù)同步
數(shù)據(jù)庫中的數(shù)據(jù)極為重要,必須同步到主機,否則將會有非常大的數(shù)據(jù)丟失風險。
這里以 mysql 鏡像為例演示數(shù)據(jù)同步的過程。
啟動 mysql 鏡像。
[root@sail ~]# docker run -d -p 3310:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7
Unable to find image 'mysql:5.7' locally
5.7: Pulling from library/mysql
ffbb094f4f9e: Pull complete
6c1cb25f7525: Pull complete
Digest: sha256:d1cc87a3bd5dc07defc837bc9084f748a130606ff41923f46dec1986e0dc828d
Status: Downloaded newer image for mysql:5.7
a016e564d977550e475474556cfd033fb1c731002381bc9f9544c63fccb7f60c
其中 -e 為環(huán)境配置。安裝啟動 mysql 需要配置密碼。
使用docker inspect查看掛載情況。

已經(jīng)生成了兩個目錄的掛載。
查看主機同步的目錄。
[root@sail ~]# cd /home
[root@sail home]# ls
admin ceshi f2 f3 mysql sail test.java
[root@sail home]# cd mysql
[root@sail mysql]# ls
conf data
主機已經(jīng)同步了容器掛載的目錄。
使用數(shù)據(jù)庫管理工具連接測試(這里使用 IDEA 自帶的數(shù)據(jù)庫工具)。

浙公網(wǎng)安備 33010602011771號