Docker容器技術(四)——Dockerfile詳解

1. 編寫一個簡單的Dockerfile

創建一個Dockerfile

創建Dockerfile儘量不要在根目錄,因爲默認在構建的時候會把當前目錄所有數據發送到docker引擎,如果在根目錄,會把跟目錄所有數據發送給docker引擎進行構建。

mkdir docker
cd docker/
echo hello > testfile
vim Dockerfile
FROM busybox
COPY testfile /

COPY參數要求要拷貝的文件必須在當前目錄,不能寫絕對路徑,只能是相對路徑。拷貝的目的地可以是目錄或文件
在這裏插入圖片描述

構建鏡像

docker build -t demo:v1 .

在這裏插入圖片描述

查看鏡像的分層結構

docker history demo:v1

在這裏插入圖片描述

通過Dockerfile來構建鏡像,可以清除的看到每一層都幹了什麼,有安全審計的功能。而通過docker commit 構建新鏡像的方式則無法知曉具體在鏡像內做了什麼操作,無法對鏡像進行審計,存在安全隱患。

鏡像的緩存特性

構建鏡像中有相同的鏡像層時,會使用緩存來加速構建。

vim Dockerfile
FROM busybox
COPY testfile /
RUN echo helloword > file1
docker build -t demo:v2 .
docker history demo:v1
docker history demo:v2

在這裏插入圖片描述

vim Dockerfile
FROM busybox
COPY testfile /
RUN echo helloword > file1
RUN echo haha > file2
docker build -t demo:v2 .
docker history demo:v1
docker history demo:v2

在這裏插入圖片描述

在這裏插入圖片描述

docker run -it --rm demo:v1
docker run -it --rm demo:v2
docker run -it --rm demo:v3

在這裏插入圖片描述
Dockerfile最佳實踐

在這裏插入圖片描述
通過Dockerfile構建鏡像,有很好的審計功能,比較安全,推薦使用,不推薦使用docker commit 來直接構建

2. Dockerfile詳解

2.1 dockerfile常用指令

  • FROM:指定base鏡像,如果本地不存在會從遠程倉庫下載。
  • MAINTAINER:設置鏡像的作者,比如用戶郵箱等。
  • COPY:把文件從build context複製到鏡像
    支持兩種形式:COPY src dest 和 COPY [“src”, “dest”]
    src必須指定build context中的文件或目錄
  • ADD:用法與COPY類似,不同的是src可以是歸檔壓縮文件,文件會被自動解壓到dest,也可以自動下載URL並拷貝到鏡像:
    ADD html.tar /var/www
    ADD http://ip/html.tar /var/www
  • ENV:設置環境變量,變量可以被後續的指令使用:
    ENV HOSTNAME server1.example.com
  • EXPOSE:如果容器中運行應用服務,可以把服務端口暴露出去:
    EXPOSE 80
  • VOLUME:申明數據卷,通常指定的是應用的數據掛載點:
    VOLUME ["/var/www/html"]
  • WORKDIR:爲RUN、CMD、ENTRYPOINT、ADD和COPY指令設置鏡像中的當前工作目錄,如果目錄不存在會自動創建。
  • RUN:在容器中運行命令並創建新的鏡像層,常用於安裝軟件包:
    RUN yum install -y vim
  • CMD 與 ENTRYPOINT
    這兩個指令都是用於設置容器啓動後執行的命令,但CMD會被docker run後面的命令行覆蓋,而ENTRYPOINT不會被忽略,一定會被執行。
    docker run後面的參數可以傳遞給ENTRYPOINT指令當作參數。
    Dockerfile中只能指定一個ENTRYPOINT,如果指定了很多,只有最後一個有效。

2.2 dockerfile使用案例

ADD自動解壓文件

ADD:用法與COPY類似,不同的是src可以是歸檔壓縮文件,文件會被自動解壓到dest,也可以自動下載URL並拷貝到鏡像:
ADD html.tar /var/www
ADD http://ip/html.tar /var/www

step1 放一個nginx的壓縮包在/root/docker下
在這裏插入圖片描述

step2 修改Dockerfile:

vim Dockerfile 
FROM busybox
ADD nginx-1.16.1.tar.gz /

在這裏插入圖片描述

step3 構建鏡像:

docker build -t demo:v4 .

在這裏插入圖片描述

ADD的用法與COPY類似,但不同的是它可以將文件自動解壓到dest

step4 測試:

docker run -it -rm demo:v4

在這裏插入圖片描述

ENV定義環境變量

ENV:設置環境變量,變量可以被後續的指令使用:
ENV HOSTNAME sevrer1.example.com

step1 修改Dockerfile:

vim Dockerfile 
FROM busybox
ENV hostname server1		#定義環境變量hostname爲server1
ADD nginx-1.16.1.tar.gz /	

在這裏插入圖片描述

step2 構建鏡像:

docker build -t demo:v5 .

在這裏插入圖片描述

step3 測試:

docker run -it --rm demo:v5

env查看到環境變量信息:

在這裏插入圖片描述

VOLUME聲明數據卷,在封裝應用容器時常用

VOLUME:申明數據卷,通常指定的是應用的數據掛載點:
VOLUME ["/var/www/html"]

step1 修改Dockerfile:

vim Dockerfile
FROM busybox
ENV hostname server1
ADD nginx-1.16.1.tar.gz /
VOLUME ["/data"]

在這裏插入圖片描述

step2 構建鏡像:

docker build -t demo:v6 .

在這裏插入圖片描述

step3 查看鏡像的創建歷史:

docker history demo:v6

在這裏插入圖片描述

step4 進入容器,創建文件:

docker run -it demo:v6

cd /data/
touch file1

按ctrl+p+q退出

在這裏插入圖片描述

step5 查看demov6的掛載信息:

docker ps						#找出對應的容器ID
docker inspect 5231e1ce76fe

在這裏插入圖片描述

在這裏插入圖片描述

docker引擎在啓動容器時發現定義了卷,會自動生成一個卷。而docker引擎在啓動容器時,自動在本地爲它創建了這個目錄,並且掛載在容器內,可以讓容器讀取到本地的數據目錄。

step6 進入目錄,查看到剛剛創建的文件file:

cd /var/lib/docker/volumes/ebe2016c773e0ae350be1f6dc9c6463bb71009bcb6a8b8355e58509c8741f2fe/_data
ls

在這裏插入圖片描述

step7 在此目錄下修改文件,容器中的文件同樣會被修改:

echo hello > file1
echo hello >> file1
echo hello >> file1
echo hello >> file1
echo hello >> file1
echo hello >> file1
cat file1
docker ps
docker attach 5231e1ce76fe

/data # ls
/data # cat file1 
/data # rm -f file1 
按ctrl+p+q退出

在這裏插入圖片描述

step8 釋放數據卷:

docker ps
docker rm -f 52			#刪除容器(此處使用容器ID的簡寫,因爲只有一個52開頭的ID)
docker volume ls		#顯示所有數據卷
docker volume prune		#釋放數據卷(刪除沒有被容器使用的卷)

在這裏插入圖片描述

在這裏插入圖片描述

WORKDIR設置鏡像中的當前工作目錄

WORKDIR:爲RUN、CMD、ENTRYPOINT、ADD和COPY指令設置鏡像中的當前工作目錄,如果目錄不存在會自動創建。

step1 修改Dockerfile:

vim Dockerfile
FROM busybox
ENV hostname server1
WORKDIR /nginx
ADD nginx-1.16.1.tar.gz /nginx
VOLUME ["/data"]

在這裏插入圖片描述

step2 構建鏡像:

docker build -t demo:v7 .

在這裏插入圖片描述

step3 測試:

docker run -it --rm demo:v7

在這裏插入圖片描述

我們可以發現,進入容器時就默認在/nginx這個目錄下,而將nginx的包解壓在了這個目錄中。
這個目錄之前並不存在,是WORKDIR自動創建的

CMD與ENTRYPOINT

這兩個指令都是用於設置容器啓動後執行的命令,但CMD會被docker run後面的命令行覆蓋,而ENTRYPOINT不會被忽略,一定會被執行。
docker run後面的參數可以傳遞給ENTRYPOINT指令當作參數。
Dockerfile中只能指定一個ENTRYPOINT,如果指定了很多,只有最後一個有效。

CMD:

step1 修改Dockerfile:

vim Dockerfile 
FROM busybox
ENV hostname server1
WORKDIR /nginx
ADD nginx-1.16.1.tar.gz /nginx
VOLUME ["/data"]
CMD echo helloword

在這裏插入圖片描述

step2 構建鏡像:

docker build -t demo:v8 .

在這裏插入圖片描述

step3 測試:

docker run -it --rm demo:v8
docker run -it --rm demo:v8 sh	#命令被覆蓋

在這裏插入圖片描述

ENTRYPOINT:

step1 修改Dockerfile:

vim Dockerfile 
FROM busybox
ENV hostname server1
WORKDIR /nginx
ADD nginx-1.16.1.tar.gz /nginx
VOLUME ["/data"]
ENTRYPOINT echo helloword

在這裏插入圖片描述

step2 構建鏡像:

docker build -t demo:v9 .

在這裏插入圖片描述

step3 測試:

docker run -it --rm demo:v9
docker run -it --rm demo:v9 sh	#命令沒有被覆蓋

在這裏插入圖片描述

2.3 shell和exec格式的區別

區別一

shell格式底層會調用/bin/sh -c來執行命令,可以解析變量,而exec格式不會

shell格式

step1 修改Dockerfile:

vim Dockerfile 
FROM busybox
ENV name redhat
ENTRYPOINT echo $hostname

在這裏插入圖片描述

step2 構建鏡像:

docker build -t demo:v10 .

在這裏插入圖片描述

step3 測試:

docker run -it --rm demo:v10

在這裏插入圖片描述

可以看到變量$hostname的值被輸出了

exec格式

step1 修改Dockerfile:

vim Dockerfile 
FROM busybox
ENV name redhat
ENTRYPOINT ["/bin/echo","$hostname"]

在這裏插入圖片描述

step2 構建鏡像:

docker build -t demo:v11 .

在這裏插入圖片描述

step3 測試:

docker run -it --rm demo:v11

在這裏插入圖片描述

可以看到變量$hostname沒有被解析,而是直接輸出了$hostname

所以exec格式需要改寫:

vim Dockerfile 

FROM busybox
ENV name redhat
ENTRYPOINT ["/bin/sh","-c","echo $hostname"]

在這裏插入圖片描述

再次測試,變量就被解析了

在這裏插入圖片描述

區別二

exec格式時,ENTRYPOINT可以通過CMD提供額外參數,CMD的額外參數可以在容器啓動時動態替換。在shell格式時,ENTRYPOINT會忽略任何CMD或者docker run提供的參數

exec格式

step1 修改Dockerfile:

vim Dockerfile 
FROM busybox
ENTRYPOINT ["/bin/echo","hello"]
CMD ["world"]

在這裏插入圖片描述

step2 構建鏡像:

docker build -t demo:v12 .

在這裏插入圖片描述

step3 測試:

docker run -it --rm demo:v12
docker run -it --rm demo:v12 linux		#輸出的world變爲linux
docker run -it --rm demo:v12 redhat		#輸出的world變爲redhat

在這裏插入圖片描述

shell格式

step1 修改Dockerfile:

vim Dockerfile 
FROM busybox
ENTRYPOINT echo hello
CMD echo world

在這裏插入圖片描述

step2 構建鏡像:

docker build -t demo:v13 .

在這裏插入圖片描述

step3 測試:

docker run -it --rm demo:v13
docker run -it --rm demo:v13 linux		#輸出的world變爲linux
docker run -it --rm demo:v13 redhat		#輸出的world變爲redhat

在這裏插入圖片描述
可以看到,在shell格式時,ENTRYPOINT會忽略任何CMD提供的參數

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