|
1 | 1 | FROM debian:bookworm-slim |
2 | 2 |
|
3 | 3 | RUN apt-get update && apt-get install -y --no-install-recommends \ |
4 | | - bash \ |
5 | | - bash-completion \ |
6 | 4 | ca-certificates \ |
7 | 5 | curl \ |
8 | | - git \ |
9 | 6 | gnupg \ |
10 | | - less \ |
11 | 7 | 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 |
| 8 | + wget |
228 | 9 | 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 | 10 | 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 | 11 | RUN wget -O- https://raw.githubusercontent.com/ros/rosdistro/master/ros.key | tee /usr/share/keyrings/ros-archive-keyring.gpg > /dev/null |
231 | 12 | 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' |
| 13 | +&& echo $VERSION_CODENAME && \ |
| 14 | +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' && \ |
| 15 | +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' && \ |
| 16 | +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' && \ |
| 17 | +bash -c 'echo -e "Package: intel-oneapi-runtime-*\nPin: version 2024.1.*\nPin-Priority: 1001" > /etc/apt/preferences.d/oneapi' && \ |
| 18 | +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' && \ |
| 19 | +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 | 20 | RUN apt-get update && apt-get install -y intel-cmt-cat |
240 | | - |
241 | | -ENTRYPOINT ["/entrypoint.sh"] |
242 | | -CMD ["/bin/bash", "-l"] |
0 commit comments