Docker——理解好映象和容器的關係

Java極客技術發表於2019-08-06

關注公眾號,大家可以在公眾號後臺回覆“部落格園”,免費獲得作者 Java 知識體系/面試必看資料。 

映象也是 docker 的核心元件之一,映象時容器執行的基礎,容器是映象執行後的形態。前面我們介紹了容器的用法,今天來和大家聊聊映象的問題。

​本文是本系列的第四篇,閱讀前面文章有助於更好的理解本文:


1.Docker 入門及安裝[Docker 系列-1]

2.Docker 容器基本操作[Docker 系列-2]

3.Docker 容器高階操作[Docker 系列-3]


總體來說,映象是一個包含程式執行必要以來環境和程式碼的只讀檔案,它採用分層的檔案系統,將每一層的改變以讀寫層的形式增加到原來的只讀檔案上。這有點像洋蔥,一層一層的,當我們後面學習了 Dockerfile ,相信大家對於這樣的架構理解將更為準確。

映象與容器的關係

前文已經向讀者介紹過容器的使用了,細心的讀者可能已經發現,容器在啟動或者建立時,必須指定一個映象的名稱或者 id ,其實,這時映象所扮演的角色就是容器的模版,不同的映象可以構造出不同的容器,同一個映象,我們也可以通過配置不同引數來構造出不通的容器。如下命令:

  1. docker run -itd --name nginx nginx

命令中的最後一個 nginx 即表示建立該容器所需要的映象(模版),當然這裡還省略了一些資訊,例如版本號等,這些我們後文會詳細介紹。

映象的體系結構

映象的最底層是一個啟動檔案系統(bootfs)映象,bootfs 的上層映象叫做根映象,一般來說,根映象是一個作業系統,例如 Ubuntu、CentOS 等,使用者的映象必須構建於根映象之上,在根映象之上,使用者可以構建出各種各樣的其他映象。
從上面的介紹讀者可以看出,映象的本質其實就是一系列檔案的集合,一層套一層的結構有點類似於 Git ,也有點類似於生活中的洋蔥

映象的寫時複製機制

通過 docker run 命令指定一個容器建立映象時,實際上是在該映象之上建立一個空的可讀寫的檔案系統層級,可以將這個檔案系統層級當成一個臨時的映象來對待,而命令中所指的模版映象則可以稱之為父映象。父映象的內容都是以只讀的方式掛載進來的,容器會讀取共享父映象的內容,使用者所做的所有修改都是在檔案系統中,不會對父映象造成任何影響。當然使用者可以通過其他一些手段使修改持久化到父映象中,這個我們後面會詳細介紹到。

簡而言之,映象就是一個固定的不會變化的模版檔案,容器是根據這個模版建立出來的,容器會在模版的基礎上做一些修改,這些修改本身並不會影響到模版,我們還可以根據模版(映象)建立出來更多的容器。

如果有必要,我們是可以修改模版(映象)的。

映象檢視

使用者可以通過 docker images 命令檢視本地所有映象,如下:

這裡一共有五個引數,含義分別如下:

  • TAG: TAG用於區分同一倉庫中的不同映象,預設為latest。

  • IMAGE ID: IMAGE ID是映象的一個唯一識別符號。

  • CREATED: CREATED表示映象的建立時間。

  • SIZE: SIZE表示映象的大小。

  • REPOSITORY:倉庫名稱,倉庫一般用來存放同一型別的映象。倉庫的名稱由其建立者指定。如果沒有指定則為 <none> 。一般來說,倉庫名稱有如下幾種不同的形式:

  1. [namespace\ubuntu]:這種倉庫名稱由名稱空間和實際的倉庫名組成,中間通過 \ 隔開。當開發者在 Docker Hub 上建立一個使用者時,使用者名稱就是預設的名稱空間,這個命令空間是用來區分 Docker Hub 上註冊的不同使用者或者組織(類似於 GitHub 上使用者名稱的作用),如果讀者想將自己的映象上傳到 Docker Hub 上供別人使用,則必須指定名稱空間,否則上傳會失敗。

  2. [ubuntu]:這種只有倉庫名,對於這種沒有名稱空間的倉庫名,可以認為其屬於頂級名稱空間,該空間的倉庫只用於官方的映象,由 Docker 官方進行管理,但一般會授權給第三方進行開發維護。當然使用者自己建立的映象也可以使用這種命名方式,但是將無法上傳到 Docker Hub 上共享。

  3. [hub.c.163.com/library/nginx]:這種指定 url 路徑的方式,一般用於非 Docker Hub 上的映象命名,例如一個第三方服務商提供的映象或者開發者自己搭建的映象中心,都可以使用這種命名方式命名。

使用 docker images 命令可以檢視本地所有的映象,如果映象過多,可以通過萬用字元進行匹配,如下:

如果需要檢視映象的詳細資訊,也可以通過上文提到的 docker inspect 命令來檢視。

映象下載

當使用者執行 docker run 命令時,就會自動去 Docker Hub 上下載相關的映象,這個就不再重複演示,開發者也可以通過 search 命令去 Docker Hub 上搜尋符合要求的映象,如下:

其中:

  • NAME:表示映象的名稱。

  • DESCRIPTION:表示映象的簡要描述。

  • STARS:表示使用者對映象的評分,評分越高越可以放心使用。

  • OFFICIAL:是否為官方映象。

  • AUTOMATED:是否使用了自動構建。

在執行 docker run 命令時再去下載,速度會有點慢,如果希望該命令能夠快速執行,可以在執行之前,先利用 docker pull 命令將映象先下載下來,然後再執行。

執行命令如下:

映象刪除

映象可以通過 docker rmi 命令進行刪除,引數為映象的id或者映象名,引數可以有多個,多個引數之間用空格隔開。如下:

有的時候,無法刪除一個映象,大部分原因是因為該映象被一個容器所依賴,此時需要先刪除容器,然後就可以刪除映象了,刪除容器的命令可以參考本系列前面的文章。

通過前面文章的閱讀,讀者已經瞭解到所謂的容器實際上是在父映象的基礎上建立了一個可讀寫的檔案層級,所有的修改操作都在這個檔案層級上進行,而父映象並未受影響,如果讀者需要根據這種修改建立一個新的本地映象,有兩種不同的方式,先來看第一種方式:commit。

建立容器

首先,根據本地映象執行一個容器,如下:

 

命令解釋:

  1. 首先執行 docker images 命令,檢視本地映象。

  2. 根據本地映象中的 nginx 映象,建立一個名為 nginx 的容器,並啟動。

  3. 將宿主機中一個名為 index.html 的檔案拷貝到容器中。

  4. 訪問容器,發現改變已經生效。

  5. 接下來再重新建立一個容器,名為 nginx2.

  6. 訪問 nginx2 ,發現 nginx2 中預設的頁面還是 nginx 的預設頁面,並未發生改變。

commint 建立本地映象

接下來,根據剛剛建立的第一個容器,建立一個本地映象,如下:

 

命令解釋:

  1. 引數 -m 是對建立的該映象的一個簡單描述。

  2. --author 表示該映象的作者。

  3. ce1fe32739402 表示建立映象所依據的容器的 id。

  4. sang/nginx 則表示倉庫名,sang 是名稱空間,nginx 是映象名。

  5. v1 表示倉庫的 tag。

  6. 建立完成後,通過 docker images 命令就可以檢視到剛剛建立的映象。

  7. 通過剛剛建立的映象執行一個容器,訪問該容器,發現 nginx 預設的首頁已經發生改變。

這是我們通過 commint 方式建立本地映象的方式,但是 commit 方式存在一些問題,比如不夠透明化,無法重複,體積較大,為了解決這些問題,可以考慮使用 Dockerfile ,實際上,主流方案也是 Dockerfile。

Dockerfile

Dockerfile 就是一個普通的文字檔案,其內包含了一條條的指令,每一條指令都會構建一層。先來看一個簡單的例子。

 

首先在一個空白目錄下建立一個名為 Dockerfile 的檔案,內容如下:

命令解釋:

  1. FROM nginx 表示該映象的構建,以已有的 nginx 映象為基礎,在該映象的基礎上構建。

  2. MAINTAINER 指令用來宣告建立映象的作者資訊以及郵箱資訊,這個命令不是必須的。

  3. RUN 指令用來修改映象,算是使用比較頻繁的一個指令了,該指令可以用來安裝程式、安裝庫以及配置應用程式等,一個 RUN 指令執行會在當前映象的基礎上建立一個新的映象層,接下來的指令將在這個新的映象層上執行,RUN 語句有兩種不同的形式:shell 格式和 exec 格式。本案例採用的 shell 格式,shell 格式就像 linux 命令一樣,exec 格式則是一個 JSON 陣列,將命令放到陣列中即可。在使用 RUN 命令時,適當的時候可以將多個 RUN 命令合併成一個,這樣可以避免在建立映象時建立過多的層。

  4. COPY 語句則是將映象上下文中的 hello.html 檔案拷貝到映象中。

 

檔案建立完成後,執行如下命令進行構建:

命令解釋:

  1. -t 引數用來指定映象的名稱空間,倉庫名以及 TAG 等資訊。

  2. 最後面的 . 是指映象構建上下文。

注意

Docker 採用了 C/S 架構,分為 Docker 客戶端(Docker 可執行程式)與 Docker 守護程式,Docker 客戶端通過命令列和 API 的形式與 Docker 守護程式進行通訊,Docker 守護程式則提供 Docker 服務。因此,我們操作的各種 docker 命令實際上都是由 docker 客戶端傳送到 docker 守護程式上去執行。我們在構建一個映象時,不可避免的需要將一些本地檔案拷貝到映象中,例如上文提到的 COPY 命令,使用者在構建映象時,需要指定構建映象的上下文路徑(即前文的 . ), docker build 在獲得這個路徑之後,會將路徑下的所有內容打包,然後上傳給 Docker 引擎。

 

映象構建成功後,可以通過 docker images 命令檢視,如下:

然後建立容器並啟動,就可以看到之前的內容都生效了。

總結

本文主要向大家介紹了 Docker 中映象的基本操作,操作其實並不難,關鍵是理解好映象和容器的關係,以及映象洋蔥式的檔案結構。

Java 極客技術公眾號,是由一群熱愛 Java 開發的技術人組建成立,專注分享原創、高質量的 Java 文章。如果您覺得我們的文章還不錯,請幫忙讚賞、在看、轉發支援,鼓勵我們分享出更好的文章。

 

相關文章