Skip to content

Keep build-only dependencies out of the main image (#356) - #2

Draft
dv-picknik wants to merge 1 commit into
add-dockerfrom
reduce-image-size
Draft

Keep build-only dependencies out of the main image (#356)#2
dv-picknik wants to merge 1 commit into
add-dockerfrom
reduce-image-size

Conversation

@dv-picknik

Copy link
Copy Markdown
Member

[written by AI]

Addresses space-ros#356. Stacked on PickNikRobotics/space-ros#388 (add-docker) — review that first; this PR's base is add-docker, so the diff shown here is only the size work.

The Earthly version of this work is space-ros#357, which space-ros#388 conflicts with by deleting the Earthfile. This is that work ported to the Dockerfile, minus the parts that measurement or review killed.

Problem

Everything the main image needs to compile Space ROS also ships in it: GCC, CMake, binutils, ros-dev-tools (which drags in colcon, rosdep, vcstool, bloom), plus the headers and CMake config files of the built install. None of it is used to run Space ROS.

Approach

  • New pre-installation-build stage holding bison build-essential cmake git wget. setup, ikos-install, and rosdep derive from it; prepare-image — the final image's parent — stays on plain pre-installation and no longer installs ros-dev-tools. The dev image reinstalls ros-dev-tools in the image stage as before.
  • build strips the install for non-dev variants: include/, share/**/cmake/, *.cmake, CMakeLists.txt, *.pyc. Done in build, before image copies ${SPACEROS_DIR} — a delete in a later layer only writes a whiteout over the parent layer and reclaims nothing.
  • clang-format added to excluded-deps.txt, so main skips it and dev still gets it.
  • prepare-image runs rosdeps.sh with APT::Install-Recommends "false" and cleans /var/lib/apt/lists/* in that same layer. Without the first, dropping ros-dev-tools newly pulls 23 MB of Recommends (manpages-dev, DejaVu fonts, libgd/libjpeg/libtiff/X11) behind libc6-dev; the baseline dodged that only because build-essential had already installed libc6-dev under --no-install-recommends. Without the second, the rm -rf already in the image stage masks those bytes instead of reclaiming them.
  • docs/USAGE.md: one note that :latest carries no compiler, CMake, or colcon and no headers, and that building against Space ROS means :dev.

Two latent bugs this surfaced

Both are pre-existing and only fixed here because dropping ros-dev-tools exposed them. Both were found by running the image, not by reading it.

  • python3-yaml reached the image only through ros-dev-tools. Replace Earthly with Docker Buildx for Space ROS builds (#107) space-ros/space-ros#388 converted the Earthfile's pip3 install pyyaml lark packaging catkin_pkg psutil to apt packages but dropped pyyaml; it kept working by accident. It is not a resolved rosdep at all — only libyaml-dev is. Without it import rclpy raises ModuleNotFoundError: No module named 'yaml' and the whole ros2 CLI is dead. Now requested explicitly in prepare-image.
  • python3-argcomplete is a resolved rosdep that excluded-deps.txt filtered out, so it too arrived only via ros-dev-tools. It is a real ros2cli runtime dependency: without it ros2cli swallows the extension's ImportError and silently drops every ros2 topic verb (bw delay echo find hz info list pub type) and ros2 service echo. No error, the commands just cease to exist — and ros2 pkg list still returns all 212 packages, so a smoke test that only checks package discovery passes green on a broken image. Removed from excluded-deps.txt.

Verification

Both variants built locally and compared against add-docker at 8c27019.

add-docker this PR
main image (docker image inspect --format '{{.Size}}') 462,923,055 (462.9 MB) 208,581,660 (208.6 MB)
apt packages 423 296
ros2 pkg list 212 212, identical set

−254.3 MB, −55%. 127 apt packages gone (gcc/g++/binutils/cmake/make, git/wget/subversion/mercurial/bzr, all of colcon, rosdep, vcstool, bloom, clang-format, python3-pytest); zero packages added. Of the shrink, /opt/ros/spaceros drops 168 MB → 128 MB, include/ alone accounting for 40 MB.

Parity against the baseline image, not just liveness:

  • ros2 {topic,node,param,service,action,interface,lifecycle,pkg} --help expose byte-identical verb sets.
  • ros2 topic pub + ros2 topic echo --once round-trips a std_msgs/msg/String; rclpy.create_node works.
  • import rclpy, yaml, lark, catkin_pkg, psutil, netifaces, numpy, packaging, argcomplete all succeed.
  • Dev image (946 MB): 212 packages, gcc/cmake/colcon/git/vcs/clang-format all present, /opt/ikos/bin/ikos present, include/ and 154 *Config.cmake files retained. Its baseline was not built, so no dev-image delta is claimed.

pre-commit (including hadolint) passes. docker buildx build --call check is clean for main/dev × image/export-build-test/export-repos.

Deliberately not done

Follow-ups

  • Resolve runtime deps with rosdep --dependency-types exec. rosdeps.sh currently installs build dependencies into the runtime image. Measured against this branch's rosdep stage: 45 resolved deps → 35. Five are not already in excluded-deps.txtlibgtest-dev libssl-dev pkg-config python3-dev python3-jsonschema — and python3-dev is what pulls libc6-dev + libpython3.12-dev. That chain is 68 MB installed, though other retained -dev packages also depend on libc6-dev, so the realized saving is lower. This is the central idea of a parallel Earthfile-based attempt at Reduce image size by removing build dependencies unused at runtime space-ros/space-ros#356 (Reduce runtime image build dependencies (#356). sylvesterkaczmarek/space-ros#1) and is worth taking.
  • A main-image smoke job in CI. Assert ros2 topic list and a Python import check, not ros2 pkg list — per the python3-argcomplete bug above, package discovery survives breakage that removes half the CLI.
  • rosdeps.sh's header line is dead code. The generator writes apt-get install -y \ followed by rosdep's #[apt] Installation commands: comment, so the continuation is swallowed and the real work is one apt-get install -y <pkg> per line, emitted verbatim by rosdep. That is why this PR sets the apt config instead of adding a flag there. Worth straightening out separately, in Replace Earthly with Docker Buildx for Space ROS builds (#107) space-ros/space-ros#388's code.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant