天天看點

6. Dockerfile詳解

一、Dockerfile 概念

Docker 鏡像是一個特殊的檔案系統,除了提供容器運作時所需的程式、庫、資源、配置等檔案外,還包含了一些為運作時準備的一些配置參數(如匿名卷、環境變量、使用者等)。鏡像不包含任何動态資料,其内容在建構之後也不會被改變。

鏡像的定制實際上就是定制每一層所添加的配置、檔案。如果我們可以把每一層修改、安裝、建構、操作的指令都寫入一個腳本,用這個腳本來建構、定制鏡像,那麼之前提及的無法重複的問題、鏡像建構透明性的問題、體積的問題就都會解決。這個腳本就是 Dockerfile。

Dockerfile 是一個文本檔案,其内包含了一條條的指令(Instruction),每一條指令建構一層,是以每一條指令的内容,就是描述該層應當如何建構。有了 Dockerfile,當我們需要定制自己額外的需求時,隻需在 Dockerfile 上添加或者修改指令,重新生成 image 即可,省去了敲指令的麻煩。

Dockfile最多不超過128層, 也就是一個docker最多128行

1.1. Dockerfile的體系結構

先來看一下我們最常用的centos的Dockerfile

在hub.docker.com中所有centos

FROM scratch
MAINTAINER The CentOS Project <[email protected]>
ADD c68-docker.tar.xz /
LABEL name="CentOS Base Image" \
    vendor="CentOS" \
    license="GPLv2" \
    build-date="2016-06-02"

# Default command
CMD ["/bin/bash"]      

含義:

FROM scratch
這裡引用了一個父鏡像. 我們通常在使用tomcat或者jdk的時候, 他的父類鏡像是centos. 而centos的父類鏡像是scratch, scratch是所有鏡像的基礎鏡像


MAINTAINER The CentOS Project <[email protected]>
MAINTAINER是備注的意思, 這是哪個團隊,哪個人寫的


ADD c68-docker.tar.xz /
這個參數後面講解

LABEL name="CentOS Base Image" \
    vendor="CentOS" \
    license="GPLv2" \
    build-date="2016-06-02"
LABEL顧名思義,就是描述的含義


# Default command
CMD ["/bin/bash"]
表示運作/bin/bash. 
我們通常在運作docker run -it lxl/centos的時候, 有時候加/bin/bash,有時候不加. 那麼什麼時候加, 什麼時候不加呢? 
其實加和不加都是可以的....因為這裡已經給我們自動加了/bin/bash, 如果不加就是用預設的, 如果加了, 就相當于有兩個/bin/bash, 他隻會執行一個      

 1.2. dockerfile的編寫規則

1. 每條保留字指令都必須為大寫字母且後面要跟随至少一個參數

2. 指令按照順序, 從上到下, 一條指令就是一層

3. #表示注釋

4. 每條指令都會建立一個新的鏡像層, 并對鏡像進行送出

1.3 docker執行dockerfile的流程

1. docker從基礎鏡像運作一個容器

2. 執行一條指令并對容器修改

3. 執行類似docker commit的操作送出一個新的鏡像層

4. docker在基于剛送出的鏡像運作一個新容器

5. 執行dockerfile中的下一條指令直到所指令都執行完成

1.4 dockerfile的保留字指令

  1. FROM: 

    基礎鏡像, 目前鏡像是基于哪一個鏡像      
  2. MAINTAINER:

    鏡像維護者的姓名, 郵箱位址      
  3. RUN:

    容器建構時需要運作的指令      
  4. EXPOSE:

    目前容器對外暴露的端口号      
  5. WORKDIR:

    指定在建立容器後, 終端預設登入進來的工作目錄, 一個落腳點
    沒有指定, 進入到容器的根目錄      
  6. ENV:

    用來在建構鏡像的過程中設定環境變量
    這個環境你變量可以在後續的任務Run指令中使用, 這就如同在指令前面指定了環境變量字首一樣, 也可以在其他指令中直接使用這些環境變量.
    
    舉個例子: 
    ENV MY_PATH /usr/home
    WORKDIR $MY_PATH
    
    這就是說, 進入到容器以後, 直接進入的工作目錄不是根目錄, 而是/usr/home      
  7. ADD & COPY

    ADD 和 COPY一起說
    他倆都有将主控端指定目錄下的檔案拷貝到到鏡像中的含義.
    ADD比COPY更強大. 
    ADD有拷貝并解壓的含義
    
    例如:
          
    ADD c68-docker.tar.xz /      
    這個含義就是, 拷貝到根目錄, 并進行解壓      
  8. VOLUME:

    容器資料卷, 用于資料儲存和持久化      
  9. CMD:

    指定一個容器啟動時需要運作的指令, 
    Dockerfile中可以有多個CMD指令, 但隻有最後一個生效, CMD會被docker run之後的參數替代      
  10. ENTRYPOINT:

    和CMD有相同之處
    指定一個容器啟動時要運作的指令
    
    ENTRYPOINT的目的和CMD一樣, 都是在綁定容器啟動程式及參數.
    不同之處是, ENTRYPOINT 不會被docker run後面的參數代替, 而是追加      
  11. ONBUILD:

    子鏡像繼承自父類鏡像以後, 父鏡像的onbuild就會被觸發, 
    這就相當于一個觸發器, 滿足一定條件的時候觸發      
6. Dockerfile詳解

 二. Dockerfile案例

2.1 Base鏡像

  Docker hub中99%的鏡像都是通過在base鏡像中安裝和配置需要的軟體建構出來的.

  最基礎的base鏡像是scratch, 這是所有鏡像的祖先

2.2 案例1

目标: 練習使用WORKDIR, FROM, EVN, RUN, CMD指令

以centos鏡像為例. 我們看

6. Dockerfile詳解

1. 目标: 下面我們要處理的就是以上兩個問題:

  1) 設定進入容器的目錄不是根目錄

  2) 為centos安裝vim和ifconfig指令

2. 編寫dockerfile

FROM scratch
MAINTAINER LXL<[email protected]
ENV MYPATH /usr/local
WORKDIR $MYPATH

RUN yum -y install vim
RUN yum -y install net-tools

EXPOSE 80

CMD echo "success"
CMD /bin/bash      

下面來詳細看看其含義

基礎鏡像
FROM scratch

指定鏡像維護的作者和郵箱
MAINTAINER LXL<[email protected]

設定環境變量mypath
ENV MYPATH /usr/local

設定進入容器的預設目錄是/usr/local
WORKDIR $MYPATH

安裝vim和net-tools工具
RUN yum -y install vim
RUN yum -y install net-tools

設定端口号是80
EXPOSE 80

運作指令,列印success
CMD echo "success"

運作指令, 進入/bin/bash
CMD /bin/bash      

3. 建構dockerfile, 生成鏡像

docker build -f Dockerfile2 -t mycentos:1.3 .      

4. 運作建構好的鏡像

docker run -it mycentos:1.3 /bin/bash      

5. 檢視dockerfile的建構曆史

docker history 鏡像ID      

這個指令可以查詢鏡像建構的各個層

6. Dockerfile詳解

2.3 案例2--CMD指令 和 EntryPoint的差別

1. CMD指令

CMD: dockerfile中可以有多個CMD指令,但是隻有最後一個生效. CMD會被docker run中最後的參數替換      

檢視tomcat的dockerfile. 

.....
最後幾行

RUN set -e \
    && nativeLines="$(catalina.sh configtest 2>&1)" \
    && nativeLines="$(echo "$nativeLines" | grep 'Apache Tomcat Native')" \
    && nativeLines="$(echo "$nativeLines" | sort -u)" \
    && if ! echo "$nativeLines" | grep -E 'INFO: Loaded( APR based)? Apache Tomcat Native library' >&2; then \
        echo >&2 "$nativeLines"; \
        exit 1; \
    fi

EXPOSE 8080
CMD ["catalina.sh", "run"]      

最後一行是啟動tomcat的指令. 是以, 我們運作tomcat鏡像的時候, 會啟動tomcat

6. Dockerfile詳解

下面, 我們在指令行中使用其他CMD指令. 按照規則, docker run中最後的參數将替換dockerfile中的參數

docker run -it -p 8080:8080 docker.io/tomcat ls -l      

運作結果:

6. Dockerfile詳解

 沒有啟動tomcat,而是進入了檢視目前目錄的檔案.

2. ENTRYPOINT指令

ENTRYPOINT: 執行命名, 和CMD類似, 不同的是, ENTRYPOINT指令不會被docker run中的指令替換, 而是被追加      

我們來看一個案例, curl http://ip.cn 是查詢目前網絡資訊

第一步: 編寫一個dockerfile

FROM docker.io/centos

MAINTAINER lxl < [email protected]

RUN yum install -y curl

CMD ["curl", "-s", "https://www.ip.cn"]      

第二步: 建構dockerfile

docker build -f Dockerfile3 -t myip .       
6. Dockerfile詳解

第三步: 運作容器

docker run -it myip      

運作結果

您現在的 IP:**.**.**
所在地理位置:北京市 聯通
GeoIP: Beijing, China      

第四步: 我們還想檢視header. 于是追加一個參數-i即可

如果使用CMD就會以docker run中的指令替換dockerfile, 這時我們應該使用ENTRYPOINT.

FROM docker.io/centos

MAINTAINER lxl < [email protected]

RUN yum install -y curl

ENTRYPOINT ["curl", "-s", "https://www.ip.cn"]      

重新build, 然後在docker run啟動的時候增加 -i指令

docker run -it myip2 -i      

1. 建立檔案, 建立一個DockerFile

檔案名叫Dockerfile. 固定叫法

檔案内容如下

From ubuntu
MAINTAINER lxl
CMD echo 'hello docker'      

2. 建構Dockerfile

docker build -t demo-docker .      

domo-docker: 是生成的新的docker鏡像的名字. 

. 表示的是檔案生成在目前目錄

建構的時候, 首先會判斷基礎鏡像是否存在, 如果不存在, 則下載下傳

6. Dockerfile詳解

3. 檢視建構好的鏡像

docker image demo-docker      
6. Dockerfile詳解

 我們看到生産了一個64.2M的鏡像. 版本定義了一個最新版本

4. 運作鏡像

docker run demo-docker      
6. Dockerfile詳解

 運作鏡像, 列印輸出hello docker

以上我們就自己定義了一個dockerfile,并運作起來了.

2.4 案例3--ONBUILD指令 

第一步: 建構一個父類鏡像

FROM docker.io/centos
MAINTAINER LXL<[email protected]

CMD ["/bin/bash"]

增加了觸發器
ONBUILD RUN echo "onbuild starting ...... 886"      

第二步: 編譯父類鏡像

docker build -f dockerfile4 -t centos03 .      
6. Dockerfile詳解

第三步: 建構一個子類鏡像

這引用的父類鏡像是centos03
FROM centos03
MAINTAINER LXL<[email protected]

CMD ["/bin/bash"]      

第四步: 編譯子類鏡像

docker build -f dockerfile5 -t child-centos04 .      
6. Dockerfile詳解

 2.5 案例4

練習COPY ADD指令

 按照如下操作執行

1. 建立一個/docker/tomcat9檔案夾, 裡面放三個檔案

touch c.txt

apache-tomcat-9.0.8.tar.gz

jdk.tar.gz

其中後兩個檔案是tomcat和jdk的壓縮包, 我們提前下載下傳好,放到檔案夾裡即可. 如下圖所示:

6. Dockerfile詳解
下載下傳tomcat
sudo curl -OL https://mirror.bit.edu.cn/apache/tomcat/tomcat-9/v9.0.35/bin/apache-tomcat-9.0.35.tar.gz


下載下傳jdk
sudo curl -OL https://www.oracle.com/webapps/redirect/signon?nexturl=https://download.oracle.com/otn/java/jdk/8u251-b08/3d5a2bb8f8d4428bbe94aed7ec7ae784/jdk-8u251-linux-x64.tar.gz      

2. 在/docker/tomcat9檔案夾下建立一個dockerfile檔案

FROM docker.io/centos

# 設定dockerfile的作者和郵箱
MAINTAINER lxl < [email protected]

# 拷貝檔案到指定目錄并解壓

ADD apache-tomcat-9.0.35.tar.gz /usr/local
ADD jdk-8u251-linux-x64.tar.gz /usr/local

# 定義環境變量
ENV WORKPATH /usr/local

# 設定工作目錄
WORKDIR $WORKPATH


# 設定jdk和tomcat的環境變量
ENV JAVA_HOME /usr/local/jdk1.8.0_251
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.35
ENV CATALINA_BASE /usr/local/apache-tomcat-9.0.35

ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_BASE/bin

# 設定端口号
EXPOSE 8080

# 啟動并運作tomcat
CMD $WORKPATH/apache-tomcat-9.0.35/bin/startup.sh && tail -F $WORKPATH/apache-tomcat-9.0.35/logs/catalina.out

      

3. 建構dockerfile

6. Dockerfile詳解

4. docker run 運作鏡像

docker run -it tomcat9      

5. 驗證tomcat啟動結果

在本地輸入localhost:8080. 看到tomcat啟動頁       
6. Dockerfile詳解