Skip to content

Commit 8e6fae8

Browse files
committed
feat: Add ephemeral-docker.sh for running docker in temporary environment
This script creates an isolated temporary docker environment that: - Starts temporary containerd and dockerd with unique state directories - Cleans up completely on exit (processes, mounts, files) - Handles signals and timeouts properly - Preserves command exit codes Useful for running docker commands before the system dockerd is started, e.g., during early boot in init scripts.
1 parent dd45fed commit 8e6fae8

1 file changed

Lines changed: 118 additions & 0 deletions

File tree

basefiles/ephemeral-docker.sh

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
#!/bin/bash
2+
# ephemeral-docker.sh - Run docker commands in a temporary dockerd environment
3+
# Usage: ephemeral-docker.sh <docker-command> [args...]
4+
# Example: ephemeral-docker.sh run --rm hello-world
5+
#
6+
# This script creates an isolated temporary docker environment that:
7+
# - Uses a unique temporary directory for all state
8+
# - Cleans up completely on exit
9+
10+
set -e
11+
12+
if [ $# -eq 0 ]; then
13+
echo "Usage: $0 <docker-command> [args...]" >&2
14+
echo "Example: $0 run --rm hello-world" >&2
15+
exit 1
16+
fi
17+
18+
TMPDIR=$(mktemp -d)
19+
CONTAINERD_PID=""
20+
DOCKERD_PID=""
21+
EXIT_CODE=0
22+
23+
cleanup() {
24+
local exit_code=$?
25+
set +e # Don't exit on error during cleanup
26+
27+
# Stop dockerd first (it depends on containerd)
28+
if [ -n "$DOCKERD_PID" ] && kill -0 $DOCKERD_PID 2>/dev/null; then
29+
kill -TERM $DOCKERD_PID 2>/dev/null
30+
# Wait with timeout
31+
for i in $(seq 1 50); do
32+
kill -0 $DOCKERD_PID 2>/dev/null || break
33+
sleep 0.1
34+
done
35+
# Force kill if still running
36+
kill -9 $DOCKERD_PID 2>/dev/null || true
37+
wait $DOCKERD_PID 2>/dev/null || true
38+
fi
39+
40+
# Stop containerd
41+
if [ -n "$CONTAINERD_PID" ] && kill -0 $CONTAINERD_PID 2>/dev/null; then
42+
kill -TERM $CONTAINERD_PID 2>/dev/null
43+
for i in $(seq 1 50); do
44+
kill -0 $CONTAINERD_PID 2>/dev/null || break
45+
sleep 0.1
46+
done
47+
kill -9 $CONTAINERD_PID 2>/dev/null || true
48+
wait $CONTAINERD_PID 2>/dev/null || true
49+
fi
50+
51+
# Unmount any netns that docker created
52+
if [ -d "$TMPDIR/docker-exec/netns" ]; then
53+
find "$TMPDIR/docker-exec/netns" -type f 2>/dev/null | while read ns; do
54+
umount "$ns" 2>/dev/null || true
55+
done
56+
fi
57+
58+
# Remove temporary directory
59+
rm -rf "$TMPDIR"
60+
61+
exit ${EXIT_CODE:-$exit_code}
62+
}
63+
trap cleanup EXIT INT TERM
64+
65+
# Create all directories
66+
mkdir -p "$TMPDIR"/{containerd,containerd-state,docker-data,docker-exec}
67+
68+
# Start temporary containerd with isolated state
69+
containerd \
70+
--root "$TMPDIR/containerd" \
71+
--state "$TMPDIR/containerd-state" \
72+
--address "$TMPDIR/containerd.sock" \
73+
&>/dev/null &
74+
CONTAINERD_PID=$!
75+
76+
# Wait for containerd socket with timeout
77+
TIMEOUT=100 # 10 seconds
78+
for i in $(seq 1 $TIMEOUT); do
79+
[ -S "$TMPDIR/containerd.sock" ] && break
80+
if ! kill -0 $CONTAINERD_PID 2>/dev/null; then
81+
echo "Error: containerd exited unexpectedly" >&2
82+
exit 1
83+
fi
84+
sleep 0.1
85+
done
86+
if [ ! -S "$TMPDIR/containerd.sock" ]; then
87+
echo "Error: Timeout waiting for containerd socket" >&2
88+
exit 1
89+
fi
90+
91+
# Start temporary dockerd with isolated state
92+
dockerd \
93+
--data-root "$TMPDIR/docker-data" \
94+
--exec-root "$TMPDIR/docker-exec" \
95+
--pidfile "$TMPDIR/docker.pid" \
96+
--host "unix://$TMPDIR/docker.sock" \
97+
--containerd "$TMPDIR/containerd.sock" \
98+
&>/dev/null &
99+
DOCKERD_PID=$!
100+
101+
# Wait for docker socket with timeout
102+
for i in $(seq 1 $TIMEOUT); do
103+
[ -S "$TMPDIR/docker.sock" ] && break
104+
if ! kill -0 $DOCKERD_PID 2>/dev/null; then
105+
echo "Error: dockerd exited unexpectedly" >&2
106+
exit 1
107+
fi
108+
sleep 0.1
109+
done
110+
if [ ! -S "$TMPDIR/docker.sock" ]; then
111+
echo "Error: Timeout waiting for docker socket" >&2
112+
exit 1
113+
fi
114+
115+
# Run the docker command and capture exit code
116+
docker -H "unix://$TMPDIR/docker.sock" "$@" || EXIT_CODE=$?
117+
118+
# Cleanup happens via trap

0 commit comments

Comments
 (0)