參考:
Docker鏡像
在之前的介紹中,我們知道鏡像是Docker的三大組件之一。
Docker運行容器前需要本地存在對應的鏡像,如果鏡像不存在本地,Docker會從鏡像倉庫下載(默認是Docker Hub公共注冊服務器中的倉庫)。
本文將介紹關於鏡像的內容,包括:
- 從倉庫獲取鏡像
- 管理本地主機上的鏡像
- 介紹鏡像實現的基本原理
獲取鏡像
可以使用docker pull
命令來從倉庫獲取所需要的鏡像。
舉例:從Docker Hub倉庫下載一個Ubuntu操作系統的鏡像。
[root@localhost /]# docker pull ubuntu:latest
latest: Pulling from library/ubuntu
7b1a6ab2e44d: Pull complete
Digest: sha256:626ffe58f6e7566e00254b638eb7e0f3b11d4da9675088f4781a50ae288f3322
Status: Downloaded newer image for ubuntu:latest
docker.io/library/ubuntu:latest
下載過程中,會輸出獲取鏡像的每一層的信息。
該命令等價於docker pull registry.hub.docker.com/ubuntu:latest
命令,即從注冊服務器registry.hub.docker.com
中的ubuntu
倉庫來下載latest的鏡像。
有時候官方倉庫注冊服務器下載比較慢,可以從其他倉庫中下載。以阿里雲鏡像加速為例,配置流程:
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://<個人的地址號>.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
*注意:容器鏡像服務 (aliyun.com),登陸阿里雲賬號,可查看自己的鏡像加速器地址。
配置完之后可以通過docker info
查看
列出本地鏡像
使用docker images
顯示本地已有的鏡像。
[root@localhost /]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu latest ba6acccedd29 7 weeks ago 72.8MB
ubuntu test ba6acccedd29 7 weeks ago 72.8MB
hello-world latest feb5d9fea6a5 2 months ago 13.3kB
在列出的信息中,可以看到幾個字段
- REPOSITORY:來源於哪個倉庫,比如ubuntu
- TAG:鏡像的標簽,比如latest
- IMAGE ID:鏡像ID(唯一)
- CREATED:創建時間
- SIZE:鏡像大小
其中鏡像的IMAGE ID
唯一標識了鏡像,上面ubuntu:latest
和ubuntu:test
具有相同的鏡像IMAGE ID
,說明它們實際上是同一鏡像。
TAG
信息用來標記來自同一個倉庫的不同鏡像。例如ubuntu
倉庫中有多個鏡像,通過TAG
信息來區分發行版本,例如10.04
、12.04
、14.04
等,而latest
標識最新的版本。
下面的命令指定使用鏡像ubuntu:latest
來啟動一個容器。
sudo docker run -it ubuntu:latest /bin/bash
如果不指定具體的標記,則默認使用latest
標記信息。
其中-it
的含義:
選項 | 簡寫 | 說明 |
---|---|---|
-detach | -d | 在后台運行容器,並且打印容器ID。 |
-interactive | -i | 即使沒有連接,也要保持標准輸入保持打開狀態,一般與-t連用。 |
-tty | -t | 分配一個偽tty,一般與-i連用。 |
創建鏡像
創建鏡像有很多方法,用戶可以從Docker Hub獲取已有鏡像並更新,也可以利用本地文件系統創建一個。
方法一:修改已有鏡像
通過修改原有的鏡像,來定制創建鏡像,以上面的ubuntu鏡像為例子。
- 啟動鏡像,寫入一些文件或者更新軟件。
[root@localhost /]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu latest ba6acccedd29 7 weeks ago 72.8MB
hello-world latest feb5d9fea6a5 2 months ago 13.3kB
[root@localhost /]#
[root@localhost /]# docker run -it ubuntu:latest /bin/bash
root@ad84bf1eb7d8:/#
root@ad84bf1eb7d8:/# cd ~
root@ad84bf1eb7d8:~# echo "Modify test" >> test.txt
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ad84bf1eb7d8 ba6acccedd29 "/bin/bash" 27 seconds ago Up 26 seconds
- 提交鏡像更改(將容器轉為鏡像)
[root@localhost ~]# docker commit -m="Ubuntu image commit test" -a="Skybiubiu" ad84bf1eb7d8 ubuntu2:test
sha256:5299c83968a8ef1a44308d851593f74620945ccda08a6ea516fd0ad9055dc019
[root@localhost ~]#
[root@localhost ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu2 test 5299c83968a8 4 seconds ago 72.8MB
ubuntu latest ba6acccedd29 7 weeks ago 72.8MB
hello-world latest feb5d9fea6a5 2 months ago 13.3kB
格式:docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
-m
:提交的描述信息
-a
:指定鏡像作者
方法二:通過Dockerfile構建鏡像
使用docker commit
來擴展一個鏡像比較簡單,但是不方便在一個團隊中分享。
我們可以使用docker build
來創建一個新的鏡像。為此,首先需要創建一個Dockerfile,包含一些如何創建鏡像的指令。
新建一個目錄和一個Dockerfile。
cd ~
mkdir Dockerfile_dir
cd Dockerfile_dir
touch Dockerfile
Dockerfile中每一條指令都創建鏡像的一層(並非絕對),以構建一個Nginx鏡像為例子
[root@localhost Dockerfile_dir]# vim Dockerfile
FROM nginx
MAINTAINER SkyBiuBiu
RUN echo "It 's a Nginx image,created by skybiubiu." > /usr/share/nginx/html/index.html
Dockerfile基本的語法是
- 使用
#
來注釋。 FROM
關鍵字告訴Docker使用哪個鏡像作為基礎。- 接着
MAINTAINER
是維護者信息。 RUN
開頭的指令會在創建中運行,比如安裝一個軟件包。
編寫完成的Dockerfile可以通過docker build
命令來生成鏡像。
docker build -t="skybiubiu/nginx:v1" .
格式:
-t
:打標簽.
:表示當前文件夾下
*注意:更多寫法,在后面Dockerfile章節補充。
方法三:從本地文件系統導入
通過docker import
命令從本地文件系統導入鏡像。
將一個本地文件夾導入轉化成一個鏡像。
上傳鏡像
首先,得通過docker login
命令登陸Docker Hub。
[root@localhost ~]# docker login
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username: skybiubiu
Password:
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
然后通過docker push
命令上傳鏡像。
格式docker push 倉庫ID/鏡像名:Tag
[root@localhost ~]# docker push skybiubiu/nginx:v1
The push refers to repository [docker.io/skybiubiu/nginx]
42bab3f962bd: Pushed
2bed47a66c07: Mounted from library/nginx
82caad489ad7: Mounted from library/nginx
d3e1dca44e82: Mounted from library/nginx
c9fcd9c6ced8: Mounted from library/nginx
0664b7821b60: Mounted from library/nginx
9321ff862abb: Mounted from library/nginx
v1: digest: sha256:57227eb210f8abbeacd1f54f3334300636968371adfbe7a9a3a94f00931444d8 size: 1777
保存和載入鏡像
鏡像列表如下
[root@localhost ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
skybiubiu/nginx v1 c841f47ef705 3 hours ago 141MB
ubuntu2 test 5299c83968a8 3 hours ago 72.8MB
nginx latest f652ca386ed1 6 days ago 141MB
ubuntu latest ba6acccedd29 7 weeks ago 72.8MB
hello-world latest feb5d9fea6a5 2 months ago 13.3kB
將ubuntu2:test
導出到本地,-o
表示output。
[root@localhost ~]# docker save -o ubuntu2.tar ubuntu2:test
[root@localhost ~]# ls | grep ubuntu2.tar
ubuntu2.tar
將本地ubuntu2.tar
導入為鏡像,-i
表示input。
[root@localhost ~]# docker load -i ubuntu2.tar
Loaded image: ubuntu2:test
移除本地鏡像
通過docker rmi
命令可以刪除鏡像。
通過命令刪除skybiubiu/nginx:v1的鏡像。
[root@localhost ~]# docker rmi skybiubiu/nginx:v1
Untagged: skybiubiu/nginx:v1
Untagged: skybiubiu/nginx@sha256:57227eb210f8abbeacd1f54f3334300636968371adfbe7a9a3a94f00931444d8
Deleted: sha256:c841f47ef70593e223dfd75f23df2c21dbe7e75cd1a63eea9dd454bf0f6f0d99
Deleted: sha256:79ff50c01b6592d364734334d08ea63d7bd7a00646d710c8e1a4927666271544
Deleted: sha256:e94202cb0e93a88978d0bacfd032e2158fb68b4803d900868595b351a7801fb3
*注意:docker rm
命令刪除的是容器
有一個刪除所有鏡像的小技巧,如下。
docker rmi -f $(docker images -q)
上面命令中,docker images -q
輸出的是鏡像ID,將鏡像ID作為變量傳入docker rmi -f
中,刪除所有鏡像。
鏡像的實現原理
Docker 鏡像是怎么實現增量的修改和維護的? 每個鏡像都由很多層次構成,Docker 使用 Union FS 將這 些不同的層結合到一個鏡像中去。
通常 Union FS 有兩個用途, 一方面可以實現不借助 LVM、RAID 將多個 disk 掛到同一個目錄下,另一個更 常用的就是將一個只讀的分支和一個可寫的分支聯合在一起,Live CD 正是基於此方法可以允許在鏡像不 變的基礎上允許用戶在其上進行一些寫操作。 Docker 在 AUFS 上構建的容器也是利用了類似的原理。
*注意:關於Docker鏡像實現原理,后面專門寫一篇博客來研究。