Skip to content

Commit 6fe6d54

Browse files
authored
Merge pull request #7 from zededa/rucoder/eve-containers
Standalone EVE OS containers with RT benchmarking support
2 parents df964a1 + 59d5a41 commit 6fe6d54

12 files changed

Lines changed: 2160 additions & 73 deletions

Dockerfile.base.eve

Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
FROM debian:bookworm-slim
2+
3+
RUN apt-get update && apt-get install -y --no-install-recommends \
4+
bash \
5+
bash-completion \
6+
ca-certificates \
7+
curl \
8+
git \
9+
gnupg \
10+
less \
11+
lsb-release \
12+
ncurses-base \
13+
ncurses-term \
14+
openssh-server \
15+
procps \
16+
wget \
17+
&& rm -rf /var/lib/apt/lists/*
18+
19+
# Shell environment
20+
ENV SHELL=/bin/bash
21+
ENV TERM=xterm-256color
22+
ENV LANG=C.UTF-8
23+
ENV LC_ALL=C.UTF-8
24+
25+
# Login banner (motd)
26+
RUN cat > /etc/motd <<'MOTD'
27+
28+
╔═════════════════════════════════════════════════════════════╗
29+
║ RT Benchmarking Container ║
30+
╠═════════════════════════════════════════════════════════════╣
31+
║ ║
32+
║ BENCHMARKS ║
33+
║ Run benchmark: cd /app && uv run python main.py \ ║
34+
║ run.docker=false pqos.enable=false ║
35+
║ Pre-flight: cd /app && uv run python -m \ ║
36+
║ src.rt_preflight ║
37+
║ ║
38+
║ JUPYTER NOTEBOOK ║
39+
║ Start: jupyter-start ║
40+
║ Then open: http://<this-host>:8888 ║
41+
║ ║
42+
║ RESULTS ║
43+
║ Output dir: /app/outputs/ ║
44+
║ Notebooks: /app/notebook/ ║
45+
║ SCP results: scp -i <key> root@<host>:/app/outputs . ║
46+
║ ║
47+
║ USEFUL COMMANDS ║
48+
║ rt-preflight Run RT environment checks ║
49+
║ rt-info Show detected CPUs and kernel info ║
50+
║ ll List files (long format) ║
51+
║ ║
52+
╚═════════════════════════════════════════════════════════════╝
53+
54+
MOTD
55+
56+
# Minimal but usable bashrc
57+
RUN cat > /root/.bashrc <<'EOF'
58+
# prompt
59+
PS1='\[\e[1;32m\]\u@\h\[\e[0m\]:\[\e[1;34m\]\w\[\e[0m\]\$ '
60+
61+
# history
62+
HISTSIZE=1000
63+
HISTFILESIZE=2000
64+
HISTCONTROL=ignoreboth
65+
shopt -s histappend
66+
67+
# usability
68+
shopt -s checkwinsize
69+
70+
# color ls
71+
alias ls='ls --color=auto'
72+
alias ll='ls -alF'
73+
alias la='ls -A'
74+
alias l='ls -CF'
75+
76+
# RT tools aliases
77+
jupyter-start() {
78+
local ip
79+
ip=$(hostname -I 2>/dev/null | awk '{print $1}')
80+
ip=${ip:-0.0.0.0}
81+
echo ""
82+
echo " Starting Jupyter Notebook..."
83+
echo " Connect at: http://${ip}:8888"
84+
echo ""
85+
cd /app && uv run jupyter notebook \
86+
--ip=0.0.0.0 \
87+
--port=8888 \
88+
--no-browser \
89+
--allow-root \
90+
--notebook-dir=/app/notebook \
91+
--ServerApp.custom_display_url="http://${ip}:8888"
92+
}
93+
alias rt-preflight='cd /app && uv run python -m src.rt_preflight'
94+
alias rt-info='echo "=== Kernel ===" && uname -a && echo && echo "=== CPUs (cgroup) ===" && cat /sys/fs/cgroup/cpuset.cpus.effective 2>/dev/null || cat /sys/fs/cgroup/cpuset/cpuset.cpus 2>/dev/null || echo "N/A" && echo && echo "=== RT cmdline params ===" && cat /proc/cmdline | tr " " "\n" | grep -E "isolcpus|nohz|rcu_nocbs|irqaffinity|cstate|pstate|hugepages"'
95+
96+
# bash completion
97+
if [ -f /usr/share/bash-completion/bash_completion ]; then
98+
. /usr/share/bash-completion/bash_completion
99+
fi
100+
101+
# show motd on interactive login
102+
if [ -f /etc/motd ] && [ -t 0 ]; then
103+
cat /etc/motd
104+
fi
105+
EOF
106+
107+
RUN cp /root/.bashrc /etc/skel/.bashrc
108+
109+
# SSH server configuration
110+
ARG SSH_KEY
111+
RUN mkdir -p /run/sshd /root/.ssh && \
112+
chmod 700 /root/.ssh && \
113+
ssh-keygen -A && \
114+
sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin prohibit-password/' /etc/ssh/sshd_config && \
115+
sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config && \
116+
sed -i 's/^#\?PubkeyAuthentication.*/PubkeyAuthentication yes/' /etc/ssh/sshd_config && \
117+
sed -i 's/^#\?UsePAM.*/UsePAM no/' /etc/ssh/sshd_config && \
118+
echo "${SSH_KEY}" > /root/.ssh/authorized_keys && \
119+
chmod 600 /root/.ssh/authorized_keys
120+
121+
EXPOSE 22 8888
122+
123+
# Entrypoint script: start sshd, run CMD, keep container alive
124+
RUN cat > /entrypoint.sh <<'ENTRY'
125+
#!/bin/bash
126+
127+
# --- Detect cpuset and split into housekeeping vs benchmark cores ---
128+
CPUSET=""
129+
for f in /sys/fs/cgroup/cpuset.cpus.effective \
130+
/sys/fs/cgroup/cpuset/cpuset.cpus \
131+
/sys/fs/cgroup/cpuset/cpuset.effective_cpus; do
132+
if [ -f "$f" ]; then
133+
CPUSET=$(cat "$f")
134+
break
135+
fi
136+
done
137+
138+
# Expand cpuset string (e.g. "2,4-6") into a sorted list of cores
139+
expand_cpuset() {
140+
local result=""
141+
IFS=',' read -ra parts <<< "$1"
142+
for part in "${parts[@]}"; do
143+
if [[ "$part" == *-* ]]; then
144+
IFS='-' read -r lo hi <<< "$part"
145+
for ((i=lo; i<=hi; i++)); do
146+
result="$result $i"
147+
done
148+
else
149+
result="$result $part"
150+
fi
151+
done
152+
echo "$result" | tr ' ' '\n' | sort -n | tr '\n' ' '
153+
}
154+
155+
ALL_CORES=( $(expand_cpuset "$CPUSET") )
156+
NUM_CORES=${#ALL_CORES[@]}
157+
158+
if [ "$NUM_CORES" -ge 2 ]; then
159+
# First core is housekeeping, rest are for benchmarks
160+
HOUSEKEEPING_CORE=${ALL_CORES[0]}
161+
BENCHMARK_CORES=$(IFS=,; echo "${ALL_CORES[*]:1}")
162+
echo "CPU layout: housekeeping=${HOUSEKEEPING_CORE} benchmark=${BENCHMARK_CORES} (from cpuset: ${CPUSET})"
163+
else
164+
# Only one core, everything shares it
165+
HOUSEKEEPING_CORE=${ALL_CORES[0]:-0}
166+
BENCHMARK_CORES=${ALL_CORES[0]:-0}
167+
echo "WARNING: Only ${NUM_CORES} core(s) available (${CPUSET}), no isolation possible"
168+
fi
169+
170+
# Export for child processes (main.py can read these)
171+
export RT_HOUSEKEEPING_CORE="$HOUSEKEEPING_CORE"
172+
export RT_BENCHMARK_CORES="$BENCHMARK_CORES"
173+
174+
# Pin this shell (and all children: sshd, python, uv) to housekeeping core
175+
taskset -pc "$HOUSEKEEPING_CORE" $$ 2>/dev/null || true
176+
177+
# --- Start services pinned to housekeeping core ---
178+
mkdir -p /run/sshd
179+
echo "Starting SSH server on core ${HOUSEKEEPING_CORE}..."
180+
taskset -c "$HOUSEKEEPING_CORE" /usr/sbin/sshd -e || echo "WARNING: sshd failed to start (exit code $?)"
181+
182+
IP=$(hostname -I 2>/dev/null | awk '{print $1}')
183+
IP=${IP:-<unknown>}
184+
185+
echo ""
186+
echo "============================================================"
187+
echo " RT Benchmarking Container"
188+
echo "============================================================"
189+
echo ""
190+
echo " Housekeeping core: ${HOUSEKEEPING_CORE}"
191+
echo " Benchmark cores: ${BENCHMARK_CORES}"
192+
echo ""
193+
echo " SSH: ssh -i <key> root@${IP}"
194+
echo " Jupyter: ssh in, then run: jupyter-start"
195+
echo " or from this console:"
196+
echo " cd /app && uv run jupyter notebook --ip=0.0.0.0 \\"
197+
echo " --port=8888 --no-browser --allow-root \\"
198+
echo " --notebook-dir=/app/notebook"
199+
echo " then open: http://${IP}:8888"
200+
echo ""
201+
echo " Results: /app/outputs/"
202+
echo " Notebooks: /app/notebook/"
203+
echo "============================================================"
204+
echo ""
205+
206+
if [ $# -gt 0 ]; then
207+
echo "Running: $@"
208+
"$@"
209+
EXIT_CODE=$?
210+
echo ""
211+
echo "============================================================"
212+
echo " Command finished with exit code ${EXIT_CODE}"
213+
echo ""
214+
echo " Jupyter: http://${IP}:8888"
215+
echo " To start: ssh root@${IP} then run: jupyter-start"
216+
echo " SSH: ssh -i <key> root@${IP}"
217+
echo " Results: /app/outputs/"
218+
echo "============================================================"
219+
echo ""
220+
fi
221+
222+
echo "Container staying alive (sshd running on core ${HOUSEKEEPING_CORE}). SSH in or ctrl-c to stop."
223+
sleep infinity
224+
ENTRY
225+
RUN chmod +x /entrypoint.sh
226+
227+
# Intel and ECI repository keys and sources
228+
RUN wget -O- https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB | gpg --dearmor | tee /usr/share/keyrings/oneapi-archive-keyring.gpg > /dev/null
229+
RUN wget -O- https://eci.intel.com/repos/gpg-keys/GPG-PUB-KEY-INTEL-ECI.gpg | tee /usr/share/keyrings/eci-archive-keyring.gpg > /dev/null
230+
RUN wget -O- https://raw.githubusercontent.com/ros/rosdistro/master/ros.key | tee /usr/share/keyrings/ros-archive-keyring.gpg > /dev/null
231+
RUN . /etc/os-release \
232+
&& echo $VERSION_CODENAME && \
233+
bash -c 'echo "deb [signed-by=/usr/share/keyrings/eci-archive-keyring.gpg] https://eci.intel.com/repos/$(source /etc/os-release && echo $VERSION_CODENAME) isar main" | tee /etc/apt/sources.list.d/eci.list' && \
234+
bash -c 'echo "deb-src [signed-by=/usr/share/keyrings/eci-archive-keyring.gpg] https://eci.intel.com/repos/$(source /etc/os-release && echo $VERSION_CODENAME) isar main" | tee -a /etc/apt/sources.list.d/eci.list' && \
235+
bash -c 'echo "deb [signed-by=/usr/share/keyrings/oneapi-archive-keyring.gpg] https://apt.repos.intel.com/oneapi all main" | tee /etc/apt/sources.list.d/oneAPI.list' && \
236+
bash -c 'echo -e "Package: intel-oneapi-runtime-*\nPin: version 2024.1.*\nPin-Priority: 1001" > /etc/apt/preferences.d/oneapi' && \
237+
bash -c 'echo "deb [signed-by=/usr/share/keyrings/oneapi-archive-keyring.gpg] https://apt.repos.intel.com/openvino/2024 ubuntu24 main" > /etc/apt/sources.list.d/intel-openvino-2024.list' && \
238+
bash -c 'echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu $(source /etc/os-release && echo $VERSION_CODENAME) main" | tee /etc/apt/sources.list.d/ros2.list'
239+
RUN apt-get update && apt-get install -y intel-cmt-cat
240+
241+
ENTRYPOINT ["/entrypoint.sh"]
242+
CMD ["/bin/bash", "-l"]

Dockerfile.eve

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
FROM eci-base:latest
2+
3+
# Add ECI repository key and sources
4+
RUN wget -O- https://eci.intel.com/repos/gpg-keys/GPG-PUB-KEY-INTEL-ECI.gpg | tee /usr/share/keyrings/eci-archive-keyring.gpg > /dev/null
5+
6+
RUN . /etc/os-release && \
7+
echo "deb [signed-by=/usr/share/keyrings/eci-archive-keyring.gpg] https://eci.intel.com/repos/${VERSION_CODENAME} isar main" | tee /etc/apt/sources.list.d/eci.list && \
8+
echo "deb-src [signed-by=/usr/share/keyrings/eci-archive-keyring.gpg] https://eci.intel.com/repos/${VERSION_CODENAME} isar main" | tee -a /etc/apt/sources.list.d/eci.list
9+
10+
RUN bash -c 'echo -e "Package: *\nPin: origin eci.intel.com\nPin-Priority: 1000" > /etc/apt/preferences.d/isar' && \
11+
bash -c 'echo -e "\nPackage: libflann*\nPin: version 1.19.*\nPin-Priority: -1\n\nPackage: flann*\nPin: version 1.19.*\nPin-Priority: -1" >> /etc/apt/preferences.d/isar'
12+
13+
RUN apt-get update && apt-get install -y --no-install-recommends \
14+
eci-realtime-benchmarking \
15+
rt-tests \
16+
intel-cmt-cat \
17+
git \
18+
&& rm -rf /var/lib/apt/lists/*
19+
20+
ENV USER=root
21+
RUN chmod +x /opt/benchmarking/caterpillar/caterpillar
22+
23+
# Install uv package manager
24+
RUN curl -LsSf https://astral.sh/uv/install.sh | sh
25+
ENV PATH="/root/.local/bin:$PATH"
26+
27+
WORKDIR /app
28+
29+
# Copy project files
30+
COPY pyproject.toml uv.lock* ./
31+
COPY src/ ./src/
32+
COPY conf/ ./conf/
33+
COPY main.py ./
34+
35+
# Install Python 3.12 and sync dependencies
36+
RUN uv python install 3.12 && uv sync
37+
38+
# Default: run main.py with docker=false so benchmarks execute natively
39+
ENTRYPOINT ["uv", "run", "python", "main.py", "run.docker=false", "pqos.enable=false", "run.stressor=false"]
40+
# Override command to select benchmark, e.g.:
41+
# docker run ... rt-tools-main:latest run.command=caterpillar
42+
# docker run ... rt-tools-main:latest run.command=cyclictest

0 commit comments

Comments
 (0)