日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

dockerfile arg_Dockerfile最佳实践

發布時間:2024/9/30 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 dockerfile arg_Dockerfile最佳实践 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

帆仔

16年入職網易,先后負責過多個重要手游項目;關注自動化、容器、云等方向;

在容器領域,docker 公司提出的容器鏡像已經成為目前容器打包交付的事實標準。構建鏡像需要編寫 Dockerfile,如何編寫一個優雅的 Dockerfile 呢?在 Docker 公司的官方文檔中給出了一篇 ?

Best practices for writing Dockerfiles。

(https://g.126.fm/03ncYHS)

本文在此基礎上做了一些刪減,力圖讓大家在短時間內寫出一份不錯的 Dockerfile。
本文分為三個部分,首先會直接給出一份 Dockerfile 的參考模板,然后說明如和構建高效的鏡像并解釋這個模板這樣組織的原因,最后會補充說明一些編寫過程中的常見問題。

一份簡單的Dockerfile參考模板

docker 官方給出的參考文檔中給出的 Dockerfile 指令接近 20 個,而我們平時在編寫的時候,經常用到的不超過 10 個。因此,這里給出了一份 Dockerfile 的參考模板,幾乎可以覆蓋大部分的使用場景。

FROM?base_image:tag????#?引用基礎鏡像?*必要*

ARG?arg_key[=default_value1]?????#?聲明變量
ENV?env_key=value2?????#?聲明環境變量

#?構建幾乎不變的部分,例如整體的目錄結構,build時依賴的文件和工具包等
COPY?src?dst
RUN?command1?&&?command2?...

WORKDIR?/path/to/work/dir???#?設置工作目錄?

#?構建較少變動的部分,例如應用的依賴的文件、依賴的包等
COPY?src?dst
RUN?command3?&&?command4?...

#?構建經常變動的部分,例如應用的編譯生成
COPY?src?dst
RUN?command5?&&?command6?...

#?容器入口??*必要*
ENTRYPOINT?["/entry.app"]??#?指定容器啟動時默認執行的命令
CMD?["--options"]?#?指定容器啟動時默認命令的默認參數

構建高效鏡像生命周期

容器的一個重要的特點就是能夠快速迭代,因此在容器鏡像迭代的各個環節也應該盡量做到簡潔高效。

1. 鏡像build

  • 精簡 context:每次 build,context 都會復制給 docker daemon,因此要去掉 context 中無關的部分

  • 多層鏡像:如果鏡像很復雜,通常將其分成基礎鏡像(適用于多種應用,內容基本不變的部分)和應用鏡像,應用鏡像通過 FROM 基礎鏡像來減少 build 的步驟

  • 利用構建緩存(build cache):每次在 build 時,docker daemon 會默認從已在緩存中的父鏡像開始,將下一條指令與從該基本鏡像派生的所有子鏡像進行比較,以查看是否其中一個是使用完全相同的指令構建的。如果不是,則緩存無效。因此,為了能夠提高緩存的命中率,在編寫 Dockerfile 時,應該盡量按照變動的頻率來組織(如上文中的模板)

  • 減少 layers:RUN, COPY, ADD 等指令會在 build 時產生對應的 layer,在較舊的 Docker 版本中,需要最小化鏡像中的層數以確保其性能。因此,使用&&來連接多個 RUN 命令是一個常用的方法(如上文中的模板)

  • 使用 multi-stage builds:新特性,后文會詳細介紹

2. 鏡像pull

docker 官方詳細描述了 docker 鏡像和容器在宿主機上的存儲方式:https://docs.docker.com/storage/storagedriver/,簡單來說就是:

  • 鏡像層 ,只讀,使用相同鏡像的多個容器共用一份。鏡像又按照 layers 分層:

    • 每層都有獨立的 ID

    • 不同鏡像如果有相同 ID 的 layer 時,共用一份

  • 容器層,可寫,采用寫時復制,容器在運行時修改的內容會在這一層

根據鏡像的存儲方式,我們也可以加快鏡像的 pull 過程:

  • 多層鏡像:和 build 時的分層鏡像一樣,利用本地已經存儲的基礎鏡像來減少需要 pull 的 size

  • 利用 image layer 復用相同層:和 build 時利用緩存類似,利用本地已經存儲的 layer 來減少需要 pull 的 size

  • 鏡像預熱:提前或空閑時 pull 鏡像

常見問題

1. 注意Dockerfile中的指令是逐條執行,且相互獨立

#?下面這種寫法會報錯,第二個RUN執行時的WORKDIR依舊是原來的目錄,不是/some/dir
RUN?cd?/some/dir
RUN?bash?script.sh

#?改成下面兩種之一
RUN?cd?/some/dir?&&?bash?script.sh
RUN?bash?/some/dir/script.sh

2. 提防“過度”緩存

前文也提到過,Dockerfile 中每條指令逐條執行,且相互獨立。大部分的指令在 build 時會生成對應的一層(layer),并被緩存。這種機制在絕大部分的情況下都工作的很好,但是有時也會產生問題:

#?Dockerfile1
FROM?ubuntu:18.04
RUN?apt-get?update
RUN?apt-get?install?-y?nginx

#?Dockerfile2
FROM?ubuntu:18.04
RUN?apt-get?update
RUN?apt-get?install?-y?nginx?curl

如上,原 Dockerfile1 使用一段時間之后修改成 Dockerfile2(只修改了install這一行)。由于緩存機制(假設之前 build 的緩存還存在),Dockerfile2 在 build 時,update這一行不會真的執行,而是直接拿之前的緩存。此時安裝的 nginx 和 curl 可能就不是當前的最新版本。

#?官方推薦的apt-get使用方式:
RUN?apt-get?update?&&?apt-get?install?-y?\
????curl?\
????nginx=1.16.*?\
????&&?rm?-rf?/var/lib/apt/lists/*

3. ARG與ENV

兩種指令都可以用來定義變量,但是使用上有很多要注意的點:

  • FROM 前的 ARG 只能在 FROM 中使用,如果在 FROM 后也要使用,需要重新聲明

ARG?key=value
FROM?xxx${key}xxxx
ARG?key?#?這里需要再次聲明才能使用
  • ARG 變量的作用范圍是 build 階段 ARG 之后的指令,不會帶入鏡像

  • ENV 環境變量作用范圍是 build 階段 ENV 聲明的指令,并且會編入鏡像,容器運行時也會這些環境變量也生效

  • CMD 和 ENTRYPOINT 中不能使用 ARG 和 ENV 定義的變量

  • 當 ARG 和 ENV 變量同名時(無論是誰先定義),ENV 環境變量的值會覆蓋 ARG 變量

  • ENV 會產生中間層(layer),被編入鏡像,即使使用 unset 也無法去掉,例如:

FROM?alpine
ENV?ADMIN_USER="mark"??#?此時產生了layer
RUN?echo?$ADMIN_USER?>?./mark
RUN?unset?ADMIN_USER?#?使用unset只是去掉了build時的環境變量,但是最終生成的鏡像中還是會有這個變量

#?運行鏡像還是會打印環境變量
docker?run?--rm?test?sh?-c?'echo?$ADMIN_USER'
mark

#?如果想要消除這種影響,可以改成:
FROM?alpine
RUN?export?ADMIN_USER="mark"?\
????&&?echo?$ADMIN_USER?>?./mark?\
????&&?unset?ADMIN_USER
CMD?sh

4. COPY與ADD

兩個指令幾乎相同,當你只想復制本地 context 中的文件到鏡像中時,請無腦用 COPY

COPY 與 ADD 使用時,注意以下規則:

  • 注意文件的屬性,復制時可以同時修改屬主和屬組 COPY/ADD [--chown=:]

  • 如果不清楚目錄與反斜線對這兩個指令的影響,對所有目錄都加上反斜線就比較好理解了,如COPY / /,因為:

    • 是目錄時,是否帶反斜線都只會復制目錄下的所有文件,不會復制目錄本身,如果要復制目錄本身,需要使用``的父目錄

    • 是目錄時,必須帶反斜線才會把文件復制到dest下

  • 必須在 context 下,不能使用../跳出 context

ADD 指令除了 COPY 的所有功能外,還有以下特性,如非必要,盡量少用:

  • 是本地 tar 文件(常見的壓縮格式)時,會自動解包

  • 可以是 url,支持從遠程拉取

5. CMD與ENTRYPOINT

又是一對很類似的指令,使用時需要注意:

  • CMD 單獨使用時,用來指定容器啟動時默認執行的命令

  • ENTRYPOINT 單獨使用時,可以完全取代 CMD

  • ENTRYPOINT 和 CMD 一起使用時,CMD 變成 ENTRYPOINT 的默認參數

  • 推薦使用 ENTRYPOINT/CMD 的 exec 書寫形式:即ENTRYPOINT ["entry.app", "arg"],因為 shell 書寫形式(ENTRYPOINT entry.app arg)會額外啟動 shell 進程

下表列出了 CMD 與 ENTRYPOINT 的各種組合時的效果:

另外,通過在 docker run 最后的添加字段,可以指定 ENTRYPOINT 的實際參數

??#?鏡像?test_entrypoint
??ENTRYPOINT?["./entry.app"]
??CMD?["--help"]

??#?運行?test_entrypoint
??docker?run?test_entrypoint?#?即./entry.app?--help
??#?帶參數運行
??docker?run?test_entrypoint?-a?-t??#?即?./entry.app?-a?-t

6. multi-stage builds

Docker 17.05 之后的版本支持一種新的 build 方式:多階段構建(multi-stage builds)。與傳統方式的區別在與,多階段構建能夠使用多個 FROM 將整個 build 階段分成多個階段:

  • 通過為不同階段命名,可以通過一份 Dockerfile 來管理 debug、test、product 等多種環境的鏡像

  • 通過COPY --from=stage_name,來復制中間 stage 的文件到目標階段,使得最終生成更小的鏡像

例如,上文提到的模板就可以通過多階段構建的方式來優化。假設我們最終只想得到 entry.app 及其運行環境,而不需要它的編譯環境,那么可以通過如下方式優化最終生成的鏡像的大小:

#?使用多階段構建,這里命名一個builder階段,生成編譯后的app
FROM?base_image:tag?AS?builder???

ARG?arg_key[=default_value1]?????#?聲明變量
ENV?env_key=value2?????#?聲明環境變量

#?構建整體的目錄結構,build時依賴的文件和工具包等
COPY?src?dst
RUN?command1?&&?command2?...

WORKDIR?/path/to/work/dir???#?設置工作目錄?

#?構建編譯環境
COPY?src?dst
RUN?command3?&&?command4?...

#?編譯生成entry.app
COPY?src?dst
RUN?compile_entry_app

#?構建最終鏡像的階段,只保留應用和其運行環境,編譯的依賴都不需要
FROM?base_image:tag
COPY?src?dest????#?復制運行環境
WORKDIR?/path/to/work/dir???#?設置工作目錄?
COPY?--from=builder?entry.app?.?#?從builder階段復制app
#?容器入口
ENTRYPOINT?["/entry.app"]??#?指定容器啟動時默認執行的命令
CMD?["--options"]?#?指定容器啟動時默認命令的默認參數

往期精彩

NEW

ceph 部分數據所有副本先后故障的搶救

那些年,CDN 踩過的坑

智能監控中的時間序列預測

使用 d3.js 繪制資源拓撲圖

運維里的人工智能

總結

以上是生活随笔為你收集整理的dockerfile arg_Dockerfile最佳实践的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。