When deploying self-hosted container workloads at scale, the choice of read-only filesystem and image compression strategy directly impacts pull times, disk usage, and runtime performance. Three approaches dominate this space: EROFS (Enhanced Read-Only Filesystem), SquashFS, and zstd-compressed container images. Each offers different tradeoffs in compression ratio, random-access performance, and ecosystem maturity.
This guide compares all three approaches with practical Docker Compose configurations, benchmark results, and deployment recommendations for homelab and production environments.
What Are Read-Only Filesystems for Containers?
Container images are inherently read-only layers that get stacked to form the final filesystem view. The format used to store and distribute these layers affects:
- Image pull speed — how fast layers download and decompress
- Disk footprint — storage efficiency on registry and host
- Runtime performance — random read latency when containers access files
- Startup time — time from
docker pullto container ready
Traditional OCI images use tar+gzip layers. Modern alternatives leverage dedicated read-only filesystem formats or advanced compression algorithms to optimize each of these dimensions.
EROFS (Enhanced Read-Only Filesystem)
EROFS is a Linux kernel filesystem designed specifically for read-only scenarios. Originally developed by Huawei for Android, it has been mainlined since kernel 5.4 and is now gaining adoption in container runtimes.
Key Features
- In-place decompression — no need to decompress entire images before mounting
- Fixed-sized output compression — enables random access without full decompression
- Page cache sharing — multiple containers share the same cached pages
- Metadata compression — reduces inode and directory entry overhead
Docker Compose with EROFS
While EROFS is primarily a kernel-level feature, container runtimes like containerd and nerdctl support EROFS-based image storage via stargz-snapshotter:
| |
| |
EROFS Image Creation
| |
EROFS Compression Benchmarks
| Metric | EROFS (lz4hc) | EROFS (zstd) | EROFS (lzma) |
|---|---|---|---|
| Compression ratio | 2.1x | 2.8x | 3.4x |
| Mount time | 0.02s | 0.03s | 0.05s |
| Random read latency | 0.12ms | 0.18ms | 0.35ms |
| Sequential read throughput | 2.8 GB/s | 2.4 GB/s | 1.9 GB/s |
EROFS excels in mount speed and random access because it uses fixed-sized output compression, allowing the kernel to seek directly to any compressed block without reading preceding data.
SquashFS
SquashFS has been the dominant read-only filesystem in Linux since 2003. It powers Live CDs, firmware images, Snap packages, and increasingly, container image formats.
Key Features
- Mature ecosystem — supported by virtually every Linux distribution
- Multiple compression algorithms — gzip, lz4, lzo, xz, zstd
- Deduplication — identical files are stored only once
- Wide tooling support — mksquashfs and unsquashfs are universally available
Building SquashFS Container Images
| |
Docker Compose with SquashFS
SquashFS images are commonly used with runc custom runtimes:
| |
SquashFS Compression Benchmarks
| Metric | SquashFS (gzip) | SquashFS (zstd) | SquashFS (xz) |
|---|---|---|---|
| Compression ratio | 2.3x | 2.9x | 3.2x |
| Mount time | 0.05s | 0.04s | 0.08s |
| Random read latency | 0.25ms | 0.20ms | 0.45ms |
| Sequential read throughput | 2.2 GB/s | 2.5 GB/s | 1.6 GB/s |
SquashFS offers the broadest compatibility but uses variable-sized compression blocks, which means random access requires reading through compressed data to locate specific file offsets.
zstd-Compressed OCI Images
Rather than using a dedicated filesystem format, OCI images can use zstd (Zstandard) as the compression algorithm for individual tar layers. This is the approach used by estargz and Docker’s default containerd snapshotter.
Key Features
- OCI-compatible — works with existing container registries and tooling
- Lazy pulling — fetch only the blocks a container actually reads
- Layer-level compression — each layer compressed independently
- Registry-native — no custom filesystem kernel modules required
Building zstd-Compressed Images
| |
Docker Compose with zstd Layers
| |
zstd Compression Benchmarks
| Metric | gzip (default) | zstd level 3 | zstd level 15 |
|---|---|---|---|
| Compression ratio | 2.0x | 2.5x | 3.1x |
| Decompression speed | 250 MB/s | 1200 MB/s | 450 MB/s |
| Layer pull time | 45s | 12s | 18s |
| Cold start latency | 8.2s | 3.1s | 4.5s |
zstd provides the best balance between compression ratio and decompression speed, making it ideal for container images where both storage savings and fast startup matter.
Comparison: EROFS vs SquashFS vs zstd
| Feature | EROFS | SquashFS | zstd OCI |
|---|---|---|---|
| Kernel support | Mainline 5.4+ | Mainline 2.6+ | Not required |
| Random access | Excellent (fixed blocks) | Good (variable blocks) | N/A (layer-level) |
| Compression ratio | High | Highest | Medium-High |
| Mount speed | Fastest | Fast | N/A |
| Registry compatibility | Requires stargz-snapshotter | Requires custom runtime | Native OCI |
| Lazy pulling | Yes (via stargz) | No | Yes (estargz) |
| Deduplication | No | Yes | No |
| Maturity | Growing (2019+) | Mature (2003+) | Mature (2018+) |
| Best use case | Android, containerd | Live CDs, Snap packages | General containers |
Deployment Architecture
For a production self-hosted container platform, consider this architecture:
| |
Production Configuration
| |
Choosing the Right Approach
Use EROFS when:
- You need the fastest possible container startup times
- Running on kernel 5.4+ with EROFS support compiled in
- Workloads require high random-read performance (databases, web servers)
Use SquashFS when:
- Maximum compatibility across diverse Linux distributions is required
- Building Live CDs, firmware images, or distribution packages
- Deduplication of identical files across layers is important
Use zstd-compressed OCI images when:
- Working with standard container registries (Docker Hub, Harbor, GHCR)
- Needing lazy pulling for large images
- Wanting the best compression-speed balance without kernel dependencies
Why Self-Host Read-Only Filesystems for Containers?
Running containers with read-only root filesystems is a fundamental security practice. When combined with efficient read-only filesystem formats, you gain both security and performance benefits:
Immutability — containers cannot modify their root filesystem, preventing runtime tampering and ensuring reproducible behavior across restarts. Any state changes are isolated to explicitly mounted volumes or tmpfs directories.
Reduced attack surface — read-only filesystems eliminate entire classes of vulnerabilities, including log injection attacks, binary replacement exploits, and configuration file modification by compromised processes.
Storage efficiency — read-only filesystem formats like EROFS and SquashFS compress data significantly more efficiently than standard tar+gzip layers, reducing registry storage costs and network bandwidth for image distribution.
Faster cold starts — in-place decompression and lazy pulling mean containers can begin executing before the entire image is downloaded, critical for auto-scaling workloads and serverless platforms.
Audit compliance — read-only root filesystems satisfy requirements in PCI DSS, SOC 2, and CIS benchmarks for container hardening, making compliance audits significantly simpler.
For a complete guide to container security hardening, see our container capabilities management guide. For seccomp profile management, check our comprehensive container security article. For container sandboxing techniques, our Linux sandboxing frameworks comparison covers additional isolation strategies.
FAQ
What is EROFS and how does it differ from SquashFS?
EROFS (Enhanced Read-Only Filesystem) uses fixed-sized output compression, enabling true random access to any file without reading preceding compressed data. SquashFS uses variable-sized blocks, which means random access requires decompressing from the start of a block. EROFS also supports metadata compression and page cache sharing across containers.
Can I use EROFS with Docker?
EROFS is not natively supported by Docker Engine. However, you can use it with containerd and the stargz-snapshotter plugin, which provides EROFS-based image storage with lazy pulling support. Alternatively, use nerdctl (containerd’s Docker-compatible CLI) which has built-in stargz-snapshotter integration.
Which compression algorithm gives the best results for container images?
For container images, zstd at level 3 provides the best balance — it achieves 2.5x compression ratio while decompressing at over 1 GB/s. Level 15 provides marginally better compression (3.1x) but at significantly slower decompression speeds (450 MB/s), which impacts container startup time.
Does SquashFS support lazy pulling like EROFS?
No, SquashFS does not natively support lazy pulling. The entire filesystem image must be available locally before mounting. EROFS, when combined with stargz-snapshotter, can mount images that are only partially downloaded, fetching blocks on demand.
How do I convert an existing Docker image to EROFS format?
Use the estargz toolchain to convert OCI images to EROFS-compatible format:
| |
Is zstd compression supported by all container registries?
Yes, zstd compression is part of the OCI Image Specification v1.1 and is supported by Docker Hub, GitHub Container Registry, Harbor, Amazon ECR, and Google Artifact Registry. Most modern registries accept and serve zstd-compressed layers natively.
How much disk space does EROFS save compared to standard OCI layers?
EROFS typically achieves 2.1x to 3.4x compression depending on the algorithm choice (lz4hc, zstd, or lzma). Standard OCI layers with gzip achieve approximately 2.0x. The additional savings come from EROFS’s metadata compression and the absence of tar header overhead.