5 ms·
If you're using Go with Docker 17.05 or higher, I recommend a multi-stage Docker build. Official documentation here: https://docs.docker.com/develop/develop-ima
by aodin 8y ago
If you're using Go with Docker 17.05 or higher, I recommend a multi-stage Docker build. Official documentation here: https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds https://docs.docker.com/develop/develop-images/multistage-bu...
The default Go Docker images include everything needed to compile Go. But once you have a binary, you really only need an image capable of running your binary. I've seen images sizes reduced by over 95%.
Revising the example in the article:
FROM golang:1.10
COPY . /go/src/bitbucket.code.company-name.com.au/scm/code
WORKDIR /go/src/bitbucket.code.company-name.com.au/scm/code/
RUN CGO_ENABLED=0 go build main.go
FROM alpine:3.7
RUN apk add --no-cache ca-certificates
COPY --from=0 /go/src/bitbucket.code.company-name.com.au/scm/code/main .
CMD ["./main"]
The `CGO_ENABLED=0` and `apk` are oddities of Alpine Linux specifically. The image you choose to run your binary may not need these.
- ImJasonH 8y agoAnother option for even smaller images is to use distroless: https://github.com/GoogleContainerTools/distroless#examples-with-docker https://github.com/GoogleContainerTools/distroless#examples-...
- nemothekid 8y agoI've been using `scratch` final builds .- FROM golang:1.10 WORKDIR /go/src/bitbucket.code.company-name.com.au/scm/code COPY ./ ./ RUN CGO_ENABLED=0 go build -a -installsuffix cgo -o /dist/main . FROM scratch COPY --from=0 /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ COPY --from=0 /go/src/bitbucket.code.company-name.com.au/scm/code/dist/main / ENTRYPOINT ["/main"] It requires a bit more "magic", but is a smaller build at the end.
- reacharavindh 8y agoSerious question: Why do you need Docker for a Go project? Cant you build it, and copy the binaries over to the host you want to run it on?
- d4l3k 8y agoThere's definitely use cases for Docker with Go that mostly revolve around running untrusted code or wanting to be able to set tight restrictions on CPU usage, memory etc. Though you could also just do the latter via cgroups. Another use case might be if you have extra files that need to be deployed with the binary as well. I wrote up some documentation about this for my use case just in case I ever have to go back and change it. You can see it here: https://fn.lc/post/docker-scratch/ https://fn.lc/post/docker-scratch/
- dijit 8y ago>There's definitely use cases for Docker with Go that mostly revolve around running untrusted code. Please don't run untrusted code in Docker, it's not designed for security. https://security.stackexchange.com/questions/107850/docker-as-a-sandbox-for-untrusted-code/108013 https://security.stackexchange.com/questions/107850/docker-a...
- Zekio 8y agoDocker containers can run in other places where they are secure, IIRC then Joyent has way to do this in their cloud
- dijit 8y agoYou havent refuted my point. People take a stance that docker can run untrusted code without actually looking at what they have to do for that to be true.
- d4l3k 8y agoI haven't taken the stance that all docker containers can run untrusted code, but I've certainly done my best to harden my docker containers as much as possible. If you took a look at that write up I cover it. I run with the flags: --net=none --cap-drop=all --cpus=1 --read-only --tmpfs=/tmp:rw,size=1g,mode=1777,noexec This gives it no way to communicate with the outside world and drops all capabilities so it's not allowed to interact with the kernel at all. Setting CPU limit to be 1 also prevents DOS attacks internally. I also run the process under the nobody user which entirely avoids the "container root is system root" issue. I'm also only sort of running "untrusted" code. I'm running tensorflow models which can do arbitrary computation but are more secure than just running raw code.
- duey 8y agoYou can remove CGO_ENABLED=0 by using the Go Alpine image (golang:1.10-alpine). The issue is caused by Alpine images being musl libc based.
- aodin 8y agoUsing the `golang:1.10-alpine` image to run your binary would defeat the purpose of a multi-stage build, since it includes everything needed to compile Go and weighs in around 376MB. The `alpine:3.7` image is about 4MB. edit I misunderstood the parent, they meant to use `golang:1.10-alpine` as the build image, not the run image, as in: FROM golang:1.10-alpine COPY . /go/src/bitbucket.code.company-name.com.au/scm/code WORKDIR /go/src/bitbucket.code.company-name.com.au/scm/code/ RUN go build main.go FROM alpine:3.7 RUN apk add --no-cache ca-certificates COPY --from=0 /go/src/bitbucket.code.company-name.com.au/scm/code/main . CMD ["./main"] Which works! Thank you!
- duey 8y agoNo, use golang:1.10-alpine for the build, keep the second stage the same.
- theshrike79 8y agoI had some weird issues trying to cross-compile to alpine, but using the golang-alpine image fixed them all.