← Back to list

Understanding Container Runtime Internals: containerd and runc in Practice

Most of us start our container journey with Docker. We run a simple command, and everything just works. But have you ever wondered what…

Shivaji Bedre · 2026-04-03 06:33 · 0 claps · 3.6 min read
#containerd #devops #containers #docker #runc
Open on Medium ↗
Wiki topics: ☁️ · DevOps & Cloud 🥊 · Combat Sports

Understanding Container Runtime Internals: containerd and runc in Practice

Most of us start our container journey with Docker. We run a simple command, and everything just works. But have you ever wondered what actually happens under the hood?

In this article, I explored container internals using containerd and runc, going beyond Docker to understand how containers really run.

📦 What is containerd?

containerd is a high-level container runtime responsible for managing the full lifecycle of containers. It handles operations such as pulling images, managing storage, creating containers, and running workloads.

It sits between tools like Docker or Kubernetes and the Linux kernel, acting as the core engine that actually runs containers.

🔧 Architecture Flow

Client (ctr / CRI / Docker)
        ↓
    containerd
        ↓
   containerd-shim
        ↓
       runc
        ↓
     Linux Kernel
  • containerd daemon → manages images, containers, tasks
  • containerd-shim → keeps containers alive independently
  • runc → actually runs containers using Linux features

🧠 Key Concepts You Must Know

Understanding containerd becomes easy when you separate these three concepts:

📌 Image

A packaged application (like hello-openshift) stored in registries.

📌 Container

A configured instance of an image — but not running yet.

📌 Task

The actual running process inside a container.

👉 The most important takeaway:

Container ≠ Running Task = Execution

🧪 Hands-On: Container Lifecycle Using containerd (ctr)

To understand this practically, I performed a simple lifecycle task using ctr.

🔹 Step 1: Pull Image

ctr image pull docker.io/openshift/hello-openshift:latest

🔹 Step 2: Create Container

ctr container create docker.io/openshift/hello-openshift:latest mycont2

🔹 Step 3: Start Task

ctr task start -d mycont2

At this point:

  • Container exists ✅
  • Task is running ✅

Key Observation

If you create a container but don’t start it:

  • Container exists
  • Task does NOT exist

Once you start it:

  • Task appears
  • Container becomes active

This is one of the most important concepts in container runtimes.

⚠️ Important Notes About containerd

  • containerd does not build images (Docker does)
  • It focuses only on runtime
  • Used by:
  • Kubernetes (via CRI)
  • Docker internally

⚙️ Going Deeper: Running a Container Using runc

To truly understand containers, I went one level deeper and used runc directly — without Docker or containerd.

This is where things get interesting.

🔹 What is runc?

runc is a low-level runtime that directly interacts with the Linux kernel to create containers using:

  • Namespaces
  • cgroups

It does not manage images — it only runs containers from a prepared bundle.

.

🧪 Hands-On with runc

🔹 1. Install runc

First, ensure runc is installed on your system:

apt-get update
apt-get install -y runc

🔹 2. Create Working Directory

Create a directory to store your container bundle:

mkdir mycontainer
cd mycontainer

🔹 3. Create OCI Configuration

Generate the default OCI config file:

runc spec

👉 This creates:

  • config.json (defines how the container will run)

🔹 4. Create Root Filesystem and Download BusyBox

Create a minimal root filesystem:

mkdir rootfs
cd rootfs
wget https://busybox.net/downloads/binaries/1.21.1/busybox-x86_64
chmod +x busybox-x86_64

🔹 5. Run the Container

Go back and run the container:

cd ~/mycontainer
runc run myrunccontainer

🧠 What I Learned (Real Insight)

This exercise changed how I think about containers.

👉 A container is not a virtual machine 👉 It is just a process with isolation

runc creates that isolation using:

  • PID namespace → separate process IDs
  • Mount namespace → separate filesystem
  • UTS namespace → separate hostname
  • Network namespace → separate networking

🔥 The Big Picture

Now everything connects:

  • Docker → User-friendly tool
  • containerd → Manages lifecycle
  • runc → Actually runs the container

👉 In short: containerd manages, runc executes

🚀 Final Thoughts

Before this, containers felt like a black box. After working with containerd and runc directly, things became much clearer.

Understanding these internals is especially useful if you’re working with:

  • Kubernetes
  • DevOps
  • Cloud-native systems

Because at the end of the day:

Containers are just processes with boundaries.

📌 If You’re Learning DevOps

Don’t stop at Docker. Go one layer deeper — that’s where real understanding begins.


메타데이터
post_id
152a1c751ffd
slug
understanding-container-runtime-internals-containerd-and-runc-in-practice-152a1c751ffd
url
https://medium.com/@shivajibedre67/understanding-container-runtime-internals-containerd-and-runc-in-practice-152a1c751ffd
canonical_url
https://medium.com/@shivajibedre67/understanding-container-runtime-internals-containerd-and-runc-in-practice-152a1c751ffd
author_url
https://medium.com/@shivajibedre67
status
ok
fetched_at
2026-06-23 03:48:11