一区二区三区三上|欧美在线视频五区|国产午夜无码在线观看视频|亚洲国产裸体网站|无码成年人影视|亚洲AV亚洲AV|成人开心激情五月|欧美性爱内射视频|超碰人人干人人上|一区二区无码三区亚洲人区久久精品

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

Dockerfile的最佳實(shí)踐

汽車(chē)電子技術(shù) ? 來(lái)源:程序猿技術(shù)大咖 ? 作者: xcbey0nd ? 2023-01-20 10:59 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

微信截圖_20230105161930.png

隨著應(yīng)用的容器化、上云后,將伴隨著 Docker 鏡像的構(gòu)建,構(gòu)建 Docker 鏡像成為了最基本的一步,其中 Dockerfile 便是用來(lái)構(gòu)建鏡像的一種文本文件,鏡像的優(yōu)劣全靠 Dockerfile 編寫(xiě)的是否合理、合規(guī)。本文將講述編寫(xiě) Dockerfile 的一些最佳實(shí)踐和技巧,讓我們的鏡像更小、更優(yōu)。

1、Docker 鏡像是如何工作的

首先,我們一起回顧下 Docker 鏡像的相關(guān)概念及工作流程吧。

1.1 鏡像

鏡像(image)是一堆只讀層(read-only layer)的統(tǒng)一視角,也許這個(gè)定義有些難以理解,下面的這張圖能夠幫助您理解鏡像的定義。

微信截圖_20230105161930.png

從左邊我們看到了多個(gè)只讀層,它們重疊在一起。除了最下面一層,其它層都會(huì)有一個(gè)指針指向下一層。這些層是 Docker 內(nèi)部的實(shí)現(xiàn)細(xì)節(jié),并且能夠在主機(jī)的文件系統(tǒng)上訪問(wèn)到。統(tǒng)一文件系統(tǒng)技術(shù)能夠?qū)⒉煌膶诱铣梢粋€(gè)文件系統(tǒng),為這些層提供了一個(gè)統(tǒng)一的視角,這樣就隱藏了多層的存在,在用戶的角度看來(lái),只存在一個(gè)文件系統(tǒng)。我們可以在圖片的右邊看到這個(gè)視角的形式。

您可以在您的主機(jī)文件系統(tǒng)上找到有關(guān)這些層的文件。需要注意的是,在一個(gè)運(yùn)行中的容器內(nèi)部,這些層是不可見(jiàn)的。在我的主機(jī)上,我發(fā)現(xiàn)它們存在于 /var/lib/docker/overlay2 目錄下。

1.2 鏡像分層結(jié)構(gòu)

為什么說(shuō)是鏡像分層結(jié)構(gòu),因?yàn)?Docker 鏡像是以層來(lái)組織的,可以通過(guò)命令 docker image inspect 或者 docker inspect 來(lái)查看鏡像包含哪些層。

例如,鏡像 busybox :

xcbeyond@xcbeyonddeMacBook-Pro ~ % docker inspect busybox
[
    {
        "Id": "sha256:3c277069c6ae3f3572998e727b973ff7418c3962b9403de4b3a3f8624399b8fa",
        "RepoTags": [
            "busybox:latest"
        ],
        "RepoDigests": [
            "busybox@sha256:d2b53584f580310186df7a2055ce3ff83cc0df6caacf1e3489bff8cf5d0af5d8"
        ],
        "Parent": "",
        "Comment": "",
        "Created": "2022-04-14T00:39:25.923517152Z",
        "Container": "39aaf4eecc48824531078c316f5b16e97549417e07c8f90b26ae16053111ea57",
        "ContainerConfig": {
            "Hostname": "39aaf4eecc48",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
            ],
            "Cmd": [
                "/bin/sh",
                "-c",
                "#(nop) ",
                "CMD [\"sh\"]"
            ],
            "Image": "sha256:3289bc85dc0eba79657979661460c7f6f97688ad8a4f93174e0cabdd6b09a365",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": {}
        },
        "DockerVersion": "20.10.12",
        "Author": "",
        "Config": {
            "Hostname": "",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
            ],
            "Cmd": [
                "sh"
            ],
            "Image": "sha256:3289bc85dc0eba79657979661460c7f6f97688ad8a4f93174e0cabdd6b09a365",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": null
        },
        "Architecture": "arm64",
        "Variant": "v8",
        "Os": "linux",
        "Size": 1411540,
        "VirtualSize": 1411540,
        "GraphDriver": {
            "Data": {
                "MergedDir": "/var/lib/docker/overlay2/e89181e7cadd3a6ee49f66bae34fed369621a1a5cfbe0003ce4621d0eec020e6/merged",
                "UpperDir": "/var/lib/docker/overlay2/e89181e7cadd3a6ee49f66bae34fed369621a1a5cfbe0003ce4621d0eec020e6/diff",
                "WorkDir": "/var/lib/docker/overlay2/e89181e7cadd3a6ee49f66bae34fed369621a1a5cfbe0003ce4621d0eec020e6/work"
            },
            "Name": "overlay2"
        },
        "RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:31a5597e16d3c5adaaf5826162216e256126d2fbf1beaa2b6c45c1822a2b9ca3"
            ]
        },
        "Metadata": {
            "LastTagTime": "0001-01-01T00:00:00Z"
        }
    }
]

其中,RootFS 就是鏡像 busybox:latest 的鏡像層,只有一層,這層數(shù)據(jù)是存儲(chǔ)在宿主機(jī)哪里的呢?動(dòng)手實(shí)踐的同學(xué)會(huì)在上面的輸出中看到一個(gè)叫做 GraphDriver 的字段內(nèi)容如下:

"GraphDriver": {
            "Data": {
                "MergedDir": "/var/lib/docker/overlay2/e89181e7cadd3a6ee49f66bae34fed369621a1a5cfbe0003ce4621d0eec020e6/merged",
                "UpperDir": "/var/lib/docker/overlay2/e89181e7cadd3a6ee49f66bae34fed369621a1a5cfbe0003ce4621d0eec020e6/diff",
                "WorkDir": "/var/lib/docker/overlay2/e89181e7cadd3a6ee49f66bae34fed369621a1a5cfbe0003ce4621d0eec020e6/work"
            },
            "Name": "overlay2"
        }

GraphDriver 負(fù)責(zé)鏡像本地的管理和存儲(chǔ)以及運(yùn)行中的容器生成鏡像等工作,可以將 GraphDriver 理解成鏡像管理引擎,我們這里的例子對(duì)應(yīng)的引擎名字是 overlay2(overlay 的優(yōu)化版本)。除了 overlay 之外,Docker 的 GraphDriver 還支持 btrfs、aufs、devicemapper、vfs 等。

我們可以看到其中的 Data 包含了多個(gè)部分,這個(gè)對(duì)應(yīng) OverlayFS 的鏡像組織形式,雖然我們上面的例子中的 busybox 鏡像只有一層,但是正常情況下很多鏡像都是由多層組成的。

1.3 Dockerfile、鏡像、容器間的關(guān)系

Dockerfile 是軟件的原材料,Docker 鏡像是軟件的交付品,而 Docker 容器則可以認(rèn)為是軟件的運(yùn)行態(tài)。從應(yīng)用軟件的角度來(lái)看,Dockerfile、Docker 鏡像與 Docker 容器分別代表軟件的三個(gè)不同階段,Dockerfile 面向開(kāi)發(fā),Docker 鏡像成為交付標(biāo)準(zhǔn),Docker 容器則涉及部署與運(yùn)維,三者缺一不可,合力充當(dāng) Docker 體系的基石。

簡(jiǎn)單來(lái)講,Dockerfile 構(gòu)建出 Docker鏡像,通過(guò) Docker 鏡像運(yùn)行Docker容器。

我們可以從 Docker 容器的角度,來(lái)反推三者的關(guān)系,如下圖:

微信截圖_20230105161930.png

2、Dockerfile

Dockerfile 是一個(gè)用來(lái)構(gòu)建鏡像的文本文件,文本內(nèi)容包含了一條條構(gòu)建鏡像所需的指令和說(shuō)明,它是構(gòu)建鏡像的關(guān)鍵。

一個(gè) Docker 鏡像包含了很多只讀層,每一層都由一個(gè) Dockerfile 指令構(gòu)成,這些層堆疊在一起,每一層都是前一層變化的增量。例如:

FROM ubuntu:18.04COPY . /appRUN make /appCMD python /app/app.py

每條指令都會(huì)創(chuàng)建一層:

  • FROM:從 ubuntu:18.04 Docker 鏡像創(chuàng)建了一層,也作為基礎(chǔ)鏡像層。
  • COPY:從 Docker 客戶端的當(dāng)前目錄添加文件。
  • RUN:執(zhí)行 make 命令.
  • CMD:指定要在容器中運(yùn)行的命令。

上述就是一個(gè)簡(jiǎn)單的 Dockerfile 文件,再通過(guò) docker build -t 命令便可直接構(gòu)建出鏡像。

在這里就不過(guò)多介紹 Dockerfile 的各個(gè)指令的用法,更多更詳細(xì)的可參考:Dockerfile reference

3、Dockerfile 的最佳實(shí)踐

本節(jié)將列舉出一些最佳實(shí)踐技巧,來(lái)幫助我們更好的寫(xiě)好 Dockerfile。

3.1 盡可能使用官方鏡像作為基礎(chǔ)鏡像

Docker 鏡像是基于基礎(chǔ)鏡像構(gòu)建而來(lái),因此選擇的基礎(chǔ)鏡像越恰當(dāng),我們要做的底層工作就越少。比如,如果構(gòu)建一個(gè) Java 應(yīng)用鏡像,選擇一個(gè) openjdk 鏡像作為基礎(chǔ)比選擇一個(gè) alpine 鏡像更簡(jiǎn)單。

盡可能使用當(dāng)前的官方鏡像作為基礎(chǔ)鏡像,無(wú)論是從鏡像大小,還是安全性來(lái)講,都是比較可靠的。

下面的一些鏡像,可根據(jù)使用場(chǎng)景來(lái)選擇合適的基礎(chǔ)鏡像:

鏡像名稱 大小 說(shuō)明和使用場(chǎng)景
busybox 754.7 KB 一個(gè)超級(jí)簡(jiǎn)化版嵌入式 Linux 系統(tǒng)。臨時(shí)測(cè)試用。
alpine 2.68 MB 一個(gè)面向安全的、輕量級(jí)的Linux系統(tǒng),基于musl libc 和 busybox。主要用于測(cè)試,也可用于生產(chǎn)環(huán)境。
centos 79.65 MB 主要用于生產(chǎn)環(huán)境,支持CentOS/Red Hat,常用于追求穩(wěn)定性的企業(yè)應(yīng)用。
ubuntu 29.01 MB 主要用于生產(chǎn)環(huán)境,常用于人工智能計(jì)算和企業(yè)應(yīng)用。
debian 52.4 MB 主要用于生產(chǎn)環(huán)境。
openjdk 161.02 MB 主要用于 Java 應(yīng)用。

3.2 減少 Dockerfile 指令的行數(shù)

Dockerfile 中每一行指令都代表了一層,多一層都可能帶來(lái)鏡像大小變大。

因此,在實(shí)際編寫(xiě) Dockerfile 時(shí),可以將同類(lèi)操作放在一起來(lái)避免多行指令,更有助于促進(jìn)層緩存。比如將多條 RUN 操作進(jìn)行合并,并用 ;\\ 或者 && 連接在一起。

(減少指令行數(shù),并不意味著越少越好,需要從改動(dòng)頻繁程度來(lái)決定是否合并為一條指令。)

例如下面的 Dockerfile,會(huì)執(zhí)行多條命令,通過(guò) ;\\ 連接將其用一條 RUN 指令來(lái)完成。

FROM node:6.14LABEL MAINTAINER xcbeyondRUN npm install gitbook-cli -g;\\
   gitbook -V; \\
   npm install svgexport -g --unsafe-permCMD ["/bin/sh"]

3.3 改動(dòng)不頻繁的內(nèi)容往前放

對(duì)于 Docker 鏡像而言,每一層都代表了 Dockerfile 中的一行指令,每一層都是前一層變化的增量。例如一個(gè) Docker 鏡像有ABCD 四層,B 層修改了,那么 BCD 都會(huì)變化。

因此,在編寫(xiě) Dockerfile 時(shí),盡量將改動(dòng)不頻繁的內(nèi)容往前放,即:將系統(tǒng)依賴往前寫(xiě),因?yàn)橄?apt, yum 這些安裝的東西,是很少修改的。然后寫(xiě)應(yīng)用的庫(kù)依賴,比如 pip install,最后 copy 應(yīng)用,編譯應(yīng)用。

例如下面這個(gè) Dockerfile,就會(huì)在每次代碼改變的時(shí)候都重新 Build 大部分層,即使只改了一個(gè)頁(yè)面的標(biāo)題。

FROM python:3.7-buster # copy sourceRUN mkdir -p /opt/appCOPY myapp /opt/app/myapp/WORKDIR /opt/app# install dependencies nginxRUN apt-get update && apt-get install nginxRUN pip install -r requirements.txtRUN chown -R www-data:www-data /opt/app # start serverEXPOSE 8020STOPSIGNAL SIGTERMCMD ["/opt/app/start-server.sh"]

我們可以改成,先安裝 Nginx,再單獨(dú) copy requirements.txt,然后安裝 pip 依賴,最后 copy 應(yīng)用代碼。

FROM python:3.7-buster # install dependencies nginxRUN apt-get update && apt-get install nginxCOPY myapp/requirements.txt /opt/app/myapp/requirements.txtRUN pip install -r requirements.txt # copy sourceRUN mkdir -p /opt/appCOPY myapp /opt/app/myapp/WORKDIR /opt/app RUN chown -R www-data:www-data /opt/app # start serverEXPOSE 8020STOPSIGNAL SIGTERMCMD ["/opt/app/start-server.sh"]

3.4 編譯和運(yùn)行需分離

我們?cè)诰幾g應(yīng)用時(shí)很多時(shí)候會(huì)用到很多編譯工具、編譯環(huán)境,例如:node、Golang 等,但是編譯后,運(yùn)行時(shí)卻不再需要。這樣的編譯環(huán)境往往占用很大,使得鏡像額外變大。

因此,可以將應(yīng)用事先在某個(gè)固定編譯環(huán)境編譯完成,得到編譯后的二進(jìn)制文件,再將其 COPY 到鏡像中即可,這樣鏡像中只包含應(yīng)用的運(yùn)行二進(jìn)制文件。

例如下面這個(gè) Dockerfile,將 Golang 程序編譯好的二進(jìn)制文件 app,構(gòu)建到鏡像中:

FROM alpine:latestLABEL maintainer xcbeyondWORKDIR /appCOPY app /appCMD ["/app/app"]

3.5 刪除不需要的依賴項(xiàng)

Docker 鏡像應(yīng)該盡可能小。在編寫(xiě) Dockerfile 時(shí)僅包含基本內(nèi)容,不要引入無(wú)關(guān)內(nèi)容,從而使得鏡像大小更小、構(gòu)建速度更快,并且減少受攻擊的可能面。

鏡像更小,也更利于存放到鏡像倉(cāng)庫(kù),減少網(wǎng)絡(luò)帶寬開(kāi)銷(xiāo)。

不要安裝應(yīng)用程序?qū)嶋H不使用的任何包、庫(kù)。

3.6 避免憑證構(gòu)建到鏡像

這是最常見(jiàn)和最危險(xiǎn)的 Dockerfile 問(wèn)題之一。在構(gòu)建鏡像過(guò)程中,復(fù)制配置文件可能很誘人,但你切記可能會(huì)引入很大的安全隱患。

在 Dockerfile 中通過(guò) COPY 指令將任何配置文件內(nèi)容都復(fù)制到你的鏡像,并且任何可以訪問(wèn)它的人都可以訪問(wèn)它。如果這個(gè)配置文件中,無(wú)意間包含了數(shù)據(jù)庫(kù)密碼配置,那么你就徹底將這些密碼暴露給了所有使用該鏡像的所有人。

為了避免這類(lèi)問(wèn)題,必須將配置密鑰、敏感數(shù)據(jù)只能提供給具體的容器,而不是提供給構(gòu)建它們的鏡像??墒褂铆h(huán)境變量、掛載卷等方式在容器啟動(dòng)時(shí)注入數(shù)據(jù)。這樣就避免了意外的信息暴露,并確保你的鏡像可跨環(huán)境重復(fù)使用。


感謝您的閱讀,也歡迎您發(fā)表關(guān)于這篇文章的任何建議,關(guān)注我,技術(shù)不迷茫!

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 容器
    +關(guān)注

    關(guān)注

    0

    文章

    511

    瀏覽量

    22458
  • 鏡像
    +關(guān)注

    關(guān)注

    0

    文章

    178

    瀏覽量

    11251
  • Docker
    +關(guān)注

    關(guān)注

    0

    文章

    515

    瀏覽量

    12974
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    C編程最佳實(shí)踐.doc

    C編程最佳實(shí)踐.doc
    發(fā)表于 08-17 14:37

    Dockerfile最佳實(shí)踐

    ”微服務(wù)一條龍“最佳指南-“最佳實(shí)踐”篇:Dockerfile
    發(fā)表于 07-11 16:22

    Dockerfile使用規(guī)則

    Dockerfile編寫(xiě)規(guī)范
    發(fā)表于 08-12 14:30

    變量聲明最佳實(shí)踐?

    所以我們開(kāi)始編寫(xiě)32位和16位代碼,并過(guò)渡到MPLAB X和XC編譯器。我想到的一個(gè)主題是聲明變量的最佳實(shí)踐。常規(guī)IpType。h或類(lèi)型。h pr STDIN?;騃t8或字節(jié)char等任何想法,走哪條路?
    發(fā)表于 09-30 12:01

    虛幻引擎的紋理最佳實(shí)踐

    紋理是游戲不可或缺的一部分。 這是一個(gè)藝術(shù)家可以直接控制的領(lǐng)域,以提高游戲的性能。 本最佳實(shí)踐指南介紹了幾種紋理優(yōu)化,這些優(yōu)化可以幫助您的游戲運(yùn)行得更流暢、看起來(lái)更好。 最佳實(shí)踐系列指
    發(fā)表于 08-28 06:39

    MySql5.6性能優(yōu)化最佳實(shí)踐

    MySql5.6性能優(yōu)化最佳實(shí)踐
    發(fā)表于 09-08 08:47 ?13次下載
    MySql5.6性能優(yōu)化<b class='flag-5'>最佳</b><b class='flag-5'>實(shí)踐</b>

    全面詳解Dockerfile文件

    Docker 可以通過(guò)讀取 Dockerfile 中的指令自動(dòng)構(gòu)建鏡像。Dockerfile 是一個(gè)文本文檔,其中包含了用戶創(chuàng)建鏡像的所有命令和說(shuō)明。 一、 變量 變量用
    的頭像 發(fā)表于 09-22 15:38 ?2122次閱讀

    DevOps最佳實(shí)踐

      遵循上述最佳實(shí)踐,組織可以開(kāi)發(fā)和自動(dòng)化其解決方案的交付過(guò)程,以有效地實(shí)現(xiàn)其業(yè)務(wù)目標(biāo)。
    的頭像 發(fā)表于 08-15 14:41 ?1190次閱讀

    鏡像構(gòu)建Dockerfile的介紹

    Dockerfile 是一個(gè)用來(lái)構(gòu)建鏡像的文本文件,文本內(nèi)容包含了一條條構(gòu)建鏡像所需的指令和說(shuō)明。
    的頭像 發(fā)表于 09-06 09:36 ?1458次閱讀

    圖像傳感器處理和最佳實(shí)踐

    圖像傳感器處理和最佳實(shí)踐
    發(fā)表于 11-15 20:30 ?0次下載
    圖像傳感器處理和<b class='flag-5'>最佳</b><b class='flag-5'>實(shí)踐</b>

    SAN管理最佳實(shí)踐指南

    電子發(fā)燒友網(wǎng)站提供《SAN管理最佳實(shí)踐指南.pdf》資料免費(fèi)下載
    發(fā)表于 08-29 09:20 ?0次下載
    SAN管理<b class='flag-5'>最佳</b><b class='flag-5'>實(shí)踐</b>指南

    SAN設(shè)計(jì)和最佳實(shí)踐指南

    電子發(fā)燒友網(wǎng)站提供《SAN設(shè)計(jì)和最佳實(shí)踐指南.pdf》資料免費(fèi)下載
    發(fā)表于 09-01 11:02 ?2次下載
    SAN設(shè)計(jì)和<b class='flag-5'>最佳</b><b class='flag-5'>實(shí)踐</b>指南

    Windows 10遷移的最佳實(shí)踐

    電子發(fā)燒友網(wǎng)站提供《Windows 10遷移的最佳實(shí)踐.pdf》資料免費(fèi)下載
    發(fā)表于 09-07 15:37 ?0次下載
    Windows 10遷移的<b class='flag-5'>最佳</b><b class='flag-5'>實(shí)踐</b>

    Dockerfile定義Docker鏡像的構(gòu)建過(guò)程

    了解Dockerfile Dockerfile 是一個(gè)文本文件,用于定義 Docker 鏡像的構(gòu)建過(guò)程。它以指令的形式描述了如何構(gòu)建鏡像,從基礎(chǔ)鏡像開(kāi)始逐步添加配置、文件和依賴,最終形成我們所需
    的頭像 發(fā)表于 09-30 10:22 ?2928次閱讀

    如何使用dockerfile創(chuàng)建鏡像

    Docker是一個(gè)開(kāi)源的平臺(tái),用于快速構(gòu)建、打包、部署應(yīng)用程序的容器化工具。而Dockerfile是一個(gè)文本文件,包含了一組可自動(dòng)化構(gòu)建Docker鏡像的指令。本文將詳細(xì)介紹
    的頭像 發(fā)表于 11-23 09:52 ?1110次閱讀