Docker+UPX 構建更小的鏡像

來源:互聯網
上載者:User

無論是在我們的生產環境或測試環境中,一旦涉及到docker pull和push的時候,我們都迫切希望Docker鏡像是一個非常小的file,一方面在網路頻寬有限的情況下,image的size越小下載所付出的時間代價就越小,另一方面image始終是一個檔案,size對儲存空間是有一定影響的,看來這是個提高生產力的問題,那麼我們如何去構建一個size很小的image呢?

本文內容
  • 單階段構建鏡像
  • 多階段構建鏡像
  • 更小的鏡像構建

註:多階段構建是 Docker 17.05 及更高版本提供的功能

查看一下image列表:

$ docker imagesREPOSITORY                                 TAG                 IMAGE ID            CREATED             SIZEgolang                                     1.10.3              d0e7a411e3da        6 weeks ago         794MBalpine                                     3.8                 11cd0b38bc3c        8 weeks ago         4.41MB

通常在我們什麼都不考慮的情況下,構建一個golang的應用鏡像是非常簡單的,只需要pull官方的golang環境,把我們的程式copy進去就可以了,下面我們先建立一個工程的目錄如下:

$ tree -L 2   -C.├── Dockerfile└── src    └── main.go    1 directory, 2 files
單階段構建鏡像
  • Dockerfile:
FROM golang:1.10.3WORKDIR /go/src/testRUN go get github.com/gin-gonic/ginCOPY src srcRUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main src/main.goCMD ["./main"]
  • Build
$ docker build -t zev/test:1.0.0 .Sending build context to Docker daemon  17.41kBStep 1/6 : FROM golang:1.10.3 ---> d0e7a411e3daStep 2/6 : WORKDIR /go/src/test ---> Running in 94d1ede51e17Removing intermediate container 94d1ede51e17 ---> 2b643ce8b3cfStep 3/6 : RUN go get github.com/gin-gonic/gin ---> Running in de5e9adb7c10Removing intermediate container de5e9adb7c10 ---> ff970f45de1eStep 4/6 : COPY src src ---> 6b79fef06e45Step 5/6 : RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main src/main.go ---> Running in 6d4ef8c0b580Removing intermediate container 6d4ef8c0b580 ---> 59678a3ab4d8Step 6/6 : CMD ["./main"] ---> Running in a5cea54f2ccbRemoving intermediate container a5cea54f2ccb ---> a253cfcddd6aSuccessfully built a253cfcddd6aSuccessfully tagged zev/test:1.0.0
  • RUN
$ docker run -it -p 8080:8080 zev/test:1.0.0          [GIN-debug] [WARNING] Now Gin requires Go 1.6 or later and Go 1.7 will be required soon.[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production. - using env:   export GIN_MODE=release - using code:  gin.SetMode(gin.ReleaseMode)[GIN-debug] GET    /ping                     --> main.main.func1 (3 handlers)[GIN-debug] Listening and serving HTTP on :8080
  • Images
$ docker imagesREPOSITORY                                 TAG                 IMAGE ID            CREATED             SIZEzev/test                                   1.0.0               a253cfcddd6a        4 minutes ago       857MB

image的size為857MB,內部包含了整個golang環境,這麼大的檔案在傳輸中絕對是個災難,接下來我們用多階段構建一個相對比較小的image。

多階段構建鏡像
  • Dockerfile:
FROM golang:1.10.3 as builderWORKDIR /go/src/testRUN go get github.com/gin-gonic/ginCOPY src srcRUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main src/main.goFROM alpine:3.8WORKDIR /rootCOPY --from=builder /go/src/test/main .CMD ["./main"]
  • Build
$ docker build -t zev/test:1.0.1 .                                                                                                            Sending build context to Docker daemon  17.41kBStep 1/9 : FROM golang:1.10.3 as builder ---> d0e7a411e3daStep 2/9 : WORKDIR /go/src/test ---> Using cache ---> 2b643ce8b3cfStep 3/9 : RUN go get github.com/gin-gonic/gin ---> Using cache ---> ff970f45de1eStep 4/9 : COPY src src ---> Using cache ---> 6b79fef06e45Step 5/9 : RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main src/main.go ---> Using cache ---> 59678a3ab4d8Step 6/9 : FROM alpine:3.8 ---> 11cd0b38bc3cStep 7/9 : WORKDIR /root ---> Running in 1640c71479d6Removing intermediate container 1640c71479d6 ---> ec68dc839562Step 8/9 : COPY --from=builder /go/src/test/main . ---> 5bb444c91affStep 9/9 : CMD ["./main"] ---> Running in a80305feba6eRemoving intermediate container a80305feba6e ---> 5923597f59c2Successfully built 5923597f59c2Successfully tagged zev/test:1.0.1
  • RUN
$ docker run -it -p 8080:8080 zev/test:1.0.1  [GIN-debug] [WARNING] Now Gin requires Go 1.6 or later and Go 1.7 will be required soon.[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production. - using env:   export GIN_MODE=release - using code:  gin.SetMode(gin.ReleaseMode)[GIN-debug] GET    /ping                     --> main.main.func1 (3 handlers)[GIN-debug] Listening and serving HTTP on :8080
  • Images
$ docker imagesREPOSITORY                                 TAG                 IMAGE ID            CREATED             SIZEzev/test                                   1.0.1               5923597f59c2        2 minutes ago       19.8MB

多階段構建讓images縮小了40倍,19.8M的size無論在測試環境還是生產環境都能很好的工作了,但是這樣就結束了嗎?
當然不是了,我們的目的是讓image變得更小,下面看我們的操作。

更小的鏡像構建
  • Dockerfile:
FROM golang:1.10.3 as builderRUN apt-get update && apt-get install -y xz-utils \    && rm -rf /var/lib/apt/lists/*ADD https://github.com/upx/upx/releases/download/v3.95/upx-3.95-amd64_linux.tar.xz /usr/localRUN xz -d -c /usr/local/upx-3.95-amd64_linux.tar.xz | tar -xOf - upx-3.95-amd64_linux/upx > /bin/upx && \    chmod a+x /bin/upxWORKDIR /go/src/testRUN go get github.com/gin-gonic/ginCOPY src srcRUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main src/main.goRUN strip --strip-unneeded mainRUN upx mainFROM alpine:3.8WORKDIR /rootCOPY --from=builder /go/src/test/main .CMD ["./main"]
  • Build
$ docker build -t zev/test:1.0.2 .                                                                                                            Sending build context to Docker daemon  17.92kBStep 1/14 : FROM golang:1.10.3 as builder ---> d0e7a411e3daStep 2/14 : RUN apt-get update && apt-get install -y xz-utils     && rm -rf /var/lib/apt/lists/* ---> Running in 65772cb8fdabIgn:1 http://deb.debian.org/debian stretch InReleaseGet:2 http://security.debian.org/debian-security stretch/updates InRelease [94.3 kB]Get:3 http://deb.debian.org/debian stretch-updates InRelease [91.0 kB]Get:4 http://security.debian.org/debian-security stretch/updates/main amd64 Packages [392 kB].....此處省略Step 10/14 : RUN upx main ---> Running in d802406ee44a                       Ultimate Packer for eXecutables                          Copyright (C) 1996 - 2018UPX 3.95        Markus Oberhumer, Laszlo Molnar & John Reiser   Aug 26th 2018        File size         Ratio      Format      Name   --------------------   ------   -----------   -----------   9848136 ->   2945384   29.91%   linux/amd64   mainPacked 1 file.Removing intermediate container d802406ee44a ---> 0c29f4b2272dStep 11/14 : FROM alpine:3.8 ---> 11cd0b38bc3cStep 12/14 : WORKDIR /root ---> Using cache ---> ec68dc839562Step 13/14 : COPY --from=builder /go/src/test/main . ---> a2c265cc9affStep 14/14 : CMD ["./main"] ---> Running in 7e350a4620eeRemoving intermediate container 7e350a4620ee ---> a4d7753c8112Successfully built a4d7753c8112Successfully tagged zev/test:1.0.2
  • RUN
$ docker run -it -p 8080:8080 zev/test:1.0.2 [GIN-debug] [WARNING] Now Gin requires Go 1.6 or later and Go 1.7 will be required soon.[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production. - using env:   export GIN_MODE=release - using code:  gin.SetMode(gin.ReleaseMode)[GIN-debug] GET    /ping                     --> main.main.func1 (3 handlers)[GIN-debug] Listening and serving HTTP on :8080
  • Images
$ docker imagesREPOSITORY                                 TAG                 IMAGE ID            CREATED             SIZEzev/test                                   1.0.2               a4d7753c8112        4 minutes ago       7.36MB

OK 非常漂亮,到現在我們已經看到image的size已經縮小到7.36MB,這已經非常的小了,換算過來我們的程式只有2.95M。
我們來一張全景對比看下:

$ docker imagesREPOSITORY                                 TAG                 IMAGE ID            CREATED             SIZEzev/test                                   1.0.2               a4d7753c8112        6 minutes ago       7.36MBzev/test                                   1.0.1               5923597f59c2        About an hour ago   19.8MBzev/test                                   1.0.0               a253cfcddd6a        About an hour ago   857MBgolang                                     1.10.3              d0e7a411e3da        6 weeks ago         794MBalpine                                     3.8                 11cd0b38bc3c        8 weeks ago         4.41MB

那麼怎麼做到的呢,原理很簡單,因為alpine的size已經固定了,能讓image變得更小的入手點只能是可執行檔,利用UPX的加殼技術可以壓縮main可執行程式,可以把main體積縮小50%-70%。

Tip:UPX(the Ultimate Packer for eXecutables)是一個免費且開源的可執行程式檔案加殼器,支援許多不同作業系統下的可執行檔格式。想瞭解更多關於UPX的資訊可以點擊這裡 ,也可點擊這裡.

總結:

好的,到此為止本文首先展示了單階段構建鏡像,並得到了一個~857MB的鏡像,然後利用多階段構建了一個只包含可執行檔的鏡像~19.8MB,最後我們利用多階段+UPX壓縮把我們的鏡像縮小到了~7.36MB,這樣的鏡像無論在測試環境還是生產環境,都一定能大大的提高我們的生產力。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.