溫馨提示×

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

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

如何寫一個(gè)最優(yōu)的Dockerfile

發(fā)布時(shí)間:2020-07-24 06:02:35 來(lái)源:網(wǎng)絡(luò) 閱讀:313 作者:ygqygq2 欄目:系統(tǒng)運(yùn)維

[TOC]

1. 為什么要優(yōu)化Dockerfile

我們?nèi)绻褂?code>Dockerfile來(lái)構(gòu)建Docker鏡像,如果一不小心就會(huì)導(dǎo)致鏡像大小超過(guò)1G,這是非??植赖摹R话阋捕际呛脦装僬?。較大的鏡像往往會(huì)導(dǎo)致移植,遷移緩慢,部署上線也就慢。
Dockerfile就像代碼一樣需要持續(xù)去進(jìn)行優(yōu)化。使用下面的幾個(gè)優(yōu)化方案,可以大幅度的減小鏡像的大小。

2. 優(yōu)化方案

2.1 減少鏡像層數(shù)

最重要的因素是減少鏡像的層數(shù),這樣能大大減小鏡像的大??;
當(dāng)然在減少層數(shù)和增加層數(shù)但能減少編譯時(shí)長(zhǎng)上,可以適當(dāng)衡量。

如何寫一個(gè)最優(yōu)的Dockerfile

說(shuō)明:

  1. docker鏡像可以看出是分層的,分層方向與Dockerfile相反,自下而上;
  2. docker鏡像每一層是共享的,即同一臺(tái)機(jī)器中,如果Dockerfile編譯的時(shí)候,前面的內(nèi)容相同,則相應(yīng)的層是引用相同的,當(dāng)然內(nèi)容自Dockerfile中要自上而下相同,有出現(xiàn)不一樣的層數(shù)的時(shí)候,后面的層內(nèi)容都會(huì)不同,基于這個(gè)原理,在沒(méi)有任何修改的情況下,后面的編譯都是使用之前的鏡像緩存;
  3. 一層新的命令形成新的一層,如果涉及磁盤更新,而且沒(méi)有在同一層刪除,無(wú)論文件是否最后刪除,都會(huì)帶到下一層。

基于上面的說(shuō)明,層數(shù)越小,每一層大小越小,鏡像總體就越小。

以下為一個(gè)示例,其優(yōu)化原理是相鄰的命令間用&&讓其只形成一層。

# 基礎(chǔ)鏡像
FROM node:10.16-alpine as builder

# 拷貝靜態(tài)資源文件
COPY . /app/

# 工作目錄
WORKDIR /app

RUN yarn config set registry https://registry.npm.taobao.org \
  && yarn config set sass-binary-site http://npm.taobao.org/mirrors/node-sass \
  && yarn global add http-server@0.9.0 \
  && yarn install \
  && yarn build

# 暴露端口
EXPOSE 80

# 啟動(dòng)參數(shù)
CMD [ "http-server", "build", "-p", "80" ]

但是,有種情況是分層更優(yōu)的,共目的是為了減少docker編譯時(shí)間,比如:

FROM alpine:latest

# command1耗時(shí)久,且比較穩(wěn)定
RUN command1
# command2涉及更新內(nèi)容頻繁
RUN command2

因?yàn)?code>command1耗時(shí)久,比如安裝依賴包,而command2更新頻繁,比如代碼修改。這種場(chǎng)景下,如果每次編譯都需要安裝很久的依賴包,這樣體驗(yàn)非常差,因?yàn)榘惭b依賴包這部分很少有變化,所以如果分開2層,前面安裝依賴包就會(huì)使用緩存,這樣編譯就非常快了。

2.2 基于更小的鏡像

在保證功能前提下,盡量使用更小的鏡像。比如使用基于alpine制作的鏡像,或者帶alpine tag的鏡像。
還有使用谷歌Distroless

Alpine Linux 是:一個(gè)基于 musl libc 和 busybox 的面向安全的輕量級(jí) Linux 發(fā)行版。
換句話說(shuō),它是一個(gè)體積更小也更安全的 Linux 發(fā)行版。

比如以下示例,選擇帶alpine

FROM node:lts-alpine

RUN apk --no-cache add ca-certificates curl git \
  && rm -rf /var/cache/apk/* \
  && update-ca-certificates

2.3 在每一層清理產(chǎn)生的垃圾文件或臨時(shí)文件

以下整理了常用的基礎(chǔ)鏡像的清理命令:

基礎(chǔ)鏡像 清理命令
alpine rm -rf /var/cache/apk/*
centos/oraclelinux rm -rf /var/cache/yum/*
ubuntu/debian apt autoclean -y && apt autoremove -y && rm -rf /var/lib/apt/*

仍然是這個(gè)示例,以下含有刪除緩存命令rm -rf /var/cache/apk/*

FROM node:lts-alpine

RUN apk --no-cache add ca-certificates curl git \
  && rm -rf /var/cache/apk/* \
  && update-ca-certificates

2.4 使用.dockerignore

.dockerignore 文件的作用類似于 git 工程中的 .gitignore 。不同的是 .dockerignore 應(yīng)用于 docker 鏡像的構(gòu)建,它存在于 docker 構(gòu)建上下文的根目錄,用來(lái)排除不需要上傳到 docker 服務(wù)端的文件或目錄。

docker 在構(gòu)建鏡像時(shí)首先從構(gòu)建上下文找有沒(méi)有 .dockerignore 文件,如果有的話則在上傳上下文到 docker 服務(wù)端時(shí)忽略掉 .dockerignore 里面的文件列表。這么做顯然帶來(lái)的好處是:

  • 構(gòu)建鏡像時(shí)能避免不需要的大文件上傳到服務(wù)端,從而拖慢構(gòu)建的速度、網(wǎng)絡(luò)帶寬的消耗,減少鏡像體積;
  • 可以避免構(gòu)建鏡像時(shí)將一些敏感文件及其他不需要的文件打包到鏡像中,從而提高鏡像的安全性;

.dockerignore 示例:

.codeclimate
.gitlab-ci.yml
Dockerfile
.git
.gitignore
ci

使用方法具體參考:
https://docs.docker.com/engine/reference/builder/#dockerignore-file

2.5 使用multi-stage功能

前提:docker版本17.05或更高

示例Dockerfile

# 基礎(chǔ)鏡像
FROM node:10.16-alpine as builder

# 拷貝靜態(tài)資源文件
COPY . /app/

# 工作目錄
WORKDIR /app

################# 舊版本使用http-server插件 #####################
# 舊運(yùn)行命令
#RUN yarn config set registry https://registry.npm.taobao.org \
#  && yarn config set sass-binary-site http://npm.taobao.org/mirrors/node-sass \
#  && yarn global add http-server@0.9.0 \
#  && yarn install \
#  && yarn build

## 暴露端口
#EXPOSE 80
#
## 啟動(dòng)參數(shù)
#CMD [ "http-server", "build", "-p", "80" ]
################# 舊版本使用http-server插件 #####################

# 新運(yùn)行命令
RUN yarn config set registry https://registry.npm.taobao.org \
  && yarn config set sass-binary-site http://npm.taobao.org/mirrors/node-sass \
  && yarn install \
  && yarn build

FROM nginx:1.17.5-alpine

# 維護(hù)人
LABEL maintainer="ygqygq2"

# 工作目錄
WORKDIR /usr/share/nginx/html

copy --from=builder /app/build .

######################## 使用默認(rèn),可不必添加 #######################
# 暴露端口
#EXPOSE 80

# 啟動(dòng)命令及參數(shù)
#ENTRYPOINT ["nginx", "-g", "daemon off;"]
######################## 使用默認(rèn),可不必添加 #######################

關(guān)鍵的地方是
FROM image:tag AS name
copy --from name /path/ /path/

參考資料:
[1] https://docs.docker.com/engine/reference/builder/#dockerignore-file
[2] https://docs.docker.com/develop/develop-images/multistage-build/

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

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

AI