Dockerfile使用介紹

一、Dockerfile概念
  Dockerfile是一個文本格式的配置文件,用戶可以使用Dockerfile來快速創建自定義的鏡像。我們使用Dockerfile定義鏡像,依賴鏡像來運行容器,因此Dockerfile是鏡像和容器的關鍵。首先通過一張圖來了解Docker鏡像、容器和Dockerfile三者之間的關係。
  在這裏插入圖片描述
  通過上圖我們可以看出使用Dockerfile來定義鏡像,運行鏡像然後啓動鏡像。
  Dockerfile鏡像是一個特殊的文件系統,除了提供容器運行時所需的程序、庫、資源、配置等文件外,還包括一些爲運行時準備的一些配置參數(如匿名卷、環境變量、用戶)。鏡像不包含任何動態數據,其內容在構建之後也不會被改變。
  鏡像的定製實際上就是定製每一層所添加的配置文件;如果我們可以把每一層的修改、安裝、構建、操作的命令都寫入一個腳本,用這個腳本來構建、定製鏡像,那麼之前提及的無法重複的問題、鏡像構建透明性的問題、體積的問題就都會解決了。這個腳本就是Dockerfile。
  Dockerfile是一個文本文件,其包含了一條條的指令,每一條指令構建一層,因此每一條指令的內容,就是描述該層應當如何構建。有了Dockerfile,當我們需要定製自己額外的需求時,只需要再Dockerfile上添加或者修改指令,重新生成image即可,省去了敲命令的麻煩。

二、Dockerfile的基本結構
Dockerfile由一行行命令語句組成,並支持以#開頭的註釋行。
Dockerfile文件格式如下:

1 ##  Dockerfile文件格式
2 # This dockerfile uses the ubuntu image
3 # VERSION 2 - EDITION 1
4 # Author: docker_user
5 # Command format: Instruction [arguments / command] ..
6 # 1、第一行必須指定 基礎鏡像信息
7 FROM ubuntu
8 # 2、維護者信息
9 MAINTAINER docker_user [email protected]
10 # 3、鏡像操作指令
11 RUN echo "deb http://archive.ubuntu.com/ubuntu/ raring main universe" >> /etc/apt/sources.list
12 RUN apt-get update && apt-get install -y nginx
13 RUN echo "\ndaemon off;" >> /etc/nginx/nginx.conf
14 
15 # 4、容器啓動執行指令
16 CMD /usr/sbin/nginx

Dockerfile分爲四部分:1.基礎鏡像信息、2.維護者信息、3.鏡像操作指令、4.容器啓動執行指令。一開始必須要指明所基於基礎鏡像的名稱,接下來一般會說明維護者信息;後面則是鏡像操作指令,例如RUN指令。每執行一條RUN指令,鏡像添加新的一層,並提交;最後是CMD指令,來指明運行容器時的操作指令。

三、構建鏡像
  docker build命令會根據Dockerfile文件以及上下文構建新的Docker鏡像。構建上下文是指Dockerfile所在的本地路徑或一個URL(Git倉庫地址)。構建上下文環境會被遞歸處理,所以構建所指定的路徑還包含了子目錄,而URL還包括了其中指定的子模塊。
  將當前目錄作爲構建上下文時,可以像下面這樣使用docker build命令構建鏡像:

1 docker build .
2 Sending build context to Docker daemon  6.51 MB
3 ...

說明:構建會在Docker後臺的守護進程(daemon)中執行,而不是CLI中。構建前,構建進程會將全部內容(遞歸)發送到守護進程。大多數情況下,應該將一個空目錄作爲構建Dockerfile上下文環境,並將Dockerfile文件放在該目錄下。
  在構建上下文中使用的Dockerfile文件,是一個構建指令的文件。爲了提高構建性能,可以通過.dockerignore文件排除上下文目錄下不需要的文件和目錄。
  在Docker構建鏡像的第一步,docker CLI會先在上下文目錄中尋找.dockerignore文件,根據.dockerignore文件排除上下文目錄中的部分文件和目錄,然後把剩下的文件和目錄傳遞給Docker服務。
  Dockerfile一般位於構建上下文的根目錄,也可以通過-f來指定該文件的位置:

1 docker build -f /path/to/a/Dockerfile .

構建時,還可以通過-t參數來對指定構建成的鏡像打標籤。

四、緩存
  Docker守護進程會一條一條的執行Dockerfile中的指令,而且會在每一步提交併生成一個新鏡像,最後會輸出最終鏡像的ID。生成完成後,Docker守護進程會自動清理你發送的上下文。Dockerfile文件中的每條指令會被獨立執行,並會創建一個新鏡像,RUN cd /tmp等命令不會對下條指令影響。Docker會重用已經生成的中間鏡像,以加速docker build的構建速度。以下是一個使用了緩存鏡像的執行過程:

1 $ docker build -t svendowideit/ambassador .
2 Sending build context to Docker daemon 15.36 kB
3 Step 1/4 : FROM alpine:3.2
4  ---> 31f630c65071
5 Step 2/4 : MAINTAINER [email protected]
6  ---> Using cache
7  ---> 2a1c91448f5f
8 Step 3/4 : RUN apk update &&      apk add socat &&        rm -r /var/cache/
9  ---> Using cache
10  ---> 21ed6e7fbb73
11  Step 4/4 : CMD env | grep _TCP= | (sed 's/.*_PORT_\([0-9]*\)_TCP=tcp:\/\/\(.*\):\(.*\)/socat -t 100000000 TCP4-
12  ---> Using cache
13  ---> 7ea8aef582cc
14 Successfully built 7ea8aef582cc

構建緩存僅會使用本地父生成鏈上的鏡像,如果不想使用本地緩存的鏡像,也可以通過–cache-from指定緩存。指定後將不再使用本地生成的鏡像鏈,而是從鏡像倉庫中下載。

Docker尋找緩存的邏輯其實就是樹形結構根據Dockerfile指令遍歷子節點的過程。下圖可以說明這個邏輯。

 FROM base_image:version           Dockerfile:
           +----------+                FROM base_image:version
           |base image|                RUN cmd1  --> use cache because we found base image
           +-----X----+                RUN cmd11 --> use cache because we found cmd1
                / \
               /   \
       RUN cmd1     RUN cmd2           Dockerfile:
       +------+     +------+           FROM base_image:version
       |image1|     |image2|           RUN cmd2  --> use cache because we found base image
       +---X--+     +------+           RUN cmd21 --> not use cache because there's no child node
          / \                                        running cmd21, so we build a new image here
         /   \
RUN cmd11     RUN cmd12
+-------+     +-------+
|image11|     |image12|
+-------+     +-------+

大部分指令可以根據上述邏輯去尋找緩存,除了ADD和COPY。這兩個指令會複製文件內容到鏡像內,除了指令相同以外,Docker還會檢查每個文件內容校驗(不包括最後修改時間和最後訪問時間),如果檢驗不一致,則不會使用緩存。
  除了這兩個命令,Docker並不會去檢查容器內的文件內容,比如RUN apt-get -y update,每次執行時文件可能都不一樣,但是Docker認爲命令一致,會繼續使用緩存。這樣一來,以後構建時都不會再重新運行apt-get -y update。
  如果Docker沒有找到當前指令的緩存,則會構建一個新的鏡像,並且之後所要的指令都不會再去尋找緩存。

五、利用Dockerfile構建鏡像的簡單示例
1)編輯Dockerfile文件
  接下來用一個簡單的示例來感受一下Dockerfile是如何用來構建鏡像啓動容器。我們以定製Nginx鏡像爲例子,在一個空白目錄中,建立一個文本文件,並命名爲Dockerfile:

1 mkdir mynginx
2 cd mynginx
3 vim Dockerfile

構建一個Dockerfile文件內容爲:

1 FROM nginx
2 #前提是使用yum安裝nginx,或者指定nginx中的index.html的位置
3 RUN echo '<h1>Hello,Docker!</h1>' > /usr/share/nginx/html/index.html

這個Dockerfile很簡單,一共就兩行涉及到了兩條指令:FROM和RUN。FROM表示獲取指定的基礎鏡像,RUN執行命令,在執行的過程中重寫了nginx的默認頁面信息,並將信息替換爲:Hello,Docker!。

2)構建鏡像
  在Dockerfile文件所在的目錄執行(或者通過-f選項來指定其路徑):

1 # 命令最後有一個.表示的當前目錄
2 docker build -t nginx:v1 . 

3)查看鏡像
  構建完成之後,使用docker image命令查看所有的鏡像,如果存在REPOSITORY爲nginx和TAG是v1的信息,就表示構建成功。

REPOSITORY                    TAG                 IMAGE ID            CREATED              SIZE
nginx                         v1                  c7ccff6ef09b        About a minute ago   126MB
nginx                         latest              ab56bba91343        2 days ago           126MB

4)運行鏡像
  接下來我們就可以使用docker run 命令來啓動容器

[root@docker mynginx]# docker run --name docker_nginx_v1 -d -p 80:80 nginx:v1 
4af7cb4e7f917aee15bc0bdddc6b2f1deae9dc46724145eb986b981ebb7816c4
[root@docker mynginx]# docker port docker_nginx_v1 
80/tcp -> 0.0.0.0:80
[root@docker mynginx]# 

這條命令會用nginx鏡像啓動一個容器,命名爲docker_nginx_v1,並且映射到了宿主機的80端口,這樣我們就可以用瀏覽器去訪問這個nginx服務器:xx.xx.xx.xx,頁面返回信息入下:
  在這裏插入圖片描述
  這樣一個簡單使用Dockerfile構建鏡像並運行容器的實例就完成了。

5)修改容器內容
  容器啓動後,如果需要對容器內的文件進行進一步的完善,我們可以使用docker exec -it xx /bin/bash命令進入容器實例內再次對容器的配置進行修改,以上面的示例爲基礎,修改nginx啓動的頁面內容:

[root@docker mynginx]# docker exec -it  docker_nginx_v1  /bin/bash
root@4af7cb4e7f91:/# echo "<h1>Hello,Docker JiangYiYang</h1>" > /usr/share/nginx/html/index.html 
root@4af7cb4e7f91:/# exit
exit

在這裏插入圖片描述
  以交互式終端的方式進入docker_nginx_v1容器,並執行了bash命令,也就是獲得了一個可操作的Shell。然後,我們用<h1>Hello,Docker JiangYiYang</h1>覆蓋了/usr/share/nginx/html/index.html的內容。再次刷新瀏覽器,會發現內容被改變。
  修改了容器的文件,也就是改動了容器的存儲層,可以通過docker diff命令看到具體的改動。

[root@docker mynginx]# docker diff docker_nginx_v1 
C /usr
C /usr/share
C /usr/share/nginx
C /usr/share/nginx/html
C /usr/share/nginx/html/index.html
C /run
A /run/nginx.pid
C /var
C /var/cache
C /var/cache/nginx
A /var/cache/nginx/client_temp
A /var/cache/nginx/fastcgi_temp
A /var/cache/nginx/proxy_temp
A /var/cache/nginx/scgi_temp
A /var/cache/nginx/uwsgi_temp
C /root
A /root/.bash_history

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