前言
docker的系統學習可以看我這篇博文:https://www.cnblogs.com/zisefeizhu/p/11298818.html 有非常詳細的講解
容器現在都是用kubernetes來編排了, 存盤、網路、都歸Kubernetes層面管理了,所以對于docker的主要掌握點也就剩dockerfile了,這也是docker的重點,
簡介
Dockerfile是一個文本檔案,里面包含一條條指令,每一條指令就是一層鏡像,
Dockerfile 一般分為四部分:基礎鏡像資訊、維護者資訊、鏡像操作指令和容器啟動時執行指令,’#’ 為 Dockerfile 中的注釋,
Docker以從上到下的順序運行Dockerfile的指令,為了指定基本鏡像,第一條指令必須是FROM,一個宣告以#字符開頭則被視為注釋,
Dockerfile中所用的所有檔案一定要和Dockerfile檔案在同一級父目錄下,可以為Dockerfile父目錄的子目錄,
Dockerfile中相對路徑默認都是Dockerfile所在的目錄,
Dockerfile中一定要惜字如金,能寫到一行的指令,一定要寫到一行,原因是分層構建,聯合掛載這個特性,Dockerfile中每一條指令被視為一層,
Dockerfile中指明大寫(約定俗成)
dockerfile 圖解

dockerfile詳解
FROM
指定基礎鏡像,并且必須是第一條非注釋指令,
如果不以任何鏡像為基礎,那么寫法為:FROM scratch,
同時意味著接下來所寫的指令將作為鏡像的第一層開始
語法:
FROM <image>
FROM <image>:<tag>
FROM <image>:<digest>
三種寫法,其中<tag>和<digest> 是可選項,如果沒有選擇,那么默認值為latest
在一個 Dockerfile 檔案中創建多個鏡像時,FROM 可以多次出現,只需在每個新命令 FROM 之前,記錄提交上次的鏡像 ID,
LABEL
功能是為鏡像指定標簽
語法:
LABEL <key>=<value> <key>=<value> <key>=<value> ...
一個Dockerfile種可以有多個LABEL,不建議這么寫,最好是寫成一行,如太長需要換行的話則使用\符號
LABEL會繼承基礎鏡像中的LABEL,如遇到key相同,則值覆寫
ENV
設定環境變數
語法:
ENV <key> <value>
ENV <key>=<value> ...
兩者的區別就是第一種是一次設定一個,第二種是一次設定多個
ADD
一個復制命令,把檔案復制到鏡像中
如果把虛擬機與容器想象成兩臺linux服務器的話,那么這個命令就類似于scp,只是scp需要加用戶名和密碼的權限驗證,而ADD不用
語法:
ADD <src>... <dest>
ADD ["<src>",... "<dest>"]
路徑的填寫可以是容器內的絕對路徑,也可以是相對于作業目錄的相對路徑,推薦寫成絕對路徑
可以是一個本地檔案或者是一個本地壓縮檔案,還可以是一個url
如果把寫成一個url,那么ADD就類似于wget命令
src為一個目錄的時候,會自動把目錄下的檔案復制過去,目錄本身不會復制
如果src為多個檔案,dest一定要是一個目錄
如果 docker 發現檔案內容被改變,則接下來的指令都不會再使用快取,關于復制檔案時需要處理的/,基本跟正常的 copy 一致
COPY
看這個名字就知道,又是一個復制命令
語法:
COPY <src>... <dest>
COPY ["<src>",... "<dest>"]
與ADD的區別:
COPY的只能是本地檔案,其他用法一致
RUN
功能為運行指定的命令
語法:
RUN <command>
RUN ["executable", "param1", "param2"]
第一種后邊直接跟shell命令
在linux作業系統上默認 /bin -c
在windows作業系統上默認 cmd /S /C
第二種是類似于函式呼叫,
可將executable理解成為可執行檔案,后面就是兩個引數,
RUN 指令創建的中間鏡像會被快取,并會在下次構建中使用,如果不想使用這些快取鏡像,可以在構建時指定 --no-cache 引數,如:docker build --no-cache,
CMD
功能為容器啟動時要運行的命令
語法:
CMD ["executable","param1","param2"]
CMD ["param1","param2"]
CMD command param1 param2
第三種比較好理解了,就時shell這種執行方式和寫法
第一種和第二種其實都是可執行檔案加上引數的形式
舉例說明兩種寫法:
CMD [ "sh", "-c", "echo $HOME"
CMD [ "echo", "$HOME" ]
這里邊包括引數的一定要用雙引號,就是",不能是單引號,千萬不能寫成單引號,
原因是引數傳遞后,docker決議的是一個JSON array
RUN&&CMD
RUN是構件容器時就運行的命令以及提交運行結果
CMD是容器啟動時執行的命令,在構件時并不運行,構件時僅僅指定了這個命令到底是做什么的
WORKDIR
設定作業目錄,對RUN,CMD,ENTRYPOINT,COPY,ADD生效,如果不存在則會創建,也可以設定多次,
語法:
WORKDIR /path/to/workdir
WORKDIR也可以決議環境變數
ENV DIRPATH /path
WORKDIR $DIRPATH/$DIRNAME
RUN pwd
pwd的執行結果是/path/$DIRNAME
VOLUME
實作掛載功能,可以將宿主機目錄掛載到容器中
可用專用的檔案存盤當作Docker容器的資料存盤部分
語法:
VOLUME ["/data"]
使用場景為需要持久化存盤資料時.
容器使用的是AUFS,這種檔案系統不能持久化資料,當容器關閉后,所有的更改都會丟失,
所以當資料需要持久化時用這個命令,
VOLUME ["/var/log/"]
VOLUME /var/log
VOLUME /var/log /var/db
卷可以容器間共享和重用
容器并不一定要和其它容器共享卷
修改卷后會立即生效
對卷的修改不會對鏡像產生影響
卷會一直存在,直到沒有任何容器在使用它
VOLUME 讓我們可以將源代碼、資料或其它內容添加到鏡像中,而又不并提交到鏡像中,并使我們可以多個容器間共享這些內容,
USER
設定啟動容器的用戶,可以是用戶名或UID
語法:
USER daemo
USER UID
如果設定了容器以daemon用戶去運行,那么RUN, CMD 和 ENTRYPOINT 都會以這個用戶去運行,
使用這個命令一定要確認容器中擁有這個用戶,并且擁有足夠權限,
ENTRYPOINT
啟動時的默認命令
語法:
ENTRYPOINT ["executable", "param1", "param2"]
ENTRYPOINT command param1 param2
第一種就是可執行檔案加引數
第二種就是寫shell
ENTRYPOINT&&CMD
相同點:
只能寫一條,如果寫了多條,那么只有最后一條生效
容器啟動時才運行,運行時機相同
不同點:
ENTRYPOINT不會被運行的command覆寫,而CMD則會被覆寫
如果我們在Dockerfile種同時寫了ENTRYPOINT和CMD,并且CMD指令不是一個完整的可執行命令,那么CMD指定的內容將會作為ENTRYPOINT的引數,
FROM ubuntu
ENTRYPOINT ["netstat", "-ln"]
CMD ["-tup"]
如果在Dockerfile種同時寫了ENTRYPOINT和CMD,并且CMD是一個完整的指令,那么它們兩個會互相覆寫,誰在最后誰生效
FROM ubuntu
ENTRYPOINT ["netstat", "-ln"]
CMD ls -l
那么將執行ls -l ,netstat -ln不會執行,
ARG
設定變數命令,ARG命令定義了一個變數,在docker build創建鏡像的時候,使用 --build-arg =來指定引數
語法:
ARG <name>[=<default value>]
如果用戶在build鏡像時指定了一個引數沒有定義在Dockerfile中,那么將有一個Warning
[Warning] One or more build-args [foo] were not consumed.
可以定義一個或多個引數
FROM busybox
ARG user1
ARG buildno
可以給引數一個默認值
FROM busybox
ARG user1=someuser
ARG buildno=1
如果給了ARG定義的引數默認值,那么當build鏡像時沒有指定引數值,將會使用這個默認值
HEALTHCHECK
容器健康狀況檢查命令
語法:
HEALTHCHECK [OPTIONS] CMD command
HEALTHCHECK NONE
第一個的功能是在容器內部運行一個命令來檢查容器的健康狀況
第二個的功能是在基礎鏡像中取消健康檢查命令
[OPTIONS]的選項支持以下三中選項:
–interval=DURATION 兩次檢查默認的時間間隔為30秒
–timeout=DURATION 健康檢查命令運行超時時長,默認30秒
–retries=N 當連續失敗指定次數后,則容器被認為是不健康的,狀態為unhealthy,默認次數是3
注意:
HEALTHCHECK命令只能出現一次,如果出現了多次,只有最后一個生效,
CMD后邊的命令的回傳值決定了本次健康檢查是否成功,具體的回傳值如下:
0: success - 表示容器是健康的
1: unhealthy - 表示容器已經不能作業了
2: reserved - 保留值
例:
HEALTHCHECK --interval=5m --timeout=3s \
CMD curl -f http://localhost/8080 || exit 1
健康檢查命令是:curl -f http://localhost/8080 || exit 1
兩次檢查的間隔時間是5秒
命令超時時間為3秒
ONBUILD
用于在dockerfile中定義一個觸發器,只對當前鏡像的子鏡像生效
語法:
ONBUILD [INSTRUCTION]
dockerfile用于build鏡像檔案,此鏡像檔案亦可作為base image被另一個dockerfile用作FROM指令引數,并以之構建新的鏡像,在后面的dockerfile中的FROM指令在build程序中被執行時,將會觸發創建其baseimage的dockerfile檔案中的ONBUILD指令定義的觸發器,
比如當前鏡像為A,在Dockerfile種添加:
ONBUILD RUN ls -l
這個 ls -l 命令不會在A鏡像構建或啟動的時候執行
此時有一個鏡像B是基于A鏡像構建的,那么這個ls -l 命令會在B鏡像構建的時候被執行,
EXPOSE
功能為暴漏容器運行時的監聽埠給外部
語法:
EXPOSE <port>/<tcp/udp>
但是EXPOSE并不會使容器訪問主機的埠
EXPOSE 指令并不會讓容器監聽 host 的埠,如果需要,需要在 docker run 時使用 `-p`、`-P` 引數來發布容器埠到 host 的某個埠上,
STOPSIGNAL
STOPSIGNAL命令是的作用是當容器停止時給系統發送什么樣的指令,默認是15
語法:
STOPSIGNAL signal
Dockerfile中使用變數的方式
$varname
${varname}
${varname:-default value}
${varname:+default value}
第一種和第二種相同
第三種表示當變數不存在使用-號后面的值
第四種表示當變數存在時使用+號后面的值
原則及建議
容器輕量化,從鏡像中產生的容器應該盡量輕量化,能在足夠短的時間內停止、銷毀、重新生成并替換原來的容器,
使用 .gitignore,在大部分情況下,Dockerfile 會和構建所需的檔案放在同一個目錄中,為了提高構建的性能,應該使用 .gitignore 來過濾掉不需要的檔案和目錄,
為了減少鏡像的大小,減少依賴,僅安裝需要的軟體包,
一個容器只做一件事,解耦復雜的應用,分成多個容器,而不是所有東西都放在一個容器內運行,如一個 Python Web 應用,可能需要 Server、DB、Cache、MQ、Log 等幾個容器,一個更加極端的說法:One process per container,
減少鏡像的圖層,不要多個 Label、ENV 等標簽,
對續行的引數按照字母表排序,特別是使用apt-get install -y安裝包的時候,
使用構建快取,如果不想使用快取,可以在構建的時候使用引數--no-cache=true來強制重新生成中間鏡像,
實戰
我的一篇docker實戰博文
https://blog.csdn.net/zisefeizhu/article/details/90729970
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/2422.html
標籤:其他
上一篇:專案微管理39 - 懲罰
