如何寫一個最優的Dockerfile

[TOC]html

1. 爲何要優化Dockerfile

咱們若是使用Dockerfile來構建Docker鏡像,若是一不當心就會致使鏡像大小超過1G,這是很是恐怖的。通常也都是好幾百兆。較大的鏡像每每會致使移植,遷移緩慢,部署上線也就慢。
Dockerfile就像代碼同樣須要持續去進行優化。使用下面的幾個優化方案,能夠大幅度的減少鏡像的大小。node

2. 優化方案

2.1 減小鏡像層數

最重要的因素是減小鏡像的層數,這樣能大大減少鏡像的大小;
固然在減小層數和增長層數但能減小編譯時長上,能夠適當衡量。linux

如何寫一個最優的Dockerfile

說明:nginx

  1. docker鏡像能夠看出是分層的,分層方向與Dockerfile相反,自下而上;
  2. docker鏡像每一層是共享的,即同一臺機器中,若是Dockerfile編譯的時候,前面的內容相同,則相應的層是引用相同的,固然內容自Dockerfile中要自上而下相同,有出現不同的層數的時候,後面的層內容都會不一樣,基於這個原理,在沒有任何修改的狀況下,後面的編譯都是使用以前的鏡像緩存;
  3. 一層新的命令造成新的一層,若是涉及磁盤更新,並且沒有在同一層刪除,不管文件是否最後刪除,都會帶到下一層。

基於上面的說明,層數越小,每一層大小越小,鏡像整體就越小。git

如下爲一個示例,其優化原理是相鄰的命令間用&&讓其只造成一層。github

# 基礎鏡像
FROM node:10.16-alpine as builder

# 拷貝靜態資源文件
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

# 啓動參數
CMD [ "http-server", "build", "-p", "80" ]

可是,有種狀況是分層更優的,共目的是爲了減小docker編譯時間,好比:docker

FROM alpine:latest

# command1耗時久,且比較穩定
RUN command1
# command2涉及更新內容頻繁
RUN command2

由於command1耗時久,好比安裝依賴包,而command2更新頻繁,好比代碼修改。這種場景下,若是每次編譯都須要安裝好久的依賴包,這樣體驗很是差,由於安裝依賴包這部分不多有變化,因此若是分開2層,前面安裝依賴包就會使用緩存,這樣編譯就很是快了。npm

2.2 基於更小的鏡像

在保證功能前提下,儘可能使用更小的鏡像。好比使用基於alpine製做的鏡像,或者帶alpine tag的鏡像。
還有使用谷歌Distrolessubuntu

Alpine Linux 是:一個基於 musl libc 和 busybox 的面向安全的輕量級 Linux 發行版。
換句話說,它是一個體積更小也更安全的 Linux 發行版。centos

好比如下示例,選擇帶alpine

FROM node:lts-alpine

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

2.3 在每一層清理產生的垃圾文件或臨時文件

如下整理了經常使用的基礎鏡像的清理命令:

基礎鏡像 清理命令
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/*

仍然是這個示例,如下含有刪除緩存命令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 應用於 docker 鏡像的構建,它存在於 docker 構建上下文的根目錄,用來排除不須要上傳到 docker 服務端的文件或目錄。

docker 在構建鏡像時首先從構建上下文找有沒有 .dockerignore 文件,若是有的話則在上傳上下文到 docker 服務端時忽略掉 .dockerignore 裏面的文件列表。這麼作顯然帶來的好處是:

  • 構建鏡像時能避免不須要的大文件上傳到服務端,從而拖慢構建的速度、網絡帶寬的消耗,減小鏡像體積;
  • 能夠避免構建鏡像時將一些敏感文件及其餘不須要的文件打包到鏡像中,從而提升鏡像的安全性;

.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

# 基礎鏡像
FROM node:10.16-alpine as builder

# 拷貝靜態資源文件
COPY . /app/

# 工做目錄
WORKDIR /app

################# 舊版本使用http-server插件 #####################
# 舊運行命令
#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
#
## 啓動參數
#CMD [ "http-server", "build", "-p", "80" ]
################# 舊版本使用http-server插件 #####################

# 新運行命令
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

# 維護人
LABEL maintainer="ygqygq2"

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

copy --from=builder /app/build .

######################## 使用默認,可沒必要添加 #######################
# 暴露端口
#EXPOSE 80

# 啓動命令及參數
#ENTRYPOINT ["nginx", "-g", "daemon off;"]
######################## 使用默認,可沒必要添加 #######################

關鍵的地方是
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/

相關文章
相關標籤/搜索