編寫 Dockerfile 生成自定義鏡像

一般情況下我們可以從公共渠道諸如 DockerHub 獲取鏡像上獲取鏡像,但是在實際生產過程中,往往需要訂製化的鏡像,例如修改一些配置文件,增加一些特殊的命令或軟體等需求,這時就需要通過編寫 Dockerfile 來生成自定義的鏡像文件。

Dockerfile介紹

Dockerfile 是一個文本格式的配置文件,通過編寫 Dockerfile 腳本來定義自己需要的鏡像。Dockerfile 文件由一行行命令語句組成,文件中的注釋資訊以 # 開頭。編輯好 Dcokerfile 文件之後,我們可以通過 docker build -t . 命令生成自己定義的鏡像文件。

Dockerfile基本結構

我們看一下 alpine 的 Dockerfile 文件:

FROM scratch
ADD alpine-minirootfs-20201218-x86_64.tar.gz /
CMD ["/bin/sh"]

Dockerfile 文件主要由三部分組成:

  • FROM 屬於配置指令部分,表明基於的鏡像名稱。scratch 指從空白開始。
  • ADD 屬於操作指令部分,表示向鏡像內加入內容。
  • CMD 也屬於操作指令部分,一般做為最後一行,表示運行容器時的操作命令。

指令說明

Dockerfile 中指令的一般格式為 INSTRUCTION arguments ,指令分兩種 配置指令 和 操作指令,具體如下:

  • 配置指令
    • ARG : 定義創建鏡像過程中使用的變數,格式為 ARG <name>[=<default value>]
    • FROM : 指定所創建鏡像的基礎鏡像。格式為 FROM <image>:<tag>
    • LABEL : 為生成的鏡像添加元數據標籤資訊,輔助過濾特定鏡像。格式為 LABEL <key>=<value> <key>=<value>
    • EXPOSE : 聲明鏡像內服務監聽的埠。格式為 EXPOSE <port>[/<protocol>]
    • ENV : 指定環境變數,該變數在容器中存在,也可在容器啟動時覆蓋。格式為 ENV <key> <value>
    • ENTRYPOINT : 指定鏡像的默認入口命令,做為容器啟動時的根命令執行。格式為 ENTRYPOINT ["executable", "param1", "param2"] 或者 ENTRYPOINT command param1 param2
    • VOLUME : 創建一個數據卷掛載點。格式為 VOLUME ["/data"]
    • USER : 指定容器運行時的用戶名或UID,後續的RUN指令也使用該用戶身份。格式為 USER daemon
    • WORKDIR : 配置RUN\CMD\ENTRYPOINT等指令的工作目錄,推薦使用絕對路徑。格式為:WORKDIR /path/to/workdir
    • ONBUILD : 指定當基於所生成鏡像創建子鏡像時,自動執行的操作指令。
    • STOPSIGNAL : 指定容器接收退出的訊號值。格式為: STOPSIGNAL signal
    • HEALTHCHECK : 配置容器健康檢查命令,自 Docker 1.12 開始支援。格式為: HEALTHCHECK [OPTIONS] CMD command
    • SHELL : 指定默認的shell類型。格式為: SHELL ["executable", "parameters"]
  • 操作指令
    • RUN : 運行指定命令。格式為: RUN <command>RUN ["executable", "param1", "param2"] 當命令較長時,可以用 \ 來換行。
    • CMD : 指定容器啟動時默認執行的命令,每個Dockerfile只能有一條CMD命令。格式有三種,分別為:CMD ["executable", "param1", "param2"]CMD command param1 param2CMD ["param1", "param2"]
    • ADD : 添加內容到鏡像中,將SRC內容複製到DEST中。格式為: ADD <src> <dest>
    • COPY : 複製內容到鏡像中。格式為 : COPY <src> <dest>

創建鏡像

創建鏡像的命令格式為

$ docker build [OPTIONS] PATH | URL | -

docker build 命令讀取指定路徑下的 Dockerfile 文件,並將該路徑下的所有數據作為上下文發送給 Docker 服務端。服務端完成 Dockerfile 格式校驗後,按順序執行指令命令,遇到ADD、COPY和RUN指令會生成新一層的鏡像文件。鏡像創建成功後,返回鏡像ID。

docker build 還有很多選項,最常用的是通過 -t 增加標籤。

$ docker build -t test:0.1 .

當 Dockerfile 所在的文件夾文件過多時,為避免向服務端上傳上下文過大,可以通過 .dockerignore 文件來讓 Docker 忽略無關的文件。

$ cat .dockerignore
*xls
*docx
README.md

實戰案例

總的來說,通過編寫 Dockerfile 生成自定義鏡像的過程不複雜,但是能生成高效的鏡像還需要不斷的嘗試和聯繫,一般來說用於生產的鏡像都盡量保證用途單一,減少鏡像的層數,選擇合適的基礎鏡像減小鏡像文件大小,形成自己的版本號和標籤管理規則,這樣能提高自己生成鏡像的品質。

下面就以一個簡單定義 python 基礎鏡像的例子,基礎的 python 鏡像缺少很多包例如爬蟲常用的 requests ,自己定義一個包含 requests 包的鏡像,編寫的 Dockerfile 如下:

FROM python:3.6

RUN pip3 install -i //pypi.tuna.tsinghua.edu.cn/simple requests  

執行鏡像的創建命令

$ docker build -t python-requests-3.6:0.1 .
$ docker images
REPOSITORY                                      TAG                 IMAGE ID            CREATED             SIZE
python-requests-3.6                             0.1                 3c2bb72b2066        2 minutes ago       884MB
python                                          3.6                 85146760634c        7 weeks ago         874MB
$ docker run --rm -it -v "$PWD":/usr/src -w /usr/src python-requests-3.6:0.1 python3
Python 3.6.12 (default, Nov 18 2020, 14:46:32) 
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import requests
>>> response = requests.get("//baidu.com")
>>> print(response.text)
<html>
<meta http-equiv="refresh" content="0;url=//www.baidu.com/">
</html>

可以看到鏡像內的 python 環境已經支援 requests 包了。利用這種方式,我們不用在本地維護開發環境,特別是多個版本的開發環境,通過 Docker 生成不同版本的鏡像能夠快速的實現多版本的開發環境,大家可以參考 利用 Docker 構建一個簡單的 java 開發編譯環境 。自己定義的各種鏡像,可以上傳到 DockerHub,更換電腦後僅需要安裝 Docker,之前的各種開發環境就回來了。

對於 Docker 有進一步興趣的,可以參考我的其他文章:

最後說點雜事,2021年剛開始沒幾天,年前立下的雄心壯志馬上被各種無計劃的事打亂了,感覺總是被打斷,感覺總是時間不夠用,原來以為是自己能力不夠用,最近在雲+社區上讀了一個時間管理系列文章,才發現原來是自己堅持不夠,給了自己點信心,2021剛開始還要繼續加油才是,附上這個系列文章的鏈接,感興趣的朋友可以讀一讀。

Tags: