3 Docker
Anagnostakis Ioannis edited this page 2026-07-13 10:54:16 +03:00

EN

Docker

A minimal, bootstrappable Slackware64-current container - with slacker as its package manager.

~54MB pull, 195MB on disk, 31 stock packages + slacker. It ships without gnupg and without a system CA store, and grows itself to full GPG-verified operation with its first install. Real glibc, real GNU coreutils, real pkgtools - every official Slackware package installs and runs, resolved by slacker's resolve-stock from a precomputed dependency database.

docker pull ghcr.io/rizitis/slackware64-current-ci:slacker-very_mini-testing
docker run --rm -it ghcr.io/rizitis/slackware64-current-ci:slacker-very_mini-testing

# or the same image from Docker Hub:
docker run --rm -it rizitis/slackware-slacker:slacker-very_mini-testing

Status: testing. The tag name says so. Built for CI and for exercising slacker on a bare system - not (yet?) a supported production base image.


Why it exists

A full Slackware installation has every stock library already, so official packages never declare dependencies - they simply assume a complete system. A container is the opposite: almost nothing is present, for example a naive installpkg gnupg2-*.txz gives you a binary that cannot load.

This image is the reason slacker grew RESOLVE_STOCK: the container asks for a package, and slacker pulls exactly what that package needs to run on a bare system - from data, not guesses. See Dependencies for the .dep side of resolution; stock deps are a separate, optional layer on top.


What is inside

The 31 stock packages, chosen from the real dependency graph (not guessed):

group packages
base aaa_glibc-solibs aaa_libraries aaa_base etc bash
GNU tools (pkgtools need them) coreutils findutils gawk grep sed gzip tar xz file
package handling pkgtools util-linux
libraries the above load ncurses readline zlib bzip2 acl attr libcap gmp mpfr pcre2 zstd lz4 lzlib
comfort nano less

plus the slacker package itself.

Worth knowing:

  • util-linux is there for installpkg, which needs rev to detect the package compression (without it every install fails with "external compression utility missing"). Some other util-linux tools (su, login, mount) lack their libraries until you install them - irrelevant in a container, and resolve-stock brings them if ever needed.
  • less is there for slacker show-changelog - without a pager the whole ChangeLog would dump to the terminal. (PAGER is respected, and more from util-linux also works: PAGER=more slacker show-changelog.)
  • No gnupg, no ca-certificates, no openssl. slacker's TLS is rustls with the Mozilla roots compiled into the binary - ldd on slacker shows only glibc. The mirror's certificate is verified without any system CA store, and gnupg2 arrives in the bootstrap below.

Preconfigured in /etc/slacker/slacker.conf, /etc/slacker/mirrors and /etc/slacker/blacklist:

VERIFY=md5
RESOLVE_STOCK=yes
STOCK_DB_URL=https://raw.githubusercontent.com/rizitis/Slackware64-Current-sofiles/main

VERIFY=md5 is required at first boot: the default VERIFY=all refuses to work without a gpg binary, and the image ships none - yet.

#  --- UNITED KINGDOM (UK) ---------------------------------------------------
https://slackware.uk/slackware/slackware64-current/

This is the preconfigured default slackware64-current mirror - replace it with your own at any time (slacker find-mirror lists the fastest ones).

The 31 base packages are also blacklisted by default - they are frozen: no slacker operation (remove, remove-template, clean-system, upgrade replacing them with another repo's build) will ever touch the image's foundation. The only way to remove one is a manual removepkg - which you should not do, it breaks the container. See Blacklist for how the mechanism works; edit /etc/slacker/blacklist if you really know better.


The bootstrap

The image is born small and arms itself. In order - steps 2-4 are optional: they upgrade the default md5-only verification to full GPG:

%%{init: {'theme':'base','themeVariables':{'primaryColor':'#161b22','primaryBorderColor':'#1f6feb','primaryTextColor':'#e6edf3','lineColor':'#6e7781','fontFamily':'monospace'}}}%%
flowchart LR
  A["update<br/>(md5 + stock-db)"] --> B["install gnupg2<br/>(15 pkgs via closure)"]
  B --> C["update gpg<br/>(TOFU key pin)"]
  C --> D["VERIFY=all"]
  D --> E["full GPG<br/>forever after"]
  classDef blue fill:#0d1117,stroke:#1f6feb,color:#e6edf3;
  classDef green fill:#0d1117,stroke:#2ea043,color:#e6edf3;
  class A,B,C,D blue
  class E green
# 0) OPTIONAL: pick a faster mirror and replace the stock one - exactly ONE
#    line must be uncommented in /etc/slacker/mirrors
slacker find-mirror
nano /etc/slacker/mirrors

# 1) metadata + the stock dependency database, md5-verified over HTTPS
slacker update

# 2) OPTIONAL: gnupg2 + its whole crypto chain (15 packages, not 300 - see below)
slacker install gnupg2

# 3) OPTIONAL: pin the Slackware signing key (trust-on-first-use - see the Security wiki page)
slacker update gpg

# 4) OPTIONAL: full signature verification from now on
nano /etc/slacker/slacker.conf     # VERIFY=md5  ->  VERIFY=all

# 5) Doctor: Checking your setup. 
slacker status

# 6) Update repository metadata
slacker update

After step 4 the container verifies every package's GPG signature exactly like a full installation. The md5 window exists only between first boot and step 3, and even inside it every transfer is HTTPS against rustls' pinned roots plus md5 integrity - the trust model is "the official mirror, over verified TLS", upgraded to "the Slackware signing key" as soon as gpg exists.

Non-interactive use (CI / workflows)

Every prompt slacker asks - the update repo selection, the install plan's y/N, the multi-match picker - is auto-accepted with --yes. That is what CI pipelines and Dockerfiles want:

slacker --yes update
slacker --yes install gnupg2
slacker --yes update gpg

One-shot example (a workflow step or a RUN line):

docker run --rm ghcr.io/rizitis/slackware64-current-ci:slacker-very_mini-testing \
    bash -c "slacker --yes update && slacker --yes install gnupg2"

--dry-run still works with it if you only want the plan printed.

More options and all 39 actions: slacker --help - and see Commands for the full reference.


Stock dependency resolution

slacker status shows the extra row when RESOLVE_STOCK=yes:

  ✓ Stock-db   present, valid, in sync with -current

The database (depgraph.db, from Slackware64-Current-sofiles) ships a precomputed closure table: for every stock package, what it needs to run on a bare system. It is computed from the real ELF files - level 1 is the whole package's own NEEDED plus its runtime hints; deeper levels follow only the NEEDED chains of libraries, i.e. exactly what the dynamic loader would pull. Tool-only dependencies of other packages never cascade in: glibc's memusagestat links libgd, gnupg2's dirmngr links openldap, and a naive graph walk through such edges drags in half the distribution (~300 packages for gnupg2 - measured). The closure stops where the loader stops.

Real numbers from this image, all verified live:

slacker install ... packages pulled result
gnupg2 15 (gnutls, nettle, libgcrypt, sqlite, icu4c, ...) runs, verifies
ffmpeg 66 (codecs, X/VA/VD, SDL2 - all genuine NEEDED) loads
xsnow 37 (the whole GTK3 stack) loads, snows over X11

slacker itself stays dumb on purpose: one SELECT on the closure table, no graph-walking, no guessing - the repository's data is the resolver. With RESOLVE_STOCK=no (the default outside this image) nothing changes anywhere.


Templates: a build environment in one command

The slacker inside this image ships 36 curated templates - plain-text package lists (one name per line, plus include <template> lines) that turn the minimal container into a ready build environment with a single command. Combined with resolve-stock, every package a template names arrives with its full runtime closure - so install-template cargo really does leave you with a working Rust toolchain, not a pile of unlinkable binaries. See Templates for the general feature reference; this section is about how they are used (and curated) in the container.

The four commands:

generate-template  Snapshot installed packages into a template
install-template   Install all packages listed in a template
remove-template    Remove all packages listed in a template
delete-template    Delete a template file (does not touch installed packages)

What ships, by family:

family templates
toolchain base base (gcc, binutils, glibc, kernel-headers, make, pkgconf, patch, diffutils, which)
build systems autotools cmake meson cargo
languages ada cxx d fortran go lua nodejs objc perl php python ruby tcl vala
stacks gtk qt5 qt6 llvm kernel
SlackBuilds.org build sets sbo_autotools sbo_cargo sbo_cmake sbo_go sbo_haskell sbo_meson sbo_perl sbo_python sbo_rubygem
misc docs extras vcs

Typical CI usage - a Rust build job on this image is literally:

docker run --rm ghcr.io/rizitis/slackware64-current-ci:slacker-very_mini-testing \
    bash -c "slacker --yes update && slacker --yes install-template cargo && cargo build --release"

Most language templates start with include base - installing go gives you the Go compiler and the C toolchain underneath it, because that is what building software needs. Includes resolve recursively; a template only lists what is specific to it.

How the container templates are curated - and why it matters: no template in this image references ANY of the 31 base packages. That is deliberate, and it is a safety rule, not tidiness: remove-template removes everything a template names, following its includes. An early version of base listed file, tar, coreutils and friends - so remove-template go (which includes base) stripped them out of the running container and broke it. The fix lives in the data, where slacker's philosophy says it belongs: templates describe what they ADD on top of the image, never the image itself. If you write your own templates for this container, follow the same rule.

And there is a second, independent safety layer: the 31 base packages ship blacklisted (see above), so even a template that DOES name one of them cannot make slacker remove it - the blacklist wins. Belt and suspenders: the curation keeps templates honest, the blacklist keeps the foundation standing even against a dishonest one.

Two behaviours worth knowing before you script around them:

  • remove-template follows includes. remove-template go removes google-go-lang AND the whole base toolchain (gcc, make, ...). In a CI container that is usually exactly what you want - "tear down the build environment" - but if you built several environments on top of base, removing one tears the shared foundation from under the others. Remove the leaf templates last, or just throw the container away (--rm does it for you).
  • generate-template snapshots the container. After hand-installing a working set, slacker generate-template mystack writes it as a reusable list - drop it in /etc/slacker/templates/ of your own image build and your environment is reproducible.

All template commands honor --yes, so they are workflow-safe.


Running X11 programs (but, hey do you need X in a slackware docker image?)

The container has no display. To show windows on the host's desktop (X11 or Wayland via XWayland):

# on the host, once:
xhost +local:docker

docker run --rm -it \
    -e DISPLAY=$DISPLAY \
    -v /tmp/.X11-unix:/tmp/.X11-unix \
    ghcr.io/rizitis/slackware64-current-ci:slacker-very_mini-testing bash

# inside:
slacker update
slacker install xsnow      # pulls the GTK3 stack (37 packages)
xsnow                      # ❄

Add --device /dev/dri for GPU acceleration. Revoke access afterwards with xhost -local:docker.


Building the image yourself

The build script lives in its own repository: slackware64-current-ci. It needs:

  • a local Slackware64-current tree (rsync mirror) - set SLACKWARE_TREE at the top of the script;
  • the slacker binary package (slacker-*.txz) in a BINS/ folder next to the script - build it from source first, see Installation;
  • docker and root (the script uses installpkg --root into a scratch rootfs).
sudo bash slacker-docker.sh

The script installs the 31 packages into a scratch rootfs with installpkg --root, installs everything from BINS/, writes the bootstrap config, strips docs/man/info and locales (~15MB), produces a single-layer FROM scratch image, and (optionally - uncomment the push lines) publishes it to GHCR / Docker Hub.

Two build details that cost real debugging time, recorded here so nobody repeats them:

  • Use installpkg --root, not upgradepkg --root, for a fresh rootfs. upgradepkg --install-new --reinstall --root fails silently on an empty root - the log claims success, the rootfs stays empty.
  • The build host's tools are not the container's tools. installpkg works during the build (it runs on the host, which has rev) and then fails inside the container if util-linux is missing. Test installs in the container, not just the build.

FAQ

Why is the image 195MB when alpine is 8MB? Alpine is musl + busybox - a different world, binary-incompatible with Slackware packages. This image is genuine Slackware: real glibc (~35MB by itself), real GNU userland, and aaa_libraries (~30MB), which is what lets the closure table resolve libstdc++/zlib/readline needs to the always-present base bundle instead of dragging in gcc-g++. For comparison: debian-slim ~75MB, fedora ~180MB - and no other Slackware image is both this small and able to install the whole distribution correctly.

slacker install fails with "external compression utility missing". Your image predates util-linux in the package list (installpkg needs its rev). Rebuild with the current script.

show-changelog dumps everything. No pager found. slacker install less, or PAGER=more slacker show-changelog (more ships in util-linux).

Can I skip the bootstrap and stay on md5? Yes - it keeps working. You are trusting HTTPS (rustls pinned roots) plus the official mirror's checksums instead of the Slackware signing key. For anything beyond throwaway CI, do the three extra commands.

Does RESOLVE_STOCK=yes change slacker's behaviour on my real machine? On a full installation every stock dep is already installed, so the plan shows nothing new - it is effectively a no-op there. The feature earns its keep exactly here, on bare systems.


slacker is free software under the Apache License 2.0, by Ioannis Anagnostakis (rizitis). Sources: https://forge.slackware.nl/rizitis/slacker.