Docker新手入門之四:Docker鏡像和倉庫的基本使用

2021-01-13 念師

在之前的文章中,我們已經講解了什麼是Docker,以及如何運行Docker容器。

接下來,我們將要繼續講解Docker鏡像的相關概念與操作。

Docker鏡像是啟動容器的基石。

本文中將會講解如何管理、修改鏡像以及鏡像存儲倉庫Registry的相關知識。

什麼是Docker鏡像

Docker鏡像是由文件系統疊加而成。最底端是一個文件引導系統,即bootfs。Docker用戶不會與引導文件系統有直接的交互。Docker鏡像的第二層是root文件系統rootfs,通常是一種或多種作業系統,例如ubuntu等。在Docker中,文件系統永遠都是只讀的,在每次修改時,都是進行拷貝疊加從而形成最終的文件系統。Docker稱這樣的文件為鏡像。一個鏡像可以迭代在另一個鏡像的頂部。位於下方的鏡像稱之為父鏡像,最底層的鏡像稱之為基礎鏡像。最後,當從一個鏡像啟動容器時,Docker會在最頂層加載一個讀寫文件系統作為容器。

Docker的這種機制我們稱之為寫時複製。

查看鏡像列表

接下來,我們將詳細了解一下關於鏡像相關的一些操作。首先是查詢鏡像列表:

sudo docker images

該命令可以用於查找當前系統中所有存在的鏡像列表。Ps:本地鏡像默認保存在Docker宿主機的/var/lib/docker目錄下。所有的鏡像都是保存在倉庫中,而倉庫位於Registry中。默認的Registry是Docker公司運營的Docker Hub。每個鏡像倉庫都可以存放很多的鏡像。例如ubuntu鏡像倉庫存放著各種不同版本的Ubuntu鏡像。使用如下命令可以拉取鏡像:

sudo docker pull ubuntu

上述命令會拉取所有版本的ubuntu鏡像到本地。為了區分同一個倉庫中不同的鏡像,Docker提供了一種tag的功能。我們可以給每個版本的鏡像添加一個唯一的tag來標識該鏡像。此時,鏡像的名稱如下:倉庫名稱:tag。我們在運行鏡像或拉取鏡像時,可以直接指定對應的標籤。例如:

sudo docker run -it ubuntu:16.04 /bin/bash

默認情況下,在run中如果沒有指定鏡像的tag,將會默認去尋找latest標籤的鏡像。除了倉庫名稱和tag以外,我們還可以將鏡像分為兩個類別:一種是Docker用戶自己創建的用戶倉庫,還有一種是Docker官方維護的頂層倉庫。用於倉庫的完整名稱是由用戶名稱/倉庫名稱組成的。而對於頂層倉庫而言,則沒有用戶名稱,直接是倉庫名稱。總結一下,對於一個倉庫而言,完成的格式如下:[用戶名稱/]倉庫名稱:tag。

拉取鏡像

在使用docker run從一個鏡像啟動容器時,Docker首先會現在本地查找是否存在該鏡像。如果在本地沒有找到該鏡像,則會先從Dockers Hub上下載該鏡像後在運行。Ps:如之前所說,如果沒有指定tag,則默認使用latest標籤。

查找鏡像

我們如果想要從Docker Hub查找有哪些公共的可用鏡像時,可以使用如下命令:

sudo docker search keywords

構建鏡像

在上面的內容中,我們已經了解了如下查詢,拉取,運行鏡像,那麼接下來我們將會繼續學習如何修改、更新和管理自己的鏡像。構建鏡像的方式有以下兩種:

使用docker commit構建使用docker build和Dockerfile文件來構建

相比較而言,我們更加推薦使用方法2來構建。因為方法2更加的靈活和強大。Ps:我們通常並不是從零開始構建一個鏡像,而是從一個base鏡像開始修改構建的。在接下來的內容中,我們首先將會簡單的講解一下如何通過docker commit來修改鏡像。但更多的精力將會用於詳細講解如何利用dockerfile來構建鏡像。

創建docker hub帳號

在構建鏡像中,很重要的一環就是共享和發布鏡像。通常,我們都會將鏡像推送到Docker Hub來共享鏡像。我們需要進入Docker Hub首先註冊一個帳號:https://hub.docker.com/註冊完成後,我們可以通過命令行在本地綁定對應的Docker Hub帳號。

sudo docker login# Username: ***# Password:# Email: ***# Login Succeed

使用docker commit命令來創建鏡像

創建Docker鏡像的第一種方法就是通過commit命令。流程簡介如下:

根據某個鏡像創建一個容器對該容器進行一些修改提交該容器並生成一個新的鏡像。

示例:

sudo docker run -it ubuntu /bin/bashroot@b3f9427a5039:/# apt-get -yqq updateroot@b3f9427a5039:/# apt-get -y install apache2root@b3f9427a5039:/# exit

可以看到,在這個過程中,我們首先根據ubuntu鏡像創建了一個容器,容器id為b3f9427a5039。接下來,我們對這個容器進行了一些修改,例如安裝了Apache。安裝完成後,我們退出了該容器。下面,我們將會使用commit命令來創建一個新的鏡像。

sudo docker commit b3f9427a5039 wangzhe0912/apache2

上面的命令表示將我們剛才的容器創建為一個wangzhe0912用戶下的apache鏡像。接下來,我們可以使用docker images來查看是否有該新增的鏡像。

ps:在commit命令中,我們可以添加更多的參數來對鏡像進行描述:

-m=」message」 可以用於對提交的鏡像添加一些文本描述–author=」person」 可以用於添加提交人信息提交時,我們可以設置tag。

示例:

sudo docker commit -m="install apache" --author="wangzhe0912" b3f9427a5039 wangzhe0912/apache2:v1

接下來,我們可以使用

docker inspect 鏡像名

命令來查看鏡像的一些詳細信息:

docker inspect wangzhe0912/apache2:v1

下面,我們也可以直接根據我們新建的鏡像來創建一個容器:

sudo docker run -it wangzhe0912/apache2:v1 /bin/bash

使用dockerfile來構建鏡像

在上面的內容中,我們簡單的講解了如何通過commit來創建新的鏡像。

下面,我們將會繼續將講解如何使用Dockerfile來創建鏡像,這是一種更加強大和靈活的方式。首先,我們需要創建一個工作目錄,並在目錄中創建一個Dockerfile文件。

mkdir workdircd ./workdirtouch Dockerfile

這個目錄我們通常稱之為構建環境,Docker會在構建鏡像時將構建上下文和該文件上下文的文件和目錄傳遞給Docker守護進程。我們編輯Dockerfile如下:

# Version: 0.0.1FROM ubuntu:14.04MAINTAINER Wangzhe0912 "Wangzhe0912@tju.edu.cn"RUN apt-get updateRUN apt-get install -y nginxRUN echo "Hi, I am your contrainer" > /usr/share/nginx/html/index.htmlEXPOSE 80

下面,我們來詳細剖析一下這段代碼的含義:

每個Dockerfile的第一行指令都應該是FROM開頭。FROM用於制定一個已經存在的鏡像,後續指令都是基於該鏡像來運行。這個鏡像我們稱之為基礎鏡像。MAINTAINER後說明該作者和作者郵箱信息。接下來是三條RUN指令。默認情況下,指令後的內容會通過/bin/sh -c來執行。最後設置了EXPOSE,該指令用於指定容器內的應用程式會使用哪些埠(可以指定多個)。PS:出於安全考慮,默認Docker不會自動打開這些埠,需要在docker run指令中指定需要打開的埠。

那麼這段代碼在運行過程中的機制是什麼樣子的呢?

首先從基礎鏡像ubuntu:14.04中啟動一個容器執行一條run指令執行類似commit指令,提交一個新的鏡像層。基於步驟3提交的鏡像運行一個新的容器。返回步驟2,繼續執行下一條運行指令,直至沒有運行指令。

Ps:這樣的優點的如果在Dockerfile中,存在某個步驟執行失敗,我們將會得到上一步中生成的鏡像,利用該鏡像,我們可以進行單步調試。

基於dockerfile構建新鏡像

當我們寫完Dockerfile文件後,可以通過執行docker build命令來執行Dockerfile中的所有指令並生成一個新的鏡像。

示例如下:

docker build -t="wangzhe0912/nginx:v1"` .

其中,-t="wangzhe0912/nginx:v1"指定了新生成鏡像的鏡像名稱。 .表示的是在當前目錄下尋找Dockerfile文件。

除了在本地尋找Dockerfile文件之外,我們還可以直接指定git倉庫來尋找Dockerfile文件。

docker build -t="wangzhe0912/nginx:v1"` git@github.com:wangzhe0912/docker_web

Ps:如果在構建目錄中存在.dockerignore命令的文件時,那麼該文件內容將會被按行分割,按行匹配過濾,類似於.gitignore文件。

Dockerfile和構建緩存

Docker在構建過程中,會從在一定的緩存機制。例如我們修改了Dockerfile的第五行後重新進行構建,那麼構建過程中前四行將不會進行重複執行,而是直接從緩存中進行讀取。如果我們希望強制忽略緩存時,可以額外添加--no-cache參數進行設置。

sudo docker build --no-cache -t="wangzhe0912/nginx:v1" .

基於構建緩存的Dockerfile模版

為了合理利用緩存機制,而又不需要手工添加命令強制清除緩存,那麼可以借鑑如下模板:

FROM ubuntu:14.04MAINTAINER Wangzhe0912 "Wangzhe0912@tju.edu.cn"ENV REFRESHED_AT 2018-01-28RUN apt-get update...

觀察一下該模板,我們在其中添加了一行ENV。 ENV的作用是設置環境變量。而在此時,我們的目的是用於刷新構建和緩存,當ENV的值發生變化時,將會忽略後續的緩存,重新執行。而噹噹ENV的值沒有發生變化時,則可以充分利用緩存的機制快速構建。

查看新鏡像

當構建完成後,我們就完成了一個新鏡像的構建。我們可以使用如下命令來查看該鏡像的完整構建過程:

docker history image_name/id

從新鏡像啟動容器

下面,我們將使用剛才構建的鏡像來詳細了解一下nginx鏡像該如何運行和使用。下面我們以如下命令進行講解:

docker run -d -p 80 --name wangzhe_nginx wangzhe0912/nginx:v1 nginx -g "daemon off;"

其中:

-d表示以後臺程序進行運行-p 80用於指定在運行時公開80埠給宿主機。默認情況下,宿主機會在隨機選擇一個埠號映射到容器的80埠上。當然,我們也可以指定用宿主機的某個埠(例如8080)來映射到容器的80埠,使用方式如下:-p 8080:80。當然,還有一種更加簡單的方式,之前我們在Dockerfile文件中指定了EXPOSE對應埠,我們可以直接使用-P來打開在Dockerfile文件中指定的埠。--name wangzhe_nginx指定容器的名稱nginx -g "daemon off;"表示了容器需要執行的命令。

運行完成後,我們需要查看一下我們的容器映射到了宿主機的哪個埠中。可以執行如下命令docker ps來查看:

可以看到,宿主機的32768埠指向了容器的80埠。還有一種更加簡單的埠映射查詢方式如下:

docker port wangzhe_nginx 80# 0.0.0.0:32768

即指定容器名稱和容器埠,可以直接查詢映射的埠地址。下面,我們來訪問一下該地址,看下我們的nginx服務是否已經正常啟動。

curl localhost:32768# Hi, I am your contrainer

Dockerfile指令

在之前的學習中,我們已經學習到了一部分Dockerfile指令,例如FROM, ENV, RUN, EXPOSE等,在本節中,我們將會詳細學習相關的一系列指令。

1.CMDCMD是一個容器啟動時要運行的命令。例如,我們之前啟動一個容器時的代碼類似如下:

docker run -it wangzhe0912/nginx /bin/bash

其中,/bin/bash表示的是啟動容器時需要執行的命令。

可以等效如下:

CMD ["/bin/bash"]

此外,我們還可以給運行命令參數相關參數,例如:

CMD ["/bin/bash", "-l"]

PS:在啟動容器時,可以通過docker run命令來覆蓋CMD指令。還有在Dockerfile中只能指定一條CMD指令,如果指定多條,最後一條CMD指令將會生效。

2.ENTRYPOINTENTRYPOINT與CMD十分類似,相比較而言ENTRYPOINT更不容易被覆蓋。簡單的說,我們通常會設置可執行文件在ENTRYPOINT中,而在CMD中設置需要傳入的參數。因為通常而言,默認運行的可執行文件通常不會發生變化,但是參數變化則相對可能會頻繁一些。示例如下:

ENTRYPOINT ["/usr/sbin/nginx"]CMD ["-h"]

Ps:如果有需要,可以在docker run時,使用--entrypoint="***"

來強制覆蓋ENTRYPOINT。

3.WORKDIRWORKDIR用於在容器內設置工作目錄,ENTRYPOINT和CMD命令會在指定的目錄下執行。示例:

WORKDIR /opt/webappRUN bundle installWORKDIR /opt/webapp/dbENTRYPOINT ["rackup"]

Ps:-w可以在運行時覆蓋工作目錄。

例如:

docker run -it -w /var/log ubuntu pwd

4.ENV在鏡像構建過程中設置環境變量。新設置的環境變量可以在後續任何的RUN指令中使用。

示例:

ENV RVM_PATH /home/rvm/RUN gem install unicorn

PS:在運行時可以使用-e來傳遞環境變量,示例:

docker run -it -e "WEB_PORT=8080" pwd

5.USERUSER指令用於設定該鏡像會以什麼用戶去執行。默認會以root用戶執行。可以在運行命令中使用-u進行覆蓋。

示例:

docker run -it -u "nginx" pwd

6.VOLUMNVOLUMN用戶指定向基於鏡像創建的容器添加卷。卷是指可以存在於一個或者多個容器內的特定目錄,這個目錄可以繞過聯合文件系統來共享數據或者數據持久化。以下是一些卷的特點:

卷可以在容器中共享和重用。對卷的修改是實時生效。對卷的修改不會影響鏡像。卷會一直存在到沒有容器使用他。

卷功能可以將數據、代碼、資料庫等信息添加到鏡像而不是把這些內容提交到鏡像。使用示例:

VOLUMN ["/opt/project", "/data"]

7.ADDADD指令用於將構建環境下的文件和目錄複製到鏡像中。常用的場景例如安裝一個應用程式。ADD指令需要源文件和目的文件位置兩個參數。示例代碼:

ADD software.lic /opt/applicaion/software.lic

Ps:ADD命令本身來有一些相對需要注意的點:ADD命令可以自動將一些壓縮文件進行自動解壓:

ADD latest.tar.gz /var/www/wordpress/

此外,如果目的文件夾不存在的話,Docker會自動幫助我們創建完整的路徑。新創建的文件和目錄的權限都是0755。還有一點是ADD指令會使之前的緩存全部失效。

8.COPYCOPY指令與ADD指令相類似,不過COPY只關注與複製文件,而不會做文件的提取和解壓。

9.ONBUILDONBUILD指令可以為鏡像添加觸發器。當一個鏡像被其他鏡像用作基礎鏡像時,該鏡像的觸發器會執行。觸發器可以是任何構建指令,通常是緊跟在FROM後面的。

ONBUILD ADD . /app/srcONBUILD RUN cd /app/src && make

將鏡像推送至Docker Hub

當我們完成鏡像的構建後,可以將其上傳到Docker Hub中。我們可以使用docker push命令來推送Docker鏡像。

sudo docker push wangzhe0912/nginx

推送完成後,我們可以在我們的Docker Hub中看到我們上傳的鏡像。

自動構建

除了我們通過命令行構建後推送鏡像之外,Docker Hub本身來支持自動構建。自動構建只需要我們將Github中含有Dockerfile文件的倉庫連接到Docker Hub即可。每次推送代碼後,會自動觸發構建一個新的鏡像。

刪除鏡像

當我們不再需要某一個鏡像時,我們可以刪除該鏡像。刪除鏡像的方式如下:

sudo docker rmi 鏡像名稱

執行該命令後,我們只是會刪除本地的鏡像,在Docker Hub中的鏡像則不會自動刪除。

搭建自己的Dockers Registry

利用Docker容器安裝一個Registry十分簡單,只需要運行對應的容器即可。

docker run -d -p 5000:5000 registry

此時,我們已經啟動了一個本地的registry。下面,我們需要使用本地的registry為我們想要推送的鏡像打好標籤。

docker tag 鏡像id 127.0.0.1:5000/wangzhe0912/nginx

然後直接直接docker push命令來推送即可。

docker push 127.0.0.1:5000/wangzhe0912/nginx

相關焦點

  • 使用 Docker 鏡像 | Docker 系列
    使用 docker inspect 命令來獲取鏡像的詳細信息。使用 docker history 命令列出鏡像各層的創建信息。搜索鏡像使用 docker search 命令來搜索鏡像。使用 docker rmi 命令來刪除鏡像,分兩種方式:一種是通過鏡像名和標籤來刪除;一種是通過鏡像 ID 來刪除。
  • Docker新手入門之三:Docker容器的基本使用
    在之前的文章中,我們已經講解了Docker的基本概念以及如何在各個平臺下進行Docker的安裝。在接下來,我們將繼續講解Docker容器的基本使用。查看Docker服務是否正常執行如下命令後,我們可以看到Docker的一些基本信息,包括容器、鏡像的數量,執行與存儲驅動以及Docker的基本配置等。
  • docker 鏡像的使用
    docker images我的本地主機中只有ubuntu和busybox 2個鏡像,ubuntu鏡像是我自己下載的,busybox鏡像是docker自動下載的。鏡像列表的各個選項說明:REPOSITORY:表示鏡像的倉庫源TAG:鏡像的標籤IMAGE ID:鏡像IDCREATED:鏡像創建時間SIZE:鏡像大小同一個倉庫源可以有多個TAG,代表不同的版本,我們可以使用倉庫源:鏡像標籤的方式表示不同的鏡像。
  • docker系列學習之入門使用
    docker快速入門(基於centos)設置docker倉庫yum-utils 提供了 yum-config-manager ,並且 device mapper 存儲驅動程序需要 device-mapper-persistent-data
  • 使用Docker鏡像
    公共註冊伺服器的倉庫),用戶也可以通過配置來使用自定義的鏡像倉庫,筆者在前面就自定義了鏡像倉庫。既然鏡像這麼重要,那麼本篇就圍繞鏡像這一核心概念來具體介紹相關操作:(1)如何使用pull命令從Docker Hub倉庫中下載鏡像到本地;(2)如何查看本地已有的鏡像信息和管理鏡像標籤;(3)如何在遠端倉庫中使用search命令進行搜索和過濾;(4)如何刪除鏡像標籤和鏡像文件;(5)如何創建用戶定製的鏡像並且保存為外部文件;(6)如何往Docker Hub倉庫中推送自己的鏡像。
  • 使用Docker 鏡像|Docker 系列
    其實,我們常看到的鏡像是長這樣的 name:tag,因為從 Docker 官方倉庫拉下來的鏡像,是可以省略前兩部分的。獲取鏡像使用 docker pull name[:tag] 命令來下載鏡像,如果不顯式指定 tag,則默認會選擇 latest 標籤。
  • Docker篇-Docker快速入門
    美圖鎮樓讓我們一起進行下docker的安裝和使用1、安裝docker2、docker安裝redis3、docker基本概念和常用命令如果有老版本的docker可以先卸載:sudo yum remove docker-ce
  • docker系列——使用maven構建docker鏡像並上傳鏡到像倉庫
    摘要上幾遍都說到了docker的相關指令和使用Dockerfile構建鏡像,但有些時候我們在本地開發,想要使用maven>一鍵式構建鏡像或者直接使用maven將鏡像推送到我們的指定倉庫,那麼這裡就需要使用maven的docker插件了。
  • Docker 私有鏡像倉庫的搭建及認證
    DockerHub 為我們提供了很多官方鏡像和個人上傳的鏡像,我們可以下載機構或個人提供的鏡像,也可以上傳我們自己的本地鏡像,但缺點是:由於網絡的原因,從 DockerHub 下載和上傳鏡像速度可能會比較慢;在生產上使用的 Docker 鏡像可能包含我們的代碼
  • 蹲坑學Docker之十五:使用Harbor搭建Docker私有倉庫
    Docker官方提供的私有倉庫registry,用起來雖然簡單,但在管理的功能上存在不足。Harbor是一個用於存儲和分發Docker鏡像的企業級Registry伺服器,Harbor使用的是官方的docker registry v2服務去完成。
  • Docker實戰007:docker倉庫使用詳解
    我們也可以在 https://hub.docker.com/ 註冊一個 Docker 帳號免費使用docker倉庫,通過docker push命令來將自己的鏡像推送到 Docker Hub(操作跟git相似,很容易上手)。
  • Docker實戰005:docker鏡像使用詳解
    Docker鏡像是docker的核心成員,類似於虛擬機鏡像的文件系統(一個鏡像往往由多層文件系統組成,相當於一個精簡的作業系統同時還包含應用運行所必須的文件和依賴包。),用來提供容器運行時所需的程序、庫、資源、配置等資源。Docker鏡像是基於Dockerfile文件構建的,Dockerfile文件內包含了一條條構建鏡像所需的指令和說明。
  • Docker系列教程01-使用Docker鏡像
    前言學習Docker,我們需要掌握它的三大核心概念:鏡像、容器和倉庫。今天先帶大家學習Docker鏡像相關的基礎知識。如果只要其中一項內容時,可使用-f指定,例如,獲取鏡像的創建時間:3)使用history命令查看鏡像歷史docker pull 下載鏡像時也我們發現了鏡像文件由多個層組成,可以使用history子命令列出各層的創建信息。
  • 雲計算核心技術Docker教程: Docker鏡像使用
    當運行容器時,使用的鏡像如果在本地中不存在,docker 就會自動從 docker 鏡像倉庫中下載,默認是從 Docker Hub 公共鏡像源下載。我們可以使用 docker images 來列出本地主機上的鏡像。
  • 雲計算核心技術Docker教程:Docker鏡像使用
    來源:TechWeb.com.cn當運行容器時,使用的鏡像如果在本地中不存在,docker 就會自動從 docker 鏡像倉庫中下載,默認是從 Docker Hub 公共鏡像源下載。我們可以使用 docker images 來列出本地主機上的鏡像。
  • Docker 鏡像構建之 docker commit
    我們可以通過公共倉庫拉取鏡像使用,但是,有些時候公共倉庫拉取的鏡像並不符合我們的需求。儘管已經從繁瑣的部署工作中解放出來,但是實際開發時,我們可能希望鏡像包含整個項目的完整環境,在其他機器上拉取打包完整的鏡像,直接運行即可。
  • 一起學習docker04-docker鏡像
    Docker 運行容器前需要本地存在對應的鏡像,如果鏡像不存在本地,Docker 會從鏡像倉庫下載(默認是Docker Hub 公共註冊伺服器中的倉庫)。一般公司內部會搭建私有倉庫,公司自己的鏡像會放到私有倉庫裡。
  • docker新手常見問題以及解決辦法
    主流平臺docker的安裝與基本設置Windows10MACLinux目前主要的三個作業系統,在docker官網,win10和Mac都提供了文件,直接下載即可。Linux文件的話,推薦直接使用安裝腳本。
  • docker如何搭建個人鏡像倉庫
    簡介很多時候我們不想把我們docker鏡像直接暴露出來,那麼我們就不能直接上傳docker-hub上。所以對於個人或者企業,有一個自己的鏡像倉庫,也是很重要的。本文主要利用harbor這個插件,來搭建個人倉庫安裝OS:Centos7docker:191、安裝docker-compose(前提你的系統安裝好python
  • 雲計算核心技術Docker教程:使用registry搭建私有鏡像倉庫
    來源:TechWeb.com.cn在之前的教程中我們使用docker拉取的鏡像都是docker hub上的使用的是公共倉庫,當我們在企業項目中開發時不可能把鏡像放到公共倉庫進行管理,所以為了更好的管理鏡像,我們需要搭建私有鏡像倉庫,今天我們介紹使用Docker官方提供的鏡像registry