The science of uniting the background
I worked overtime day and night to develop the simplest Go Hello World app. Although I just ran and printed and quit, my boss also required me to launch the only app I could write.
The project structure is as follows:
.Exercises ── goCopy the code
Hello. Go looks like this:
package main
func main(a) {
println("hello world!")}Copy the code
In addition, the boss required to use Docker deployment, it seems that we follow the trend, a little higher…
First try
After visiting some martial arts friends, I found that it would be better to throw the whole process into docker and compile it. After some thinking, I got the following Dockerfile:
FROM golang:alpine
WORKDIR /build
COPY hello.go .
RUN go build -o hello hello.go
CMD ["./hello"]
Copy the code
Build an image:
$ docker build -t hello:v1 .
Copy the code
There we go. Let’s take a closer look.
docker run -it --rm hello:v1 ls -l /build
total 1260
-rwxr-xr-x 1 root root 1281547 Mar 6 15:54 hello
-rw-r--r-- 1 root root 55 Mar 6 14:59 hello.go
Copy the code
Dude, the code THAT I wrote with great difficulty is also in there, it seems that the code can’t be bad, or the operation and maintenance girl will laugh at me…
Let’s see how big the mirror image is, because they say it takes longer to pull the mirror image
$ docker docker images | grep hello
hello v1 2783ee221014 44 minutes ago 314MB
Copy the code
Wow, it’s 314MB. Did Docker build Java? Bigger is not always better…
Let’s see why it’s so big!
Let’s see, we already run 300+MB before the first instruction (WORKDIR).
Anyway, why don’t we take a run
$ docker run -it --rm hello:v1
hello world!
Copy the code
No problem, at least you can work
Second attempt
After a cigarette and wine, plus a friend to give advice, found that we used the basic mirror is too big.
$ docker images | grep golang
golang alpine d026981a7165 2 days ago 313MB
Copy the code
And my friend told me that I could compile the code first, and then copy it in, so that there is no need for the huge base image, but it is easy to say, I still spend some time, finally Dockerfile looks like this:
FROM alpine
WORKDIR /build
COPY hello .
CMD ["./hello"]
Copy the code
Give it a run
$ docker build -t hello:v2 .. => ERROR [3/3] COPY hello.0.0s ------ > [3/3] COPY hello .:
------
failed to compute cache key: "/hello" not found: not found
Copy the code
Hello. Go = hello. Go = hello
$ go build -o hello hello.go
Copy the code
Docker build-t hello:v2.
$ docker run -it --rm hello:v2
standard_init_linux.go:228: exec user process caused: exec format error
Copy the code
Failure! Well, the format is not correct, originally our development machine is not Linux ah, again ~
$ GOOS=linux go build -o hello hello.go
Copy the code
The docker build is finally done. Run
$ docker run -it --rm hello:v2
hello world!
Copy the code
No problem. Let’s look at the content and size.
docker run -it --rm hello:v2 ls -l /build
total 1252
-rwxr-xr-x 1 root root 1281587 Mar 6 16:18 hello
Copy the code
I don’t have to worry about anyone looking down on my code anymore
Docker images | grep hello hello v2 0 dd53f016c93 53 seconds line 6.61 MB hello v1 ac0e37173b85 25 minutes line 314 MBCopy the code
Wow, 6.61MB, absolutely!
Look, we only have 5.3MB ahead of the first instruction (WORKDIR). Happy!
Third attempt
After a bit of show-off, someone looked down on me and said that multi-phase builds are all the rage, so what’s wrong with the second approach? After careful consideration, we found that we need to be able to build a Docker image from the Go code, which is divided into three steps:
- The native compilation
Go
Code, if it involvescgo
Cross-platform compilation is a bit trickier - Build with compiled executable files
docker
The mirror - write
shell
Script ormakefile
Make these steps available through a command
A multi-stage build is all in one Dockerfile, with no source leaks, no scripting to compile across platforms, and minimal mirroring.
Loving learning and pursuing perfection, I finally wrote the following Dockerfile: One more line means fat, one less line means thin:
FROM golang:alpine AS builder
WORKDIR /build
ADD go.mod .
COPY.
RUN go build -o hello hello.go
FROM alpine
WORKDIR /build
COPY --from=builder /build/hello /build/hello
CMD ["./hello"]
Copy the code
The first FROM FROM section is to build a Builder image in which to compile the executable hello, the second FROM section is to copy executable Hello FROM the first image, And mirroring Alpine as small a base as possible to make sure that the final image is as small as possible. As for why not use smaller Scratch, scratch really doesn’t have anything to look at, and Alpine is only 5MB, so it doesn’t have much impact on our service.
We ran first to verify:
$ docker run -it --rm hello:v3
hello world!
Copy the code
No problem, just as expected! Take a look at the size:
$ docker images | grep helloHello v3 F51e1116be11 8 hours ago 6.61MB Hello V2 0dd53f016c93 8 hours ago 6.61MB Hello V1 AC0e37173b85 8 hours ago 314MBCopy the code
The size of the image is exactly the same as that of the second method. Take a look at the mirror again:
$ docker run -it --rm hello:v3 ls -l /build
total 1252
-rwxr-xr-x 1 root root 1281547 Mar 6 16:32 hello
Copy the code
Also only one executable Hello file, perfect!
It’s pretty much the same as the second final image, but we’ve simplified the process by simply using a Dockerfile and running a command instead of all the arcane shells and makefiles I need.
Siddhi practice
At this point, all the team members thought it was perfect and gave me thumbs up one after another! However, both the pursuit of perfection, but also like lazy (touch fish) I think it, every time LET me write such a line of fat, thin line, I still feel very tired, so I wrote a tool to hide the boss, I will show ~~
#Let's set it up
$ GOPROXY=https://goproxy.cn/,direct go install github.com/zeromicro/go-zero/tools/goctl@latestGoctl migrate - verbose - version v1.3.1#Write a Dockerfile with one click
$ goctl docker -go hello.go
Copy the code
Done! Look at the generated Dockerfile ha
FROM golang:alpine AS builder
LABEL stage=gobuilder
ENV CGO_ENABLED 0
ENV GOOS linux
ENV GOPROXY https://goproxy.cn,direct
WORKDIR /build
ADD go.mod .
ADD go.sum .
RUN go mod download
COPY.
RUN go build -ldflags="-s -w" -o /app/hello ./hello.go
FROM alpine
RUN apk update --no-cache && apk add --no-cache ca-certificates tzdata
ENV TZ Asia/Shanghai
WORKDIR /app
COPY --from=builder /app/hello /app/hello
CMD ["./hello"]
Copy the code
Some of them can be understood:
- Disabled by default
cgo
- To enable the
GOPROXY
- The debugging information is deleted
-ldflags="-s -w"
To reduce the image size - Installation of the
ca-certificates
, so usedTLS
The certificate is fine - The local time zone is automatically set so that we see Beijing time in the log
Let’s look at the size of the image built with this auto-generated Dockerfile:
$ docker images | grep helloHello V4 v7c3baed2706 4 seconds ago 7.97MB Hello V3 F51e1116be11 8 hours ago 6.61MB Hello V2 0dd53f016c93 8 hours ago 6.61MB Hello v1 AC0e373b85 9 hours ago 362 MBCopy the code
Slightly larger because we have ca-Certificates and TZData installed. Verify:
Let’s see what’s in the mirror image:
$ docker run -it --rm hello:v4 ls -l /app
total 832
-rwxr-xr-x 1 root root 851968 Mar 7 08:36 hello
Copy the code
There are only Hello executables, and the file size has been reduced from 1281KB to 851KB. Take a run:
$ docker run -it --rm hello:v4
hello world!
Copy the code
Ok, ok, no more entangling Dockerfile, I am going to learn something else ~
The project address
Github.com/zeromicro/g…
Do you think it’s good? Welcome to the tip. Simply light up the GitHub star ⭐️
Wechat communication group
Pay attention to the public account of “micro-service Practice” and click on the exchange group to obtain the QR code of the community group.