Differencebetween Alpine Docker Image and Busybox Docker Image

What is the difference between alpine docker image and busybox docker image?

The key difference between these is that older versions of the busybox image statically linked busybox against glibc (current versions dynamically link busybox against glibc due to use of libnss even in static configuration), whereas the alpine image dynamically links against musl libc.

Going into the weighting factors used to choose between these in detail would be off-topic here (software recommendation requests), but some key points:

Comparing glibc against musl libc, a few salient points (though there are certainly many other factors as well):

  • glibc is built for performance and portability over size (often adding special-case performance optimizations that take a large amount of code).
  • musl libc is built for correctness and size over performance (it's willing to be somewhat slower to have a smaller code size and to run in less RAM); and it's much more aggressive about having correct error reporting (instead of just exiting immediately) in the face of resource exhaustion.
  • glibc is more widely used, so bugs that manifest against its implementation tend to be caught more quickly. Often, when one is the first person to build a given piece of software against musl, one will encounter bugs (typically in that software, not in musl) or places where the maintainer explicitly chose to use GNU extensions instead of sticking to the libc standard.
  • glibc is licensed under LGPL terms; only software under GPL-compatible terms can be statically linked against it; whereas musl is under a MIT license, and usable with fewer restrictions.

Comparing the advantages of a static build against a dynamic build:

  • If your system image will only have a single binary executable (written in C or otherwise using a libc), a static build is always better, as it discards any parts of your libraries that aren't actually used by that one executable.
  • If your system image is intended to have more binaries added that are written in C, using dynamic linking will keep the overall size down, since it allows those binaries to use the libc that's already there.
  • If your system image is intended to have more binaries added in a language that doesn't use libc (this can be the case for Go and Rust, f/e), then you don't benefit from dynamic linking; you don't need the unused parts of libc there because you won't be using them anyhow.

Honestly, these two images don't between themselves cover the whole matrix space of possibilities; there are situations where neither of them is optimal. There would be value to having an image with only busybox that statically links against musl libc (if everything you're going to add is in a non-C language), or an image with busybox that dynamically links against glibc (if you're going to add more binaries that need libc and aren't compatible with musl).

Cannot run executables with Alpine and Busybox docker images

TL;DR:

The error lua: not found is a symptom of a dynamic linking failure, and is common when trying to run mainland Linux binaries on musl-libc based Linux, such as Alpine Linux and the busybox based image.

To fix this, switch to a lightweight glibc based image (e.g. Debian Slim) or install glibc on the Alpine container. Making this work for BusyBox is unpractical.

Full Explanation:

A bit of background. libc, the standard C library, provides the C and POSIX APIs to Linux programs and is an intrinsic part of the Linux system. Most Linux distributions are based on glibc, the GNU C library. However, both Alpine Linux and BusyBox images are based on musl standard C library, which is generally incompatible with glibc. Consequently, executables that are built on glibc-based distros such as Ubuntu, Debian or Arch Linux, won't work out of the box on Alpine Linux or BusyBox.

The linking error is manifested when trying to run the glibc executable. You could verify this by switching the image to alpine and running ldd:

/ataraxis # ldd /usr/local/bin/luarocks 
/lib64/ld-linux-x86-64.so.2 (0x7fbd14310000)
libdl.so.2 => /lib64/ld-linux-x86-64.so.2 (0x7fbd14310000)
libpthread.so.0 => /lib64/ld-linux-x86-64.so.2 (0x7fbd14310000)
libm.so.6 => /lib64/ld-linux-x86-64.so.2 (0x7fbd14310000)
libc.so.6 => /lib64/ld-linux-x86-64.so.2 (0x7fbd14310000)
Error relocating /usr/local/bin/luarocks: __fprintf_chk: symbol not found
Error relocating /usr/local/bin/luarocks: makecontext: symbol not found
Error relocating /usr/local/bin/luarocks: setcontext: symbol not found
Error relocating /usr/local/bin/luarocks: __register_atfork: symbol not found
Error relocating /usr/local/bin/luarocks: __strdup: symbol not found
Error relocating /usr/local/bin/luarocks: __libc_alloca_cutoff: symbol not found
Error relocating /usr/local/bin/luarocks: __stpncpy: symbol not found
Error relocating /usr/local/bin/luarocks: __syslog_chk: symbol not found
Error relocating /usr/local/bin/luarocks: getcontext: symbol not found
Error relocating /usr/local/bin/luarocks: __open_2: symbol not found
Error relocating /usr/local/bin/luarocks: errno: symbol not found

The simple and safe solution for working with Alpine Linux is installing compatible software using the Alpine package manager, apk. However, the desired package may not exist for Alpine, for the specific package version may not be available. In this case, you have two options:

  • Use a glibc-based Docker image, such as Debian slim image (e.g. debian:buster-slim - 27MB compressed), instead of Alpine/BusyBox
  • Install glibc on the musl based image, making it compatible with glibc programs, but also increasing the image size considerably.

Why not BusyBox:

BusyBox is not suitable for this customization. Since it doesn't even have a package manager, all changes and additions to it must be be done manually. It is surely an extremely tedious and lengthy procedure. Alpine is still a very lightweight image, where you could install glibc fairly simply.

Updating the image to Alpine with glibc:

First, replace busybox with Alpine, preferably alpine:3.14 which is the latest Alpine release (in both places - line 1 and line 37).

Second, add the following lines after the COPY command:

ENV GLIBC_REPO=https://github.com/sgerrand/alpine-pkg-glibc
ENV GLIBC_VERSION=2.30-r0
RUN set -ex && \
apk --update add libstdc++ curl ca-certificates && \
for pkg in glibc-${GLIBC_VERSION} glibc-bin-${GLIBC_VERSION}; \
do curl -sSL ${GLIBC_REPO}/releases/download/${GLIBC_VERSION}/${pkg}.apk -o /tmp/${pkg}.apk; done && \
apk add --allow-untrusted /tmp/*.apk && \
rm -v /tmp/*.apk && \
/usr/glibc-compat/sbin/ldconfig /lib /usr/glibc-compat/lib

This will install glibc on the Alpine container. Finally, run luarocks.

For reference, I have posted the docker build output on pastebin.

Why do we use alpine image to create our custom image

In the first line of you Dockerfile you select which "virtual machine" you want to use.

Alpine 3.11 diff: unrecognized option: c BusyBox v1.31.1 () multi-call binary

Well I just had to add the diffutils package to the list after installing it everything works well



Related Topics



Leave a reply



Submit