Docker之- 使用Docker 鏡像和倉庫

Docker之- 使用Docker 鏡像和倉庫
目錄

使用Docker 鏡像和倉庫
什麼是 Docker 鏡像
列出 Docker 鏡像
tag 標籤
Docker Hub
拉取鏡像
查找鏡像
構建鏡像
創建Docker Hub 賬號
使用 Docker 的commit 命令創建鏡像
使用 Dockerfile 構建鏡像
基於 Dockerfile 構建新鏡像
指令失敗時呢?
Dockerfile 和構建緩存
基於構建緩存的 Dockerfile 模版
查看新鏡像
從新鏡像啓動容器
Dockerfile 指令
將鏡像推送至 Docker Hub
刪除鏡像
總結
使用Docker 鏡像和倉庫
上一篇文章中,我們學習了包括 docker run 在內的許多對容器進行操作的基本指令,那麼在本節中,我們主要探討 Docker 鏡像的一些概念,比如什麼是鏡像,如何對鏡像進行管理,如何修改鏡像,如何創建、存儲、共享自己創建的鏡像等,那麼就開始我們的學習

什麼是 Docker 鏡像
Docker 鏡像是由文件系統疊加而成,最底端是一個引導文件系統,也就是bootfs,這很像典型的 Linux/Unix 的引導文件系統。Docker 用戶永遠不會和引導文件系統有什麼交互。實際上,一個容器啓動後,它就會被移入內容,而引導文件系統則會被卸載,從而留出更多的空間。(感覺有點像古代的餐館招待?負責引導顧客進入餐館,自己的工作就算是完成了)

傳統的Linux 引導過程中,root文件系統最先以只讀的方式加載,當引導結束後,會切換爲讀寫模式。但是在Docker 中,root文件系統永遠只是只讀狀態,並且使用聯合加載的技術一次同時加載多個文件系統。聯合加載會將各層系統文件疊加在一起,最終的文件系統包含底層的文件和目錄。

聯合加載:聯合加載指的是一次同時加載多個文件系統,但是外面看起來只有一個文件系統。

Docker 將這樣的文件系統成爲鏡像。一個鏡像可以放到另一個鏡像的頂部。位於下面的鏡像稱爲父鏡像,一次類推,知道鏡像棧的最底部,最底部的鏡像稱爲基礎鏡像。最後,當一個鏡像啓動容器時,Docker會在鏡像的最頂層加載一個文件系統。我們想在 Docker 中運行的程序就是在這個讀寫層中執行的。

用一幅圖來表示一下:

列出 Docker 鏡像
我們先從如何列出系統中的 Docker 鏡像來開始,可以使用 docker images 命令來實現,如下

可以看到,我們已經獲取了一個鏡像列表。那麼,這些鏡像是從哪來的呢?我們執行 docker run 命令時,同時進行了鏡像下載

鏡像從倉庫下載下來。鏡像保存在倉庫中,而倉庫存在於 Registry 中。默認的 Registry 是由 Docker 公司運行的公共 Registry 服務,即 Docker Hub。需要進行ID的註冊

Docker Registry 的代碼是開源的,你也可以擁有自己的Registry。

在 Docker Hub (或者是你自己運營的 Docker Registry)中,鏡像是保存在倉庫中的,可以將鏡像倉庫想象成類似於Git 倉庫的東西。它包括鏡像、層、以及包括鏡像的元數據。

倉庫可以包含很多鏡像,你可以使用docker pull來拉取倉庫中的鏡像,如下

Git 拉取代碼的指令是 git pull ,這樣就很相似了。

再來使用 docker images 看一下現在有哪些鏡像

因爲我的 Docker Hub 倉庫中只有一個 ubuntu 的鏡像,所以圖中標紅的這個鏡像是我們剛從 Docker Hub 上下載下來的。

tag 標籤
爲了區分同一個倉庫中的不同鏡像,Docker 爲我們提供了 tag 這個標籤,每個鏡像在列出來的時候都帶有一個標籤,如12.10、 12.04等,這種標籤機制使得一個倉庫中允許存儲多個鏡像。

我們可以在倉庫後面加一個冒號:標籤名 的方式來指定該倉庫中的某一個鏡像,例如 docker run -t -i --name new_container ubuntu:12.04 /bin/bash

Docker 會自動幫我們切換到 Ubuntu 的環境下,當然,這種方式創建了一個交互式任務。

在構建容器時指定倉庫的標籤也是一個好習慣,這樣便可以準確的指定容器來源於哪裏。

Docker Hub
Docker Hub 有兩種倉庫,一種是用戶倉庫,一種是頂層倉庫。用戶倉庫是由開發人員自己創建的,頂層倉庫是由Docker Hub 內部人員管理。

用戶倉庫的命名由兩部分構成,如 cxuan/ubuntu

用戶名 例如 : cxuan
倉庫名 例如 : ubuntu
相對的,頂層倉庫的命名就比較嚴謹,如 ubuntu 倉庫。頂層倉庫由 Docker 公司和選定的優質基礎鏡像廠商來管理,用戶可以基於這些鏡像構建自己的鏡像。

用戶鏡像都是由愛好者社區自己提供的,沒有經過 Docker 公司的認證,所以需要自己承擔相應的風險。

拉取鏡像
還記得docker run 的啓動過程嗎?再來一下這張圖回顧一下

其實也可以通過 docker pull 命令先預先拉取鏡像到本地,使用 docker pull 命令可以節省從一個新鏡像啓動一個容器所需要的時間。下面就來領取一下fedora基礎鏡像( fedora 是 Fedora 優質廠商提供的基礎鏡像 )

可以使用 docker images 查看新鏡像是否拉取到本地,不過我們這次只希望看到 fedora 的鏡像,那麼你可以使用這個命令: docker images fedora

可以看到我們已經把 fedora 鏡像拉取到了本地

查找鏡像
我們可以通過 docker search 命令來查找所有 Docker Hub 上公共可用的鏡像,如下

下面還有很多鏡像,我們主要看一下每條鏡像都返回了哪些內容

倉庫名稱
鏡像描述
用戶評價 --- 反應一個鏡像的受歡迎程度
是否官方 --- 是否由Docker 公司及其指定廠商開發的鏡像
是否自動構建 --- 表示這個鏡像是由 Docker Hub 自動構建的
從上面查詢的結果中選擇一個鏡像進行拉取,docker pull jamtur01/puppetmaster這條命令將會下載 jamtur01/puppetmaster鏡像到本地。

接下來就可以使用這個鏡像來構建一個容器,下面就用 docker run 命令構建一個容器。

...

查看版本號

構建鏡像
上面我們看到如何拉取並且構建好帶有定製內容的 Docker 鏡像,那麼我們如何修改自己的鏡像,並且管理和更新這些鏡像呢?

使用 docker commit 命令
使用 docker build 命令和 Dockerfile 文件
現在我們不推薦使用 docker commit 命令,相反應該使用更靈活更強大的 Dockerfile 來構建鏡像。不過,爲了對 Docker 又一個更深的瞭解,我們還是會先介紹一下 docker commit 構建鏡像。之後,我們重點介紹Docker 所推薦的構建方法:編寫 Dockerfile 之後使用 docker build 命令。

創建Docker Hub 賬號
構建鏡像中很重要的一環就是如何共享和發佈鏡像。可以將鏡像推送到 Docker Hub中或者自己的私有 Registry 中。爲了完成這項工作,需要在 Docker Hub上創建一個賬號

如果你還沒有Docker 通行證,在 hub.docker.com 註冊一個,記下你的用戶名,登錄本地計算機上的Docker公共註冊表。使用docker login,輸入用戶名和密碼進行登錄

你的個人信息會保存在 $HOME/.dockercfg 文件中

使用 Docker 的commit 命令創建鏡像
創建 Docker鏡像的第一種方式是使用 docker commit 命令。可以將此想象爲我們是在版本控制系統裏面提交變更,畢竟這和 git commit 命令真是太像了。

我們先從創建一個容器開始,這個容器基於我們前面見過的 ubuntu 鏡像。如下

接下來,我們在 ubuntu 中安裝 apache 服務器,使用apt-get -yqq update 和 apt-get -y install apache2 命令。

我們啓動了一個容器,並安裝了 Apache 服務器,我們會將這個服務器作爲 Web 服務器運行,所以我們想把它當前狀態保存起來。這樣下次啓動就不用重新安裝了。爲了完成這項工作,需要先使用 exit 從 ubuntu 中退出,之後再運行 docker commit 命令。如下

我們看到,在上圖所示的 docker commit 命令中,指定了要提交修改過的容器ID(可以通過 docker ps -l -q 命令得到剛剛創建的容器 ID),以及一個鏡像倉庫和鏡像名,這裏是 jamtur01/puppetmaster

可以使用 docker images jamtur01/puppetmaster 命令查看剛剛創建的鏡像。

可以在提交時指定更多的數據,就和 git 的命令是一樣的,使用 docker commit -m命令

這條命令中我們使用 -m(message) 指定提交信息,同時指定了 --authro 選項,列出鏡像作者信息。接着列出了想要提交的容器ID, 最後指定了 jamtur01/puppetmaster ,併爲其打上了 webserver 的tag 標籤。

可以使用 docker inspect 命令來查看新創建的鏡像的詳細信息。

使用 Dockerfile 構建鏡像
我們並不推薦使用 docker commit 方法來構建鏡像。相反,我們推薦使用 Dockerfile和 docker build的命令來構建鏡像。Dockerfile 使用基於 DSL 語法的指令來構建一個 Docker 鏡像,之後使用 docker build 命令基於 Dockerfile 中的指令構建一個新的鏡像。

我們的第一個 Dockerfile
下面我們創建一個目錄並初始化 Dockerfile,我們創建一個包含簡單web服務器的Docker鏡像

如上圖所示,我們在 /usr/local/docker 目錄下創建了一個 static_web 的目錄,再創建了一個 Dockerfile 文件。那麼這個 static_web 目錄就是我們的構建環境。Docker 稱此環境爲上下文(context)或者 構建上下文(build context),Docker 會在構建鏡像時將構建上下文和該上下文中的文件和目錄上傳到 Docker 守護進程。這樣 Docker 守護進程就可以直接訪問你鏡像中的 代碼、文件和數據。

下面是一個通過 Dockerfile 來構建 web 服務器的 Docker 鏡像

Version: 0.0.1

FROM ubuntu:14.04
MAINTAINER James Turnbull "[email protected]"
RUN apt-get update
RUN apt-get install -y nginx
RUN echo 'Hi, I am in your container' \

    >/usr/share/nginx/html/index.html

EXPOSE 80
該 Dockerfile 由一系列指令和參數組成。每條指令,如FROM,都必須爲大寫字母,而且後面要跟隨一個參數: FROM ubuntu:14.04。Dockerfile 中的指令會按照順序由上向下執行,所以編寫 Dockerfile 時,請注意它的順序。

如果不能使用 :wq 來進行保存的話,請首先使用 sudo su切換到管理員模式,然後就可以保存啦。

每條指令都會創建一個新的鏡像層並對鏡像進行提交。Docker 大體按照如下流程執行 Dockerfile 指令

Docker 從基礎鏡像運行一個容器
執行一條指令,對容器作出修改
執行類似docker commit 操作,提交一個新的鏡像層
Docker 再基於剛提交的鏡像運行一個新容器
執行 Dockerfile 中的下一條指令,直到所有指令都執行完畢
從上面可以看出,如果你的Dockerfile 由於某些原因(例如指令失敗了)沒有正常結束,那麼你將得到了一個可以使用的鏡像。這對調試很有幫助: 可以基於鏡像運行一個具備交互功能的容器,使用最後創建的鏡像對你最後失敗的指令做出調試

Dockerfile 也支持中文註釋,以 # 開頭的行都會被認爲是註釋。Dockerfile 中的第一行就是註釋的例子

每個 Dockerfile 的第一行指令都應該是 FROM。FROM指令指定一個已經存在的鏡像,後續指令都將基於該鏡像進行,這個鏡像被稱爲基礎鏡像(base image)。

在上面的示例中,我們使用了 ubuntu:14.04 作爲新鏡像基礎鏡像。基於這個 Dockerfile 構建的新鏡像以 Ubuntu 14.04 操作系統爲基礎。再運行一個容器時,必須要指明基於哪個基礎鏡像進行構建。

接着指定了 MAINTAINER 指令,這條指令會告訴 Docker 該鏡像的作者是誰,以及作者的電子郵件地址,這有助於標示鏡像的所有者以及聯繫方式。

在這些指令之後,我們指定了三條 RUN 指令。RUN指令會在當前的鏡像中運行指定的命令。在這個例子中,我們通過 RUN 指令更新了已經安裝的 APT 倉庫,安裝了 nginx 包,之後創建了 /usr/share/nginx/html/index.html 文件,該文件由一些簡單的示例文本。像前面說的那樣,每條RUN指令都會創建一個新的鏡像層,如果該命令執行成功,就會將此鏡像提交,繼續執行下一條指令。

默認情況下,RUN指令會在shell裏使用命令包裝器 /bin/sh -c 來執行。如果是在一個不支持 shell 的平臺上運行或者不希望在 shell 中運行,也可以使用 exec 格式的 RUN 指令

如下 : RUN["apt-get", "install", "-y", "nginx"]

在這種方式中,我們使用數組的方式來指定要運行的命令和要傳遞的參數。

接着設置了 EXPOSE 命令,這條執行告訴 Docker 容器內的應用程序將會使用容器的指定接口。這並不意味着可以自動訪問任意容器運行中的服務端口,可以指定多個 EXPOSE 指令向外公開多個端口。

基於 Dockerfile 構建新鏡像
執行 docker build 命令時,Dockerfile 中的所有指令都會被執行並且提交,並且在命令成功結束後返回一個新鏡像,下面就來看看如何構建一個新鏡像。

一定不要忘記最後面有個空格 和. ,也可以在構建鏡像的過程中爲鏡像設置一個標籤: 使用方法爲“鏡像名 : 標籤”,如下所示

指令失敗時呢?
之前大致介紹了一下指令失敗時的執行過程,下面來看一個例子: 假設我們在上面的 Dockerfile 中把 nginx 拼成了 ngnx ,再來構建一遍

我們可以看到,程序出錯了,這個時候我們希望去調試一下這次失敗。我們使用 docker run 命令來基於這次構建到目前爲止已經成功的最後一步創建一個容器,這裏它的ID 是 dee85a65a396,我們可以使用如下命令

docker run -t -i dee85a65a396 /bin/bash,來恢復到出錯之前的鏡像,然後重新運行出錯的指令apt-get install -y ngnx ,可以看到哪裏出錯了

但是感覺這個步驟是多餘了一些,如果 Dockerfile 中出現了錯誤,那麼 Docker 就會給你提示,用不着重新運行命令來找出問題原因。

Dockerfile 和構建緩存
由於每一步的結果都會作爲下一步的基礎鏡像,所以Docker 構建鏡像的過程非常聰明,它會將之前的鏡像層作爲緩存。

正如上面 Dockerfile 來舉例,比如,在我們調試過程中,不需要在第一步和第三步之間做任何修改,因此 Docker 會將之前構建時創建的鏡像當作緩存並作爲新的開始點。再次構建時,Docker 會直接從第四步開始。當之前的構建步驟沒有變化時,這會節省大量的時間。如果第一步到第三步之間有什麼變化,則回到第一步開始。

然而,有的時候不希望有緩存的功能,這個時候你需要使用 apt-get update,那麼 Docker 將不會刷新 APT 包的緩存,要想略過緩存,可以使用 docker build 的 --no-cache 標誌。

基於構建緩存的 Dockerfile 模版
構建緩存的一個好處就是,我們可以實現簡單的 Dockerfile 模版,一般會在 Dockerfile 文件頂部使用相同的指令集模版,比如對 ubuntu ,使用下面的模版

FROM ubuntu:14.04
MAINTAINER James Turnbull "[email protected]"
ENV REFRESHED_AT 2019-08-15
RUN apt-get -qq update
我們來分析一下這個新的 Dockerfile :

首先,通過 FROM 指令爲新鏡像設置了一個基礎鏡像 ubuntu:14.04。
接着,使用 MAINTAINER 指令添加了自己的詳細信息
然後,通過 ENV 指令設置了一個名爲 REFRESHED_AT 的環境變量,用來表示最後一次的更新時間
最後,使用 RUN 指令運行 apt-get -qq update 命令,該指令會刷新 APT 包的緩存,用來確保每個安裝的軟件包都在最新版本。
查看新鏡像
現在來看一下新構建的鏡像,使用 docker images 命令來完成

如果想要了解鏡像是如何構建出來的,可以使用 docker history 命令,如下

從結果可以看出鏡像構建的每一層都是哪些指令構成的

從新鏡像啓動容器
我們可以基於新構建的鏡像啓動新容器,來檢查我們的構建工作是否正常

在這裏,我們使用 docker run 命令,啓動一個 static_web 的容器, -d表示的是以分離(detached) 的方式在後臺運行。這種方式適合 nginx守護進程 這種需要長時間運行的進程。我們也指定了需要在 容器中運行的命令: nginx -g "daemon off;",將以前臺方式運行 nginx 作爲我們的服務器。

我們這裏也使用了一個新的 -p 標誌,用來控制 Docker 再運行時應該給外部開放哪些端口

Docker 可以在宿主機上隨機選擇 49153 --- 65535 之間的一個比較大的端口映射到 80 端口上
可以在 Docker 宿主機指定一個具體的端口來映射到 80 端口上
使用 docker ps查看一下端口分配情況

Docker 把 32769 端口映射到了 80 端口上

也可以通過 docker port查看端口的映射情況

Dockerfile 指令
Dockerfile 指令比較多,這裏我們會對 Dockerfile 單獨列一個章節進行說明

將鏡像推送至 Docker Hub
鏡像構建完畢之後,我們也可以將它上傳到 Docker Hub 上面去,這樣其他人就能使用這個鏡像了。

Docker Hub 的私有倉庫是需要收費的

我們可以使用 docker push 命令將鏡像推送至 Docker Hub。命令如下

爲什麼推送不上去?

網上搜索了一下,大概是鏡像標籤的問題,重新爲鏡像設置一個標籤

然後把這個標籤推送上去,相當於就是把鏡像推送上去

我們可以在 Docker Hub 上看到我們推送的鏡像了

刪除鏡像
如果不再需要一個鏡像了,也可以將它刪除,使用 docker rmi命令來刪除一個鏡像

該操作只能刪除本地鏡像,如果你已經推送至 Docker Hub 上,那麼你還需要在 Docker Hub 上將其刪除

登錄 Docker Hub ,直接點下面的鏈接刪除

docker rmi 刪除多個容器的方式直接在後面枚舉容器即可,中間用空格隔開

總結
本篇文章主要講述了 Docker 中的鏡像和倉庫的一些概念和基本用法,那麼你是否能回顧起來下面這些內容呢?

什麼是鏡像
如何列出Docker中的鏡像,tag標籤是幹什麼用的
如何拉取遠程倉庫中的鏡像
如何查找鏡像
對於鏡像構建,你能想到哪些內容
如何推送鏡像至 Docker Hub
如何刪除鏡像
原文地址https://www.cnblogs.com/cxuanBlog/p/11370739.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章