精簡Docker鏡像的幾個方法


使用更精簡的鏡像

常用的Linux系統鏡像一般有 Debian、Ubuntu、CentOS和Alpine,其中Alpine是面向安全的輕量級Linux發行版本。Docker的Alpine鏡像僅有不到5M的大小,非常適合作為基礎鏡像。

Alpine使用ash這個輕量級的shell,而上述其他Linux發行版默認使用bash作為其shell。另外,Aline使用apk作為其包管理工具,軟件安裝包的名字可能與其他發行版不同,可以在https://pkgs.alpinelinux.org/packages搜索確定安裝包的名字。

 

壓縮RUN語句&清理不必要的文件和程序

壓縮RUN語句

Docker鏡像是分層的,Dockerfile中的每一條RUN語句都會增加一層鏡像,導致鏡像非常臃腫。多個RUN命令應盡量用一條RUN命令完成,用“&&”和“\”串聯每一條命令。

比如下面的兩條RUN命令

RUN apt-get update RUN apt-get install -y git

可以壓縮成一條

RUN apt-get update && \ apt-get install -y git

清理不必要的程序和文件

另外,在用apt安裝軟件包時,我們可以使用--no-install-recommends參數來避免安裝非必須的文件,從而減小鏡像的體積;安裝完成之后rm -rf /var/lib/apt/lists/* ,清理apt緩存,進一步縮小鏡像。

RUN apt-get update && \ apt-get install -y --no-install-recommends git && \ rm -rf /var/lib/apt/lists/*

使用apk安裝軟件包時,我們可以使用--no-cache參數達到同樣的目的,或者在安裝完軟件包后使用rm -rf /var/cache/apk/*。

RUN apk -U --no-cache add git 或者 RUN apk -U add git && \ rm -rf /var/cache/apk/*

要注意的是,安裝軟件包和清理緩存需要在同一條RUN語句中執行,因為每一條RUN語句都會增加一層,這樣把apt-get和rm -rf /var/lib/apt/lists/*分開的話,就不能清理apt-get產生的緩存;apk也是同理。

# 正確
RUN apt-get update && \
    apt-get install -y --no-install-recommends git && \
    rm -rf /var/lib/apt/lists/*
# 錯誤
RUN apt-get update && \
    apt-get install -y --no-install-recommends git && \
RUN rm -rf /var/lib/apt/lists/*

 在構建鏡像的時候,我們在編譯階段可能會下載一些依賴的頭文件和用於編譯的程序,或者其他相關程序(比如git),這些在程序運行時完全不需要,可以刪除掉。

RUN apt-get update && \
  apt-get install -y git make gcc libssl-dev && \
……
# 編譯完成后,清理編譯環境和跟程序運行無關的軟件
  apt-get purge -y git make gcc libssl-dev
……

 

多段構建

從Docker 17.05開始,一個Dockerfile文件可以使用多條FROM語句,每條FROM語句可以使用不同的鏡像。這樣我們可以把Docker的構建階段分層多個階段,以兩個FROM語句為例,我們可以使用一個鏡像編譯我們的程序;另一個鏡像使用更精簡的鏡像,拷貝上一階段的編譯的結果。

在使用FROM語句時,我們可以用AS為不同的鏡像起別名,方便后續操作。用COPY命令從其他鏡像拷貝文件時,我們可以用--from=alias src dst從別的階段復制文件;如果沒有為鏡像起別名,第一個鏡像的ID為0,第二個為1,我們可以用ID從別的階段拷貝文件,--from=0 src dst

FROM golang:1.9-alpine as builder
RUN apk --no-cache add git
WORKDIR /go/src/github.com/go/helloworld/
RUN go get -d -v github.com/go-sql-driver/mysql
COPY app.go .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .

FROM alpine:latest as prod
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=0 /go/src/github.com/go/helloworld/app .
CMD ["./app"]

 

壓縮鏡像

使用docker export和docker import

docker export是用來保存一個容器的,所以我們需要有一個正在運行的容器才能使用此命令。

docker export <CONTAINER ID> > export.tar

docker import用來加載保存的容器,但是不能恢復成一個容器,而是變成一個鏡像

docker import export.tar <IMAGE NAME>:[TAG]

可以用一條命令實現

docker export <容器ID> | docker import - <鏡像名>[:標簽]

使用export和import后得到的鏡像不會保存鏡像的歷史,所以鏡像會變小。

docker save是用來保存一個鏡像的,docker save <IMAGE ID> > save.tar;然后可以用docker load加載我們保存的鏡像,docker load < save.tar。使用docker save和load恢復后的鏡像依然會保存鏡像的歷史。

test鏡像未經過壓縮的,test/import鏡像是經過壓縮的鏡像,可以看到已經變小了一些 

使用docker-squash 

github地址:https://github.com/jwilder/docker-squash

docker save <image id> | sudo docker-squash -t newtag | docker load

參考文章

https://www.cnblogs.com/kuku0223/p/8421964.html

https://zhuanlan.zhihu.com/p/42815689

https://stackoverflow.com/questions/49118579/alpine-dockerfile-advantages-of-no-cache-vs-rm-var-cache-apk

https://www.cnblogs.com/zhangmingcheng/p/7122386.html

https://www.jianshu.com/p/1d889800cdfe

https://tuhrig.de/flatten-a-docker-container-or-image/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM