Back to Blog
ContainersHPCReproducibility

Docker vs Singularity/Apptainer: Choosing a Container Tool for Bioinformatics

Why HPC clusters ban Docker's root daemon, how Apptainer's rootless .sif images fix it, and how to pull or convert a container image for the cluster.

SSSudipta SardarJuly 20, 202610 min read
Docker vs Singularity/Apptainer: Choosing a Container Tool for Bioinformatics

You built a variant-calling pipeline on your laptop with Docker, it works perfectly, and now your PI wants it run across 500 samples on the university cluster. You SSH in, type docker pull, and the command does not exist — or worse, it prints a permission error and a note telling you to email the sysadmin. This is not a misconfiguration. Nearly every academic HPC cluster deliberately refuses to install Docker, and understanding why is the difference between fighting the system and working with it. The answer is a second container tool built for exactly this world: Apptainer, formerly known as Singularity.

Why Containers at All

Bioinformatics has a reproducibility problem that conda alone does not fully solve. A tool might depend on a specific glibc version, a compiled binary, a system library, or a Perl module that behaves differently across operating systems. A container packages the entire userland — the tool, its dependencies, and a minimal Linux filesystem — into one artifact that runs identically on your Mac, a colleague's Ubuntu box, and a cluster node running a decade-old RHEL. If you have used conda environments with bioconda channels, think of a container as the next layer of isolation: conda pins your Python and R packages, while a container pins the operating system underneath them too.

The payoff is real reproducibility. A paper that ships a container image lets a reviewer reproduce every figure years later, long after the original conda channels have shifted. That is why workflow managers like Nextflow and Snakemake treat containers as first-class citizens.

The Root Daemon Problem

Docker's architecture is the whole story. When you run docker run, you are not launching a process directly — you are asking a background service, the Docker daemon (dockerd), to launch it for you. That daemon runs as root. Any user who can talk to the Docker socket can therefore start a container that mounts the host filesystem and hands them root access to the entire machine. On a single-tenant laptop, fine. On a shared cluster with thousands of users and sensitive genomic data under HIPAA or dbGaP controls, it is a catastrophe: membership in the docker group is effectively equivalent to sudo.

Cluster administrators cannot allow that. They also run batch schedulers like Slurm that need to track and limit each job's CPU, memory, and walltime. Docker's daemon launches processes outside the scheduler's control, so a container's resource usage becomes invisible to Slurm. Between the security hole and the scheduling blind spot, Docker is a non-starter in HPC — not because admins are behind the times, but because the design is fundamentally wrong for a multi-tenant machine.

The security risk is not hypothetical or about "trusting users." Even a completely honest user running an honest container can be handed root by a bug in an image. The threat model on a shared cluster assumes accidents, not just malice, and one compromised login node can expose every other user's unpublished data.

How Apptainer Solves It

Apptainer (and its lineage through Singularity) was written at Lawrence Berkeley National Laboratory specifically for HPC. Two design choices flip the Docker model on its head.

First, there is no persistent root daemon. A container runs as a normal child process of your shell, under your user ID. If your account can read a given file, so can the process inside the container; if it cannot, neither can the process. You cannot escalate to a root you did not already have. Slurm sees the process as an ordinary job and accounts for it normally.

Second, images are single files. A Docker image is a stack of layers cached in /var/lib/docker, a directory you do not own and cannot access on a cluster. An Apptainer image is one .sif file (Singularity Image Format) sitting in your home or scratch directory. You can cp, scp, rsync, or md5sum it like any other file, drop it in your project folder next to your .bam and .vcf outputs, and cite its checksum in a methods section. That single-file, user-owned model is what makes it deployable where Docker is not.

Docker vs Apptainer at a Glance

AspectDockerApptainer / Singularity
Runs asroot daemon (dockerd)your user, no daemon
Image formlayered cache in /var/lib/dockersingle portable .sif file
Default HPC availabilityalmost never installedthe standard container runtime
Home directory insideisolated by defaultbind-mounted automatically
GPU / MPI accessextra flags, root setupfirst-class, built for it
Build step needs rootyes--fakeroot, often unprivileged
Best fitlocal dev, CI, web servicesshared clusters, reproducible science

The takeaway is not that one tool is better. Docker is excellent for local development and building images; Apptainer is what you deploy to the cluster. Most groups use both: build and test with Docker on a laptop, convert and run with Apptainer on HPC.

Pulling a Biocontainer

You rarely need to build an image from scratch. The Biocontainers project automatically packages nearly every Bioconda recipe as a container and hosts it on Quay.io. If a tool is on bioconda, a container almost certainly exists.

Say you want samtools on a cluster with no modules for it. Apptainer can pull directly from a Docker registry and convert on the fly to .sif:

bash
# Pull the samtools Biocontainer from Quay.io and get a local .sif
apptainer pull samtools.sif docker://quay.io/biocontainers/samtools:1.21--h50ea8bc_0

# Run it — your current directory and $HOME are bound automatically
apptainer exec samtools.sif samtools --version

# Sort a BAM using the containerized binary, no local install needed
apptainer exec samtools.sif samtools sort -@ 4 input.bam -o sorted.bam

Two details matter. The docker:// prefix tells Apptainer to fetch a Docker/OCI image and repack it as SIF. And the version tag — 1.21--h50ea8bc_0 — is not decoration. The string after -- is the Bioconda build hash. Pinning the exact tag, rather than :latest, is what makes the run reproducible; :latest will silently drift the day a new build lands. If BAM sorting is unfamiliar, our primer on SAM and BAM files explains what these commands are doing.

Apptainer bind-mounts your home directory and current working directory into the container by default, which is convenient but surprising if you come from Docker. It means the container can read and write your real files with no -v flag. If a tool insists a file is missing, check that it lives under a bound path; use --bind /scratch/project:/scratch/project to expose directories outside your home, such as a shared reference-genome location.

Converting a Docker Image for the Cluster

Sometimes the image you need is a custom one your lab built, or a tool published only to Docker Hub, not Biocontainers. The workflow is: build and test locally with Docker, then hand a portable artifact to Apptainer.

The cleanest route pushes to a registry the cluster can reach:

bash
# On your laptop: build and push to Docker Hub
docker build -t yourname/mypipeline:1.0 .
docker push yourname/mypipeline:1.0

# On the cluster: pull and convert to a single .sif
apptainer pull mypipeline.sif docker://docker.io/yourname/mypipeline:1.0

If the cluster has no internet on its compute nodes — common for secure genomics environments — export the image to a file and copy it over instead:

bash
# Laptop: save the Docker image to a tarball
docker save yourname/mypipeline:1.0 -o mypipeline.tar

# Copy it to the cluster, then convert the local tar to SIF
scp mypipeline.tar user@cluster:~/
apptainer build mypipeline.sif docker-archive://mypipeline.tar

Note apptainer build versus apptainer pull: build is the general command that produces a .sif from many sources — a Docker archive, a definition file, or a registry URL — while pull is a convenience wrapper for the registry case. Once you have mypipeline.sif, it is a plain file. Version it, checksum it, and archive it alongside your results.

Building from a Definition File

For full control, Apptainer uses a definition file (.def), its analogue to a Dockerfile. You can bootstrap from an existing Docker image and layer your own steps on top:

Bootstrap: docker
From: quay.io/biocontainers/samtools:1.21--h50ea8bc_0

%post
    apt-get update && apt-get install -y bcftools

%runscript
    exec samtools "$@"

Build it with apptainer build mytools.sif mytools.def. Historically this needed root; modern Apptainer offers --fakeroot, letting an unprivileged user build inside a user namespace so you can construct images on the cluster itself without bothering an admin. Whether --fakeroot is enabled is a site policy, so check your cluster's docs.

When to Reach for Which

Choose based on where the code will ultimately run. If you are prototyping on a laptop, developing a web service, or wiring up CI, Docker's ecosystem and tooling are hard to beat. The moment your work needs to scale across a shared cluster — batch variant calling, large RNA-seq differential expression runs, or anything touching controlled-access data — Apptainer is the tool the environment is built around. Because a .sif can be produced from any Docker image, you lose nothing by developing with Docker and deploying with Apptainer; that is the mainstream pattern in genomics today.

Practical Takeaways

  • HPC clusters ban Docker because its root daemon is a privilege-escalation risk and its processes escape the Slurm scheduler — this is deliberate, not backward.
  • Apptainer runs containers as your user with no daemon, and ships each image as one portable .sif file you own and can checksum.
  • Pull almost any bioinformatics tool straight from Biocontainers with apptainer pull tool.sif docker://quay.io/biocontainers/NAME:VERSION and always pin the exact version tag, never :latest.
  • Convert a Docker image for the cluster by pushing to a registry and pulling with docker://, or by docker save to a tarball plus apptainer build docker-archive://.
  • Apptainer auto-mounts your home and working directory; use --bind to expose shared paths like reference genomes on scratch.
  • Develop with Docker locally, deploy with Apptainer on HPC — the two are complementary, not rivals.

Containers sit one layer above your package manager, so they pair naturally with the reproducibility habits you already have. If you have not locked down that lower layer yet, start with conda and bioconda channels, then wrap the whole thing in a .sif when it is time to move to the cluster.