###### tags: `docker`
# Dockerfile 詳細說明
- [FROM](#FROM)
- [ENV](#ENV) | [ARG](#ARG)
- [ADD](#ADD) | [COPY](#COPY)
- [RUN](#RUN) | [CMD](#CMD) | [ENTRYPOINT](#ENTRYPOINT)
- [LABEL](#LABEL)
- [EXPOSE](#EXPOSE)
- [WORKDIR](#WORKDIR)
- [HEALTHCHECK](#HEALTHCHECK)
## 指令說明
### FROM
```dockerfile
FROM [--platform=<platform>] <image> [AS <name>]
FROM [--platform=<platform>] <image>[:<tag>] [AS <name>]
FROM [--platform=<platform>] <image>[@<digest>] [AS <name>]
```
- 用來指定要引進的基礎image,會先從本地搜尋,若無則到網路上的[DockerHub](https://hub.docker.com/)找。可以用自定義的image檔。
- Ex:
```dockerfile
FROM mariadb
```
此指令就是指令指定引入mariadb當作基礎image。
### ENV
```dockerfile
ENV <key>=<value> ...
```
- 新增環境變數到該image裡。
- Ex:
```dockerfile
ENV my_env=your_variable
```
![]()
<img src="https://i.imgur.com/PP0xN01.png" width="75%"/>
在裡面就可以呼叫了
### ARG
```dockerfile
ARG <name>[=<default value>]
```
- ARG在build時候是可以從外部以--build-arg帶入的變數,讓build的動作可結合外部的指令給定一些建構時候所需的參數。
- Ex:
```dockerfile
ARG MY_FILE
ADD ./${MY_FILE} /
```
```shell
docker build -build-arg MY_FILE=./file.txt .
```
用-build-arg把MY_FILE這個變數帶入Dockerfile裡來使用
- ARG不能在CMD或ENTRYPOINT裡使用。
>在ENV與ARG參數的設定上,可以透過下面方式增加一些變化...
> - ${variable:-word} 代表,如果variable有給值,則以variable設定的文字為主,如未設定,則以word字串為主。
> - ${variable:+word} 代表,如果variable有給值,則值為word;如果variable未給值,則最後結果為空字串(empty)。
### ADD
```dockerfile
ADD [--chown=<user>:<group>] [--checksum=<checksum>] <src>... <dest>
ADD [--chown=<user>:<group>] ["<src>",... "<dest>"]
```
- src: 不限於本地路徑,可以用網址之類的。
- Ex:
```dockerfile
ADD http://example.com/font.js /opt/
ADD my_big_lib.tar.gz /var/lib/myapp
```
第1行示範從遠端下載檔案到/opt/,第2行則示範使用ADD傳送tar檔會自動解壓縮到目的地(僅限於tar檔)。
### COPY
```dockerfile
COPY [--chown=<user>:<group>] <src>... <dest>
COPY [--chown=<user>:<group>] ["<src>",... "<dest>"]
```
- COPY與ADD類似,但COPY只支援本地路徑
- Ex:
```dockerfile
COPY ./file.txt /home/user/folder
```
上面範例則是將本地路徑的file.txt複製到image的/home/user/folder
### RUN
```dockerfile
RUN [command,param1,param2,...]
RUN command param1, param2 ...
```
- 支援shell格式或exec格式
- 每次執行RUN都會多建立一層layer,所以盡量減少執行RUN的次數以增加效能。Ex:
```dockerfile
RUN ["apt-get", "update"]
RUN ["apt-get", "-y", "install", "cron"]
RUN crontab -l | { cat; echo "0 4 * * * ${JAVA_EXE} -jar ${CRON_FILE} >> ${CRON_PATH}/cronlog.log";} | crontab -
```
下面的寫法相對上面還要好
```dockerfile
RUN apt-get update \
&& apt-get -y install cron \
&& crontab -l | { cat; echo "0 4 * * * ${JAVA_EXE} -jar ${CRON_FILE} >> ${CRON_PATH}/cronlog.log";} | crontab -
```
> COPY ,ADD ,RUN三者在執行時皆會多產生一層layer,layer越多效能就越差,所以能越少越好。
### CMD
```dockerfile
CMD ["command", "param1", "param2"] #exec form
CMD command param1 param2 #shell form
CMD ["param1","param2"]
```
- CMD 主要用途是為執行容器(container)時提供預設值,預設值可以是一個可執行檔(executable)以及其需要的參數;也可以只是單純提供參數的部分,不過這種用法一定要搭配 ENTRYPOINT 使用,也就是 CMD 只是作為 ENTRYPOINT 所需的預設參數。
- exex form:使用exec來執行
- Ex:`CMD ["/usr/bin/wc","--help"]`實際上會長這樣`exec /usr/bin/wc --help`
> <p style="color: red; font-weight:bold">exec 會替代當前shell並重新啟動一個shell,所以無法使用現有的環境變數</p>
- shell form: 使用`/bin/sh -c`來執行
- Ex: `CMD echo "This is a test." | wc -`實際上會長這樣`/bin/sh -c echo "This is a test." | wc -`
### ENTRYPOINT
```dockerfile
ENTRYPOINT ["executable", "param1", "param2"]
ENTRYPOINT command param1 param2
```
- exec form與shell form需要注意的點和CMD一樣。
### LABEL
```dockerfile
LABEL <key>=<value> <key>=<value> <key>=<value> ...
```
- 用於記載作者、版本之類的metadata。
### EXPOSE
```dockerfile
EXPOSE <port> [<port>/<protocol>...]
```
- EXPOSE 指令通知 Docker container在運行時監聽指定的port。可以指定port監聽TCP還是UDP,不指定則預設為TCP。
- 此指令僅僅聲明要使用的port,並不會自動將port映射出來。
### WORKDIR
```dockerfile
WORKDIR /path/to/workdir
```
- WORKDIR 指令為 跟在它後面的任何RUN、CMD、ENTRYPOINT、COPY和ADD指令指定當前工作目錄。如果 WORKDIR不存在,即使它沒有在任何後續的指令中使用,也會被建立。
### HEALTHCHECK
```dockerfile
HEALTHCHECK [OPTIONS] CMD command
```
- healthCheck用於檢查container是否運行中。
- option:
```dockerfile
--interval=DURATION (default: 30s)
--timeout=DURATION (default: 30s)
--start-period=DURATION (default: 0s)
--retries=N (default: 3)
```
- healthCheck會先檢查然後等interval時間後再次檢查,若單次檢查時間超過timeout時間,則該次檢查視為失敗。
- 當累積失敗次數達retries次時,則回傳unhealthy並關閉container。
- Ex:
```dockerfile
HEALTHCHECK --interval=5m --timeout=3s \
CMD curl -f http://localhost/ || exit 1
```
## 參考文獻
[Dockerfile reference](https://docs.docker.com/engine/reference/builder/)
[《Docker —— 從入門到實踐》正體中文版](https://philipzheng.gitbook.io/docker_practice)
[linux exec用法總結](https://www.796t.com/p/1390349.html)