一、編譯鏡像
1. 編譯鏡像
Dockerfile類似於Makfile,用戶使用docker build
就可以編譯鏡像,使用該命令可以設置編譯鏡像時使用的CPU數量、內存大小、文件路徑等
語法:docker build [OPTIONS] PATH| URL| - 常見選項: -t 設置鏡像的名稱和TAG,格式為name:tag -f Dockerfile的名稱,默認為PATH/Dockerfile 例子:docker build -f ~/php.Dockerfile . 注意:PATH是編譯鏡像使用的工作目錄,Docker Daemon在編譯開始時,會掃描PATH中的所有文件,可以在編譯目錄中加入.dockerignore過濾不需要的文件
Docker Daemon從Dockerfile中順序讀取指令,生成一個臨時容器,在容器中執行指令,容器編譯成功后會提交作為鏡像層加入最終鏡像,為了加快編譯過程,Docker Daemon采用了緩存機制,如果在緩存中找到了需要的中間鏡像則直接使用該鏡像而不生成臨時容器(編譯時可以使用選項–no-cache選擇不使用緩存)
2. dockerignore文件
編譯開始前,Docker Daemon會讀取編譯目錄中的.dockerignore文件,忽略其中的文件和目錄,在其中可以使用通配符(?代表一個字符,*代表零個或任意個字符),使用通配符時,總會出現那么幾個例外,這時可以使用!+文件名,Docker Daemon會讀取!后面的文件
*/temp* 忽略PATH路徑下一級子目錄中以temp開頭的文件和目錄,如PAHT/A/temp.txt */*/temp* 忽略PATH路徑下二級子目錄中以temp開頭的文件和目錄,如PATH/A/B/temp.txt *.md !README.md 忽略所有md文件,除了README.md
二、Dockerfile指令詳解
Dockerfile由多條指令組成,每條指令在編譯鏡像時執行相應的程序完成某些功能,由指令+參數組成,以逗號分隔,#作為注釋起始符,雖說指令不區分大小寫,但是一般指令使用大些,參數使用小寫
指令:FROM 功能描述:設置基礎鏡像 語法:FROM < image>[:< tag> | @< digest>] 提示:鏡像都是從一個基礎鏡像(操作系統或其他鏡像)生成,可以在一個Dockerfile中添加多條FROM指令,一次生成多個鏡像 注意:如果忽略tag選項,會使用latest鏡像
指令:MAINTAINER
功能描述:設置鏡像作者
語法:MAINTAINER < name>
指令:RUN 功能描述: 語法:RUN < command> RUN [“executable”,”param1”,”param2”] 提示:RUN指令會生成容器,在容器中執行腳本,容器使用當前鏡像,腳本指令完成后,Docker Daemon會將該容器提交為一個中間鏡像,供后面的指令使用 補充:RUN指令第一種方式為shell方式,使用/bin/sh -c < command>運行腳本,可以在其中使用\將腳本分為多行 RUN指令第二種方式為exec方式,鏡像中沒有/bin/sh或者要使用其他shell時使用該方式,其不會調用shell命令 例子:RUN source $HOME/.bashrc;\ echo $HOME RUN [“/bin/bash”,”-c”,”echo hello”] RUN [“sh”,”-c”,”echo”,”$HOME”] 使用第二種方式調用shell讀取環境變量
指令:CMD 功能描述:設置容器的啟動命令 語法:CMD [“executable”,”param1”,”param2”] CMD [“param1”,”param2”] CMD < command> 提示:CMD第一種、第三種方式和RUN類似,第二種方式為ENTRYPOINT參數方式,為entrypoint提供參數列表 注意:Dockerfile中只能有一條CMD命令,如果寫了多條則最后一條生效
指令:LABEL 功能描述:設置鏡像的標簽 延伸:鏡像標簽可以通過docker inspect查看 格式:LABEL < key>=< value> < key>=< value> … 提示:不同標簽之間通過空格隔開 注意:每條指令都會生成一個鏡像層,Docker中鏡像最多只能有127層,如果超出Docker Daemon就會報錯,如LABEL ..=.. <假裝這里有個換行> LABEL ..=..合在一起用空格分隔就可以減少鏡像層數量,同樣,可以使用連接符\將腳本分為多行 鏡像會繼承基礎鏡像中的標簽,如果存在同名標簽則會覆蓋
指令:EXPOSE 功能描述:設置鏡像暴露端口,記錄容器啟動時監聽哪些端口 語法:EXPOSE < port> < port> … 延伸:鏡像暴露端口可以通過docker inspect查看 提示:容器啟動時,Docker Daemon會掃描鏡像中暴露的端口,如果加入-P參數,Docker Daemon會把鏡像中所有暴露端口導出,並為每個暴露端口分配一個隨機的主機端口(暴露端口是容器監聽端口,主機端口為外部訪問容器的端口) 注意:EXPOSE只設置暴露端口並不導出端口,只有啟動容器時使用-P/-p才導出端口,這個時候才能通過外部訪問容器提供的服務
指令:ENV 功能描述:設置鏡像中的環境變量 語法:ENV < key>=< value>…|< key> < value> 注意:環境變量在整個編譯周期都有效,第一種方式可設置多個環境變量,第二種方式只設置一個環境變量 提示:通過${變量名}或者 $變量名使用變量,使用方式${變量名}時可以用${變量名:-default} ${變量名:+cover}設定默認值或者覆蓋值 ENV設置的變量值在整個編譯過程中總是保持不變的
指令:ADD 功能描述:復制文件到鏡像中 語法:ADD < src>… < dest>|[“< src>”,… “< dest>”] 注意:當路徑中有空格時,需要使用第二種方式 當src為文件或目錄時,Docker Daemon會從編譯目錄尋找這些文件或目錄,而dest為鏡像中的絕對路徑或者相對於WORKDIR的路徑 提示:src為目錄時,復制目錄中所有內容,包括文件系統的元數據,但不包括目錄本身 src為壓縮文件,並且壓縮方式為gzip,bzip2或xz時,指令會將其解壓為目錄 如果src為文件,則復制文件和元數據 如果dest不存在,指令會自動創建dest和缺失的上級目錄
指令:COPY 功能描述:復制文件到鏡像中 語法:COPY < src>… < dest>|[“< src>”,… “< dest>”] 提示:指令邏輯和ADD十分相似,同樣Docker Daemon會從編譯目錄尋找文件或目錄,dest為鏡像中的絕對路徑或者相對於WORKDIR的路徑
指令:ENTRYPOINT 功能描述:設置容器的入口程序 語法:ENTRYPOINT [“executable”,”param1”,”param2”] ENTRYPOINT command param1 param2(shell方式) 提示:入口程序是容器啟動時執行的程序,docker run中最后的命令將作為參數傳遞給入口程序 入口程序有兩種格式:exec、shell,其中shell使用/bin/sh -c運行入口程序,此時入口程序不能接收信號量 當Dockerfile有多條ENTRYPOINT時只有最后的ENTRYPOINT指令生效 如果使用腳本作為入口程序,需要保證腳本的最后一個程序能夠接收信號量,可以在腳本最后使用exec或gosu啟動傳入腳本的命令 注意:通過shell方式啟動入口程序時,會忽略CMD指令和docker run中的參數 為了保證容器能夠接受docker stop發送的信號量,需要通過exec啟動程序;如果沒有加入exec命令,則在啟動容器時容器會出現兩個進程,並且使用docker stop命令容器無法正常退出(無法接受SIGTERM信號),超時后docker stop發送SIGKILL,強制停止容器 例子:FROM ubuntu <換行> ENTRYPOINT exec top -b
指令:VOLUME 功能描述:設置容器的掛載點 語法:VOLUME [“/data”] VOLUME /data1 /data2 提示:啟動容器時,Docker Daemon會新建掛載點,並用鏡像中的數據初始化掛載點,可以將主機目錄或數據卷容器掛載到這些掛載點
指令:USER
功能描述:設置RUN CMD ENTRYPOINT的用戶名或UID
語法:USER < name>
指令:WORKDIR 功能描述:設置RUN CMD ENTRYPOINT ADD COPY指令的工作目錄 語法:WORKDIR < Path> 提示:如果工作目錄不存在,則Docker Daemon會自動創建 Dockerfile中多個地方都可以調用WORKDIR,如果后面跟的是相對位置,則會跟在上條WORKDIR指定路徑后(如WORKDIR /A WORKDIR B WORKDIR C,最終路徑為/A/B/C)
指令:ARG 功能描述:設置編譯變量 語法:ARG < name>[=< defaultValue>] 注意:ARG從定義它的地方開始生效而不是調用的地方,在ARG之前調用編譯變量總為空,在編譯鏡像時,可以通過docker build –build-arg < var>=< value>設置變量,如果var沒有通過ARG定義則Daemon會報錯 可以使用ENV或ARG設置RUN使用的變量,如果同名則ENV定義的值會覆蓋ARG定義的值,與ENV不同,ARG的變量值在編譯過程中是可變的,會對比使用編譯緩存造成影響(ARG值不同則編譯過程也不同) 例子:ARG CONT_IMAG_VER <換行> RUN echo $CONT_IMG_VER ARG CONT_IMAG_VER <換行> RUN echo hello 當編譯時給ARG變量賦值hello,則兩個Dockerfile可以使用相同的中間鏡像,如果不為hello,則不能使用同一個中間鏡像
指令:ONBUILD
功能描述:設置自徑想的編譯鈎子指令
語法:ONBUILD [INSTRUCTION]
提示:從該鏡像生成子鏡像,在子鏡像的編譯過程中,首先會執行父鏡像中的ONBUILD指令,所有編譯指令都可以成為鈎子指令
指令:STOPSIGNAL
功能描述:設置容器退出時,Docker Daemon向容器發送的信號量
語法:STOPSIGNAL signal
提示:信號量可以是數字或者信號量的名字,如9或者SIGKILL,信號量的數字說明在Linux系統管理中有簡單介紹
補充:ONBUILD流程
- 編譯時,讀取所有ONBUILD鏡像並記錄下來,在當前編譯過程中不執行指令
- 生成鏡像時將所有ONBUILD指令記錄在鏡像的配置文件OnBuild關鍵字中
- 子鏡像在執行FROM指令時會讀取基礎鏡像中的ONBUILD指令並順序執行,如果執行過程中失敗則編譯中斷;當所有ONBUILD執行成功后開始執行子鏡像中的指令
- 子鏡像不會繼承基礎鏡像中的ONBUILD指令
補充:CMD ENTRYPOINT和RUN的區別
RUN指令是設置編譯鏡像時執行的腳本和程序,鏡像編譯完成后,RUN指令的生命周期結束
容器啟動時,可以通過CMD和ENTRYPOINT設置啟動項,其中CMD叫做容器默認啟動命令,如果在docker run命令末尾添加command,則會替換鏡像中CMD設置的啟動程序;ENRTYPOINT叫做入口程序,不能被docker run命令末尾的command替換,而是將command當作字符串,傳遞給ENTRYPOINT作為參數
FROM ubuntu ENTRYPOINT ["ps"] //通過命令docker run --rm test啟動容器,打印ps的輸出 //通過命令docker run --rm test -ef啟動容器,打印ps -ef的輸出
在docker run中,可以通過–entrypoint替換鏡像中的入口程序,在Dockerfile中,應該至少有一條CMD或者ENTRYPOINT指令,如果同時定義了CMD和ENTRYPOINT則CMD會作為參數傳遞給ENTRYPOINT
FROM ubuntu ENTRYPOINT ["ps"] CMD ["-ef"] //通過命令docker run --rm test啟動容器,打印ps -ef的輸出
給出一份編寫好的dockerfile,大家可以參照下:
#define default args ARG APP_NAME=sckj-myproject-controller FROM registry.etest.tf.cn/base/maven:v20191019 AS source-build ARG APP_NAME COPY ./ /build/ WORKDIR /build RUN mvn clean install -Pimage RUN mv ./${APP_NAME}/target/${APP_NAME}-*.jar /${APP_NAME}.jar FROM registry.etest.tf.cn/base/jdk:v20191019 ARG APP_NAME MAINTAINER itc@tf.cn #'ADD' cmd auto to decompress(gzip tar bzip2 etc),'COPY' could not COPY --from=source-build /${APP_NAME}.jar /usr/local/ COPY --from=source-build /build/sckj20170129sc.sm2 /usr/local/ RUN groupadd -g 1155 sckj && useradd --no-log-init -u 1155 -g sckj sckj \ && chown -R sckj:sckj /usr/local USER sckj #change word dir WORKDIR /usr/local #set entry point CMD [ "-d64", "-Drocketmq.client.log4j2.resource.fileName=log4j2.xml", "-jar", "sckj-myproject-controller.jar" ]