Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
228 views
in Technique[技术] by (71.8m points)

How to flatten a Docker image?

I made a Docker container which is fairly large. When I commit the container to create an image, the image is about 7.8 GB big. But when I export the container (not save the image!) to a tarball and re-import it, the image is only 3 GB big. Of course the history is lost, but this OK for me, since the image is "done" in my opinion and ready for deployment.

How can I flatten an image/container without exporting it to the disk and importing it again? And: Is it a wise idea to do that or am I missing some important point?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Now that Docker has released the multi-stage builds in 17.05, you can reformat your build to look like this:

FROM buildimage as build
# your existing build steps here
FROM scratch
COPY --from=build / /
CMD ["/your/start/script"]

The result will be your build environment layers are cached on the build server, but only a flattened copy will exist in the resulting image that you tag and push.


Note, you would typically reformulate this to have a complex build environment and only copy over a few directories. Here's an example with Go to make a single binary image from source code and a single build command without installing Go on the host and compiling outside of docker:

$ cat Dockerfile 
ARG GOLANG_VER=1.8
FROM golang:${GOLANG_VER} as builder
WORKDIR /go/src/app
COPY . .
RUN go-wrapper download 
RUN go-wrapper install

FROM scratch
COPY --from=builder /go/bin/app /app
CMD ["/app"]

The go file is a simple hello world:

$ cat hello.go 
package main

import "fmt"

func main() {
        fmt.Printf("Hello, world.
")
}

The build creates both environments, the build environment and the scratch one, and then tags the scratch one:

$ docker build -t test-multi-hello .                                                                                                                              
Sending build context to Docker daemon  4.096kB
Step 1/9 : ARG GOLANG_VER=1.8
 ---> 
Step 2/9 : FROM golang:${GOLANG_VER} as builder
 ---> a0c61f0b0796
Step 3/9 : WORKDIR /go/src/app
 ---> Using cache
 ---> af5177aae437
Step 4/9 : COPY . .
 ---> Using cache
 ---> 976490d44468
Step 5/9 : RUN go-wrapper download
 ---> Using cache
 ---> e31ac3ce83c3
Step 6/9 : RUN go-wrapper install
 ---> Using cache
 ---> 2630f482fe78
Step 7/9 : FROM scratch
 ---> 
Step 8/9 : COPY --from=builder /go/bin/app /app
 ---> Using cache
 ---> 5645db256412
Step 9/9 : CMD /app
 ---> Using cache
 ---> 8d428d6f7113
Successfully built 8d428d6f7113
Successfully tagged test-multi-hello:latest

Looking at the images, only the single binary is in the image being shipped, while the build environment is over 700MB:

$ docker images | grep 2630f482fe78
<none>                <none>              2630f482fe78        6 days ago          700MB

$ docker images | grep 8d428d6f7113
test-multi-hello      latest              8d428d6f7113        6 days ago          1.56MB

And yes, it runs:

$ docker run --rm test-multi-hello 
Hello, world.

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...