Pull static binaries from wolfi

21 March, 2024 - Tags: binaries, wolfi


I have been using wolfi as a package manager for static binaries and this document explains the same process.

TLDR: I mount my bin directory inside the container and then I add the static binaries using apk.

Why?

If you're doing something around kubernetes then there's a lot of things that you need. The tools I often use are k9s, helm, kubectl etc. How do I ensure that I get latest version of these binaries on my system? In the past, I've used arkade and still do. This is really smooth. You don't have to goto GitHub releases page and copy the URL, come back to your terminal and use wget or curl to download the tarball/binary.

Now, how to do the same with wolfi.

$ docker run --name wolfi-install -v $HOME/.arkade/bin:/usr/bin --rm -it cgr.dev/chainguard/wolfi-base:latest sh -c 'apk add k9s'
fetch https://packages.wolfi.dev/os/x86_64/APKINDEX.tar.gz
(1/1) Installing k9s (0.32.3-r1)
OK: 133 MiB in 15 packages

In the command above, I have mounted my ~/.arkade/bin which is already there in the PATH and then I executed a command apk add k9s inside the container.

One may say that this command is really long and I don't want that. I used a simple just target to make the process easier for me.

# install something in ~/.arkade/bin/
wolfi-install *package: clean
	docker run --name wolfi-install -v $HOME/.arkade/bin:/usr/bin --rm -it cgr.dev/chainguard/wolfi-base:latest sh -c 'apk add {{package}}'

# just install a package in current working directory (./package)
wolfi-install-here *package:
	docker run --rm -it -v .:/usr/bin cgr.dev/chainguard/wolfi-base:latest sh -c 'apk add {{package}}'

I use the above two just recipes install things either in my path or current working directory. So, if I want to update my k9s binary then I use just wolfi-install k9s and if I want a temporary binary in my current working directory then we can do use the command just wolfi-install-here <pkg-name>

NOTE: Just doesn't support global justfile as of now so I have a global justfile located at ~/.justfile and I invoke the following commands in my system.

just --justfile ~/.justfile wolfi-install k9s
just --justfile ~/.justfile wolfi-install-here hcloud

This works pretty good for me.

I use the same approach while working with container as well. On this project, we put everything inside the container and then copy the same binaries on the host system tracked by a version.txt file.

What don't go well?

Packages that depend on shared system libraries break if you just install the binary. Think about the package that ties to a particular version of openssl and you don't have the same version on your host system then it will break. Mostly rust binaries have done some trouble for me in the past but some works (atuin, eza, ripgrep, fd) but some doesn't for example (lychee and few others)

From Go ecosystem, the binaries that are dynamically linked with CGO shouldn't be installed this way. They usually create problem for me.

If you're able to peek into the detailed output of ldd and realelf then you can install the binaries anyway and download the shared libraries on your system to make it work. But again, I wanted things to be simpler and fast and for that reason, I only pull static binaries from wolfi and some dynamically linked binaries as well that have worked in past for me.

Example: By invoking the following command, you can see the dependency of the rg binary.

$ readelf -d $(command -v rg)

Dynamic section at offset 0x5861d0 contains 29 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [libgcc_s.so.1]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [ld-linux-x86-64.so.2]

Thanks to the contributors and maintainers of wolfi for maintaining zero CVE packages.

On remote systems

Sometimes just is installed on the VM on which I'm running but docker is installed, I use the following.

docker run --rm -v .:/usr/bin/ cgr.dev/chainguard/wolfi-base:latest sh -c 'apk add lazygit'
fetch https://packages.wolfi.dev/os/x86_64/APKINDEX.tar.gz
(1/1) Installing lazygit (0.41.0-r0)
OK: 32 MiB in 15 packages

BIG WARNING: If you mount your libraries path inside the container and something weird happens then you're responsible for it. Please don't do that. That's highly risky and I'm pretty sure very dangerous as well given that'll break something your system. I think only mounting something in your home directory (~/.local/bin or ~/.arkade/bin) is the hacky (probably still unsecure) but way to do it. Don't mount any lib directories from your filesystem.