Build Your Own Docker
Target Audience : Senior Engineers (5+ years experience)
Language : Java (with Go & JavaScript alternatives)
Duration : 4-6 weeks
Difficulty : ⭐⭐⭐⭐⭐
Why Build Docker?
Containers are the foundation of modern infrastructure . Every major company runs containers. By building your own Docker:
Master Linux internals — namespaces, cgroups, capabilities
Understand container security — isolation mechanisms, seccomp, AppArmor
Learn filesystem concepts — overlay filesystems, copy-on-write
Network programming — virtual networking, iptables, bridge networking
Demonstrate staff-level expertise — this is the “wow factor” project
This is the most challenging project in the course. You’ll need:
Linux experience (kernel concepts, syscalls)
Systems programming knowledge
Understanding of networking fundamentals
Familiarity with Docker as a user
Container Architecture Deep Dive
┌─────────────────────────────────────────────────────────────────────────────┐
│ CONTAINER RUNTIME ARCHITECTURE │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ USER SPACE KERNEL SPACE │
│ ────────── ──────────── │
│ │
│ ┌───────────────┐ ┌────────────────────────────────────────┐ │
│ │ CLI (docker) │ │ LINUX KERNEL │ │
│ └───────┬───────┘ │ │ │
│ │ │ ┌─────────────┐ ┌─────────────────┐ │ │
│ ┌───────▼───────┐ │ │ NAMESPACES │ │ CGROUPS │ │ │
│ │ Daemon │◄───────────►│ │ ─────────── │ │ ─────────────── │ │ │
│ │ (containerd) │ │ │ • PID │ │ • cpu │ │ │
│ └───────┬───────┘ │ │ • NET │ │ • memory │ │ │
│ │ │ │ • MNT │ │ • blkio │ │ │
│ ┌───────▼───────┐ │ │ • UTS │ │ • pids │ │ │
│ │ Runtime │ │ │ • USER │ │ │ │ │
│ │ (runc) │ │ │ • IPC │ │ │ │ │
│ └───────┬───────┘ │ └─────────────┘ └─────────────────┘ │ │
│ │ │ │ │
│ ┌───────▼───────┐ │ ┌─────────────────────────────────┐ │ │
│ │ Container │◄───────────►│ │ OVERLAY FS │ │ │
│ │ Process │ │ │ ┌─────┐ ┌─────┐ ┌─────┐ │ │ │
│ └───────────────┘ │ │ │Upper│ │Layer│ │Base │ │ │ │
│ │ │ │ │◄─│ 2 │◄─│Image│ │ │ │
│ │ │ └─────┘ └─────┘ └─────┘ │ │ │
│ │ └─────────────────────────────────┘ │ │
│ └────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
What You’ll Build
Core Features
Feature Description Linux Concept PID Namespace Process isolation CLONE_NEWPIDMount Namespace Filesystem isolation CLONE_NEWNSNetwork Namespace Network isolation CLONE_NEWNETUTS Namespace Hostname isolation CLONE_NEWUTSUser Namespace User/group isolation CLONE_NEWUSERCgroups Resource limits /sys/fs/cgroupOverlay FS Layered filesystem mount -t overlayContainer Networking Bridge, veth pairs ip link, iptablesImage Format OCI image spec Layers, manifests
Implementation: Java
Java might seem unusual for container runtime development, but it demonstrates that containers aren’t magic and can be implemented in any language with proper syscall access. We’ll use JNI (Java Native Interface) to access Linux syscalls.
Project Structure
mydocker/
├── src/main/java/com/mydocker/
│ ├── MyDocker.java
│ ├── cli/
│ │ ├── CLI.java
│ │ ├── RunCommand.java
│ │ ├── PsCommand.java
│ │ └── ImagesCommand.java
│ ├── container/
│ │ ├── Container.java
│ │ ├── ContainerConfig.java
│ │ └── ContainerState.java
│ ├── runtime/
│ │ ├── Runtime.java
│ │ ├── Namespace.java
│ │ ├── Cgroup.java
│ │ └── Filesystem.java
│ ├── network/
│ │ ├── Network.java
│ │ ├── Bridge.java
│ │ └── VethPair.java
│ ├── image/
│ │ ├── Image.java
│ │ ├── Layer.java
│ │ └── Registry.java
│ └── native/
│ └── LinuxSyscalls.java
├── src/main/c/
│ └── syscalls.c
├── pom.xml
└── README.md
Core Implementation
container/Container.java
native/LinuxSyscalls.java
runtime/Namespace.java
runtime/Cgroup.java
runtime/Filesystem.java
network/Network.java
runtime/Runtime.java
cli/CLI.java
package com.mydocker.container;
import java.nio.file.Path;
import java.util.List;
import java.util.Map;
import java.util.UUID;
/**
* Represents a container instance
*/
public class Container {
private final String id ;
private final String name ;
private final ContainerConfig config ;
private ContainerState state ;
private int pid ;
private Path rootfs ;
public Container ( ContainerConfig config ) {
this . id = UUID . randomUUID (). toString (). substring ( 0 , 12 );
this . name = config . getName () != null ? config . getName () : "container_" + id . substring ( 0 , 6 );
this . config = config;
this . state = ContainerState . CREATED ;
}
public String getId () { return id; }
public String getName () { return name; }
public ContainerConfig getConfig () { return config; }
public ContainerState getState () { return state; }
public int getPid () { return pid; }
public Path getRootfs () { return rootfs; }
public void setState ( ContainerState state ) { this . state = state; }
public void setPid ( int pid ) { this . pid = pid; }
public void setRootfs ( Path rootfs ) { this . rootfs = rootfs; }
}
/**
* Container configuration
*/
class ContainerConfig {
private String image ;
private String name ;
private List < String > command ;
private Map < String , String > env ;
private String hostname ;
private boolean tty ;
private boolean interactive ;
private ResourceLimits resources ;
private NetworkConfig network ;
private List < String > volumes ;
// Builder pattern for configuration
public static class Builder {
private ContainerConfig config = new ContainerConfig ();
public Builder image ( String image ) { config . image = image; return this ; }
public Builder name ( String name ) { config . name = name; return this ; }
public Builder command ( List < String > cmd ) { config . command = cmd; return this ; }
public Builder env ( Map < String , String > env ) { config . env = env; return this ; }
public Builder hostname ( String hostname ) { config . hostname = hostname; return this ; }
public Builder tty ( boolean tty ) { config . tty = tty; return this ; }
public Builder interactive ( boolean i ) { config . interactive = i; return this ; }
public Builder resources ( ResourceLimits r ) { config . resources = r; return this ; }
public Builder network ( NetworkConfig n ) { config . network = n; return this ; }
public Builder volumes ( List < String > v ) { config . volumes = v; return this ; }
public ContainerConfig build () { return config; }
}
public String getImage () { return image; }
public String getName () { return name; }
public List < String > getCommand () { return command; }
public Map < String , String > getEnv () { return env; }
public String getHostname () { return hostname; }
public boolean isTty () { return tty; }
public boolean isInteractive () { return interactive; }
public ResourceLimits getResources () { return resources; }
public NetworkConfig getNetwork () { return network; }
public List < String > getVolumes () { return volumes; }
}
/**
* Resource limits using cgroups
*/
class ResourceLimits {
private long memoryLimit ; // bytes
private long memorySwap ; // bytes
private int cpuShares ; // relative weight
private long cpuPeriod ; // microseconds
private long cpuQuota ; // microseconds
private int pidsLimit ; // max processes
public long getMemoryLimit () { return memoryLimit; }
public void setMemoryLimit ( long limit ) { this . memoryLimit = limit; }
public int getCpuShares () { return cpuShares; }
public void setCpuShares ( int shares ) { this . cpuShares = shares; }
public long getCpuQuota () { return cpuQuota; }
public void setCpuQuota ( long quota ) { this . cpuQuota = quota; }
public int getPidsLimit () { return pidsLimit; }
public void setPidsLimit ( int limit ) { this . pidsLimit = limit; }
}
/**
* Network configuration
*/
class NetworkConfig {
private String mode ; // bridge, host, none
private List < String > ports ; // port mappings
private String ipAddress ;
public String getMode () { return mode; }
public void setMode ( String mode ) { this . mode = mode; }
public List < String > getPorts () { return ports; }
public String getIpAddress () { return ipAddress; }
}
/**
* Container state
*/
enum ContainerState {
CREATED ,
RUNNING ,
PAUSED ,
STOPPED ,
EXITED
}
Testing Your Docker
# Build
mvn package
# Run a container (requires root)
sudo java -jar target/mydocker.jar run -it alpine /bin/sh
# Inside container
/ # hostname
abc123def456
/ # ps aux
PID USER TIME COMMAND
1 root 0:00 /bin/sh
2 root 0:00 ps aux
/ # cat /etc/resolv.conf
# Container has network access
/ # exit
# List containers
sudo java -jar target/mydocker.jar ps -a
# Remove container
sudo java -jar target/mydocker.jar rm abc123
Advanced Exercises
Level 1: Core Improvements
Implement proper OCI image format support
Add container logging (capture stdout/stderr)
Implement container restart policies
Level 2: Production Features
Add seccomp filtering for security
Implement container health checks
Add volume mounting support
Level 3: Orchestration
Implement basic networking between containers
Add container-to-container DNS resolution
Build a simple container orchestrator
What You’ve Learned
Linux namespaces (PID, mount, network, UTS, user)
Cgroups for resource limits
Overlay filesystems and copy-on-write
Container networking (bridges, veth pairs, NAT)
OCI image format concepts
Container security mechanisms
Resume Impact
With this project, you can confidently say:
“Built a container runtime from scratch implementing Linux namespaces, cgroups, and overlay filesystems. Demonstrated deep understanding of kernel-level isolation, resource management, and container networking.”
This immediately signals staff-level systems expertise.
Next Steps