Image sizes created by buildpacks pack suggests
Buildpacks and pack
Buildpacks is a CNCF project in image build category. Without writing Dockerfile, you can make iamge if the given builder supports your platform.
$ pack build myapp:1 --builder heroku/buildpacks:18
pack is helpful to casually create docker images. Several companies now provide their own buildpack they maintain. I was interested in image size each buildpack creates especially for golang. I briefly checked them.
suggest-builders
pack
command has a sub-command, suggest-builders
.
It shows some available builders.
$ pack --version
0.15.1+git-79adc30.build-1660
$ pack suggest-builders
Suggested builders:
Google: gcr.io/buildpacks/builder:v1 Ubuntu 18 base image with buildpacks for .NET, Go, Java, Node.js, and Python
Heroku: heroku/buildpacks:18 heroku-18 base image with buildpacks for Ruby, Java, Node.js, Python, Golang, & PHP
Paketo Buildpacks: paketobuildpacks/builder:base Ubuntu bionic base image with buildpacks for Java, NodeJS and Golang
Paketo Buildpacks: paketobuildpacks/builder:full Ubuntu bionic base image with buildpacks for Java, .NET, NodeJS, Golang, PHP, HTTPD and NGINX
Paketo Buildpacks: paketobuildpacks/builder:tiny Tiny base image (bionic build image, distroless run image) with buildpacks for Golang
...
There are five builders provided by three organizations. Google, Heroku and Paketo. Paketo provides three kinds of builders, base, full and tiny. You can guess it's named based on image size.
I created images for the next simple golang code using each builder.
package main
import (
"flag"
"fmt"
)
var Commit string
func main() {
msg := flag.String("msg", "", "message")
flag.Parse()
fmt.Println("commit:", Commit)
fmt.Println("msg:", *msg)
}
Commit
is a variable to check how linker option works of each builder.
Regarding flags, certainly it's for command line arguments.
Let's see how to run command one by one.
Google's builder
https://github.com/GoogleCloudPlatform/buildpacks#go-buildpacks
$ pack build \
--env "GOOGLE_GOLDFLAGS=-X main.Commit=`git rev-parse HEAD`" \
--builder gcr.io/buildpacks/builder \
myapp:google
Heroku's builder
https://github.com/heroku/heroku-buildpack-go#passing-a-symbol-and-optional-string-to-the-linker
$ pack build \
--env "GO_LINKER_SYMBOL=main.Commit" \
--env "GO_LINKER_VALUE=`git rev-parse HEAD`" \
--builder heroku/buildpacks:18 \
myapp:heroku
Paketo's builder
https://paketo.io/docs/buildpacks/language-family-buildpacks/go/
$ pack build \
--builder paketobuildpacks/builder:tiny \ # aware of buildpack.yml
myapp:paketo-tiny
$ cat buildpack.yml
---
go:
build:
flags:
- -ldflags="-X main.Commit=some-value"
You need to generate buildpack.yml
to embed commit. I like the way to use environment variable like Google and Heroku.
Image size?
Here is the result.
$ docker image ls | grep ^myapp | sort
myapp google ... 40 years ago 116MB
myapp heroku ... 40 years ago 535MB
myapp paketo-base ... 40 years ago 91.8MB
myapp paketo-full ... 40 years ago 706MB
myapp paketo-tiny ... 40 years ago 22.7MB
The size of paketo-tiny is really small. paketo-base and google are about 100MB. heroku and paketo-full look not very small.
Next, let's see each execution.
$ docker run --rm myapp:google -msg hello
commit: 7aea0234dabc623302892677296858679463268a
msg: hello
$ docker run --rm myapp:heroku -msg hello
commit: 7aea0234dabc623302892677296858679463268a
msg:
$ docker run --rm myapp:paketo-tiny -msg hello # same with full and base.
msg: hello
commit: some-value
Oh? heroku's one seems not to show the value given by -msg option. I've not checked the heroku buildpack document. It may not be able to pass any command line arguments. Google and paketo can show that. Actually paketo is not very smart to pass commit value.
Conclusion
- For image size,
paketobuildpacks/builder:tiny
overwhelmingly wins. It's amazingly small. - Paketo's builder doesn't support environment variable for likner options. It's not very convenient actually.
- Google's builder seems balanced for image size and its feature.
- Heroku's builder looks not very convenient for me.