Docker之- 使用Docker 鏡像和倉庫

使用Docker 鏡像和倉庫

上一篇文章中,咱們學習了包括 docker run 在內的許多對容器進行操做的基本指令,那麼在本節中,咱們主要探討 Docker 鏡像的一些概念,好比什麼是鏡像,如何對鏡像進行管理,如何修改鏡像,如何建立、存儲、共享本身建立的鏡像等,那麼就開始咱們的學習nginx

什麼是 Docker 鏡像

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

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

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

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

用一幅圖來表示一下:apache

列出 Docker 鏡像

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

能夠看到,咱們已經獲取了一個鏡像列表。那麼,這些鏡像是從哪來的呢?咱們執行 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.十、 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 updateapt-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 方法來構建鏡像。相反,咱們推薦使用 Dockerfiledocker 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 "james@example.com"
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 "james@example.com"
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
  • 如何刪除鏡像

相關文章
相關標籤/搜索