編寫 Dockerfile 生成自定義映象
阿新 • • 發佈:2021-01-08
一般情況下我們可以從公共渠道諸如 [DockerHub](https://hub.docker.com) 獲取映象上獲取映象,但是在實際生產過程中,往往需要定製化的映象,例如修改一些配置檔案,增加一些特殊的命令或軟體等需求,這時就需要通過編寫 Dockerfile 來生成自定義的映象檔案。
## Dockerfile介紹
Dockerfile 是一個文字格式的配置檔案,通過編寫 Dockerfile 指令碼來定義自己需要的映象。Dockerfile 檔案由一行行命令語句組成,檔案中的註釋資訊以 # 開頭。編輯好 Dcokerfile 檔案之後,我們可以通過 `docker build -t .` 命令生成自己定義的映象檔案。
## Dockerfile基本結構
我們看一下 [alpine](https://github.com/alpinelinux/docker-alpine/blob/f3d17bcb7b1fa51cf9b011403cd58e00fbbcd000/x86_64/Dockerfile) 的 Dockerfile 檔案:
```dockerfile
FROM scratch
ADD alpine-minirootfs-20201218-x86_64.tar.gz /
CMD ["/bin/sh"]
```
Dockerfile 檔案主要由三部分組成:
* FROM 屬於配置指令部分,表明基於的映象名稱。`scratch` 指從空白開始。
* ADD 屬於操作指令部分,表示向映象內加入內容。
* CMD 也屬於操作指令部分,一般做為最後一行,表示執行容器時的操作命令。
## 指令說明
Dockerfile 中指令的一般格式為 `INSTRUCTION arguments` ,指令分兩種 配置指令 和 操作指令,具體如下:
* 配置指令
* ARG : 定義建立映象過程中使用的變數,格式為 `ARG [=]`
* FROM : 指定所建立映象的基礎映象。格式為 `FROM :`
* LABEL : 為生成的映象新增元資料標籤資訊,輔助過濾特定映象。格式為 `LABEL = =`
* EXPOSE : 宣告映象內服務監聽的埠。格式為 `EXPOSE [/]`
* ENV : 指定環境變數,該變數在容器中存在,也可在容器啟動時覆蓋。格式為 `ENV `
* 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 ` 或 `RUN ["executable", "param1", "param2"]` 當命令較長時,可以用 \ 來換行。
* CMD : 指定容器啟動時預設執行的命令,每個Dockerfile只能有一條CMD命令。格式有三種,分別為:`CMD ["executable", "param1", "param2"]` 或 `CMD command param1 param2` 或 `CMD ["param1", "param2"]`
* ADD : 新增內容到映象中,將SRC內容複製到DEST中。格式為: `ADD `
* COPY : 複製內容到映象中。格式為 : `COPY `
## 建立映象
建立映象的命令格式為
```sh
$ docker build [OPTIONS] PATH | URL | -
```
docker build 命令讀取指定路徑下的 Dockerfile 檔案,並將該路徑下的所有資料作為上下文傳送給 Docker 服務端。服務端完成 Dockerfile 格式校驗後,按順序執行指令命令,遇到ADD、COPY和RUN指令會生成新一層的映象檔案。映象建立成功後,返回映象ID。
docker build 還有很多選項,最常用的是通過 `-t` 增加標籤。
```sh
$ docker build -t test:0.1 .
```
當 Dockerfile 所在的資料夾檔案過多時,為避免向服務端上傳上下文過大,可以通過 .dockerignore 檔案來讓 Docker 忽略無關的檔案。
```sh
$ cat .dockerignore
*xls
*docx
README.md
```
## 實戰案例
總的來說,通過編寫 Dockerfile 生成自定義映象的過程不復雜,但是能生成高效的映象還需要不斷的嘗試和聯絡,一般來說用於生產的映象都儘量保證用途單一,減少映象的層數,選擇合適的基礎映象減小映象檔案大小,形成自己的版本號和標籤管理規則,這樣能提高自己生成映象的質量。
下面就以一個簡單定義 python 基礎映象的例子,基礎的 python 映象缺少很多包例如爬蟲常用的 requests ,自己定義一個包含 requests 包的映象,編寫的 Dockerfile 如下:
```dockerfile
FROM python:3.6
RUN pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple requests
```
執行映象的建立命令
```sh
$ 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("http://baidu.com")
>>> print(response.text)
```
可以看到映象內的 python 環境已經支援 requests 包了。利用這種方式,我們不用在本地維護開發環境,特別是多個版本的開發環境,通過 Docker 生成不同版本的映象能夠快速的實現多版本的開發環境,大家可以參考 [利用 Docker 構建一個簡單的 java 開發編譯環境](http://edulinks.cn/2020/11/12/20201111-build-java-devlopment-env-with-docker/) 。自己定義的各種映象,可以上傳到 DockerHub,更換電腦後僅需要安裝 Docker,之前的各種開發環境就回來了。
對於 Docker 有進一步興趣的,可以參考我的其他文章:
* [Docker 入門介紹](http://edulinks.cn/2018/06/20/20180620-docker-overview/)
* [在Redhat 7.3中採用離線方式安裝Docker](http://edulinks.cn/2018/07/11/20180711-install-docker-ce-in-redhat-73/)
* [建立自己的Docker基礎映象](http://edulinks.cn/2018/06/27/20180627-make-your-own-base-docker-image/)
* [Docker存出載入映象](http://edulinks.cn/2018/07/16/20180716-docker-save-load-image/)
* [Docker Compose 使用介紹](http://edulinks.cn/2020/04/15/20200415-docker-compose/)
* [使用 Docker 快速搭建PHP開發環境](http://edulinks.cn/2020/04/17/20200415-qucik-lnmp-dev-environment/)
* [Docker Compose 建立ELK叢集](http://edulinks.cn/2020/01/15/20200115-docker-compose-elk-cluster/)
最後說點雜事,2021年剛開始沒幾天,年前立下的雄心壯志馬上被各種無計劃的事打亂了,感覺總是被打斷,感覺總是時間不夠用,原來以為是自己能力不夠用,最近在雲+社群上讀了一個時間管理系列文章,才發現原來是自己堅持不夠,給了自己點信心,2021剛開始還要繼續加油才是,附上這個系列文章的連結,感興趣的朋友可以讀一讀。
![](https://img2020.cnblogs.com/blog/39469/202101/39469-20210107222052637-12775570