$ -weight: 500;">docker run
-weight: 500;">docker ps
-weight: 500;">docker logs
-weight: 500;">docker -weight: 500;">stop
-weight: 500;">docker compose up
-weight: 500;">docker run
-weight: 500;">docker ps
-weight: 500;">docker logs
-weight: 500;">docker -weight: 500;">stop
-weight: 500;">docker compose up
-weight: 500;">docker run
-weight: 500;">docker ps
-weight: 500;">docker logs
-weight: 500;">docker -weight: 500;">stop
-weight: 500;">docker compose up
tiny--weight: 500;">docker-go/
├── cmd/
│ └── tiny--weight: 500;">docker-go/
│ └── main.go
├── internal/
│ ├── app/
│ ├── cli/
│ └── runtime/
├── go.mod
└── README.md
tiny--weight: 500;">docker-go/
├── cmd/
│ └── tiny--weight: 500;">docker-go/
│ └── main.go
├── internal/
│ ├── app/
│ ├── cli/
│ └── runtime/
├── go.mod
└── README.md
tiny--weight: 500;">docker-go/
├── cmd/
│ └── tiny--weight: 500;">docker-go/
│ └── main.go
├── internal/
│ ├── app/
│ ├── cli/
│ └── runtime/
├── go.mod
└── README.md
tiny--weight: 500;">docker-go run
tiny--weight: 500;">docker-go ps
tiny--weight: 500;">docker-go -weight: 500;">stop
tiny--weight: 500;">docker-go logs
tiny--weight: 500;">docker-go run
tiny--weight: 500;">docker-go ps
tiny--weight: 500;">docker-go -weight: 500;">stop
tiny--weight: 500;">docker-go logs
tiny--weight: 500;">docker-go run
tiny--weight: 500;">docker-go ps
tiny--weight: 500;">docker-go -weight: 500;">stop
tiny--weight: 500;">docker-go logs
go run ./cmd/tiny--weight: 500;">docker-go run echo hello
go run ./cmd/tiny--weight: 500;">docker-go run echo hello
go run ./cmd/tiny--weight: 500;">docker-go run echo hello
tiny--weight: 500;">docker-go run /bin/sh
tiny--weight: 500;">docker-go ps
tiny--weight: 500;">docker-go logs <id>
tiny--weight: 500;">docker-go -weight: 500;">stop <id>
tiny--weight: 500;">docker-go run /bin/sh
tiny--weight: 500;">docker-go ps
tiny--weight: 500;">docker-go logs <id>
tiny--weight: 500;">docker-go -weight: 500;">stop <id>
tiny--weight: 500;">docker-go run /bin/sh
tiny--weight: 500;">docker-go ps
tiny--weight: 500;">docker-go logs <id>
tiny--weight: 500;">docker-go -weight: 500;">stop <id>
-weight: 500;">docker run alpine sh
-weight: 500;">docker run alpine sh
-weight: 500;">docker run alpine sh
cmd.SysProcAttr = &syscall.SysProcAttr{ Cloneflags: syscall.CLONE_NEWUTS | syscall.CLONE_NEWPID | syscall.CLONE_NEWNS,
}
cmd.SysProcAttr = &syscall.SysProcAttr{ Cloneflags: syscall.CLONE_NEWUTS | syscall.CLONE_NEWPID | syscall.CLONE_NEWNS,
}
cmd.SysProcAttr = &syscall.SysProcAttr{ Cloneflags: syscall.CLONE_NEWUTS | syscall.CLONE_NEWPID | syscall.CLONE_NEWNS,
}
UTS namespace
PID namespace
Mount namespace
UTS namespace
PID namespace
Mount namespace
UTS namespace
PID namespace
Mount namespace
syscall.Sethostname([]byte("tiny-container"))
syscall.Sethostname([]byte("tiny-container"))
syscall.Sethostname([]byte("tiny-container"))
tiny-container
tiny-container
tiny-container
/proc/self/exe
/proc/self/exe
/proc/self/exe
exec.Command("/proc/self/exe", "child", ...)
exec.Command("/proc/self/exe", "child", ...)
exec.Command("/proc/self/exe", "child", ...)
parent process
├── parse CLI
├── prepare config
├── -weight: 500;">start child with namespaces
└── track metadata child process
├── set hostname
├── prepare filesystem
├── mount proc
└── exec user command
parent process
├── parse CLI
├── prepare config
├── -weight: 500;">start child with namespaces
└── track metadata child process
├── set hostname
├── prepare filesystem
├── mount proc
└── exec user command
parent process
├── parse CLI
├── prepare config
├── -weight: 500;">start child with namespaces
└── track metadata child process
├── set hostname
├── prepare filesystem
├── mount proc
└── exec user command
/bin/sh
/etc/os-release
/lib
/usr
/bin/sh
/etc/os-release
/lib
/usr
/bin/sh
/etc/os-release
/lib
/usr
syscall.Chroot(rootfs)
os.Chdir("/")
syscall.Chroot(rootfs)
os.Chdir("/")
syscall.Chroot(rootfs)
os.Chdir("/")
-weight: 600;">sudo tiny--weight: 500;">docker-go run --rootfs ./rootfs/alpine /bin/sh
-weight: 600;">sudo tiny--weight: 500;">docker-go run --rootfs ./rootfs/alpine /bin/sh
-weight: 600;">sudo tiny--weight: 500;">docker-go run --rootfs ./rootfs/alpine /bin/sh
cat /etc/os-release
cat /etc/os-release
cat /etc/os-release
syscall.Mount("proc", "/proc", "proc", 0, "")
syscall.Mount("proc", "/proc", "proc", 0, "")
syscall.Mount("proc", "/proc", "proc", 0, "")
-weight: 500;">docker ps
-weight: 500;">docker inspect <container>
-weight: 500;">docker logs <container>
-weight: 500;">docker -weight: 500;">stop <container>
-weight: 500;">docker ps
-weight: 500;">docker inspect <container>
-weight: 500;">docker logs <container>
-weight: 500;">docker -weight: 500;">stop <container>
-weight: 500;">docker ps
-weight: 500;">docker inspect <container>
-weight: 500;">docker logs <container>
-weight: 500;">docker -weight: 500;">stop <container>
/var/lib/tiny--weight: 500;">docker/containers/<id>/
/var/lib/tiny--weight: 500;">docker/containers/<id>/
/var/lib/tiny--weight: 500;">docker/containers/<id>/
{ "id": "abc123", "command": ["/bin/sh"], "hostname": "tiny-container", "rootfs": "./rootfs/alpine", "-weight: 500;">status": "running", "created_at": "2026-05-12T10:00:00Z", "pid": 12345
}
{ "id": "abc123", "command": ["/bin/sh"], "hostname": "tiny-container", "rootfs": "./rootfs/alpine", "-weight: 500;">status": "running", "created_at": "2026-05-12T10:00:00Z", "pid": 12345
}
{ "id": "abc123", "command": ["/bin/sh"], "hostname": "tiny-container", "rootfs": "./rootfs/alpine", "-weight: 500;">status": "running", "created_at": "2026-05-12T10:00:00Z", "pid": 12345
}
CONTAINER ID PID STATUS COMMAND
abc123 12345 running /bin/sh
CONTAINER ID PID STATUS COMMAND
abc123 12345 running /bin/sh
CONTAINER ID PID STATUS COMMAND
abc123 12345 running /bin/sh
logFile, _ := os.Create("container.log")
cmd.Stdout = logFile
cmd.Stderr = logFile
logFile, _ := os.Create("container.log")
cmd.Stdout = logFile
cmd.Stderr = logFile
logFile, _ := os.Create("container.log")
cmd.Stdout = logFile
cmd.Stderr = logFile
tiny--weight: 500;">docker-go logs <container-id>
tiny--weight: 500;">docker-go logs <container-id>
tiny--weight: 500;">docker-go logs <container-id>
/var/lib/tiny--weight: 500;">docker/containers/<id>/container.log
/var/lib/tiny--weight: 500;">docker/containers/<id>/container.log
/var/lib/tiny--weight: 500;">docker/containers/<id>/container.log
tiny--weight: 500;">docker-go run /bin/sh
tiny--weight: 500;">docker-go run /bin/sh
tiny--weight: 500;">docker-go run /bin/sh
interactive mode
├── stdin -> terminal
├── stdout -> terminal
└── stderr -> terminal detached mode
├── stdin -> maybe closed
├── stdout -> log file
└── stderr -> log file
interactive mode
├── stdin -> terminal
├── stdout -> terminal
└── stderr -> terminal detached mode
├── stdin -> maybe closed
├── stdout -> log file
└── stderr -> log file
interactive mode
├── stdin -> terminal
├── stdout -> terminal
└── stderr -> terminal detached mode
├── stdin -> maybe closed
├── stdout -> log file
└── stderr -> log file
tiny--weight: 500;">docker-go logs <id>
tiny--weight: 500;">docker-go logs -f <id>
tiny--weight: 500;">docker-go logs <id>
tiny--weight: 500;">docker-go logs -f <id>
tiny--weight: 500;">docker-go logs <id>
tiny--weight: 500;">docker-go logs -f <id>
tiny--weight: 500;">docker-go -weight: 500;">stop <container-id>
tiny--weight: 500;">docker-go -weight: 500;">stop <container-id>
tiny--weight: 500;">docker-go -weight: 500;">stop <container-id>
send SIGTERM
wait
if still running, send SIGKILL
-weight: 500;">update metadata
send SIGTERM
wait
if still running, send SIGKILL
-weight: 500;">update metadata
send SIGTERM
wait
if still running, send SIGKILL
-weight: 500;">update metadata
/sys/fs/cgroup
/sys/fs/cgroup
/sys/fs/cgroup
/sys/fs/cgroup/tiny--weight: 500;">docker/<container-id>/
/sys/fs/cgroup/tiny--weight: 500;">docker/<container-id>/
/sys/fs/cgroup/tiny--weight: 500;">docker/<container-id>/
echo 134217728 > memory.max
echo 134217728 > memory.max
echo 134217728 > memory.max
cgroup.procs
cgroup.procs
cgroup.procs
echo <pid> > cgroup.procs
echo <pid> > cgroup.procs
echo <pid> > cgroup.procs
-weight: 500;">docker run --memory 128m ...
-weight: 500;">docker run --memory 128m ...
-weight: 500;">docker run --memory 128m ...
python3 -c "a = 'x' * 200 * 1024 * 1024; print('allocated')"
python3 -c "a = 'x' * 200 * 1024 * 1024; print('allocated')"
python3 -c "a = 'x' * 200 * 1024 * 1024; print('allocated')"
syscall.CLONE_NEWNET
syscall.CLONE_NEWNET
syscall.CLONE_NEWNET
ip link set lo up
ip link set lo up
ip link set lo up
tiny--weight: 500;">docker-go run --net isolated --rootfs ./rootfs/alpine /bin/sh
tiny--weight: 500;">docker-go run --net isolated --rootfs ./rootfs/alpine /bin/sh
tiny--weight: 500;">docker-go run --net isolated --rootfs ./rootfs/alpine /bin/sh
-p 8080:80
-weight: 500;">docker network ls
-weight: 500;">docker network inspect
-p 8080:80
-weight: 500;">docker network ls
-weight: 500;">docker network inspect
-p 8080:80
-weight: 500;">docker network ls
-weight: 500;">docker network inspect
create network namespace
create interface
move interface into namespace
assign IP
set route
configure NAT
create network namespace
create interface
move interface into namespace
assign IP
set route
configure NAT
create network namespace
create interface
move interface into namespace
assign IP
set route
configure NAT
Host network namespace
│
├── eth0 / main host interface
│
├── td0 bridge
│ └── veth-host
│
└── container network namespace └── veth-container
Host network namespace
│
├── eth0 / main host interface
│
├── td0 bridge
│ └── veth-host
│
└── container network namespace └── veth-container
Host network namespace
│
├── eth0 / main host interface
│
├── td0 bridge
│ └── veth-host
│
└── container network namespace └── veth-container
bridge td0: 10.10.0.1/24
container eth0: 10.10.0.2/24
default gateway: 10.10.0.1
bridge td0: 10.10.0.1/24
container eth0: 10.10.0.2/24
default gateway: 10.10.0.1
bridge td0: 10.10.0.1/24
container eth0: 10.10.0.2/24
default gateway: 10.10.0.1
ip link add td0 type bridge
ip addr add 10.10.0.1/24 dev td0
ip link set td0 up ip link add veth-host type veth peer name veth-container
ip link set veth-host master td0
ip link set veth-host up ip link set veth-container netns <container-pid>
ip link add td0 type bridge
ip addr add 10.10.0.1/24 dev td0
ip link set td0 up ip link add veth-host type veth peer name veth-container
ip link set veth-host master td0
ip link set veth-host up ip link set veth-container netns <container-pid>
ip link add td0 type bridge
ip addr add 10.10.0.1/24 dev td0
ip link set td0 up ip link add veth-host type veth peer name veth-container
ip link set veth-host master td0
ip link set veth-host up ip link set veth-container netns <container-pid>
ip addr add 10.10.0.2/24 dev veth-container
ip link set veth-container name eth0
ip link set eth0 up
ip route add default via 10.10.0.1
ip addr add 10.10.0.2/24 dev veth-container
ip link set veth-container name eth0
ip link set eth0 up
ip route add default via 10.10.0.1
ip addr add 10.10.0.2/24 dev veth-container
ip link set veth-container name eth0
ip link set eth0 up
ip route add default via 10.10.0.1
iptables -t nat -A POSTROUTING -s 10.10.0.0/24 -j MASQUERADE
iptables -t nat -A POSTROUTING -s 10.10.0.0/24 -j MASQUERADE
iptables -t nat -A POSTROUTING -s 10.10.0.0/24 -j MASQUERADE
sysctl -w net.ipv4.ip_forward=1
sysctl -w net.ipv4.ip_forward=1
sysctl -w net.ipv4.ip_forward=1
ip addr
ip link
ip route
ip netns
iptables -t nat -L -n -v
sysctl net.ipv4.ip_forward
ping
ip addr
ip link
ip route
ip netns
iptables -t nat -L -n -v
sysctl net.ipv4.ip_forward
ping
ip addr
ip link
ip route
ip netns
iptables -t nat -L -n -v
sysctl net.ipv4.ip_forward
ping
tiny--weight: 500;">docker-go
│
├── CLI
│ ├── run
│ ├── ps
│ ├── logs
│ └── -weight: 500;">stop
│
├── Runtime
│ ├── parent process
│ ├── child process
│ ├── namespace setup
│ ├── rootfs setup
│ └── command execution
│
├── State
│ ├── container id
│ ├── metadata json
│ ├── pid
│ ├── -weight: 500;">status
│ └── created_at
│
├── Logs
│ └── stdout/stderr capture
│
├── Cgroups
│ ├── memory.max
│ └── cgroup.procs
│
└── Network ├── network namespace ├── bridge ├── veth pair └── NAT
tiny--weight: 500;">docker-go
│
├── CLI
│ ├── run
│ ├── ps
│ ├── logs
│ └── -weight: 500;">stop
│
├── Runtime
│ ├── parent process
│ ├── child process
│ ├── namespace setup
│ ├── rootfs setup
│ └── command execution
│
├── State
│ ├── container id
│ ├── metadata json
│ ├── pid
│ ├── -weight: 500;">status
│ └── created_at
│
├── Logs
│ └── stdout/stderr capture
│
├── Cgroups
│ ├── memory.max
│ └── cgroup.procs
│
└── Network ├── network namespace ├── bridge ├── veth pair └── NAT
tiny--weight: 500;">docker-go
│
├── CLI
│ ├── run
│ ├── ps
│ ├── logs
│ └── -weight: 500;">stop
│
├── Runtime
│ ├── parent process
│ ├── child process
│ ├── namespace setup
│ ├── rootfs setup
│ └── command execution
│
├── State
│ ├── container id
│ ├── metadata json
│ ├── pid
│ ├── -weight: 500;">status
│ └── created_at
│
├── Logs
│ └── stdout/stderr capture
│
├── Cgroups
│ ├── memory.max
│ └── cgroup.procs
│
└── Network ├── network namespace ├── bridge ├── veth pair └── NAT
tiny--weight: 500;">docker-go run --rootfs ./rootfs/alpine /bin/sh
tiny--weight: 500;">docker-go ps
tiny--weight: 500;">docker-go logs <container-id>
tiny--weight: 500;">docker-go -weight: 500;">stop <container-id>
tiny--weight: 500;">docker-go run --rootfs ./rootfs/alpine /bin/sh
tiny--weight: 500;">docker-go ps
tiny--weight: 500;">docker-go logs <container-id>
tiny--weight: 500;">docker-go -weight: 500;">stop <container-id>
tiny--weight: 500;">docker-go run --rootfs ./rootfs/alpine /bin/sh
tiny--weight: 500;">docker-go ps
tiny--weight: 500;">docker-go logs <container-id>
tiny--weight: 500;">docker-go -weight: 500;">stop <container-id>
images + containers + Dockerfile + ports + volumes
images + containers + Dockerfile + ports + volumes
images + containers + Dockerfile + ports + volumes
container = isolated Linux process + prepared filesystem + resource limits + networking + lifecycle metadata
container = isolated Linux process + prepared filesystem + resource limits + networking + lifecycle metadata
container = isolated Linux process + prepared filesystem + resource limits + networking + lifecycle metadata
Namespaces control what a process can see.
Cgroups control what a process can use.
Namespaces control what a process can see.
Cgroups control what a process can use.
Namespaces control what a process can see.
Cgroups control what a process can use.
PID namespace:
The process sees its own process tree. UTS namespace:
The process sees its own hostname. Mount namespace:
The process sees its own mount table. Network namespace:
The process sees its own network interfaces and routes. Cgroups:
The process can only use a limited amount of memory, CPU, pids, or IO.
PID namespace:
The process sees its own process tree. UTS namespace:
The process sees its own hostname. Mount namespace:
The process sees its own mount table. Network namespace:
The process sees its own network interfaces and routes. Cgroups:
The process can only use a limited amount of memory, CPU, pids, or IO.
PID namespace:
The process sees its own process tree. UTS namespace:
The process sees its own hostname. Mount namespace:
The process sees its own mount table. Network namespace:
The process sees its own network interfaces and routes. Cgroups:
The process can only use a limited amount of memory, CPU, pids, or IO.
tiny--weight: 500;">docker-go pull alpine
tiny--weight: 500;">docker-go pull alpine
tiny--weight: 500;">docker-go pull alpine
lowerdir = image layer
upperdir = container writable layer
workdir = overlay work directory
merged = final container rootfs
lowerdir = image layer
upperdir = container writable layer
workdir = overlay work directory
merged = final container rootfs
lowerdir = image layer
upperdir = container writable layer
workdir = overlay work directory
merged = final container rootfs
tiny--weight: 500;">docker-go run -p 8080:80 ...
tiny--weight: 500;">docker-go run -p 8080:80 ...
tiny--weight: 500;">docker-go run -p 8080:80 ...
-weight: 500;">docker run nginx
-weight: 500;">docker run nginx
-weight: 500;">docker run nginx - Linux namespaces
- root filesystems
- process lifecycle
- network namespaces
- bridge networking
- container metadata - Project structure and CLI foundation
- Linux namespaces
- Root filesystem isolation
- Container IDs and metadata
- Stop and lifecycle management
- cgroups and memory limits
- Network namespace
- Bridge and veth networking
- Polish, README, roadmap, and lessons learned - cmd/ contains the executable entrypoint.
- internal/cli handles user-facing commands.
- internal/runtime handles process execution.
- internal/app wires things together. - PID namespace gives a different process tree.
- UTS namespace gives a different hostname.
- Mount namespace gives a different mount table.
- Network namespace gives a different network stack.
- User namespace gives a different view of user and group IDs.
- IPC namespace isolates IPC resources.
- Cgroup namespace isolates cgroup views. - its own hostname
- its own PID namespace
- its own mount namespace
- its own root filesystem - What did I -weight: 500;">start?
- What PID belongs to this container?
- Where are its logs?
- Is it running or stopped?
- What command did it -weight: 500;">start with?
- What rootfs did it use? - close database connections
- finish current requests
- release locks
- write final state - sometimes devices and other controllers depending on system configuration - routing table
- IP addresses
- firewall rules view
- loopback device - loopback was down
- veth interface was created but not moved correctly
- IP address was missing
- default route was missing
- NAT rule was missing
- host forwarding was disabled
- DNS was not configured
- interface name inside namespace was not what I expected - project goal
- architecture
- installation
- usage examples
- known limitations
- what each feature demonstrates - this process should see this hostname
- this process should see this PID tree
- this process should use this root filesystem
- this process should have this memory limit
- this process should write logs here
- this process should be connected to this network
- this process should be stopped with these signals - Docker docs — Running containers: https://docs.-weight: 500;">docker.com/engine/containers/run/
- Docker docs — -weight: 500;">docker run: https://docs.-weight: 500;">docker.com/reference/cli/-weight: 500;">docker/container/run/
- Docker docs — Container logs: https://docs.-weight: 500;">docker.com/reference/cli/-weight: 500;">docker/container/logs/
- Docker docs — Container -weight: 500;">stop: https://docs.-weight: 500;">docker.com/reference/cli/-weight: 500;">docker/container/-weight: 500;">stop/
- Linux man-pages — namespaces: https://man7.org/linux/man-pages/man7/namespaces.7.html
- Linux man-pages — PID namespaces: https://man7.org/linux/man-pages/man7/pid_namespaces.7.html
- Linux kernel docs — cgroup v2: https://docs.kernel.org/admin-guide/cgroup-v2.html