From 4c0560edc63240ebb630458409762525346d4c2b Mon Sep 17 00:00:00 2001 From: Gustavo Date: Sat, 3 Oct 2026 12:25:37 -0300 Subject: [PATCH 1/2] =?UTF-8?q?=F0=9F=90=8B=20improve=20docker=20stages=20?= =?UTF-8?q?order?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker/dockerfile-suave | 25 ++++++++++++-------- docker/dockerfile-suave-headless | 39 +++++++++++++++++++------------- 2 files changed, 39 insertions(+), 25 deletions(-) diff --git a/docker/dockerfile-suave b/docker/dockerfile-suave index ebadb8a..1f764f9 100644 --- a/docker/dockerfile-suave +++ b/docker/dockerfile-suave @@ -1,3 +1,4 @@ +# syntax=docker/dockerfile:1 ARG BASE_IMAGE="ghcr.io/kas-lab/kasm-jammy:latest" FROM $BASE_IMAGE @@ -75,7 +76,6 @@ WORKDIR $HOME # Git commit SHAs — passed in by build_docker_images.sh from docker/versions.env ARG ARDUSUB_COMMIT=571e8c7bd3793fce1bc5184a2f6586feb8a616e5 ARG ARDUPILOT_GAZEBO_COMMIT=082a0fe231f6e63bc8d1598f1cba461d9e2ea7f5 -COPY --chown=ubuntu-user:kasm-user requirements.txt $HOME/requirements.txt # Install ArduSub RUN git clone https://github.com/ArduPilot/ardupilot.git @@ -84,6 +84,10 @@ RUN git checkout $ARDUSUB_COMMIT RUN git submodule update --init --recursive RUN USER=kasm-user Tools/environment_install/install-prereqs-ubuntu.sh -y + +# Copied here rather than earlier so a pin change keeps the clone and prereqs +# layers; it must still precede the waf build, which needs the pinned empy. +COPY --chown=kasm-user:kasm-user requirements.txt $HOME/requirements.txt RUN pip3 install -r $HOME/requirements.txt ENV PATH=/opt/gcc-arm-none-eabi-10-2020-q4-major/bin:$PATH @@ -121,7 +125,18 @@ COPY --chown=kasm-user:kasm-user suave.repos $HOME/suave_ws/suave.repos WORKDIR $HOME/suave_ws/ RUN vcs import src < suave.repos --recursive +# Install suave deps from the package manifests alone, so editing sources +# does not rerun rosdep or geographiclib. RUN rm -rf $HOME/suave_ws/src/suave/ +COPY --parents --chown=kasm-user:kasm-user suave*/package.xml suave_managing/*/package.xml $HOME/suave_ws/src/suave/ + +WORKDIR $HOME/suave_ws +RUN ["/bin/bash", "-c", "source /opt/ros/humble/setup.bash \ + && rosdep update \ + && rosdep install --from-paths src --ignore-src -r -y"] + +RUN ["/bin/bash", "-c", "sudo ./src/mavros/mavros/scripts/install_geographiclib_datasets.sh"] + COPY --chown=kasm-user:kasm-user suave/ $HOME/suave_ws/src/suave/suave/ COPY --chown=kasm-user:kasm-user suave_bringup/ $HOME/suave_ws/src/suave/suave_bringup/ COPY --chown=kasm-user:kasm-user suave_managing/ $HOME/suave_ws/src/suave/suave_managing/ @@ -135,14 +150,6 @@ COPY --chown=kasm-user:kasm-user suave_base/ $HOME/suave_ws/src/suave/suave_base COPY --chown=kasm-user:kasm-user suave_cli/ $HOME/suave_ws/src/suave/suave_cli/ COPY --chown=kasm-user:kasm-user env.sh $HOME/suave_ws/src/suave/env.sh -# Install suave deps -WORKDIR $HOME/suave_ws -RUN ["/bin/bash", "-c", "source /opt/ros/humble/setup.bash \ - && rosdep update \ - && rosdep install --from-paths src --ignore-src -r -y"] - -RUN ["/bin/bash", "-c", "sudo ./src/mavros/mavros/scripts/install_geographiclib_datasets.sh"] - # Build suave RUN ["/bin/bash", "-c", "source /opt/ros/humble/setup.bash \ && colcon build --symlink-install \ diff --git a/docker/dockerfile-suave-headless b/docker/dockerfile-suave-headless index aa61ae3..aaf1624 100644 --- a/docker/dockerfile-suave-headless +++ b/docker/dockerfile-suave-headless @@ -1,3 +1,4 @@ +# syntax=docker/dockerfile:1 # Use the official ROS 2 Humble base image. FROM ros:humble-ros-core-jammy @@ -59,8 +60,6 @@ WORKDIR $HOME ARG ARDUSUB_COMMIT=571e8c7bd3793fce1bc5184a2f6586feb8a616e5 ARG ARDUPILOT_GAZEBO_COMMIT=082a0fe231f6e63bc8d1598f1cba461d9e2ea7f5 -COPY --chown=ubuntu-user:ubuntu-user requirements.txt $HOME/requirements.txt - # Install ArduSub RUN git clone https://github.com/ArduPilot/ardupilot.git WORKDIR $HOME/ardupilot @@ -68,6 +67,9 @@ RUN git checkout $ARDUSUB_COMMIT RUN git submodule update --init --recursive RUN USER=ubuntu-user Tools/environment_install/install-prereqs-ubuntu.sh -y +# Copied here rather than earlier so a pin change keeps the clone and prereqs +# layers; it must still precede the waf build, which needs the pinned empy. +COPY --chown=ubuntu-user:ubuntu-user requirements.txt $HOME/requirements.txt RUN sudo pip3 install -r $HOME/requirements.txt ENV PATH=/opt/gcc-arm-none-eabi-10-2020-q4-major/bin:$PATH @@ -100,26 +102,16 @@ RUN git clone https://github.com/ArduPilot/ardupilot_gazebo && \ ENV GZ_SIM_SYSTEM_PLUGIN_PATH=$HOME/ardupilot_gazebo/build ENV GZ_SIM_RESOURCE_PATH=$HOME/ardupilot_gazebo/models:$HOME/ardupilot_gazebo/worlds -# Import external dependencies from suave.repos, then copy this checkout. +# Import external dependencies from suave.repos. RUN mkdir -p $HOME/suave_ws/src COPY --chown=ubuntu-user:ubuntu-user suave.repos $HOME/suave_ws/suave.repos WORKDIR $HOME/suave_ws RUN vcs import src < suave.repos --recursive +# Resolve dependencies from the package manifests alone, so editing sources +# does not rerun rosdep, geographiclib or pip. RUN rm -rf $HOME/suave_ws/src/suave && mkdir -p $HOME/suave_ws/src/suave -COPY --chown=ubuntu-user:ubuntu-user suave/ $HOME/suave_ws/src/suave/suave/ -COPY --chown=ubuntu-user:ubuntu-user suave_bringup/ $HOME/suave_ws/src/suave/suave_bringup/ -COPY --chown=ubuntu-user:ubuntu-user suave_managing/ $HOME/suave_ws/src/suave/suave_managing/ -COPY --chown=ubuntu-user:ubuntu-user suave_metrics/ $HOME/suave_ws/src/suave/suave_metrics/ -COPY --chown=ubuntu-user:ubuntu-user suave_missions/ $HOME/suave_ws/src/suave/suave_missions/ -COPY --chown=ubuntu-user:ubuntu-user suave_monitor/ $HOME/suave_ws/src/suave/suave_monitor/ -COPY --chown=ubuntu-user:ubuntu-user suave_msgs/ $HOME/suave_ws/src/suave/suave_msgs/ -COPY --chown=ubuntu-user:ubuntu-user suave_runner/ $HOME/suave_ws/src/suave/suave_runner/ -COPY --chown=ubuntu-user:ubuntu-user suave_tools/ $HOME/suave_ws/src/suave/suave_tools/ -COPY --chown=ubuntu-user:ubuntu-user runner/ $HOME/suave_ws/src/suave/runner/ -COPY --chown=ubuntu-user:ubuntu-user suave_base/ $HOME/suave_ws/src/suave/suave_base/ -COPY --chown=ubuntu-user:ubuntu-user suave_cli/ $HOME/suave_ws/src/suave/suave_cli/ -COPY --chown=ubuntu-user:ubuntu-user env.sh $HOME/suave_ws/src/suave/env.sh +COPY --parents --chown=ubuntu-user:ubuntu-user suave*/package.xml suave_managing/*/package.xml $HOME/suave_ws/src/suave/ RUN ["/bin/bash", "-c", "source /opt/ros/humble/setup.bash \ && sudo apt update \ @@ -135,6 +127,21 @@ RUN pip3 install -r $HOME/requirements.txt # Ubuntu Jammy flake8 plugins used by the ROS 2 Humble lint environment. RUN pip3 install flake8==4.0.1 +# Copy this checkout. +COPY --chown=ubuntu-user:ubuntu-user suave/ $HOME/suave_ws/src/suave/suave/ +COPY --chown=ubuntu-user:ubuntu-user suave_bringup/ $HOME/suave_ws/src/suave/suave_bringup/ +COPY --chown=ubuntu-user:ubuntu-user suave_managing/ $HOME/suave_ws/src/suave/suave_managing/ +COPY --chown=ubuntu-user:ubuntu-user suave_metrics/ $HOME/suave_ws/src/suave/suave_metrics/ +COPY --chown=ubuntu-user:ubuntu-user suave_missions/ $HOME/suave_ws/src/suave/suave_missions/ +COPY --chown=ubuntu-user:ubuntu-user suave_monitor/ $HOME/suave_ws/src/suave/suave_monitor/ +COPY --chown=ubuntu-user:ubuntu-user suave_msgs/ $HOME/suave_ws/src/suave/suave_msgs/ +COPY --chown=ubuntu-user:ubuntu-user suave_runner/ $HOME/suave_ws/src/suave/suave_runner/ +COPY --chown=ubuntu-user:ubuntu-user suave_tools/ $HOME/suave_ws/src/suave/suave_tools/ +COPY --chown=ubuntu-user:ubuntu-user runner/ $HOME/suave_ws/src/suave/runner/ +COPY --chown=ubuntu-user:ubuntu-user suave_base/ $HOME/suave_ws/src/suave/suave_base/ +COPY --chown=ubuntu-user:ubuntu-user suave_cli/ $HOME/suave_ws/src/suave/suave_cli/ +COPY --chown=ubuntu-user:ubuntu-user env.sh $HOME/suave_ws/src/suave/env.sh + RUN ["/bin/bash", "-c", "source /opt/ros/humble/setup.bash \ && colcon build --symlink-install \ && echo 'source ~/suave_ws/install/setup.bash' >> ~/.bashrc"] From e84064be914330fb739904674bfad6a30ed325a7 Mon Sep 17 00:00:00 2001 From: Gustavo Date: Sat, 3 Oct 2026 16:17:14 -0300 Subject: [PATCH 2/2] reducing docker images size --- docker/dockerfile-suave | 34 +++++++++++++++++++++----------- docker/dockerfile-suave-headless | 34 ++++++++++++++++++++------------ 2 files changed, 44 insertions(+), 24 deletions(-) diff --git a/docker/dockerfile-suave b/docker/dockerfile-suave index 1f764f9..2d27496 100644 --- a/docker/dockerfile-suave +++ b/docker/dockerfile-suave @@ -24,7 +24,7 @@ RUN apt update && apt install -y \ libglx-mesa0 \ bash-completion \ python3-pip \ - && rm -rf /var/lib/apt/list/ + && rm -rf /var/lib/apt/lists/* # Set the locale RUN sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && \ @@ -77,24 +77,29 @@ WORKDIR $HOME ARG ARDUSUB_COMMIT=571e8c7bd3793fce1bc5184a2f6586feb8a616e5 ARG ARDUPILOT_GAZEBO_COMMIT=082a0fe231f6e63bc8d1598f1cba461d9e2ea7f5 -# Install ArduSub -RUN git clone https://github.com/ArduPilot/ardupilot.git +# Install ArduSub. Only the pinned commit is fetched: waf needs .git for +# `git rev-parse HEAD` and submodule checks, but not the project history. +RUN mkdir $HOME/ardupilot && cd $HOME/ardupilot \ + && git init -q \ + && git remote add origin https://github.com/ArduPilot/ardupilot.git \ + && git fetch -q --depth 1 origin $ARDUSUB_COMMIT \ + && git checkout -q FETCH_HEAD \ + && git submodule update --init --recursive WORKDIR $HOME/ardupilot -RUN git checkout $ARDUSUB_COMMIT -RUN git submodule update --init --recursive -RUN USER=kasm-user Tools/environment_install/install-prereqs-ubuntu.sh -y +# DO_AP_STM_ENV=0 skips the STM32 firmware toolchain; SITL builds with the host g++. +RUN USER=kasm-user DO_AP_STM_ENV=0 Tools/environment_install/install-prereqs-ubuntu.sh -y \ + && sudo rm -rf /var/lib/apt/lists/* $HOME/.cache/pip # Copied here rather than earlier so a pin change keeps the clone and prereqs # layers; it must still precede the waf build, which needs the pinned empy. COPY --chown=kasm-user:kasm-user requirements.txt $HOME/requirements.txt -RUN pip3 install -r $HOME/requirements.txt +RUN pip3 install --no-cache-dir -r $HOME/requirements.txt -ENV PATH=/opt/gcc-arm-none-eabi-10-2020-q4-major/bin:$PATH ENV PATH=$PATH:$HOME/ardupilot/Tools/autotest ENV PATH=/usr/lib/ccache:$PATH -RUN ["/bin/bash","-c","cd $HOME/ardupilot && ./waf configure && make sub"] +RUN ["/bin/bash","-c","cd $HOME/ardupilot && ./waf configure && make sub && ccache -C"] # install ardupilot gazebo plugin RUN sudo apt update && sudo apt install -y \ @@ -106,7 +111,7 @@ RUN sudo apt update && sudo apt install -y \ gstreamer1.0-plugins-bad \ gstreamer1.0-libav \ gstreamer1.0-gl \ - && sudo rm -rf /var/lib/apt/list/ + && sudo rm -rf /var/lib/apt/lists/* WORKDIR $HOME RUN git clone https://github.com/ArduPilot/ardupilot_gazebo && \ @@ -132,8 +137,10 @@ COPY --parents --chown=kasm-user:kasm-user suave*/package.xml suave_managing/*/p WORKDIR $HOME/suave_ws RUN ["/bin/bash", "-c", "source /opt/ros/humble/setup.bash \ + && sudo apt update \ && rosdep update \ - && rosdep install --from-paths src --ignore-src -r -y"] + && rosdep install --from-paths src --ignore-src -r -y \ + && sudo rm -rf /var/lib/apt/lists/* /root/.cache"] RUN ["/bin/bash", "-c", "sudo ./src/mavros/mavros/scripts/install_geographiclib_datasets.sh"] @@ -153,6 +160,7 @@ COPY --chown=kasm-user:kasm-user env.sh $HOME/suave_ws/src/suave/env.sh # Build suave RUN ["/bin/bash", "-c", "source /opt/ros/humble/setup.bash \ && colcon build --symlink-install \ + && ccache -C \ && echo 'source ~/suave_ws/install/setup.bash' >> ~/.bashrc"] @@ -160,6 +168,10 @@ RUN sudo apt autoremove -y && sudo rm -rf /var/lib/apt/lists/ COPY --chown=kasm-user:kasm-user runner/ $HOME/suave_ws/src/suave/runner/ +# User-level pip scripts (mavproxy.py for sim_vehicle.py) must resolve in +# non-login shells too; appended so it never shadows system tools. +ENV PATH=${PATH}:${HOME}/.local/bin + # suave CLI: on PATH in every shell, including docker exec ENV SUAVE_ROOT=/home/kasm-user/suave_ws/src/suave ENV SUAVE_CLI_CONTEXT=container diff --git a/docker/dockerfile-suave-headless b/docker/dockerfile-suave-headless index aaf1624..6e2988d 100644 --- a/docker/dockerfile-suave-headless +++ b/docker/dockerfile-suave-headless @@ -60,23 +60,28 @@ WORKDIR $HOME ARG ARDUSUB_COMMIT=571e8c7bd3793fce1bc5184a2f6586feb8a616e5 ARG ARDUPILOT_GAZEBO_COMMIT=082a0fe231f6e63bc8d1598f1cba461d9e2ea7f5 -# Install ArduSub -RUN git clone https://github.com/ArduPilot/ardupilot.git +# Install ArduSub. Only the pinned commit is fetched: waf needs .git for +# `git rev-parse HEAD` and submodule checks, but not the project history. +RUN mkdir $HOME/ardupilot && cd $HOME/ardupilot \ + && git init -q \ + && git remote add origin https://github.com/ArduPilot/ardupilot.git \ + && git fetch -q --depth 1 origin $ARDUSUB_COMMIT \ + && git checkout -q FETCH_HEAD \ + && git submodule update --init --recursive WORKDIR $HOME/ardupilot -RUN git checkout $ARDUSUB_COMMIT -RUN git submodule update --init --recursive -RUN USER=ubuntu-user Tools/environment_install/install-prereqs-ubuntu.sh -y +# DO_AP_STM_ENV=0 skips the STM32 firmware toolchain. SITL builds with the host g++. +RUN USER=ubuntu-user DO_AP_STM_ENV=0 Tools/environment_install/install-prereqs-ubuntu.sh -y \ + && sudo rm -rf /var/lib/apt/lists/* $HOME/.cache/pip # Copied here rather than earlier so a pin change keeps the clone and prereqs -# layers; it must still precede the waf build, which needs the pinned empy. +# layers. It must still precede the waf build, which needs the pinned empy. COPY --chown=ubuntu-user:ubuntu-user requirements.txt $HOME/requirements.txt -RUN sudo pip3 install -r $HOME/requirements.txt +RUN pip3 install --no-cache-dir -r $HOME/requirements.txt -ENV PATH=/opt/gcc-arm-none-eabi-10-2020-q4-major/bin:$PATH ENV PATH=$PATH:$HOME/ardupilot/Tools/autotest ENV PATH=/usr/lib/ccache:$PATH -RUN ["/bin/bash", "-c", "cd $HOME/ardupilot && ./waf configure && make sub"] +RUN ["/bin/bash", "-c", "cd $HOME/ardupilot && ./waf configure && make sub && ccache -C"] # ArduPilot Gazebo plugin dependencies RUN sudo apt-get update && sudo apt-get install -y \ @@ -117,15 +122,13 @@ RUN ["/bin/bash", "-c", "source /opt/ros/humble/setup.bash \ && sudo apt update \ && rosdep update \ && rosdep install --from-paths src --ignore-src -r -y \ - && sudo rm -rf /var/lib/apt/lists/"] + && sudo rm -rf /var/lib/apt/lists/ /root/.cache"] RUN ["/bin/bash", "-c", "sudo ./src/mavros/mavros/scripts/install_geographiclib_datasets.sh"] -RUN pip3 install -r $HOME/requirements.txt - # ArduPilot installs a newer user-local flake8 which is incompatible with the # Ubuntu Jammy flake8 plugins used by the ROS 2 Humble lint environment. -RUN pip3 install flake8==4.0.1 +RUN pip3 install --no-cache-dir flake8==4.0.1 # Copy this checkout. COPY --chown=ubuntu-user:ubuntu-user suave/ $HOME/suave_ws/src/suave/suave/ @@ -144,10 +147,15 @@ COPY --chown=ubuntu-user:ubuntu-user env.sh $HOME/suave_ws/src/suave/env.sh RUN ["/bin/bash", "-c", "source /opt/ros/humble/setup.bash \ && colcon build --symlink-install \ + && ccache -C \ && echo 'source ~/suave_ws/install/setup.bash' >> ~/.bashrc"] RUN sudo apt autoremove -y && sudo rm -rf /var/lib/apt/lists/ +# User-level pip scripts (mavproxy.py for sim_vehicle.py) must resolve in +# non-login shells too; appended so it never shadows system tools. +ENV PATH=${PATH}:${HOME}/.local/bin + # suave CLI: on PATH in every shell, including docker exec ENV SUAVE_ROOT=/home/ubuntu-user/suave_ws/src/suave ENV SUAVE_CLI_CONTEXT=container