How to Migrate Docker Image Storage to containerd on Linux in 2025

Why Docker 29 Changed the Default Image Store

Docker 29 introduced a significant architectural shift by adopting containerd as the default image store for new installations. This change moves away from the legacy image storage format to a more modern, standards-compliant approach. The containerd image store offers better performance, improved compatibility with Kubernetes, and native support for modern container runtimes.

If you've upgraded to Docker 29 or later, or you're running existing installations alongside new deployments, understanding how to migrate to the containerd image store is essential.

Understanding the Storage Difference

The legacy Docker image store used a custom storage driver architecture that worked well for years. However, containerd uses the OCI Image Format specification, which provides:

  • Better interoperability with Kubernetes and other container platforms
  • Native support for snapshotters (storage backends like overlayfs, nativeFS)
  • Improved performance for image operations
  • Future-proof architecture aligned with industry standards

When you upgrade Docker Engine, existing images remain in the legacy store. New images pulled after the migration use the containerd store.

Prerequisites

Before migrating, ensure you have:

  • Docker Engine 29 or later installed
  • Linux system (Ubuntu 20.04+, Debian 11+, CentOS 8+, or similar)
  • At least 5GB free disk space for image storage
  • Docker daemon running with superuser access
  • Backup of critical container configurations

Step 1: Check Your Current Storage Configuration

First, verify which image store your Docker installation is currently using:

docker info | grep -A 10 "Storage Driver"

You'll see output similar to:

Storage Driver: overlay2
Storage Location: /var/lib/docker
Logging Driver: json-file

For containerd, look for:

Storage Driver: containerd

If you see overlay2 or aufs, you're still using the legacy image store.

Step 2: Edit Docker Daemon Configuration

Modify the Docker daemon configuration file to enable containerd as the image store. Edit /etc/docker/daemon.json:

sudo nano /etc/docker/daemon.json

Add or modify the features section to include containerd-snapshotter:

{
  "features": {
    "containerd-snapshotter": true
  },
  "storage-driver": "overlay2"
}

If the file doesn't exist, create it with the above content. For existing configurations, merge the new settings while preserving other options like insecure-registries, registry-mirrors, or custom storage-driver settings.

Step 3: Restart Docker Daemon

Apply the configuration changes by restarting Docker:

sudo systemctl restart docker

Verify the restart was successful:

sudo systemctl status docker

Step 4: Verify containerd Integration

Confirm that Docker is now using containerd:

docker info | grep -A 5 "Storage"

You should see output indicating containerd integration is active.

Step 5: Manage Image Migration

Your legacy images remain in the old storage location. You have two options:

Option A: Let Docker Handle It Gradually

New images pulled after enabling containerd-snapshotter are automatically stored in the containerd image store. Old images continue working but use legacy storage.

# Pull a new image - this goes to containerd store
docker pull ubuntu:latest

# Your old images still work
docker run myapp:v1.0

Option B: Explicitly Migrate Specific Images

To move important images to the new store immediately:

# Re-pull the image to populate containerd store
docker pull myregistry/myapp:v1.0

# Verify it's in containerd store
docker images

Step 6: Clean Up Legacy Storage (Optional)

Once you've verified all critical images work with the new store, clean up unused legacy images:

# Remove unused images
docker image prune -a

# Clean up docker system (careful - this removes dangling layers)
docker system prune

Check disk space before and after:

du -sh /var/lib/docker

Troubleshooting Common Issues

Issue: Docker daemon won't start after configuration change

Verify JSON syntax in /etc/docker/daemon.json:

jq . /etc/docker/daemon.json

If there's a syntax error, fix it and retry the restart.

Issue: Images not appearing in containerd store

Confirm containerd-snapshotter is enabled:

docker info | grep containerd-snapshotter

If not enabled, check daemon logs:

sudo journalctl -u docker -n 50

Issue: Performance degradation after migration

Ensure your storage backend (overlayfs) is properly configured:

ls -la /var/lib/docker/

If you see excessive files, consider using fuse-overlayfs on systems without native overlayfs support.

Performance Considerations

The containerd image store typically improves:

  • Image pull speed by 10-15% for large images
  • Container startup time by utilizing OCI Image Format optimizations
  • Disk usage through better deduplication

Monitor your system after migration:

docker system df

This command shows space used by images, containers, and build cache.

Migration Comparison Table

| Aspect | Legacy Store | containerd Store | |--------|--------------|------------------| | Default in Docker 29+ | No | Yes | | OCI Compliance | Partial | Full | | Kubernetes Compatibility | Indirect | Native | | Performance | Standard | Optimized | | Snapshotter Support | Limited | Full | | Migration Required | No | No* | | Coexistence Support | Yes | Yes |

*New images automatically use containerd store

Next Steps

After successful migration:

  1. Update CI/CD pipelines to leverage containerd features
  2. Test your applications with the new image store
  3. Document the change in your infrastructure runbooks
  4. Plan removal of legacy storage when no longer needed
  5. Monitor docker system df regularly for disk usage patterns

The transition to containerd-based image storage positions your Docker infrastructure for better Kubernetes integration and future container platform improvements.

Recommended Tools

  • DockerDevelop faster. Run anywhere.
  • DigitalOceanCloud hosting built for developers — $200 free credit for new users