How to Migrate from Docker to Podman: A Practical Guide to Daemonless Container Management
A step-by-step tutorial on seamlessly transitioning from Docker to Podman. Learn how to install Podman, migrate Docker CLI commands, configure Rootless security mode, and deploy a multi-container Node.js + Redis application without relying on a central daemon.

How to Migrate from Docker to Podman: A Practical Guide to Daemonless Container Management
Last month, our team's CI server crashed three times. Every single time, it was the Docker daemon consuming excessive memory until an OOM Kill took down the entire machine. After extensive debugging, I realized Docker's daemon model becomes a ticking time bomb when managing hundreds of containers: one central daemon controls everything, and if it fails, all containers go down with it.
Switching to Podman fixed the issue. The same machine has been running flawlessly for three months. Today, I'll guide you through migrating your local environment to Podman.
What You'll Achieve
By the end of this guide, you will be able to:
- Install Podman on your system
- Seamlessly migrate common Docker commands to Podman
- Run containers securely using Rootless mode (no
sudorequired) - Deploy a complete multi-container application
Prerequisites
- OS: Linux (Ubuntu/Debian/Fedora/CentOS), or Mac/Windows (via VM)
- Linux Kernel: 4.0+ recommended
- Background: Familiarity with Docker basics (images, containers, port mapping, volume mounting). If you're new, I'll highlight key differences along the way.
- Disk Space: ~200MB (Podman is lightweight and has no resident daemon)
Step 1: Install Podman
Starting with installation because setup methods vary significantly across platforms. Once this step is done, the rest is pure usage.
Linux (Ubuntu Example)
bash
## 1. Update package index
sudo apt update
## 2. Install Podman
sudo apt install -y podman
## 3. Verify installation
podman --version
## Expected output: podman version 5.x.x
For Fedora/CentOS systems, simply use sudo dnf install podman or sudo yum install podman. These distributions include it in their default repositories.
Why skip the
apt-keysetup Docker requires? Podman is an official OCI ecosystem component and is directly packaged in mainstream Linux distributions, unlike Docker which requires maintaining external repositories.
Mac / Windows
Since Mac and Windows lack native Linux kernel features, Podman uses a lightweight Linux VM via podman machine to run containers:
bash
## Install via Homebrew on Mac
brew install podman
## Initialize the VM (downloads a lightweight Linux image, ~500MB initially)
podman machine init
## Start the VM
podman machine start
## All subsequent podman commands are automatically forwarded to the VM
podman run hello-world
Why a VM? Podman relies on Linux cgroups and namespaces for isolation, which Mac/Windows kernels don't provide natively. However, this VM is significantly lighter than Docker Desktop, consuming less than 1GB of RAM by default.
Step 2: Quick Start & Docker Command Migration
If you're comfortable with Docker, here's the good news: Podman's CLI is highly compatible with Docker. The official team even maintains dedicated migration documentation.
Here's a quick reference for the most common commands:
| Docker Command | Podman Command |
|---|---|
docker run |
podman run |
docker ps |
podman ps |
docker images |
podman images |
docker pull |
podman pull |
docker stop |
podman stop |
docker exec |
podman exec |
docker logs |
podman logs |
docker rm |
podman rm |
docker build |
podman build |
docker compose |
podman-compose or podman compose |
Running Podman's "Hello World"
Podman provides a dedicated hello image. Just run it:
bash
podman run quay.io/podman/hello
You'll see output similar to this:
Trying to pull quay.io/podman/hello:latest...
Getting image source signatures
Copying blob a6b3126f3807 done
!... Hello Podman World ...!
.--"--.
/ - - \
/ (O) (O) \
~~~| -=(,Y,)=- |
What does this tell us? Podman defaults to
quay.io(unlike Docker Hub), but it fully supports pulling from Docker Hub. Your existingnginx,redis, and other image commands remain unchanged.
Real-World Example: Running Nginx
bash
## Pull the image (automatically pulls if not local)
podman pull nginx:alpine
## Run in detached mode, map port 8080
podman run -d --name my-nginx -p 8080:80 nginx:alpine
## Check running containers
podman ps
## Visit http://localhost:8080 in your browser to see the Nginx welcome page
## Stop the container
podman stop my-nginx
## Remove the container
podman rm my-nginx
How does this differ from Docker? Almost nowhere. That's by design: Podman lets you avoid learning a new CLI. The real difference is under the hood: the Docker daemon is completely gone.
Step 3: Rootless Mode for Secure Container Management
This is Podman's standout feature: running containers without root privileges.
Docker traditionally requires root access, meaning any user who can run docker commands effectively has root access to the host—a serious security risk. Podman was designed from the ground up to support Rootless mode.
Configuration Steps
bash
## 1. Verify your user has subordinate UID/GID ranges (default on most modern Linux distros)
cat /etc/subuid
## Expected: yourname:100000:65536
cat /etc/subgid
## Expected: yourname:100000:65536
## If missing, run:
sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 $USER
## 2. Install dependencies for rootless networking
sudo apt install -y slirp4netns fuse-overlayfs
## 3. Run a container as a regular user
podman run -d --name secure-nginx -p 8080:80 nginx:alpine
How does this work without root? Podman leverages Linux user namespaces. The
rootuser inside the container is mapped to your unprivileged host user. Even if the container is compromised, the attacker only gains your regular user permissions.
Verifying Rootless Mode
bash
## Check process ownership for running containers
ps aux | grep conmon
## You'll see processes owned by your user, not root
## Confirm Podman identity mode
podman info | grep -i rootless
## Should output: true
Hands-On: Build a Node.js + Redis App with Podman
Running single containers is fine, but let's build a complete microservice. We'll connect a Node.js backend to Redis using Podman.
Scenario
A simple Node.js app connects to Redis, increments a counter, and returns the current visit count via an API.
Step 1: Create the Application Code
bash
mkdir podman-demo && cd podman-demo
## Create package.json
cat > package.json << 'EOF'
{
"name": "podman-demo",
"version": "1.0.0",
"main": "app.js",
"dependencies": {
"express": "^4.18.2",
"redis": "^4.6.0"
}
}
EOF
## Create the application entry point
cat > app.js << 'EOF'
const express = require('express');
const { createClient } = require('redis');
const app = express();
const PORT = 3000;
let redisClient;
(async () => {
redisClient = createClient({ url: 'redis://redis-podman:6379' });
redisClient.on('error', err => console.log('Redis Connection Failed:', err));
await redisClient.connect();
})().catch(console.error);
app.get('/', async (req, res) => {
const count = await redisClient.incr('visits');
res.send(`Visit #${count} (Powered by Podman)\n`);
});
app.listen(PORT, '0.0.0.0', () => {
console.log(`Server running: http://0.0.0.0:${PORT}`);
});
EOF
Step 2: Create a Containerfile
Podman is fully compatible with Dockerfiles. You can name it Dockerfile, or use Containerfile (Podman's recommended convention):
dockerfile
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["node", "app.js"]
Step 3: Use Podman Networks for Inter-Container Communication
bash
## Create a dedicated network
podman network create app-network
## Run Redis container and attach to the network
podman run -d --name redis-podman \
--network app-network \
redis:alpine
## Build the application image
podman build -t my-node-app .
## Run the app container on the same network
podman run -d --name node-app \
--network app-network \
-p 3000:3000 \
my-node-app
Why use a custom network? Podman's networking model is fully compatible with Docker. Containers on the same Podman network can resolve each other via DNS using their container names. That's why
redis://redis-podman:6379in our code works instantly.
Step 4: Verification
bash
## Verify both containers are running
podman ps
## Test the API
curl http://localhost:3000
## Output: Visit #1 (Powered by Podman)
curl http://localhost:3000
## Output: Visit #2 (Powered by Podman)
Done. A real multi-container application, running entirely without ever touching a Docker daemon.
Common Pitfalls & Pro Tips
1. localhost Port Mapping on Mac/Windows
If you're on Mac or Windows, podman machine VM port forwarding might not bind directly to localhost. Use the following to check the VM IP or configure port forwarding explicitly:
bash
podman machine ssh ip address show podman0
2. Rootless Restrictions on Ports < 1024
Non-root users cannot bind to privileged ports. In Rootless mode, use high-numbered ports (e.g., 8080 instead of 80). If you strictly need port 80, run in root mode or place an Nginx reverse proxy in front.
3. Installing podman-compose
If you previously relied on docker-compose.yml, Podman's counterpart requires separate installation:
bash
## Ubuntu/Debian
sudo apt install -y podman-compose
## Or via pip
pip install podman-compose
## Usage becomes seamless
cd podman-demo
podman-compose up -d
4. Built-in Compose Support
Podman 5.x includes a native podman compose command (a compatibility layer calling podman-compose). If you're on Podman 5+, you typically don't need to install it separately.
Summary & Next Steps
Let's review what we covered today:
- Installation: One-liner setup across platforms
- CLI Migration: Drop-in replacement for most Docker commands
- Rootless Security: Run containers as a regular user, drastically reducing the attack surface
- Real-World Project: Deployed a Node.js + Redis app using Podman networking
Podman isn't just a "Docker alternative." Its daemonless architecture and native Rootless support translate to lower resource consumption and stronger security in production environments. If your team struggles with Docker daemon stability or needs to comply with strict least-privilege container audits, Podman is worth serious evaluation.
Recommended Next Steps:
- Explore Podman Pods: Group multiple containers in a shared network namespace, similar to Kubernetes Pods.
- Try
podman generate kube: Export running containers directly to Kubernetes YAML for zero-friction local-to-cloud deployments. - Check out Buildah: The ecosystem's dedicated image builder, capable of creating images without requiring a Dockerfile.
Have questions or run into edge cases? Drop them in the comments below.