溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Dockerfile怎么構(gòu)建私有鏡像

發(fā)布時間:2021-07-22 13:44:16 來源:億速云 閱讀:204 作者:chen 欄目:大數(shù)據(jù)

本篇內(nèi)容介紹了“Dockerfile怎么構(gòu)建私有鏡像”的有關(guān)知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

1. 使用 Dockerfile 定制鏡像


  • 鏡像的定制實際上就是定制每一層所添加的配置、文件。我們可以把每一層修改、安裝、構(gòu)建、操作的命令都寫入一個腳本,這個腳本就是 Dockerfile。

  • Dockerfile 是一個文本文件,其內(nèi)包含了一條條的指令,每一條指令構(gòu)建一層,因此每一條指令的內(nèi)容,就是描述該層應(yīng)當(dāng)如何構(gòu)建。

  • 以 nginx 為例。

1. 創(chuàng)建 Dockerfile 文件
  • 在一個空白目錄中,建立一個文本文件,并命名為 Dockerfile:

    mkdir mynginx
    cd mynginx
    touch Dockerfile


  • 內(nèi)容為:

    FROM nginx
    RUN echo '<h2>Hello, Docker!</h2>' > /usr/share/nginx/html/index.html


  • FROM:指定基礎(chǔ)鏡像

    • 如果你以 scratch 為基礎(chǔ)鏡像的話,意味著你不以任何鏡像為基礎(chǔ),接下來所寫的指令將作為鏡像的第一層開始存在。

    • 對于 Linux 靜態(tài)編譯的程序來說,并不需要有操作系統(tǒng)提供運行時支持,所需的一切庫都已經(jīng)在可執(zhí)行文件里了,因此直接 FROM scratch 會讓鏡像體積更加小巧。使用 Go 語言開發(fā)的應(yīng)用很多會使用這種方式來制作鏡像,這也是為什么有人認(rèn)為 Go 是特別適合容器微服務(wù)架構(gòu)的語言的原因之一。

    • 所謂定制鏡像,一定是以一個鏡像為基礎(chǔ),在其上進行定制。基礎(chǔ)鏡像是必須指定的,而 FROM 就是指定基礎(chǔ)鏡像,因此一個 Dockerfile 中的 FROM 是必備的指令,并且必須是第一條指令。在 Docker Hub 上有非常多的高質(zhì)量的官方鏡像,有可以直接拿來使用的服務(wù)類的鏡像,如 nginx、redis、mysql、tomcat 等;可以在其中尋找一個最符合我們最終目標(biāo)的鏡像為基礎(chǔ)鏡像進行定制。

    • 如果沒有找到對應(yīng)服務(wù)的鏡像,官方鏡像中還提供了一些更為基礎(chǔ)的操作系統(tǒng)鏡像,如 ubuntu、debian、centos、alpine 等,這些操作系統(tǒng)的軟件庫為我們提供了更廣闊的擴展空間。

    • 除了選擇現(xiàn)有鏡像為基礎(chǔ)鏡像外,Docker 還存在一個特殊的鏡像,名為 scratch。這個鏡像是虛擬的概念,并不實際存在,它標(biāo)識一個空白的鏡像。

      FROM scratch
      ...


  • RUN:執(zhí)行命令

    • shell 格式:RUN <命令>

      RUN echo '<h2>Hello, Docker!</h2>' > /usr/share/nginx/html/index.html


    • exec 格式:RUN ["可執(zhí)行文件", "參數(shù)1", "參數(shù)2"]

      RUN tar -zxf redis.tar.gz -C /usr/src/redis --strip-components=1
      RUN make -C /usr/src/redis
      RUN make -C /usr/src/redis install


    • RUN 指令是用來執(zhí)行命令行命令的。由于命令行的強大能力,RUN 指令在定制鏡像時是最常用的指令之一。其格式有兩種:

2. 構(gòu)建鏡像
  • 上面我們利用 Dockerfile 定制了 nginx 鏡像,然后就需要構(gòu)建鏡像。

  • 在 Dockerfile 文件所在目錄執(zhí)行:

    docker build -t nginx:v3 .


  • 從命令的輸出結(jié)果中,我們可以清晰地看到鏡像的構(gòu)建過程。在 Step2 中,RUN 指令啟動了一個容器 xxx1,執(zhí)行了所要求的命令,并最后提交了這一層 xxx2,隨后刪除了所用到的這個容器 xxx1。

2. Dockerfile 指令詳解


COPY 復(fù)制文件
  • 格式:

    • COPY <源路徑>... <目標(biāo)路徑>

    • COPY ["<源路徑1>",... "<目標(biāo)路徑>"]

  • COPY 指令將從構(gòu)建上下文目錄中 <源路徑> 的文件/目錄復(fù)制到新的一層的鏡像內(nèi)的 <目標(biāo)路徑> 位置。比如:

    COPY package.json /usr/src/app/


  • 源路徑可以是多個,甚至可以是通配符,如:

    COPY hom* /mydir/
    COPY hom?.txt /mydir/


ADD 更高級的復(fù)制文件
  • ADD 指令和 COPY 的格式和性質(zhì)基本一致。但是在 COPY 的基礎(chǔ)上增加了一些功能。比如源路徑可以是一個 URL,這種情況下,Docker 引擎會試圖去下載這個鏈接的文件放到 <目標(biāo)路徑> 去。

  • 在 Docker 官方的 Dockerfile 最佳實踐文檔中要求,盡可能地使用 COPY,因為 COPY 的語義很明確,就是復(fù)制文件而已,而 ADD 則包含了更復(fù)雜的功能,其行為也不一定清晰,最適合使用 ADD 的場景,就是所提及的需要自動解壓縮的場合。

  • 在 COPY 和 ADD 指令中選擇的時候,可以遵循這樣的原則,所有的文件復(fù)制均使用 COPY 命令,僅在需要自動解壓縮的場合使用 ADD。

CMD 容器啟動命令
  • CMD 指令的格式和 RUN 相似,也是兩種格式:

    • shell 格式:CMD <命令>

    • exec 格式:CMD ["可執(zhí)行文件", "參數(shù)1", "參數(shù)2" ...]

    • 參數(shù)列表格式:CMD ["參數(shù)1", "參數(shù)2", ...]。在指定了 ENTRYPOINT 指令后,用 CMD指定具體的參數(shù)。

  • Docker 不是虛擬機,容器就是進程。既然是進程,那么在啟動容器的時候,需要指定所運行的程序及參數(shù)。CMD 指令就是用于指定默認(rèn)的容器主進程啟動命令的。

ENTRYPOINT 入口點
  • ENTRYPOINT 的目的和 CMD 一樣,都是在指定容器啟動程序及參數(shù)。ENTRYPOINT 在運行時也可以替代,不過比 CMD 要略顯繁瑣,需要通過 docker run 的參數(shù) --entrypoint 來指定。

  • 當(dāng)指定了 ENTRYPOINT 后,CMD 的含義就發(fā)生了改變,不再是直接地運行其命令,而是將 CMD 的內(nèi)容作為參數(shù)傳給 ENTRYPOINT 指令,換句話說實際執(zhí)行時,將變?yōu)椋?/p>

    <ENTRYPOINT> "<CMD>"


ENV 設(shè)置環(huán)境變量
  • 格式有兩種:

    • ENV <key> <value>

    • ENV <key1>=<value1> <key2>=<value2>

  • 這個指令很簡單,就是設(shè)置環(huán)境變量而已,無論是后面的其他指令,如 RUN,還是運行時的應(yīng)用,都可以直接使用這里定義的環(huán)境變量。

    ENV VERSION=1.0 DEBUG=on NAME="Happy Feet"
    $VERSION  # 使用環(huán)境變量


  • 下列指令可以支持環(huán)境變量展開:ADD、COPY、ENV、EXPOSE、LABEL、USER、WORKDIR、VOLUME、STOPSIGNAL、ONBUILD。

ARG 構(gòu)建參數(shù)
  • 格式:

    • ARG <參數(shù)名>[=<默認(rèn)值>]

  • 構(gòu)建參數(shù)和 ENV 的效果一樣,都是設(shè)置環(huán)境變量。所不同的是,ARG 所設(shè)置的構(gòu)建環(huán)境的環(huán)境變量,在將來容器運行時是不會存在這些環(huán)境變量的。但是不要因此就使用 ARG 保存密碼之類的信息,因為 docker history 還是可以看到所有值的。

  • Dockerfile 中的 ARG 指令是定義參數(shù)名稱,以及定義其默認(rèn)值。該默認(rèn)值可以在構(gòu)建命令 docker build 中用 --build-arg <參數(shù)名>=<值>來覆蓋。

VOLUME 定義匿名卷
  • 格式:

    • VOLUME ["<路徑1>", "<路徑2>" ...]

    • VOLUME <路徑>

  • 容器運行時應(yīng)該盡量保持容器存儲層不發(fā)生寫操作,對于數(shù)據(jù)庫類需要保存動態(tài)數(shù)據(jù)的應(yīng)用,其數(shù)據(jù)庫文件應(yīng)該保存于劵(volume)中,為了防止運行時用戶忘記將動態(tài)文件所保存目錄掛在為卷,在 Dockerfile 中,我們可以實現(xiàn)指定某些目錄掛在為匿名卷,這樣在運行時如果用戶不指定掛載,其應(yīng)用也可以正常運行,不會向容器存儲層寫入大量數(shù)據(jù)。

    VOLUME /data


  • 這里的 /data 目錄就會在運行時自動掛載為匿名卷,任何向 /data 中寫入的信息都不會記錄進容器存儲層,從而保證了容器存儲層的無狀態(tài)化。當(dāng)然,運行時可以覆蓋這個掛載位置。比如:

    docker run -d -v mydata:/data xxxx


EXPOST 聲明端口
  • 格式為:EXPOSE <端口1> [<端口2>...]

  • EXPOSE 指令是聲明運行時容器提供服務(wù)端口,這只是一個聲明,在運行時并不會因為這個聲明應(yīng)用就會開啟這個服務(wù)的應(yīng)用。

  • 在 Dockerfile 中寫入這樣的聲明有兩個好處:

    • 是幫助鏡像使用者理解這個鏡像服務(wù)的守護端口,以方便配置映射。

    • 在運行時使隨機端口映射時,也就是 docker run -P 時,會自動隨機映射 EXPOST 端口。

WORKDIR 指定工作目錄
  • 格式為:WORKDIR <工作目錄路徑>

  • 使用 WORKDIR 指令可以來指定工作目錄(或者稱為當(dāng)前目錄),以后各層的當(dāng)前目錄就被被改為指定的目錄,如果目錄不存在,WORKDIR 會幫你建立目錄。

  • 之前提到一些初學(xué)者常犯的錯誤把 Dockerfile 等同于 Shell 腳本來書寫,這種錯誤的理解還可能會導(dǎo)致出現(xiàn)下面這樣的錯誤:

    RUN cd /app
    RUN echo "hello" > world.txt


  • 如果經(jīng)這個 Dockerfile 進行構(gòu)建鏡像運行后,會發(fā)現(xiàn)找不到 /app/world.txt。

  • 原因:

    • 在 Shell 中,連續(xù)兩行是同一個進程執(zhí)行環(huán)境,因此,前一個命令修改的內(nèi)存狀態(tài),會直接影響后一個命令。

    • 而在 Dockerfile 中,這兩行 RUN 命令的執(zhí)行環(huán)境根本不同,是兩個完全不同的容器。這就是對 Dockerfile 構(gòu)建分層存儲的概念不了解所導(dǎo)致的錯誤。

    • 每個 RUN 都是啟動一個容器、執(zhí)行命令、然后提交存儲層文件變更。

    • 第一層 RUN cd /app 的執(zhí)行僅僅是當(dāng)前進程的工作目錄變更 ,一個內(nèi)存上的變化而已,而結(jié)果不會造成任何文件變更。而到第二層的時候,啟動的是一個全新的容器,跟第一層的容器完全沒關(guān)系,自然不可能繼承前一層構(gòu)建中的內(nèi)存變化。

  • 如果需要改變以后各層的工作目錄的位置,那么應(yīng)該使用 WORKDIR 指令。

USER 指定當(dāng)前用戶
  • 格式為:USER <用戶名>

  • USER 指令和 WORKDIR 相似,都是改變環(huán)境狀態(tài)并影響以后的層。WORKDIR 是改變工作目錄,USER 則是改變之后層的執(zhí)行 RUN、CMD 以及 ENTRYPOINT 這類命令的身份。

  • 當(dāng)然,和 WORKDIR 一樣,USER 只是幫助你切換到指定用戶而已,這個用戶必須是事先建立好的,否則無法切換。

    RUN groupadd -r redis && useradd -r- g redis redis
    USER redis
    RUN ["redis-server"]


HEALTHCHECK 健康檢查
  • 格式:

    • HEALTHCHECK [選項] CMD <命令>:設(shè)置檢查容器健康狀況的命令。

    • HEALTHCHECK NONE:如果基礎(chǔ)鏡像有健康檢查指令,可以屏蔽掉其健康檢查指令。

  • HEALTHCHECK 指令是告訴 Docker 應(yīng)該如何進行判斷容器的狀態(tài)是否正常,這是 Docker 1.12 引入的新指令。通過該指令指定一行命令,用這行命令來判斷容器主進程的服務(wù)狀態(tài)是否還真長,從而比較真實的反應(yīng)容器實際狀態(tài)。

  • 一個鏡像指定了 HEALTHCHECK 指令后,用其啟動容器,初始狀態(tài)會為 starting,在 執(zhí)行健康檢查成功后變?yōu)?healthy,如果連續(xù)一定次數(shù)失敗,則會變?yōu)?unhealthy。

  • HEALTHCHECK 支持下列選項:

    • --interval=<間隔>:兩次健康檢查的間隔,默認(rèn)為 30 秒。

    • --timeout=<時長>:健康檢查命令運行超時時間,如果超過這個時間,本次健康檢查就被視為失敗,默認(rèn) 30 秒。

    • --retries=<次數(shù)>:當(dāng)連續(xù)失敗指定次數(shù)后,則將容器狀態(tài)視為 unhealthy,默認(rèn) 3 次。

  • 為了幫助排障,健康檢查命令的輸出(包括 stdout 以及 stderr)都會被存儲于健康檢查狀態(tài)里,可以用 docker inspect 來查看。

ONBUILD 為他人做衣裳
  • 格式:ONBUILD <其他指令>

  • ONBUILD 是一個特殊的指令,它后面跟的是其他指令,比如 RUN、COPY 等,而這些指令,在當(dāng)前鏡像構(gòu)建時并不會執(zhí)行。只有當(dāng)以當(dāng)前鏡像為基礎(chǔ)鏡像,去構(gòu)建下一級鏡像的時候才會被執(zhí)行。

  • Dockerfile 中的其他指令都是為了定制當(dāng)前鏡像而逐步內(nèi)的,唯有 ONBUILD 是為了幫助別人定制自己而準(zhǔn)備的。

3. 其他鏡像制作方式


docker save 和 docker load
  • Docker 還提供了 docker save 和 docker load 命令,用以將鏡像保存為一個 tar 文件,然后傳輸?shù)搅硪粋€位置上,再加載進來。這是在沒有 Docker Registry 時的做法,現(xiàn)在已經(jīng)不推薦,鏡像遷移應(yīng)該直接使用 Docker Registry,無論是直接使用 Docker Hub,還是使用內(nèi)網(wǎng)私有 Registry 都可以。

  • 例如:保存 nginx 鏡像

    docker save nginx | gzip > nginx-latest.tar.gz


  • 然后我們將 nginx-latest.tar.gz 文件復(fù)制到另一個機器上,再次加載鏡像:

    docekr load -i nginx-latest.tar.gz

“Dockerfile怎么構(gòu)建私有鏡像”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實用文章!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI