Docker+UPX 構建更小的鏡像

clipboard.png

不管是在咱們的生產環境或測試環境中,一旦涉及到docker pull和push的時候,咱們都迫切但願Docker鏡像是一個很是小的file,一方面在網絡帶寬有限的狀況下,image的size越小下載所付出的時間代價就越小,另外一方面image始終是一個文件,size對存儲空間是有必定影響的,看來這是個提升生產力的問題,那麼咱們如何去構建一個size很小的image呢?linux

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

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

查看一下image列表:github

$ docker images
REPOSITORY                                 TAG                 IMAGE ID            CREATED             SIZE
golang                                     1.10.3              d0e7a411e3da        6 weeks ago         794MB
alpine                                     3.8                 11cd0b38bc3c        8 weeks ago         4.41MB

一般在咱們什麼都不考慮的狀況下,構建一個golang的應用鏡像是很是簡單的,只須要pull官方的golang環境,把咱們的程序copy進去就能夠了,下面咱們先建立一個工程的目錄以下:golang

$ tree -L 2   -C
.
├── Dockerfile
└── src
    └── main.go
    
1 directory, 2 files
單階段構建鏡像
  • Dockerfile:
FROM golang:1.10.3
WORKDIR /go/src/test
RUN go get github.com/gin-gonic/gin
COPY src src
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main src/main.go
CMD ["./main"]
  • Build
$ docker build -t zev/test:1.0.0 .

Sending build context to Docker daemon  17.41kB
Step 1/6 : FROM golang:1.10.3
 ---> d0e7a411e3da
Step 2/6 : WORKDIR /go/src/test
 ---> Running in 94d1ede51e17
Removing intermediate container 94d1ede51e17
 ---> 2b643ce8b3cf
Step 3/6 : RUN go get github.com/gin-gonic/gin
 ---> Running in de5e9adb7c10
Removing intermediate container de5e9adb7c10
 ---> ff970f45de1e
Step 4/6 : COPY src src
 ---> 6b79fef06e45
Step 5/6 : RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main src/main.go
 ---> Running in 6d4ef8c0b580
Removing intermediate container 6d4ef8c0b580
 ---> 59678a3ab4d8
Step 6/6 : CMD ["./main"]
 ---> Running in a5cea54f2ccb
Removing intermediate container a5cea54f2ccb
 ---> a253cfcddd6a
Successfully built a253cfcddd6a
Successfully 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 images

REPOSITORY                                 TAG                 IMAGE ID            CREATED             SIZE
zev/test                                   1.0.0               a253cfcddd6a        4 minutes ago       857MB

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

多階段構建鏡像
  • Dockerfile:
FROM golang:1.10.3 as builder
WORKDIR /go/src/test
RUN go get github.com/gin-gonic/gin
COPY src src
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main src/main.go

FROM alpine:3.8
WORKDIR /root
COPY --from=builder /go/src/test/main .
CMD ["./main"]
  • Build
$ docker build -t zev/test:1.0.1 .                                                                                                            

Sending build context to Docker daemon  17.41kB
Step 1/9 : FROM golang:1.10.3 as builder
 ---> d0e7a411e3da
Step 2/9 : WORKDIR /go/src/test
 ---> Using cache
 ---> 2b643ce8b3cf
Step 3/9 : RUN go get github.com/gin-gonic/gin
 ---> Using cache
 ---> ff970f45de1e
Step 4/9 : COPY src src
 ---> Using cache
 ---> 6b79fef06e45
Step 5/9 : RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main src/main.go
 ---> Using cache
 ---> 59678a3ab4d8
Step 6/9 : FROM alpine:3.8
 ---> 11cd0b38bc3c
Step 7/9 : WORKDIR /root
 ---> Running in 1640c71479d6
Removing intermediate container 1640c71479d6
 ---> ec68dc839562
Step 8/9 : COPY --from=builder /go/src/test/main .
 ---> 5bb444c91aff
Step 9/9 : CMD ["./main"]
 ---> Running in a80305feba6e
Removing intermediate container a80305feba6e
 ---> 5923597f59c2
Successfully built 5923597f59c2
Successfully 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 images

REPOSITORY                                 TAG                 IMAGE ID            CREATED             SIZE
zev/test                                   1.0.1               5923597f59c2        2 minutes ago       19.8MB

多階段構建讓images縮小了40倍,19.8M的size不管在測試環境仍是生產環境都能很好的工做了,可是這樣就結束了嗎?
固然不是了,咱們的目的是讓image變得更小,下面看咱們的操做。網絡

更小的鏡像構建
  • Dockerfile:
FROM golang:1.10.3 as builder
RUN 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/local
RUN 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/upx
WORKDIR /go/src/test
RUN go get github.com/gin-gonic/gin
COPY src src
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main src/main.go
RUN strip --strip-unneeded main
RUN upx main

FROM alpine:3.8
WORKDIR /root
COPY --from=builder /go/src/test/main .
CMD ["./main"]
  • Build
$ docker build -t zev/test:1.0.2 .         
                                                                                                   
Sending build context to Docker daemon  17.92kB
Step 1/14 : FROM golang:1.10.3 as builder
 ---> d0e7a411e3da
Step 2/14 : RUN apt-get update && apt-get install -y xz-utils     && rm -rf /var/lib/apt/lists/*
 ---> Running in 65772cb8fdab
Ign:1 http://deb.debian.org/debian stretch InRelease
Get: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 - 2018
UPX 3.95        Markus Oberhumer, Laszlo Molnar & John Reiser   Aug 26th 2018

        File size         Ratio      Format      Name
   --------------------   ------   -----------   -----------
   9848136 ->   2945384   29.91%   linux/amd64   main

Packed 1 file.
Removing intermediate container d802406ee44a
 ---> 0c29f4b2272d
Step 11/14 : FROM alpine:3.8
 ---> 11cd0b38bc3c
Step 12/14 : WORKDIR /root
 ---> Using cache
 ---> ec68dc839562
Step 13/14 : COPY --from=builder /go/src/test/main .
 ---> a2c265cc9aff
Step 14/14 : CMD ["./main"]
 ---> Running in 7e350a4620ee
Removing intermediate container 7e350a4620ee
 ---> a4d7753c8112
Successfully built a4d7753c8112
Successfully 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 images

REPOSITORY                                 TAG                 IMAGE ID            CREATED             SIZE
zev/test                                   1.0.2               a4d7753c8112        4 minutes ago       7.36MB

OK 很是漂亮,到如今咱們已經看到image的size已經縮小到7.36MB,這已經很是的小了,換算過來咱們的程序只有2.95M。
咱們來一張全景對比看下:測試

$ docker images

REPOSITORY                                 TAG                 IMAGE ID            CREATED             SIZE
zev/test                                   1.0.2               a4d7753c8112        6 minutes ago       7.36MB
zev/test                                   1.0.1               5923597f59c2        About an hour ago   19.8MB
zev/test                                   1.0.0               a253cfcddd6a        About an hour ago   857MB
golang                                     1.10.3              d0e7a411e3da        6 weeks ago         794MB
alpine                                     3.8                 11cd0b38bc3c        8 weeks ago         4.41MB

那麼怎麼作到的呢,原理很簡單,由於alpine的size已經固定了,能讓image變得更小的入手點只能是可執行文件,利用UPX的加殼技術能夠壓縮main可執行程序,能夠把main體積縮小50%-70%。ui

Tip:UPX(the Ultimate Packer for eXecutables)是一個免費且開源的可執行程序文件加殼器,支持許多不一樣操做系統下的可執行文件格式。想了解更多關於UPX的信息能夠 點擊這裏也可點擊這裏.

總結:spa


好的,到此爲止本文首先展現了單階段構建鏡像,並獲得了一個~857MB的鏡像,而後利用多階段構建了一個只包含可執行文件的鏡像~19.8MB,最後咱們利用多階段+UPX壓縮把咱們的鏡像縮小到了~7.36MB,這樣的鏡像不管在測試環境仍是生產環境,都必定能大大的提升咱們的生產力。操作系統

相關文章
相關標籤/搜索