dockerfile最佳實(shí)踐,dockerfile 教程
chanong
1 之前寫過一篇文章,分享一些關(guān)于如何優(yōu)化Dickerfile構(gòu)建鏡像的筆記。如果你不太理解,朋友可以幫你糾正。每個(gè)人只有一項(xiàng)真正的責(zé)任。這是關(guān)于尋找你自己。并將其全心全意地記在心里,一生一世,永不止步。所有其他道路都是不完整的,人性的逃亡,懦弱地回歸大眾的理想,隨波逐流,內(nèi)心的恐懼—— Hermann Hesse 《德米安》
2 簡介Docker 提供了兩種常用的定制和構(gòu)建新鏡像的方法。
使用正在運(yùn)行的容器構(gòu)建新鏡像使用Dockerfile 文件在基礎(chǔ)鏡像的基礎(chǔ)上構(gòu)建新鏡像無論使用哪種方法,定制鏡像的原則都是一樣的鏡像層次結(jié)構(gòu)通過設(shè)計(jì)創(chuàng)建讀/寫層并更改配置。重新包裝。
在這里,我將與朋友們分享如何使用Dockerfile 優(yōu)化構(gòu)建自定義鏡像。所謂優(yōu)化也可以理解為一種比較好的構(gòu)建方法。這是有關(guān)如何構(gòu)建第一個(gè)圖像的快速指南。
通過正在運(yùn)行的容器構(gòu)建新映像通常涉及對(duì)正在運(yùn)行的映像執(zhí)行一些預(yù)構(gòu)建的操作。例如,如果您的內(nèi)網(wǎng)環(huán)境沒有依賴庫,則沒有直接的方法來拉取所需的依賴項(xiàng)。通過檢查網(wǎng)絡(luò)環(huán)境中相應(yīng)的依賴關(guān)系來創(chuàng)建依賴基礎(chǔ)映像。
比如我想在內(nèi)網(wǎng)使用Python鏡像,但是內(nèi)網(wǎng)環(huán)境沒有pip源,所以創(chuàng)建鏡像的唯一方法就是下載外部環(huán)境對(duì)應(yīng)的包。
運(yùn)行容器并構(gòu)建新鏡像[root@vms100.liruilongs.github.io]-[~]$docker run -d python python -m http.server 33333009033ff4c0155f81647b857c0bf8975ee750a13d7aa2584638af032aa 請(qǐng)輸入fa758 b 創(chuàng)建容器打包那個(gè)下載相關(guān)依賴并生成鏡像導(dǎo)出
[root@vms100.liruilongs.github.io]-[~]$docker commit bcdd82ca5b48 my-python:latestsha256:cb7c9965c541dfc794f78eb06ae1c4af0c77bb87c92e5e6e768c7770eb61a 5 bb [root@vms100.liruilongs.github.io]-[~]$docker保存my -python:latest -o ./my-python.tar 操作起來有點(diǎn)困難,所以使用Dockerfile 可能會(huì)更方便。
[root@vms100.liruilongs.github.io]-[~]$docker build - FROM python RUN python -m pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple RUN python -m pip install psycopg2 將構(gòu)建上下文發(fā)送到EOFSDocker 守護(hù)進(jìn)程2.048kBStep 1/3 : FROM python --- a5d7930b60ccStep 2/3 : RUN python -m pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple --- 在88140ad45551 上運(yùn)行寫入/root/.config/pip/pip.conf 刪除中間容器88140ad45551 --- df41fddd2cd2 步驟3/3 : RUN python -m pip install psycopg2 --- 在1eddfbf7fa58 上運(yùn)行搜索索引: https://pypi.tuna.tsinghua.edu.cn/simple 收集psycopg2 https://pypi.tuna.tsinghua.edu.cn/packages/89/d6/cd8c46417e0f7a16b4b0fc321f4ab676a5 9250d08fce5b64921897fb07cc/psycopg2-2 .9.5.tar .gz (384 kB)構(gòu)建收集的輪子packages: psycopg2 構(gòu)建psycopg2 的輪子(setup.py): 開始. 14/44f32ab3b3f40f2e9a1a9ab8281a40ff4a911a930121c928b1成功構(gòu)建psycopg2Collected 包安裝: psycopg2.刪除中間容器1edd fbf7fa58 --- 8791cb1dc692S 構(gòu)建成功8 791cb1dc692[root@vms100 .liruilongs.github.io] -[ ~] $ 我忘記添加標(biāo)簽了。在這里手動(dòng)輸入?梢栽跇(gòu)建期間使用-t 命令指定。
[root@vms100.liruilongs.github.io]-[~]$docker 標(biāo)簽8791cb1dc692 my-python:latest[root@vms100.liruilongs.github.io]-[~]$docker 鏡像my-pythonREPOSITORY TAGIMAGE IDCRETED SIZEmy-python 最新8791cb1dc692 8 分鐘前927MBDockerfile 查看構(gòu)建自定義映像的一般步驟
FROM:基礎(chǔ)鏡像RUN:創(chuàng)建鏡像時(shí)可以運(yùn)行多個(gè)命令。每個(gè)命令都有一層。 ADD:復(fù)制文件到鏡像并自動(dòng)解壓(文件類型為: tar.gz或tar.bz2) COPY:復(fù)制文件到鏡像。不要解壓縮。 MAINTAINER:圖像創(chuàng)建者信息EXPOSE:打開端口。 ENV:設(shè)置變量。 WORKDIR:定義容器的默認(rèn)工作目錄。 CMD:容器啟動(dòng)時(shí)執(zhí)行的命令只能包含一個(gè)CMD.ENTRYPOINT:函數(shù),例如: CMD指令被容器用來指定一個(gè)默認(rèn)的可執(zhí)行文件,使容器看起來是一個(gè)單獨(dú)的可執(zhí)行程序。
如果在docker run 命令中聲明了參數(shù),Docker 守護(hù)進(jìn)程將忽略CMD 命令。與CMD 不同,ENTRYPOINT 啟動(dòng)的程序不會(huì)被docker run 命令行上指定的參數(shù)覆蓋,這些命令行參數(shù)會(huì)作為參數(shù)傳遞給ENTRYPOINT 指定的程序。但是,docker run命令的--entrypoint可選參數(shù)可以覆蓋ENTRYPOINT指令中指定的程序Dockfile。如果未使用CMD 指定啟動(dòng)命令,則繼承上一個(gè)映像中的默認(rèn)啟動(dòng)命令。啟動(dòng)CMD容器只有一個(gè)命令:以及根據(jù)Dockerfile生成新鏡像的命令,build創(chuàng)建一個(gè)新鏡像; -t 指定新鏡像的名稱和標(biāo)簽; 指定所在目錄Dockerfile 文件駐留
docker build -t imagename:latest 容器和鏡像之間的主要區(qū)別在于頂層可寫層。所有添加新數(shù)據(jù)或修改現(xiàn)有數(shù)據(jù)的對(duì)容器的寫入都存儲(chǔ)在該可寫層中。當(dāng)刪除容器時(shí),可寫層也會(huì)被刪除;A(chǔ)圖像保持不變。
這里使用的是寫時(shí)復(fù)制技術(shù)(COW),對(duì)于開發(fā)伙伴來說可以結(jié)合享元設(shè)計(jì)模式來理解,對(duì)于運(yùn)維伙伴來說可以結(jié)合Openstack組件Glance來理解。原則。
通俗地說,就是修改時(shí),將數(shù)據(jù)復(fù)制到容器層進(jìn)行修改。添加時(shí)直接添加到容器層,移除時(shí)遮擋圖像層。
Docker 通過閱讀您提供的說明自動(dòng)構(gòu)建鏡像。每個(gè)都遵循特定的格式和指令集在容器映像中創(chuàng)建一個(gè)層。層是堆疊在一起的,每一層與前一層相比都有增量變化。
這里我們以官方鏡像redis:7為例,看看標(biāo)準(zhǔn)的Dockerfile是如何編寫的。您可以看到該圖像是由16 層構(gòu)建的。
[root@vms107.liruilongs.github.io]-[/etc/systemd]$docker History -- human=true redis:7 鏡像創(chuàng)建大小創(chuàng)建帶注釋19c51d4327cf 6周前/bin/sh -c #(nop ) CMD ['redis-server'] 0B 6 周前/bin/sh -c #(nop) EXPOSE 6379 0B 6 周前/bin/sh -c #(nop) ENTRYPOINT ['docker-entry. 0B 6 周前/bin /sh -c #(nop) COPY file:e873a0e3c13001b5… 661B 6 周前/bin/sh -c #(nop) WORKDIR /data 0B 6 周前/bin/sh -c #(nop) VOLUME [/data] 0B 6 周前/bin/sh -c mkdir /data chown redis:redis … 0B 6 周前/bin/sh -c set -eux; SavedAptMark='$(apt-m… 32MB 6 周前/bin/sh -c # ( nop ) ENV REDIS_DOWNLOAD_SHA=06… 0B 6 周前/bin/sh -c #(nop) ENV REDIS_DOWNLOAD_URL=ht… 0B 6 周前/bin/sh -c #(nop) ENV REDIS_VERSION=7.0.8 0B 7 周上一頁/bin /sh -c set -eux; SavedAptMark='$(apt-ma… 4.13MB 7 周前/bin/sh -c #(nop) ENV GOSU_VERSION=1.14 0B 7 周前/bin/sh -c groupadd - r - g 999 redis 用戶… 329kB 7周前/bin/sh -c #(nop) CMD ['bash'] 0B 7周前/bin/sh -c #(nop) ADD file:e2398d0bf516084b2… 80.5MB [ root @ vms107.liruilongs.github.io]-[/etc/systemd]$docker History -- human=true redis:7 | wc -l17 在鏡像構(gòu)建中包含兩個(gè)Dockerfile 文件
基礎(chǔ)形象建設(shè)
FROMScratchADD rootfs.tar.xz /CMD ['bash']reids 構(gòu)建鏡像
當(dāng)您運(yùn)行此映像來創(chuàng)建容器時(shí),它實(shí)際上在其下方的層之上添加了一個(gè)新的可寫層(容器層)。對(duì)正在運(yùn)行的容器所做的所有更改(寫入新文件、修改現(xiàn)有文件、刪除文件等)都會(huì)寫入此可寫容器層。
如您所見,上面的Dockerfile 相當(dāng)大,但我將總結(jié)一些創(chuàng)建它時(shí)需要記住的事項(xiàng)。
3Dockerfiles被編寫并優(yōu)化為使用小型基礎(chǔ)鏡像,在上面的Dockerfile中,基礎(chǔ)鏡像是FROM debian:bullseye-slim、FROMScratch。
Scratch 并不常用,因?yàn)樗且粋(gè)空?qǐng)D像,但用于構(gòu)建最基本的圖像。 debian:bullseye-slim 是Debian 系統(tǒng)bullseye 版本的精簡版鏡像。您可以看到使用的圖像非常小。較小的鏡像可以讓您更快地構(gòu)建、推送和拉取鏡像。它通常更安全,因?yàn)樗鼉H包含運(yùn)行應(yīng)用程序所需的庫和系統(tǒng)依賴項(xiàng)。尤其是在CI/CD 等管道中,大型基礎(chǔ)鏡像在每個(gè)鏈路上都會(huì)消耗時(shí)間,導(dǎo)致管道時(shí)間非常長。鏡像之間的區(qū)別主要在于底層操作系統(tǒng)
圖片選擇類型官方圖片:官方圖片(標(biāo)準(zhǔn)圖片)是通常由官方控制的圖片,是正確的選擇,但可能不是最好的選擇。該鏡像基于最新穩(wěn)定的Debian操作系統(tǒng)版本,使用上述Dockerfile構(gòu)建的鏡像是redis:7的官方鏡像。
Debian(bullseye/buster/stretch/jessie):各種Debian Linux 發(fā)行版鏡像,jessie(8.0)、stretch(9.0) 是舊版本,buster(10.0)、bullseye(11.0) 是新版本
修身:修身版。通常,會(huì)安裝運(yùn)行特定工具所需的最少軟件包。
alpine:專門為容器內(nèi)部使用而構(gòu)建的操作系統(tǒng),基于Alpine Linux 項(xiàng)目。與Debian 相比,Alpine 要小得多,但有時(shí)區(qū)和兼容性問題需要考慮。
Scratch: 顯式空?qǐng)D像,尤其是“從頭開始”構(gòu)建圖像時(shí)。
選擇最小基礎(chǔ)鏡像時(shí),盡量避免安裝不必要的軟件包。
當(dāng)你運(yùn)行指令鏈時(shí),可以清楚地看到上面Dockerfile中的RUN指令相當(dāng)長。
這是因?yàn)槊織l指令都會(huì)創(chuàng)建一個(gè)可緩存單元并構(gòu)建一個(gè)新的中間圖像層。因此,您可以通過將所有命令鏈接在一起來避免過多的層。另外,避免將太多可緩存的RUN 命令鏈接在一起。這會(huì)創(chuàng)建一個(gè)大的緩存并最終導(dǎo)致緩存爆裂。
RUN set -eux; \ \savedAptMark='$(apt-mark showmanual)'; \ apt-get update; \ apt-get install -y --no-install-recommends \ ca-certificates \ wget \ \ dpkg-dev \ gcc \ libc6-dev \ libssl-dev \ make \ ; \ rm -rf /var/lib/apt/lists/*; \ \ wget -O redis.tar.gz '$REDIS_DOWNLOAD_URL'; \ ..修改指令放在最后Dockerfile 描述要多次構(gòu)建,每層往往需要時(shí)間來構(gòu)建,但是為了加快后續(xù)構(gòu)建的速度當(dāng)Docker 在構(gòu)建一層時(shí)自動(dòng)緩存每一層時(shí),緩存如果對(duì)應(yīng)層的指令和之前的指令沒有改變就直接使用。當(dāng)修改某個(gè)步驟的相應(yīng)指令時(shí),緩存不僅對(duì)于該特定步驟而且對(duì)于所有后續(xù)步驟都無效。
因此,始終將最常更改的指令放在最后。提高構(gòu)建速度。
FROM python:3.9-slimWORKDIR /appCOPYrequirements.txt .RUN pip install -r /requirements.txtCOPY app.py . 優(yōu)先使用數(shù)組而不是字符串語法最終的進(jìn)程啟動(dòng)命令可以用兩種不同的方式編寫。
數(shù)組:ENTRYPOINT ['python','-m','http.server','33333'] 字符串:ENTRYPOINT 'python -m http.server 33333' 首選數(shù)組格式。這是因?yàn)槭褂米址袷綍?huì)導(dǎo)致Docker 使用bash 運(yùn)行進(jìn)程,而bash 無法正確處理信號(hào)。大多數(shù)shell 不處理子進(jìn)程中的信號(hào),因此如果使用shell 格式,CTRL-C(生成SIGTERM)可能無法停止子進(jìn)程。
如果您有多個(gè)步驟在COPY 而不是ADD 上下文中使用不同的文件,請(qǐng)單獨(dú)復(fù)制它們,而不是一次全部復(fù)制。這只會(huì)使每個(gè)步驟的構(gòu)建緩存無效并強(qiáng)制該步驟重新運(yùn)行,特別是在所需文件發(fā)生更改的情況下。
COPYrequirements.txt /tmp/RUN pip install --requirement /tmp/requirements.txtCOPY . /tmp/使用.dockerignore。 dockerignore 文件類似于git 項(xiàng)目中的.gitignore。不同之處在于.dockerignore 適用于構(gòu)建docker 鏡像。它位于docker 構(gòu)建上下文的根目錄中,用于忽略不需要包含在映像中的文件。
.dockerignore文件的寫法與.gitignore類似,支持正則和通配符,具體規(guī)則如下:
每行一個(gè)條目;以# 開頭的行被注釋掉;空行被忽略;構(gòu)建上下文路徑是所有文件的根路徑;gitscriptstatic!README*.md 是從stdin 構(gòu)建的stdin Docker 引擎通過管道本地構(gòu)建鏡像或遠(yuǎn)程構(gòu)建上下文Dockerfile
當(dāng)Dockerfile 不需要將文件復(fù)制到映像(COPY/ADD 將失。⿻r(shí),省略構(gòu)建上下文非常有用,并且由于沒有文件發(fā)送到Docker 守護(hù)進(jìn)程,因此可以加快構(gòu)建速度。適合簡單的圖像構(gòu)建
[root@vms107.liruilongs.github.io]-[/etc/systemd]$docker build - FROM Busybox RUN echo 'hello world' 將構(gòu)建上下文發(fā)送到EOFSDocker 守護(hù)進(jìn)程2.048kBStep 1/2 : FROM Busyboxlatest: 從中拉取Library/busybox5cc84ad355aa: Pull CompleteDigest: sha256:5acba83a746c7608ed544dc1533b87c737a0b0fb730301639a0179f9344b1678Status: Busybox : 下載最新的新鏡像--- beae1 73ccac6 Step 2/2 : RUN echo 'hello world' --- 在c56fb8343c72hello world 上運(yùn)行刪除中間容器c56fb8343c72 -- - 95bc7e44435395bc7e444353 構(gòu)建成功[root @vms107.liruilongs.github.io]-[/etc/systemd]$ 利用多階段構(gòu)建多階段構(gòu)建很難減少數(shù)量通過利用構(gòu)建緩存,您可以顯著減小最終映像的大小。中間層和文件。例如,讓我們看一下:
FROM golang:1.18-alpine AS prebuild# 安裝project所需工具RUN go get github.com/golang/dep/cmd/depCOPY Gopkg.lock Gopkg.toml /go/src/project/WORKDIR /go/src/project/RUN go build -o /bin/project# 這將創(chuàng)建一個(gè)單層圖像。 FROMScratchCOPY --from=prebuild /bin/project /bin/projectENTRYPOINT ['/bin/project'] 可以使用多個(gè)語句。每個(gè)指令都可以使用不同的基礎(chǔ),并且每個(gè)指令都會(huì)啟動(dòng)構(gòu)建的新階段。您可以有選擇地將工件從一個(gè)階段復(fù)制到另一個(gè)階段,將您不想要的所有內(nèi)容留在最終圖像中。
#syntax=docker/dockerfile:1.4FROM … AS build1COPY from=app1 . /srcFROM … AS build2COPY from=app2 . /srcFROM …COPY from=build1 /out/app1 /bin/COPY from=build2 /out/app2 /bin/4 博客文章部分內(nèi)容引用,文中引用鏈接內(nèi)容版權(quán)歸原作者所有,如有侵權(quán),敬請(qǐng)告知。
https://www.docker.com/
https://docs.docker.com/engine/reference/builder/
https://www.docker.com/blog/dockerfiles-now-support-multiple-build-contexts/
https://blog.devgenius.io/devops-in-k8s-write-dockerfile-efficiently-37eaedf87163
2018-2023 liruilonger@gmail.com,保留所有權(quán)利。署名-非商業(yè)性-相同方式共享(CC BY-NC-SA 4.0)








