編寫 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"]
- ARG : 定義創建鏡像過程中使用的變數,格式為
- 操作指令
- RUN : 運行指定命令。格式為:
RUN <command>
或RUN ["executable", "param1", "param2"]
當命令較長時,可以用 \ 來換行。 - CMD : 指定容器啟動時默認執行的命令,每個Dockerfile只能有一條CMD命令。格式有三種,分別為:
CMD ["executable", "param1", "param2"]
或CMD command param1 param2
或CMD ["param1", "param2"]
- ADD : 添加內容到鏡像中,將SRC內容複製到DEST中。格式為:
ADD <src> <dest>
- COPY : 複製內容到鏡像中。格式為 :
COPY <src> <dest>
- RUN : 運行指定命令。格式為:
創建鏡像
創建鏡像的命令格式為
$ 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 有進一步興趣的,可以參考我的其他文章:
- Docker 入門介紹
- 在Redhat 7.3中採用離線方式安裝Docker
- 創建自己的Docker基礎鏡像
- Docker存出載入鏡像
- Docker Compose 使用介紹
- 使用 Docker 快速搭建PHP開發環境
- Docker Compose 建立ELK集群
最後說點雜事,2021年剛開始沒幾天,年前立下的雄心壯志馬上被各種無計劃的事打亂了,感覺總是被打斷,感覺總是時間不夠用,原來以為是自己能力不夠用,最近在雲+社區上讀了一個時間管理系列文章,才發現原來是自己堅持不夠,給了自己點信心,2021剛開始還要繼續加油才是,附上這個系列文章的鏈接,感興趣的朋友可以讀一讀。