Skip to main content

Distroless image internals

We used a Google "distroless" image as the base image on a go application deployment in a project a while ago. I never looked into what distroless really means, but I had a guess. I'm also curious to look under the hood of a docker image if they really are just merged archives.

Recently there was a "Docker without docker" blog post in Hacker news about how simple docker (or rather, OCI) image format is. Spoiler: an image is tar archives on top of tar archives. The post has also a detailed explanation of how to pull images from a container registry. I shamelessly took the image pull script they shared and modified it a bit to pull the static distroless image from the Google container registry.

The image is only one layer, and here is how it looks like after I extracted it and removed all the root level empty directories with all directories with at least one file expanded.

It looks pretty empty to me, and I suppose that's the origin of the distroless term! :thinksmart:

I compared it to an alpine image with the GNU/Linux diff tool, and the output is enormous.

# diff -dqry alpine distroless > diff
Only in alpine/bin: arch
Only in alpine/bin: ash
Only in alpine/bin: base64
Only in alpine/bin: bbconfig
Only in alpine/bin: busybox
Only in alpine/bin: cat
Only in alpine/bin: chgrp
Only in alpine/bin: chmod
Only in alpine/bin: chown
Only in alpine/bin: cp
Only in alpine/bin: date
Only in alpine/bin: dd
Only in alpine/bin: df
Only in alpine/bin: dmesg
Only in alpine/bin: dnsdomainname
Only in alpine/bin: dumpkmap
Only in alpine/bin: echo
Only in alpine/bin: ed
Only in alpine/bin: egrep
Only in alpine/bin: false
Only in alpine/bin: fatattr
Only in alpine/bin: fdflush
Only in alpine/bin: fgrep
Only in alpine/bin: fsync
Only in alpine/bin: getopt
Only in alpine/bin: grep
Only in alpine/bin: gunzip
Only in alpine/bin: gzip
Only in alpine/bin: hostname
Only in alpine/bin: ionice
Only in alpine/bin: iostat
Only in alpine/bin: ipcalc
Only in alpine/bin: kbd_mode
Only in alpine/bin: kill
Only in alpine/bin: link
Only in alpine/bin: linux32
Only in alpine/bin: linux64
Only in alpine/bin: ln
Only in alpine/bin: login
Only in alpine/bin: ls
Only in alpine/bin: lzop
Only in alpine/bin: makemime
Only in alpine/bin: mkdir
Only in alpine/bin: mknod
Only in alpine/bin: mktemp
Only in alpine/bin: more
Only in alpine/bin: mount
Only in alpine/bin: mountpoint
Only in alpine/bin: mpstat
Only in alpine/bin: mv
Only in alpine/bin: netstat
Only in alpine/bin: nice
Only in alpine/bin: pidof
Only in alpine/bin: ping
Only in alpine/bin: ping6
Only in alpine/bin: pipe_progress
Only in alpine/bin: printenv
Only in alpine/bin: ps
Only in alpine/bin: pwd
Only in alpine/bin: reformime
Only in alpine/bin: rev
Only in alpine/bin: rm
Only in alpine/bin: rmdir
Only in alpine/bin: run-parts
Only in alpine/bin: sed
Only in alpine/bin: setpriv
Only in alpine/bin: setserial
Only in alpine/bin: sh
Only in alpine/bin: sleep
Only in alpine/bin: stat
Only in alpine/bin: stty
Only in alpine/bin: su
Only in alpine/bin: sync
Only in alpine/bin: tar
Only in alpine/bin: touch
Only in alpine/bin: true
Only in alpine/bin: umount
Only in alpine/bin: uname
Only in alpine/bin: usleep
Only in alpine/bin: watch
Only in alpine/bin: zcat
Only in distroless: boot
Only in alpine/etc: alpine-release
Only in alpine/etc: apk
Only in alpine/etc: conf.d
Only in alpine/etc: crontabs
Only in distroless/etc: debian_version
Only in distroless/etc: default
Only in distroless/etc: dpkg
Only in alpine/etc: fstab
Files alpine/etc/group and distroless/etc/group differ
Only in distroless/etc: host.conf
Only in alpine/etc: hostname
Only in alpine/etc: hosts
Only in alpine/etc: init.d
Only in alpine/etc: inittab
Files alpine/etc/issue and distroless/etc/issue differ
Only in distroless/etc: issue.net
Only in alpine/etc: logrotate.d
Only in alpine/etc: modprobe.d
Only in alpine/etc: modules
Only in alpine/etc: modules-load.d
Only in alpine/etc: motd
Only in alpine/etc: mtab
Only in alpine/etc: network
Only in distroless/etc: nsswitch.conf
Only in alpine/etc: opt
Files alpine/etc/os-release and distroless/etc/os-release differ
Files alpine/etc/passwd and distroless/etc/passwd differ
Only in alpine/etc: periodic
Only in alpine/etc: profile
Only in alpine/etc/profile.d: color_prompt
Only in alpine/etc/profile.d: locale.sh
Files alpine/etc/protocols and distroless/etc/protocols differ
Only in distroless/etc: rpc
Only in alpine/etc: securetty
Files alpine/etc/services and distroless/etc/services differ
Only in alpine/etc: shadow
Only in alpine/etc: shells
Only in distroless/etc: skel
Only in alpine/etc/ssl: cert.pem
Files alpine/etc/ssl/certs/ca-certificates.crt and distroless/etc/ssl/certs/ca-certificates.crt differ
Only in alpine/etc/ssl: ct_log_list.cnf
Only in alpine/etc/ssl: ct_log_list.cnf.dist
Only in alpine/etc/ssl: misc
Only in alpine/etc/ssl: openssl.cnf
Only in alpine/etc/ssl: openssl.cnf.dist
Only in alpine/etc/ssl: private
Only in alpine/etc: sysctl.conf
Only in alpine/etc: sysctl.d
Only in alpine/etc: udhcpd.conf
Only in distroless/etc: update-motd.d
Only in distroless/home: nonroot
Only in alpine/lib: apk
Only in alpine/lib: firmware
Only in alpine/lib: ld-musl-x86_64.so.1
Only in alpine/lib: libapk.so.3.12.0
Only in alpine/lib: libc.musl-x86_64.so.1
Only in alpine/lib: libcrypto.so.1.1
Only in alpine/lib: libssl.so.1.1
Only in alpine/lib: libz.so.1
Only in alpine/lib: libz.so.1.2.11
Only in alpine/lib: mdev
Only in alpine/lib: modules-load.d
Only in alpine/lib: sysctl.d
Only in alpine: media
Only in alpine: mnt
Only in alpine: opt
Only in alpine/sbin: acpid
Only in alpine/sbin: adjtimex
Only in alpine/sbin: apk
Only in alpine/sbin: arp
Only in alpine/sbin: blkid
Only in alpine/sbin: blockdev
Only in alpine/sbin: depmod
Only in alpine/sbin: fbsplash
Only in alpine/sbin: fdisk
Only in alpine/sbin: findfs
Only in alpine/sbin: fsck
Only in alpine/sbin: fstrim
Only in alpine/sbin: getty
Only in alpine/sbin: halt
Only in alpine/sbin: hwclock
Only in alpine/sbin: ifconfig
Only in alpine/sbin: ifdown
Only in alpine/sbin: ifenslave
Only in alpine/sbin: ifup
Only in alpine/sbin: init
Only in alpine/sbin: inotifyd
Only in alpine/sbin: insmod
Only in alpine/sbin: ip
Only in alpine/sbin: ipaddr
Only in alpine/sbin: iplink
Only in alpine/sbin: ipneigh
Only in alpine/sbin: iproute
Only in alpine/sbin: iprule
Only in alpine/sbin: iptunnel
Only in alpine/sbin: klogd
Only in alpine/sbin: ldconfig
Only in alpine/sbin: loadkmap
Only in alpine/sbin: logread
Only in alpine/sbin: losetup
Only in alpine/sbin: lsmod
Only in alpine/sbin: mdev
Only in alpine/sbin: mkdosfs
Only in alpine/sbin: mkfs.vfat
Only in alpine/sbin: mkmntdirs
Only in alpine/sbin: mkswap
Only in alpine/sbin: modinfo
Only in alpine/sbin: modprobe
Only in alpine/sbin: nameif
Only in alpine/sbin: nologin
Only in alpine/sbin: pivot_root
Only in alpine/sbin: poweroff
Only in alpine/sbin: raidautorun
Only in alpine/sbin: reboot
Only in alpine/sbin: rmmod
Only in alpine/sbin: route
Only in alpine/sbin: setconsole
Only in alpine/sbin: slattach
Only in alpine/sbin: swapoff
Only in alpine/sbin: swapon
Only in alpine/sbin: switch_root
Only in alpine/sbin: sysctl
Only in alpine/sbin: syslogd
Only in alpine/sbin: tunctl
Only in alpine/sbin: udhcpc
Only in alpine/sbin: vconfig
Only in alpine/sbin: watchdog
Only in alpine: srv
Only in alpine/usr/bin: [
Only in alpine/usr/bin: [[
Only in alpine/usr/bin: awk
Only in alpine/usr/bin: basename
Only in alpine/usr/bin: bc
Only in alpine/usr/bin: beep
Only in alpine/usr/bin: blkdiscard
Only in alpine/usr/bin: bunzip2
Only in alpine/usr/bin: bzcat
Only in alpine/usr/bin: bzip2
Only in alpine/usr/bin: cal
Only in alpine/usr/bin: chvt
Only in alpine/usr/bin: cksum
Only in alpine/usr/bin: clear
Only in alpine/usr/bin: cmp
Only in alpine/usr/bin: comm
Only in alpine/usr/bin: cpio
Only in alpine/usr/bin: crontab
Only in alpine/usr/bin: cryptpw
Only in alpine/usr/bin: cut
Only in alpine/usr/bin: dc
Only in alpine/usr/bin: deallocvt
Only in alpine/usr/bin: diff
Only in alpine/usr/bin: dirname
Only in alpine/usr/bin: dos2unix
Only in alpine/usr/bin: du
Only in alpine/usr/bin: eject
Only in alpine/usr/bin: env
Only in alpine/usr/bin: expand
Only in alpine/usr/bin: expr
Only in alpine/usr/bin: factor
Only in alpine/usr/bin: fallocate
Only in alpine/usr/bin: find
Only in alpine/usr/bin: flock
Only in alpine/usr/bin: fold
Only in alpine/usr/bin: free
Only in alpine/usr/bin: fuser
Only in alpine/usr/bin: getconf
Only in alpine/usr/bin: getent
Only in alpine/usr/bin: groups
Only in alpine/usr/bin: hd
Only in alpine/usr/bin: head
Only in alpine/usr/bin: hexdump
Only in alpine/usr/bin: hostid
Only in alpine/usr/bin: iconv
Only in alpine/usr/bin: id
Only in alpine/usr/bin: install
Only in alpine/usr/bin: ipcrm
Only in alpine/usr/bin: ipcs
Only in alpine/usr/bin: killall
Only in alpine/usr/bin: ldd
Only in alpine/usr/bin: less
Only in alpine/usr/bin: logger
Only in alpine/usr/bin: lsof
Only in alpine/usr/bin: lsusb
Only in alpine/usr/bin: lzcat
Only in alpine/usr/bin: lzma
Only in alpine/usr/bin: lzopcat
Only in alpine/usr/bin: md5sum
Only in alpine/usr/bin: mesg
Only in alpine/usr/bin: microcom
Only in alpine/usr/bin: mkfifo
Only in alpine/usr/bin: mkpasswd
Only in alpine/usr/bin: nc
Only in alpine/usr/bin: nl
Only in alpine/usr/bin: nmeter
Only in alpine/usr/bin: nohup
Only in alpine/usr/bin: nproc
Only in alpine/usr/bin: nsenter
Only in alpine/usr/bin: nslookup
Only in alpine/usr/bin: od
Only in alpine/usr/bin: openvt
Only in alpine/usr/bin: passwd
Only in alpine/usr/bin: paste
Only in alpine/usr/bin: pgrep
Only in alpine/usr/bin: pkill
Only in alpine/usr/bin: pmap
Only in alpine/usr/bin: printf
Only in alpine/usr/bin: pscan
Only in alpine/usr/bin: pstree
Only in alpine/usr/bin: pwdx
Only in alpine/usr/bin: readlink
Only in alpine/usr/bin: realpath
Only in alpine/usr/bin: renice
Only in alpine/usr/bin: reset
Only in alpine/usr/bin: resize
Only in alpine/usr/bin: scanelf
Only in alpine/usr/bin: seq
Only in alpine/usr/bin: setkeycodes
Only in alpine/usr/bin: setsid
Only in alpine/usr/bin: sha1sum
Only in alpine/usr/bin: sha256sum
Only in alpine/usr/bin: sha3sum
Only in alpine/usr/bin: sha512sum
Only in alpine/usr/bin: showkey
Only in alpine/usr/bin: shred
Only in alpine/usr/bin: shuf
Only in alpine/usr/bin: sort
Only in alpine/usr/bin: split
Only in alpine/usr/bin: ssl_client
Only in alpine/usr/bin: strings
Only in alpine/usr/bin: sum
Only in alpine/usr/bin: tac
Only in alpine/usr/bin: tail
Only in alpine/usr/bin: tee
Only in alpine/usr/bin: test
Only in alpine/usr/bin: time
Only in alpine/usr/bin: timeout
Only in alpine/usr/bin: top
Only in alpine/usr/bin: tr
Only in alpine/usr/bin: traceroute
Only in alpine/usr/bin: traceroute6
Only in alpine/usr/bin: truncate
Only in alpine/usr/bin: tty
Only in alpine/usr/bin: ttysize
Only in alpine/usr/bin: udhcpc6
Only in alpine/usr/bin: unexpand
Only in alpine/usr/bin: uniq
Only in alpine/usr/bin: unix2dos
Only in alpine/usr/bin: unlink
Only in alpine/usr/bin: unlzma
Only in alpine/usr/bin: unlzop
Only in alpine/usr/bin: unshare
Only in alpine/usr/bin: unxz
Only in alpine/usr/bin: unzip
Only in alpine/usr/bin: uptime
Only in alpine/usr/bin: uudecode
Only in alpine/usr/bin: uuencode
Only in alpine/usr/bin: vi
Only in alpine/usr/bin: vlock
Only in alpine/usr/bin: volname
Only in alpine/usr/bin: wc
Only in alpine/usr/bin: wget
Only in alpine/usr/bin: which
Only in alpine/usr/bin: whoami
Only in alpine/usr/bin: whois
Only in alpine/usr/bin: xargs
Only in alpine/usr/bin: xxd
Only in alpine/usr/bin: xzcat
Only in alpine/usr/bin: yes
Only in distroless/usr: games
Only in distroless/usr: include
Only in alpine/usr/lib: engines-1.1
Only in alpine/usr/lib: libcrypto.so.1.1
Only in alpine/usr/lib: libssl.so.1.1
Only in alpine/usr/lib: libtls-standalone.so.1
Only in alpine/usr/lib: libtls-standalone.so.1.0.0
Only in alpine/usr/lib: modules-load.d
Only in distroless/usr/lib: os-release
Only in alpine/usr: local
Only in alpine/usr/sbin: add-shell
Only in alpine/usr/sbin: addgroup
Only in alpine/usr/sbin: adduser
Only in alpine/usr/sbin: arping
Only in alpine/usr/sbin: brctl
Only in alpine/usr/sbin: chpasswd
Only in alpine/usr/sbin: chroot
Only in alpine/usr/sbin: crond
Only in alpine/usr/sbin: delgroup
Only in alpine/usr/sbin: deluser
Only in alpine/usr/sbin: ether-wake
Only in alpine/usr/sbin: fbset
Only in alpine/usr/sbin: killall5
Only in alpine/usr/sbin: loadfont
Only in alpine/usr/sbin: nanddump
Only in alpine/usr/sbin: nandwrite
Only in alpine/usr/sbin: nbd-client
Only in alpine/usr/sbin: ntpd
Only in alpine/usr/sbin: partprobe
Only in alpine/usr/sbin: rdate
Only in alpine/usr/sbin: rdev
Only in alpine/usr/sbin: readahead
Only in alpine/usr/sbin: remove-shell
Only in alpine/usr/sbin: rfkill
Only in alpine/usr/sbin: sendmail
Only in alpine/usr/sbin: setfont
Only in alpine/usr/sbin: setlogcons
Only in distroless/usr/sbin: tzconfig
Only in alpine/usr/share: apk
Only in distroless/usr/share: base-files
Only in distroless/usr/share: common-licenses
Only in distroless/usr/share: dict
Only in distroless/usr/share: doc
Only in distroless/usr/share: info
Only in distroless/usr/share: lintian
Only in alpine/usr/share: udhcpc
Only in distroless/usr/share: zoneinfo
Only in distroless/usr: src
Only in distroless/var: backups
Only in alpine/var/cache: apk
Only in alpine/var/cache: misc
Only in alpine/var: empty
Only in alpine/var/lib: apk
Only in distroless/var/lib: dpkg
Only in alpine/var/lib: udhcpd
Only in alpine/var/lock: subsys
Only in alpine/var: mail
Only in alpine/var: opt
Only in alpine/var/spool: cron
Only in alpine/var/spool: mail
view raw diff.txt hosted with ❤ by GitHub

Comments

Popular posts from this blog

I'm not a passionate developer

A family friend of mine is an airlane pilot. A dream job for most, right? As a child, I certainly thought so. Now that I can have grown-up talks with him, I have discovered a more accurate description of his profession. He says that the truth about the job is that it is boring. To me, that is not that surprising. Airplanes are cool and all, but when you are in the middle of the Atlantic sitting next to the colleague you have been talking to past five years, how stimulating can that be? When he says the job is boring, it is not a bad kind of boring. It is a very specific boring. The "boring" you would want as a passenger. Uneventful.  Yet, he loves his job. According to him, an experienced pilot is most pleased when each and every tiny thing in the flight plan - goes according to plan. Passengers in the cabin of an expert pilot sit in the comfort of not even noticing who is flying. As someone employed in a field where being boring is not exactly in high demand, this sounds pro...

Canyon Precede:ON 7

I bought or technically leased a Canyon Precede:ON 7 (2022) electric bike last fall. This post is about my experiences with it after riding for about 2000 km this winter. The season was a bit colder than usual, and we had more snow than in years, so I properly put the bike through its paces. I've been cycling for almost 20 years. I've never owned a car nor used public transport regularly. I pedal all distances below 30km in all seasons. Besides commuting, I've mountain biked and raced BMX, and I still actively ride my road bike during the spring and summer months. I've owned a handful of bikes and kept them until their frames failed. Buying new bikes or gear has not been a major part of my hobby, and frankly, I'm quite sceptical about the benefits of updating bikes or gear frequently. I've never owned an E-bike before, but I've rented one a couple of times. The bike arrived in a hilariously large box. I suppose there's no need to worry about damage durin...

Emit structured Postgres data change events with wal2json

A common thing I see in an enterprise system is that when an end-user does some action, say add a user, the underlying web of subsystems adds the user to multiple databases in separate transactions. Each of these transactions may happen in varying order and, even worse, can fail, leaving the system in an inconsistent state. A better way could be to write the user data to some main database and then other subsystems like search indexes, pull/push the data to other interested parties, thus eliminating the need for multiple end-user originating boundary transactions. That's the theory part; how about a technical solution. The idea of this post came from the koodia pinnan alla podcast about event-driven systems and CDC . One of the discussion topics in the show is emitting events from Postgres transaction logs.  I built an utterly simple change emitter and reader using Postgres with the wal2json transaction decoding plugin and a custom go event parser. I'll stick to the boring ...