一、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的保留字指令
-
FROM:
基礎鏡像, 目前鏡像是基于哪一個鏡像
-
MAINTAINER:
鏡像維護者的姓名, 郵箱位址
-
RUN:
容器建構時需要運作的指令
-
EXPOSE:
目前容器對外暴露的端口号
-
WORKDIR:
指定在建立容器後, 終端預設登入進來的工作目錄, 一個落腳點 沒有指定, 進入到容器的根目錄
-
ENV:
用來在建構鏡像的過程中設定環境變量 這個環境你變量可以在後續的任務Run指令中使用, 這就如同在指令前面指定了環境變量字首一樣, 也可以在其他指令中直接使用這些環境變量. 舉個例子: ENV MY_PATH /usr/home WORKDIR $MY_PATH 這就是說, 進入到容器以後, 直接進入的工作目錄不是根目錄, 而是/usr/home
-
ADD & COPY
ADD 和 COPY一起說 他倆都有将主控端指定目錄下的檔案拷貝到到鏡像中的含義. ADD比COPY更強大. ADD有拷貝并解壓的含義 例如:
ADD c68-docker.tar.xz /
這個含義就是, 拷貝到根目錄, 并進行解壓
-
VOLUME:
容器資料卷, 用于資料儲存和持久化
-
CMD:
指定一個容器啟動時需要運作的指令, Dockerfile中可以有多個CMD指令, 但隻有最後一個生效, CMD會被docker run之後的參數替代
-
ENTRYPOINT:
和CMD有相同之處 指定一個容器啟動時要運作的指令 ENTRYPOINT的目的和CMD一樣, 都是在綁定容器啟動程式及參數. 不同之處是, ENTRYPOINT 不會被docker run後面的參數代替, 而是追加
-
ONBUILD:
子鏡像繼承自父類鏡像以後, 父鏡像的onbuild就會被觸發, 這就相當于一個觸發器, 滿足一定條件的時候觸發
二. Dockerfile案例
2.1 Base鏡像
Docker hub中99%的鏡像都是通過在base鏡像中安裝和配置需要的軟體建構出來的.
最基礎的base鏡像是scratch, 這是所有鏡像的祖先
2.2 案例1
目标: 練習使用WORKDIR, FROM, EVN, RUN, CMD指令
以centos鏡像為例. 我們看
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
這個指令可以查詢鏡像建構的各個層
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
下面, 我們在指令行中使用其他CMD指令. 按照規則, docker run中最後的參數将替換dockerfile中的參數
docker run -it -p 8080:8080 docker.io/tomcat ls -l
運作結果:
沒有啟動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 .
第三步: 運作容器
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鏡像的名字.
. 表示的是檔案生成在目前目錄
建構的時候, 首先會判斷基礎鏡像是否存在, 如果不存在, 則下載下傳
3. 檢視建構好的鏡像
docker image demo-docker
我們看到生産了一個64.2M的鏡像. 版本定義了一個最新版本
4. 運作鏡像
docker run demo-docker
運作鏡像, 列印輸出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 .
第三步: 建構一個子類鏡像
這引用的父類鏡像是centos03
FROM centos03
MAINTAINER LXL<[email protected]
CMD ["/bin/bash"]
第四步: 編譯子類鏡像
docker build -f dockerfile5 -t child-centos04 .
2.5 案例4
練習COPY ADD指令
按照如下操作執行
1. 建立一個/docker/tomcat9檔案夾, 裡面放三個檔案
touch c.txt
apache-tomcat-9.0.8.tar.gz
jdk.tar.gz
其中後兩個檔案是tomcat和jdk的壓縮包, 我們提前下載下傳好,放到檔案夾裡即可. 如下圖所示:
下載下傳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
4. docker run 運作鏡像
docker run -it tomcat9
5. 驗證tomcat啟動結果
在本地輸入localhost:8080. 看到tomcat啟動頁