依賴文件和實際的代碼文件單獨分層
團隊/公司採用公共的基礎鏡像等
往往我們在構建階段和實際運行階段需要的依賴環境是不同的,例如Golang編寫的程序實際運行的時候僅僅需要一個二進位文件即可,對於Node來說,可能最後運行的只是一些打包之後的js文件而不需要包含node_modules裡成千上萬的依賴。Distroless,https://github.com/GoogleCloudPlatform/distroless「Distroless」 images contain only your application and its runtime dependencies. They do not contain package managers, shells or any other programs you would expect to find in a standard Linux distribution.Distroless是Google推出的一個僅僅包含運行時環境,不包含包管理器,shell等其他程序。如果你的程序沒有其他依賴的話,這是一個不錯的選擇。Alpine,https://hub.docker.com/_/alpineAlpine Linux is a security-oriented, lightweight Linux distribution based on musl libc and busybox.Alpine 是一個基於MUSL,Busybox的安全的Linux發行版。麻雀雖小五臟俱全,雖然不到10M, 但是包含了一個包管理器和shell環境,這在我們實際的使用調試當中將非常有用。但是請注意,由於Alpine使用了更小的muslc替代glibc,會導致某些應用無法使用,需要重新編譯。Scratch,https://hub.docker.com/_/scratchScratch是空白鏡像,一般用於基礎鏡像構建,例如Alpine鏡像的Dockerfile便是從Scratch開始的:FROM scratch
ADD alpine-minirootfs-20190228-x86_64.tar.gz /
CMD ["/bin/sh"]
Busybox,https://hub.docker.com/_/busybox一般而言,Distroless相對會更加的安全,但是在實際使用的過程中可能會遇到添加依賴以及調試方面的問題,alpine更小,自帶包管理器,更加貼合使用習慣,但是muslc可能會帶來兼容性的問題,一般而言我會選擇alpine作為基礎鏡像使用。除此之外,在Docker Hub當中我們可以發現常用的Debian的鏡像也會提供的只包含基礎功能的小鏡像。此處直接拉取基礎鏡像,查看鏡像大小, 通過觀察我們可以發現,alpine只有5M左右為debian的20分之一:alpine latest 5cb3aa00f899 3 weeks ago 5.53MB
debian latest 0af60a5c6dd0 3 weeks ago 101MB
ubuntu 18.04 47b19964fb50 7 weeks ago 88.1MB
ubuntu latest 47b19964fb50 7 weeks ago 88.1MB
alpine 3.8 3f53bb00af94 3 months ago 4.41MB
似乎從上面看,感覺差距不大,實踐中,不同語言的基礎鏡像都會提供一些採用不同基礎鏡像製作的tag,下面我們以Ruby的鏡像為例,查看不同基礎鏡像的差異。可以看到默認的latest鏡像881MB而alpine僅僅只有不到50MB這個差距就十分的可觀了:ruby latest a5d26127d8d0 4 weeks ago 881MB
ruby alpine 8d8f7d19d1fa 4 weeks ago 47.8MB
ruby slim 58dd4d3c99da 4 weeks ago 125MB
# dockerfile 1
FROM alpine
RUN wget https://github.com/mohuishou/scuplus-wechat/archive/1.0.0.zip && rm 1.0.0.zip
# dockerfile 2
FROM alpine
RUN wget https://github.com/mohuishou/scuplus-wechat/archive/1.0.0.zip
RUN rm 1.0.0.zip
# dockerfile 3
FROM alpine
RUN wget https://github.com/mohuishou/scuplus-wechat/archive/1.0.0.zip && rm 1.0.0.zip
test 3 351a80e99c22 5 seconds ago 5.53MB
test 2 ad27e625b8e5 49 seconds ago 6.1MB
test 1 165e2e0df1d3 About a minute ago 6.1MB
可以發現1,2兩個大小一樣,但是3小了0.5MB,這是因為Docker幾乎每一行命令都會生成一個層,刪除文件的時候:因為底下各層都是只讀的,當需要刪除這些層中的文件時,AUFS 使用whiteout機制,它的實現是通過在上層的可寫的目錄下建立對應的whiteout隱藏文件來實現的,所以在當前層去刪除上一層的文件,只是會把這個文件隱藏掉罷了。除了刪除語句需要放在一行以外,由於層的機制,我們安裝依賴的一些公共的語句最好也使用條RUN命令生成,減少最終的層數。這是一個最佳實踐,在實際的開發過程中,我們的依賴包往往是變動不大的,但是我們正在開發的源碼的變動是較為頻繁,如果我們實際的代碼只有10M,但是依賴項有1G,如果在COPY的時候直接 COPY..,會導致每次修改代碼都會使這一層的緩存失效,導致浪費複製以及推送到鏡像倉庫的時間,將COPY語句分開,每次push就可以只變更我們頻繁修改的代碼層,而不是連著依賴一起。在使用Git時,我們可以通過.gitignore忽略文件,在docker build的時候也可以使用.dockerignore在Docker上下文中忽略文件,這樣不僅可以減少一些非必要文件的導入,也可以提高安全性,避免將一些配置文件打包到鏡像中。多階段構建其實也是減少層的一種,通過多階段構建,最終鏡像可以僅包含最後生成的可執行文件,和必須的運行時依賴,大大減少鏡像體積。以Go語言為例,實際運行的過程中只需要最後編譯生成的二進位文件即可,而Go語言本省以及擴展包,代碼文件都是不必要的,但是我們在編譯的時候這些依賴又是必須的,這時候就可以使用多階段構建的方式,減少最終生成的鏡像體積。# 使用golang鏡像作為builder鏡像
FROM golang:1.12 as builder
WORKDIR /go/src/github.com/go/helloworld/
COPY app.go .
RUN go build -o app .
# 編譯完成之後使用alpine鏡像作為最終的基礎鏡像
FROM alpine:latest as prod
RUN apk --no-cache add ca-certificates
WORKDIR /root/
# 從builder中複製編譯好的二進位文件
COPY --from=builder /go/src/github.com/go/helloworld/app .
CMD ["./app"]
由於本文篇幅較長,這裡不對多階段構建展開講解,詳情可以參考多階段構建[1]。使用dive[2]查看Docker鏡像的層,可以幫助你分析減少鏡像體積。使用docker-slim[3]可以自動幫助你減少鏡像體積,對於Web應用較為有用。# ubuntu
apt-get install -y — no-install-recommends
#alpine
apk add --no-cache && apk del build-dependencies
# centos
yum install -y ... && yum clean all
bundle install --without development:test:assets -j4 --retry 3 --path=vendor/bundle \
# Remove unneeded files (cached *.gem, *.o, *.c)
&& rm -rf vendor/bundle/ruby/2.5.0/cache/*.gem \
&& find vendor/bundle/ruby/2.5.0/gems/ -name "*.c" -delete \
&& find vendor/bundle/ruby/2.5.0/gems/ -name "*.o" -delete
rm -rf node_modules tmp/cache app/assets vendor/assets spec
Golang在使用多階段構建之後,只剩下了一個二進位文件,這時候再要優化,就只有使用upx之類的工具壓縮二進位文件的體積了。https://yeasy.gitbooks.io/docker_practice/image/multistage-builds/#%E5%A4%9A%E9%98%B6%E6%AE%B5%E6%9E%84%E5%BB%BA
https://github.com/wagoodman/dive
https://github.com/docker-slim/docker-slim
https://github.com/jwilder/docker-squash
原文連結:https://lailin.xyz/post/notes/docker%E9%95%9C%E5%83%8F%E7%98%A6%E8%BA%AB/基於Kubernetes的DevOps實踐培訓將於2019年5月10日在上海開課,3天時間帶你系統掌握Kubernetes,學習效果不好可以繼續學習。本次培訓包括:容器特性、鏡像、網絡;Kubernetes架構、核心組件、基本功能;Kubernetes設計理念、架構設計、基本功能、常用對象、設計原則;Kubernetes的資料庫、運行時、網絡、插件已經落地經驗;微服務架構、組件、監控方案等,點擊下方圖片查看詳情。