Self-hosted service
phusion/baseimage-docker avatar
phusion/baseimage-docker

my_init, uutils coreutils, and the Noble default in baseimage-docker's Makefile

A minimal Ubuntu base image modified for Docker-friendliness

9,078 stars1,070 forksShellMIT

At a glance

What is it?
baseimage-docker takes Ubuntu and fixes what containers get wrong: PID 1 reaping, SIGTERM on stop, APT, and a syslog daemon. The trade is a full Ubuntu userland, and the build tooling still defaults to the Noble track while the newest published tags are Resolute.
Who is it for?
Adopt it if your container needs orderly shutdown, zombie reaping, a real log file and a package manager that works inside Docker, and if you are willing to inherit a full Ubuntu userland plus a Coreutils implementation that differs on Resolute. Check which LTS track you are on, read the Rust Coreutils section before writing start-up scripts, and remember that a local make build defaults to Noble while published tags are Resolute.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 6 days ago.
What is it written in?
Mainly Shell, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on November 13, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • phusion/baseimage-docker9,078 ★ · -7
Star history
Repository2026-09-222026-11-13
phusion/baseimage-docker9.1k9.1k

-7 Stars in the last 52 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

my_init exists because PID 1 has two jobs nobody else can do

A container's PID 1 inherits every orphaned child process and is the only process able to reap them, and that single responsibility is where most images go wrong. Baseimage-docker's answer is an init process at /sbin/my_init that performs both of the jobs the stock init systems get wrong. The first is reaping: without a correct init process a container fills up with zombie processes over time. The second is shutdown. docker stop sends SIGTERM to the init process, which should stop all services, but most init systems were built for hardware shutdowns and do not handle it correctly inside Docker, so processes get hard killed with SIGKILL instead, with no chance to deinitialize properly. The stated consequence of that is file corruption.

Resolute swaps GNU Coreutils for the Rust implementation

The newest base system changes more than the version string suggests. The components table names Ubuntu 26.04 LTS Resolute as the latest LTS, with the 24.04 Noble and 22.04 Jammy tracks also maintained, and then puts a warning in the same cell: Ubuntu 26.04 ships Rust Coreutils, the uutils implementation, instead of GNU Coreutils. A dedicated section covers the details and points at alternatives, which means the project treats the substitution as something you may need to undo. The consequence for your own Dockerfile is concrete: any layer that shells out to coreutils utilities is running a different implementation from the one those scripts were written against.

The Makefile default and the newest release are on different tracks

VERSION ?= noble-1.0.2 is the Makefile's default, while the three most recent releases are resolute-1.0.21, resolute-1.0.22 and resolute-1.0.23, dated 2026-10-18 to 2026-11-01. A plain make build therefore produces a Noble image tagged phusion/baseimage:noble-1.0.2 rather than the Resolute one you would pull. The consequence is that a local build and a published image can differ in both base system and utility implementation without either being wrong. NAME ?= phusion/baseimage supplies the image name, and setting BASE_IMAGE overrides it, deriving a name from the base image tag with the colon rewritten to a dash. Comparing behaviour between what you built and what you deploy means checking the track name first.

bash
docker build --no-cache -t $(NAME):$(VERSION_ARG) $(BUILD_ARG) --build-arg QEMU_ARCH=$(QEMU_ARCH) --platform $(PLATFORM) --rm image

Every build starts cold and targets a single platform

Two flags in the build rule decide how long a build takes and what comes out of it. The command passes --no-cache, so no layer from an earlier run is reused and each invocation rebuilds from the Dockerfile. It also passes one --platform, so the default path produces an image for a single architecture. Cross-architecture work is a separate target that hands the name and version to build-multiarch.sh through the environment, and a QEMU_ARCH build argument exists for the emulation cases that needs. The consequence is that the Dockerfile iteration speed the README attributes to the base image applies to images you build on top of it, not to the base image itself, and that supporting a second architecture means switching make targets rather than adding an option.

bash
env NAME=$(NAME) VERSION=$(VERSION_ARG) ./build-multiarch.sh

The release target refuses to push an image it has not seen

Publishing is guarded by a check rather than a script that assumes success. The rule depends on test, which runs the repository's runner script with the name and version in the environment, then pipes docker images through awk and grep looking for the exact version string. If the image is not there, the target stops with a message telling you to run make build, and only after that check does it push. The last line it prints is a reminder to create a tag by creating an official GitHub release, and a Changelog.md sits in the repository root. For a maintainer that means two systems can disagree about what a version is, and for a user it means a tag on the registry is not the same event as a GitHub release.

bash
release: test
	@if ! docker images $(NAME) | awk '{ print $$2 }' | grep -q -F $(VERSION_ARG); then echo "$(NAME) version $(VERSION_ARG) is not yet built. Please run 'make build'"; false; fi
	docker push $(NAME)
	@echo "*** Don't forget to create a tag by creating an official GitHub release."

The ssh target only finds the container you built yourself

There is one convenience for getting inside a running container, and it is narrow. The ssh target greps docker ps for the literal name and version pair, takes the first column as the container id, and hands it to tools/docker-ssh along with an optional SSH_COMMAND. When the grep comes back empty the recipe prints that the container is not running and exits with status 1. So the target assumes a container started under exactly that name and version tag. The moment you are looking at a container launched from a neighbouring version, there is no id to match and the target stops being useful. For that case the README's table of contents lists logging in via docker exec.

bash
ssh: SSH_COMMAND?=
ssh:
	ID=$$(docker ps | grep -F "$(NAME):$(VERSION_ARG)" | awk '{ print $$1 }') && \
		if test "$$ID" = ""; then echo "Container is not running."; exit 1; fi && \
		tools/docker-ssh $$ID ${SSH_COMMAND}

A syslog daemon is included so kernel messages have somewhere to go

The syslog-ng entry is not convenience. Without a syslog daemon running, services, and the kernel among them, cannot correctly log to /var/log/syslog, and important messages are simply lost. That is why the daemon is a named component of the image rather than something you add later, and it is a useful corrective about where container output comes from: redirecting your application's own stdout does not capture anything the kernel or a service wrote to the log file. Two other pointers belong in the same breath. A more complete base aimed at Ruby, Python, Node.js and Meteor applications lives in passenger-docker, and the contents list offers a way to remove optional services for people who would rather assemble their own image than inherit them.

The size pitch, the two registries, and a July release train

The opening claim is about footprint and capability at once: the image only consumes 8.3 MB of RAM, and it is presented as ahead of Busybox and Alpine on what it gives you. That is the argument for accepting a full Ubuntu userland rather than a minimal one. Delivery runs through two channels, the Docker registry and GitHub Container Registry, which matters for anyone whose builder can reach only one of them. The release train then moves fast on one track: the last push to the repository is 2026-11-01, and the newest tags are resolute-1.0.21, resolute-1.0.22 and resolute-1.0.23 from October and November 2026. So the source tree and the pullable images both sit on Resolute while the Makefile default still says Noble.

Editorial conclusion

Adopt it if your container needs orderly shutdown, zombie reaping, a real log file and a package manager that works inside Docker, and if you are willing to inherit a full Ubuntu userland plus a Coreutils implementation that differs on Resolute. Check which LTS track you are on, read the Rust Coreutils section before writing start-up scripts, and remember that a local make build defaults to Noble while published tags are Resolute.

Frequently asked questions

What is a base image docker?

A base image is what your own Dockerfile starts from, and phusion/baseimage-docker is one specific choice of it: Ubuntu 26.04 LTS Resolute or 24.04 LTS Noble, plus modifications for Docker-friendliness, administration tools that suit container use, and a mechanism for running multiple processes without breaking the one-process model.

Is Docker still relevant in 2026?

The repository does not take a position on that. It is an active image project whose last push is 2026-11-01, with resolute-1.0.23 released on 2026-11-01, and nothing in the files comments on Docker's wider adoption.

Why are people moving away from Docker?

The repository does not address that question. The project's own starting point is narrower: Ubuntu is not designed to run inside Docker, its init system assumes real or virtualized hardware, and configuring a minimal container-ready system involves many corner cases that the image exists to remove.

Does NASA use Docker?

The repository does not mention NASA. The resources it lists are its own website, the GitHub repository, the Docker registry page, a discussion forum, a Twitter account and a blog.

Official sources

  1. License: MIT
  2. phusion/baseimage-docker on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/phusion-baseimage-docker.svg)](https://hysenlabs.com/projects/phusion-baseimage-docker)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/phusion-baseimage-docker.svg)](https://hysenlabs.com/projects/phusion-baseimage-docker)

Was this useful?