Docker從入門到精通(五)——Dockerfile

YSOcean發表於2021-12-16

Dockerfile 簡單來說就是一個包含用於組合映象的命令的文字文件,Docker 通過讀取 Dockerfile 中的指令就可以按步驟生成映象,那麼在製作映象之前,我們先了解一下映象的原理。

1、映象原理

只有瞭解映象的原理,我們才能更清晰的通過 Dockerfile 製作映象。

前面幾篇文章我們簡單介紹了docker中的映象,映象是隻讀的檔案,提供了執行程式完整的軟硬體資源,是應用程式的“集裝箱”,包含執行某個軟體所需的所有內容,包括程式碼、執行時環境、所需庫、環境變數、配置檔案等等。

那麼映象是如何做到這些的呢?

1.1 UnionFS(聯合檔案系統)

聯合檔案系統(Union File System):2004 年由紐約州立大學開發,它可以把多個目錄內容聯合掛載到同一個目錄下,而目錄的物理位置是分開的。UnionFS可以把只讀和可讀寫檔案系統合併在一起,具有寫時複製功能,允許只讀檔案系統的修改可以儲存到可寫檔案系統當中。

UnionFS(Union File System) 一次性載入多個檔案系統,但是從外表看起來,只能看到一個檔案系統,聯合載入會把各層檔案系統疊加起來,這樣最終的檔案系統會包含所有底層的檔案和目錄。

1.2 Docker 映象載入原理

Docker 的映象實際上就是由一層一層的檔案系統組成,這裡給出 Docker 官方的一張圖:

圖片描述

Bootfs(boot file system):主要包含 bootloader 和 kernel,bootloader 主要是引導載入 kernel,比如 Linux 剛啟動時會載入 bootfs 檔案系統,在 Docker 映象的最底層就是 bootfs。這一層與我們典型的 Linux/Unix 系統是一樣的,包含 boot 載入器和核心。當 boot 載入完成之後整個核心就都在記憶體中了,此時記憶體的使用權已由 bootfs 轉交給核心,此時系統也會解除安裝 bootfs。

Rootfs(root file system):在 bootfs 之上,中間只讀的 rootfs 的集合稱為 Docker 映象,Docker 映象構建時,會一層層構建,前一層是後一層的基礎。每一層構建完就不會再發生改變,後一層上的任何改變只發生在自己這一層。UnionFS 使得映象的複用、定製變得更為容易。甚至可以用之前構建好的映象作為基礎層,然後進一步新增新的層,以定製自己所需的內容,構建新的映象。

Container(容器):容器 = 映象 + 讀寫層,從檔案系統上看,Docker容器比Docker映象多一層可讀寫的檔案系統掛載層。藉助於 UnionFS,容器內部的更改都被儲存到了最上面的讀寫層,而其他層都是隻讀的,這樣中間的只讀 rootfs 是可以被多個容器複用的。UnionFS 將檔案的更新掛載到老的檔案之上,而不去修改那些不更新的內容,這就意味著即使虛擬的檔案系統被反覆修改,也能保證宿主機空間佔用保持一個較低水平。

在 rootfs 的基礎上,Docker 公司創新性地提出了使用 UnionFS,多個增量 rootfs 聯合掛載一個完整 rootfs 的方案,通過“分層映象”的設計,圍繞 Docker 映象,大家甚至可以協同工作,再加上 Docker 官方提供的映象倉庫,進一步減少了共享映象的成本,這大大提高了開發部署的效率。

這樣你也能理解為什麼 docker 啟動塊,佔用資源少了吧。

1.3 實操理解分層概念

這裡我們下載一個 Tomcat9.0 映象:

image-20211031120617204

我們也可以通過上一篇文章講解的命令檢視映象層結構:

docker inspect 映象id

image-20211031121152140

2、Dockerfile 的 helloworld

例項:建立一個能訪問 Tomcat 首頁的容器

2.1 手動建立

通常我們啟動一個Tomcat容器,官方映象是簡化版的,在webapps 目錄下沒有任何內容,所有我們啟動之後訪問主頁也是沒有任何內容。

docker run -d -p 8080:8080 tomcat

但是官方映象的 webapps.dist 目錄下有首頁檔案,所以我們將 webapps.dist 目錄下的所有檔案複製到 webapps ,然後訪問首頁就有介面了。

1、進入啟動的容器

docker exec -it 容器id /bin/bash

2、將webapps.dist 目錄所有檔案複製到 webapps 目錄下

cp -r webapps.dist/* webapps/

image-20211031135744274

再次訪問首頁:

2.2 Dockerfile 建立

PS: 不同命令沒關係,後面會解釋每條命令含義。

①、提前準備好 webapps 目錄檔案

我這裡直接將官方Tomcat容器中的 webapps.dist 目錄拷貝到本機的/home/webapps 目錄下:

docker cp 容器ID:/usr/local/tomcat/webapps.dist /home/webapps

②、準備 dockerfile 檔案

在本機 /home 目錄下新建一個 Dockerfile 檔案(可以任意命名,沒有字尾),內容如下:

FROM tomcat:latest
MAINTAINER itcoke
WORKDIR /usr/local/tomcat/webapps
COPY ./webapps/ /usr/local/tomcat/webapps/

③、構建映象

docker build -f Dockerfile -t itcoke/mytomcat:1.0 .

④、執行映象

docker run -d -p 8081:8080 itcoke/mytomcat:1.0

⑤、訪問首頁測試

可以看到如下圖的首頁介面,即構建執行成功。

3、Dockerfile 指令詳解

在上面了我們編寫了一個 Dockerfile 檔案,內容如下:

FROM tomcat:latest
MAINTAINER itcoke
WORKDIR /usr/local/tomcat/webapps
COPY ./webapps/ /usr/local/tomcat/webapps/

那這裡面每條指令是什麼意思呢?接下來我們揭開這層神祕的面紗。

3.1 編寫規範

①、每條指令(每行開頭關鍵字)都必須是大寫字母;

②、執行順序是按照編寫順序從上到下;

③、# 表示註釋;

3.2 常用指令介紹

①、FROM

FROM centos #依賴官方基準映象(centos:lastest)

FROM scratch #不依賴任何基準映象

FROM tomcat:9.0-jdk8-openjdk #指定具體版本號

②、MAINTAINER

通常表示映象來自哪個機構。類似還有比如 LABEL 標籤,展示映象的一些說明資訊,不會對映象有實際影響。

LABEL version=“1.0”

LABEL description="初版xxx服務"

③、WORKDIR

WORKDIR 路徑 # WORKDIR /usr/local

指定工作目錄,也是我們進入映象的路徑,如果指定路徑不存在,該指令也會自動建立該目錄。

PS:儘量使用絕對路徑,這樣更加清晰。

④、ADD 和 COPY

都是進行檔案複製。

ADD 功能更加強大一點,支援壓縮包的解壓,還支援遠端檔案的複製。

⑤、ENV

設定環境常量。

比如:

ENV JAVA_HOME /usr/local/openjdk8

RUN ${JAVA_HOME}/bin/java -jar test.jar

儘量使用環境常量,這樣可以提高程式的可維護性。

3.3 RUN 和 CMD 和 ENTRYPOINT

RUN: 在映象構建時執行命令,比如 RUN yum -y install vim;

ENTRYPOINT:容器啟動時執行的命令;

CMD:容器啟動後執行預設的命令或引數;

①、RUN

構建時執行,有兩種命令格式:

RUN yum install -y vim #Shell 命令格式

RUN ["yum","install","-y","vim"] #Exec命令格式

官方推薦使用 Exec 命令格式。

②、ENTRYPOINT

容器啟動時執行的命令。

命令格式也是推薦使用 Exec。

注意:Dockerfile 中只有最後一個 ENTRYPOINT 會被執行。

③、CMD

用於設定預設執行的命令。

和ENTRYPOINT 命令一樣,也是隻有最後一個 CMD 命令會被執行,但是如果容器啟動時附加指令,則CMD會被忽略。

CMD ["ps","-ef"] #推薦使用 Exec 格式。

比如有如下Dockerfile 檔案:

構建,然後啟動時(不附加命令),會輸出 3:

如果啟動時附加命令,則會執行附加的命令(下圖附加 ls 命令),而不執行Dockerfile 中的CMD 命令:

image-20211104085058681

也就是說 ENTRYPOINT 指令一定會執行,但是 CMD 指令不一定會執行。

3.4 docker build 命令

編寫好的 Dockerfile 通過 docker build 構建映象。

docker build [OPTIONS] PATH | URL | -

①、-f:指定要使用的 Dockerfile 檔案路徑。

②、-t(-tag):映象的名字和標籤,通常是 name:tag。

4、Dockerfile 構建 centos

我們拉取官方的 centos 系統,發現是一個簡化版的,常用的一些 vim 命令,ifconfig 命令都無法使用。

image-20211101082327112

於是我們就編寫一個Dockerfilew 檔案來構建一個自己的 centos系統,有兩個要求:

①、安裝好vim以及一些網路命令;

②、設定工作目錄為 /usr/local;

按照要求,我們在 /home 目錄下新建 Dockerfile_MyCentos 檔案,內容如下:

FROM centos
WORKDIR /usr/local
RUN yum -y install vim
RUN yum -y install net-tools
EXPOSE 80
CMD echo "install successful"
CMD /bin/bash

通過如下語句構建:

docker build -f Dockerfile_MyCentos -t mycentos:1.0 .

PS:對於構建命令,加入你新建的 Dockerfile 檔名稱就是【Dockerfile】,那可以不加 -f 檔名 來指定,docker 會自動尋找。

構建成功後,就生成了自己的映象:

我們執行這個映象,發現這個centos 系統,vim,ifconfig 等網路命令都可以用了。

5、推送映象到阿里雲

上面我們映象製作完成,如何推送到阿里雲呢?

5.1 登入阿里雲

https://cr.console.aliyun.com/cn-hangzhou/instances

5.2 建立名稱空間

5.3 建立映象倉庫

測試階段選擇本地倉庫就行。

5.4 推送操作指南

點開建立的映象倉庫,就會看到詳細的操作指南。

看到第 3 點,將映象推送到 Registry:

docker login --username=182****5732 registry.cn-hangzhou.aliyuncs.com
docker tag [ImageId] registry.cn-hangzhou.aliyuncs.com/itcoke/test:[映象版本號]
docker push registry.cn-hangzhou.aliyuncs.com/itcoke/test:[映象版本號]

第一條命令是登入阿里雲,輸入時需要在此輸入密碼,如果忘記密碼了,可以到【訪問憑證】裡面重新設定。

第二條是設定 tag:

docker tag e10136600f85 registry.cn-hangzhou.aliyuncs.com/itcoke/test:1.0

第三條命令是推送到阿里雲:

docker push registry.cn-hangzhou.aliyuncs.com/itcoke/test:1.0

檢視阿里雲映象版本,也能看到我們推送過去的映象資訊:

點開【層資訊】,裡面的內容就是我們編寫的 Dockerfile 相關資訊。

6、從阿里雲pull映象

7、退出登入

docker logout

相關文章