Building Docker images with Kaniko

…gluten free fwiw, yes I like jokes and we just won the world cup :)

Almost a year ago to the day I wrote a post about building Docker images without Docker using Bazel. The main motivation is two fold:

1. The Docker daemon is root and some users may not be allowed to have the Docker daemon on their own machines.
2. If you want to automate docker build within a cluster, the machines doing the build need access to the Docker socket and this opens the door to attacks.

So the need is there to build a Docker image, which at the end of the day is really a file, without the Docker daemon. And since everything is a file in Linux, we should be able to create a file without any special privileges.

Since my post there has been quite some development in that space and we now have a few tools available buildah, img, skopeo …

Skopeo is quite nice, it allows you to do easy copy (from and out of registries to and from local directories) of Docker images and you get all the layers and image manifest, see:

# skopeo copy docker://debian dir:/tmp/debian

You can easily get Skopeo from Fedora. Here are the two lines of a Dockerfile that installs skopeo:


FROM fedora:27
RUN dnf install -y skopeo

It is now wrapper in the atomic CLI. I have not tested it but Red Hat users will love it.

The only drawback of Skopeo is that it does not deal with a Dockerfile , though I love it as a way to understand how to build a layer and an image manifest.

To build a container image without Docker but still using a Dockerfile kaniko comes to the rescue.

Kaniko comes from Google and I particularly like the fact that it comes as a container. Which means that you can run your docker build within a Kubernetes Pod.

Let’s check this out a bit more:


Usage

Explore the usage with:


docker run -it gcr.io/kaniko-project/executor:latest --help

It looks for a Dockerfile in the default build context which is set to /workspace and the destination image is set via the -d flag.

To be able to push the resulting image to a remote Docker registry you need to make your registry credentials available witin the kaniko container.

Assuming that you saved your Docker credentials in a file config.json and that you have a Dockerfile in the local directory. You can build and push a Docker image with the following command (replace the destination image…):


docker run -v $PWD:/workspace \
-v /path/to/config.json:/kaniko/config.json \
--env DOCKER_CONFIG=/kaniko \
gcr.io/kaniko-project/executor:latest \
-d index.docker.io/runseb/barbaz

The result will be an unprivileged build within the kaniko container, and a push to your Docker registry:


time=”2018–07–16T10:18:05Z” level=info msg=”Unpacking filesystem of debian:stable-slim…”
time=”2018–07–16T10:18:06Z” level=info msg=”Mounted directories: [/kaniko /var/run /proc /dev /dev/pts /sys /sys/fs/cgroup /sys/fs/cgroup/cpuset /sys/fs/cgroup/cpu /sys/fs/cgroup/cpuacct /sys/fs/cgroup/blkio /sys/fs/cgroup/memory /sys/fs/cgroup/devices /sys/fs/cgroup/freezer /sys/fs/cgroup/net_cls /sys/fs/cgroup/perf_event /sys/fs/cgroup/net_prio /sys/fs/cgroup/hugetlb /sys/fs/cgroup/pids /sys/fs/cgroup/systemd /dev/mqueue /workspace /kaniko/config.json /etc/resolv.conf /etc/hostname /etc/hosts /dev/shm /proc/bus /proc/fs /proc/irq /proc/sys /proc/sysrq-trigger /proc/kcore /proc/keys /proc/timer_list /proc/sched_debug /sys/firmware]”
time=”2018–07–16T10:18:07Z” level=info msg=”Unpacking layer: 0"
time=”2018–07–16T10:18:07Z” level=info msg=”Not adding /dev because it is whitelisted”
time=”2018–07–16T10:18:07Z” level=info msg=”Not adding /etc/hostname because it is whitelisted”
time=”2018–07–16T10:18:07Z” level=info msg=”Not adding /etc/resolv.conf because it is whitelisted”
time=”2018–07–16T10:18:08Z” level=info msg=”Not adding /proc because it is whitelisted”
time=”2018–07–16T10:18:08Z” level=info msg=”Not adding /sys because it is whitelisted”
time=”2018–07–16T10:18:11Z” level=info msg=”Not adding /var/run because it is whitelisted”
time=”2018–07–16T10:18:11Z” level=info msg=”Taking snapshot of full filesystem…”
time=”2018–07–16T10:18:12Z” level=info msg=”cmd: copy [foo.py]”
time=”2018–07–16T10:18:12Z” level=info msg=”dest: /foo.py”
time=”2018–07–16T10:18:12Z” level=info msg=”Copying file /workspace/foo.py to /foo.py”
time=”2018–07–16T10:18:12Z” level=info msg=”Taking snapshot of files [/foo.py]…”
2018/07/16 10:18:13 mounted blob: sha256:b66481ccd4ca0a07f33ae682e4f0d554924f4bca01ddceb21666a9a49b240e2a
2018/07/16 10:18:13 pushed blob sha256:8dbe718c90b36c92ac5de2da4b18d4ec9b3502450743110fa1cbcbb683e763cd
2018/07/16 10:18:14 pushed blob sha256:c8169151d72d7f9a6c68d310a57579577f3316e303c77dbb3bef0489025756b5
index.docker.io/runseb/barbaz:latest: digest: sha256:effad7f56a2a20fdc76fc9aac0c4ad8e9cb5a6f642993f480f742fd34bf25d74 size: 589

Later this week I will show you how to stick this in a Kubernetes Pod or something a bit newer ;)

Let me know if you would like me to test something this summer ! Sebastien Goasguen