Skip to main content
Container Isolation

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

Docker Container Architecture
┌─────────────────────────────────────────────────────────────────────────────┐
│                        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

FeatureDescriptionLinux Concept
PID NamespaceProcess isolationCLONE_NEWPID
Mount NamespaceFilesystem isolationCLONE_NEWNS
Network NamespaceNetwork isolationCLONE_NEWNET
UTS NamespaceHostname isolationCLONE_NEWUTS
User NamespaceUser/group isolationCLONE_NEWUSER
CgroupsResource limits/sys/fs/cgroup
Overlay FSLayered filesystemmount -t overlay
Container NetworkingBridge, veth pairsip link, iptables
Image FormatOCI image specLayers, 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

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

  1. Implement proper OCI image format support
  2. Add container logging (capture stdout/stderr)
  3. Implement container restart policies

Level 2: Production Features

  1. Add seccomp filtering for security
  2. Implement container health checks
  3. Add volume mounting support

Level 3: Orchestration

  1. Implement basic networking between containers
  2. Add container-to-container DNS resolution
  3. 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