前文我們聊了下docker的基礎使用方法,大概介紹了下docker的架構,管理鏡像、運行容器、管理容器的一些相關命令說明;回顧請參考https://www.cnblogs.com/qiuhom-1874/p/12933412.html;今天這邊博客主要來聊docker的鏡像的制作和分發,以及相關鏡像的操作和說明;
前面我們提到過docker最核心資源之一就是鏡像,鏡像就好比是我們的應用程序,要想運行它,前提是要擁有它,並把它裝載操作系統上;而docker里的鏡像就是把應用程序所依賴的庫、文件、環境等打包在一起,組成一個靜態的鏡像文件;這樣一來有了這個鏡像,我們就可以把我們自己的應用程序在任何有docker環境的主機上運行成容器;這也是docker受歡迎的原因之一吧,解脫了程序員為其應用程序而苦惱;
docker鏡像包含了應用程序啟動所需的文件系統以及內容,其目的就是為創建並啟動為docker容器;那么docker的鏡像到底是怎么構建的呢?我們來看看下面的圖大概就會明白

提示:docker鏡像采用分層構建的機制,最低層為bootfs,該層的主要作用是用於系統引導的文件系統,包括bootloader和內核,容器啟動完成后會被卸載以節省內存資源;在bootfs之上的是rootfs,該層主要表現為docker容器的根文件系統;傳統模式中,系統啟動之時,內核掛載rootfs時會首先將其掛載為只讀模式,完成完整性自檢后在將其重新掛載為讀寫模式;而docker中,rootfs有內核掛載為只讀模式,而后通過聯合掛載技術額外掛載一個可寫成;如下圖所示

提示:位於下層的鏡像我們稱為父鏡像,最底層的鏡像稱其為基礎鏡像;最上層為可寫層,其下的所有層都是只讀層;從上面的圖我們也可以看到,只有鏡像運行成容器以后才會有可寫層的;也就是說可寫層屬於容器而不屬於鏡像;其實docker容器是共享下面鏡像層的,只有啟動為容器后,各自的可寫層相互隔離;
了解了docker的鏡像構建方式后,我們在看看多個鏡像怎么做到聯合掛載的?
聯合掛載的技術要源於AUFS這個文件系統,該文件系統的全稱是advanced multi-layered unification filesystem翻譯過來就是高級多層統一文件系統;該文件主要作用是為Linux文件系統實現“聯合掛載”;aufs的前身是unionfs,2006年由junjiro okajima開發;docker最初使用aufs作為容器文件系統層,它目前仍作為存儲后端之一,aufs的競爭產品是overlayfs,后者自從3.18版本開始被合並到Linux內核;docker的分層鏡像,除了aufs,docker還支持btrfs,devicemapper和vfs等,在ubuntu系統下,docker默認使用的aufs;而在早期centos7上用的是devicemapper;所以早期跑docker都跑在ubuntu上,原因之一是ubuntu的內核版本較新,能夠很好的兼容aufs文件系統;現在我們在centos7上運行docker默認使用的是overlayfs2文件系統;如下所示

提示:如果用運行docker建議backing filesystem 使用xfs文件系統,不要使用ext系列文件系統;
了解了docker的文件系統后,在來說一下docker的鏡像倉庫
docker啟動容器時,docker 服務端會試圖從本地獲取相關鏡像;本地鏡像不存在時,將會從docker默認的鏡像倉庫中下載指定鏡像並保持本地,然后再啟動為容器;大致過程如下圖所示

提示:從上圖可以了解到docker客戶端和服務端的一個工作流程,客戶端通過http協議向服務端發送指令,服務端首先從本地查找是否有對應版本的鏡像,如果有就啟動為容器,如果沒有就會去默認的registry中下載對應版本的鏡像到本地,然后在啟動為容器;對於docker服務端和registry來講他們都需要各自的存儲設備驅動來存儲鏡像;registry是用於保存docker鏡像,包括鏡像的層次機構和元數據;用戶可以自建registry,也可使用官方的docker hub;registry分類主要有Sponsor registry 第三方的registry,供客戶和docker社區使用;mirror registry 第三方的registry,只讓客戶使用;vendor registry 由發布docker鏡像的供應商提供的registry;private registry 通過設有防火牆和額外的安全層的私有實體提供的registry;
registry主要包含了倉庫和索引;所謂倉庫就是由特定的docker鏡像的所有迭代版本組成的鏡像倉庫;一個registry中可以存在多個repository,而對於repository來說可以分為頂層倉庫和用戶倉庫,頂層倉庫就是沒有斜線分割的倉庫,用戶倉庫是由用戶名加斜線分割再加倉庫名組成;每個倉庫可以包含多個tag標簽,每個標簽對應一個鏡像;所謂索引(index)主要用於維護用戶帳號、鏡像的校驗以及公共命名空間的信息,相對於為registry提供一個完整用戶認證等功能的檢索接口;所以我們把registry理解為存放docker鏡像倉庫的倉庫更為准確;docker registry中的鏡像通常由開發人員制作,而后推送至公共或私有的倉庫上保持,供其他人員使用;如下圖所示

了解了registry和repository的關系后,我們在來說說docker hub;docker hub 是docker的官方倉庫,它主要有如下幾種特性;
1、image repositories,提供鏡像倉庫的功能
2、autometed builds,提供自動編譯功能,什么意思呢?它支持我們向上傳一個構建docker鏡像的源碼文件,它可以根據這個源碼文件自動生成docker 鏡像;這個源碼文件叫dockerfile 主要用於編寫鏡像的構建過程的指令文件;
3、Webhooks,提供監控目標資源的變化實現根據目標監控對象上的資源變化而變化的一種機制;比如我們可以使用github和dockerhub聯合起來,開發人員通過git向github提交代碼(dockerfile),然后dockerhub就會一直盯着github上的資源,如果有變化,它就根據監控的資源變化而重新編譯成一個鏡像,類似這種功能;
4、organizations,支持創建組的方式對鏡像倉庫的訪問管理
5、github and bitbucket integration,支持將github和bitbucket添加到你當前的docker 鏡像工作流中;
了解了以上內容,我們在dockerhub上去注冊一帳號,就可以創建倉庫去存放我們自己制作好的鏡像了;注冊帳號這里我就不多說了,我們來說一下怎樣制作鏡像和怎么把鏡像推送到我們自己的倉庫中去;
基於現有鏡像制作鏡像
1、拖鏡像到本地
[root@node1 ~]# docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE centos 7 b5b4d78bc90c 2 weeks ago 203MB nginx stable-alpine ab94f84cc474 4 weeks ago 21.3MB [root@node1 ~]# docker image pull busybox:latest latest: Pulling from library/busybox d9cbbca60e5f: Pull complete Digest: sha256:836945da1f3afe2cfff376d379852bbb82e0237cb2925d53a13f53d6e8a8c48c Status: Downloaded newer image for busybox:latest docker.io/library/busybox:latest [root@node1 ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE busybox latest 78096d0a5478 9 days ago 1.22MB centos 7 b5b4d78bc90c 2 weeks ago 203MB nginx stable-alpine ab94f84cc474 4 weeks ago 21.3MB [root@node1 ~]#
2、運行busybox為容器

提示:busybox容器默認提供的是一個模擬Linux很多命令的一個程序,本身沒有跑任何進程;所以我們啟動容器必須得用交互式終端才行,否則容器啟動不起來;-it表示啟動為交互式終端;
3、創建httpd的網頁文件

提示:到此我們在容器內部的數據就准備好了。現在需要將我們修改后的數據保存下來制作成鏡像分發給其他人使用;
4、基於現有容器制造鏡像
[root@node1 ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE busybox latest 78096d0a5478 9 days ago 1.22MB centos 7 b5b4d78bc90c 2 weeks ago 203MB nginx stable-alpine ab94f84cc474 4 weeks ago 21.3MB [root@node1 ~]# docker container commit --help Usage: docker container commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]] Create a new image from a container's changes Options: -a, --author string Author (e.g., "John Hannibal Smith <hannibal@a-team.com>") -c, --change list Apply Dockerfile instruction to the created image -m, --message string Commit message -p, --pause Pause container during commit (default true) [root@node1 ~]# docker container commit -a "qiuhom <qiuhom@admin123.com>" -p -m "this is test image" -c 'CMD ["/bin/sh","-c","/bin/httpd -f -h /var/www/web/html"]' b1 linux1874/myimg:v0.1 sha256:e408b1c6e04f0e5f5129989f35e6f613dec17d963770c4be8d6daa54343c5399 [root@node1 ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE linux1874/myimg v0.1 e408b1c6e04f 5 seconds ago 1.22MB busybox latest 78096d0a5478 9 days ago 1.22MB centos 7 b5b4d78bc90c 2 weeks ago 203MB nginx stable-alpine ab94f84cc474 4 weeks ago 21.3MB [root@node1 ~]#
提示:-a表示指定作者信息,通常情況下作者信息是帶郵箱地址的;-p 表示制作鏡像時暫停容器,這樣做主要是為了數據統一,預防制作過程中的數據增加;-m表示注解信息;-c表示指定容器內部運行的命令;從上面的結果看,我們在本地就可以看到我們制作的鏡像;這里需要特別注意一點的時,在docker容器里運行的服務必須前台運行,如果后台運行會導致容器一啟動就退出了,原因是容器內部本身就只有一個進程在跑,如果你后台運行,就沒有進程在前台,所以docker會認為該容器已經宕機;其實我們可以理解為容器內部前台跑的程序是支撐整個容器為運行態的重要骨架;
5、登錄自己dockerhub帳號
[root@node1 ~]# 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: linux1874 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 Login Succeeded [root@node1 ~]#
6、推送鏡像到dockerhub中我們自己的倉庫中去
[root@node1 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
linux1874/myimg v0.1 e408b1c6e04f 7 minutes ago 1.22MB
busybox latest 78096d0a5478 9 days ago 1.22MB
centos 7 b5b4d78bc90c 2 weeks ago 203MB
nginx stable-alpine ab94f84cc474 4 weeks ago 21.3MB
[root@node1 ~]# docker image push --help
Usage: docker image push [OPTIONS] NAME[:TAG]
Push an image or a repository to a registry
Options:
--disable-content-trust Skip image signing (default true)
[root@node1 ~]# docker image push linux1874/myimg:v0.1
The push refers to repository [docker.io/linux1874/myimg]
4d567d38fed1: Pushed
1079c30efc82: Mounted from library/busybox
v0.1: digest: sha256:6c2f6b7a0df5ca0a46cd46d858e9fd564169471e6715c0155027ac77672508f6 size: 734
[root@node1 ~]#
提示:制作的鏡像打標簽時,需要打成同倉庫名一致的名稱;到此我們就把我們制作好的鏡像推送到我們的倉庫中去了
7、到dockerhub倉庫中查看是否存在我們剛才制作好的鏡像?

提示:可以看到我們有一個叫v0.1的鏡像;
8、另外開啟一主機,下載該鏡像,看看是否能夠啟動為容器,並提供httpd服務呢?
[root@docker_node1 ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE wordpress latest c3fa1c8546fb 3 weeks ago 540MB mysql 5.7 f965319e89de 3 weeks ago 448MB httpd 2.4.37-alpine dfd436f9a5d8 17 months ago 91.8MB [root@docker_node1 ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES [root@docker_node1 ~]# docker image pull linux1874/myimg:v0.1 Error response from daemon: pull access denied for linux1874/myimg, repository does not exist or may require 'docker login': denied: requested access to the resource is denied [root@docker_node1 ~]# 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: linux1874 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 Login Succeeded [root@docker_node1 ~]# docker image pull linux1874/myimg:v0.1 v0.1: Pulling from linux1874/myimg d9cbbca60e5f: Pull complete ab68b1a31f97: Pull complete Digest: sha256:6c2f6b7a0df5ca0a46cd46d858e9fd564169471e6715c0155027ac77672508f6 Status: Downloaded newer image for linux1874/myimg:v0.1 docker.io/linux1874/myimg:v0.1 [root@docker_node1 ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE linux1874/myimg v0.1 e408b1c6e04f 20 minutes ago 1.22MB wordpress latest c3fa1c8546fb 3 weeks ago 540MB mysql 5.7 f965319e89de 3 weeks ago 448MB httpd 2.4.37-alpine dfd436f9a5d8 17 months ago 91.8MB [root@docker_node1 ~]# docker run --name myweb1 -d linux1874/myimg:v0.1 5bd8e32089c0431399c9f81bbbdcf946817d3f8ab32ffc1caf072e73ed9ef5d9 [root@docker_node1 ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 5bd8e32089c0 linux1874/myimg:v0.1 "/bin/sh -c '/bin/ht…" 8 seconds ago Up 7 seconds myweb1 [root@docker_node1 ~]#
提示:因為我建立的是私有倉庫,所以只有登錄倉庫后才可以下載;如果是公有倉庫就不需要登錄;從上面的信息看,我們下載的鏡像已經下載到本地,並啟動為容器了;
9、在宿主機上訪問容器內部httpd服務,看看是否能夠響應我們提供的主頁?
[root@docker_node1 ~]# docker container inspect -f "{{.NetworkSettings.Networks.bridge.IPAddress}}" myweb1
172.17.0.2
[root@docker_node1 ~]# curl http://172.17.0.2
this test file
[root@docker_node1 ~]#
提示:可以看到是可以訪問到內部容器的httpd服務,響應給我們的主頁也是我們自己制作鏡像時提供的主頁文件;
到此基於現有容器制作鏡像、分發鏡像到倉庫的過程就測試完了;
