Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
39d0b03
Add Dockerfile and GitHub Actions workflow for building AOC Docker im…
marc-hanheide Feb 16, 2026
6400cd7
Add GitHub Actions workflow for building AOC Docker images with multi…
marc-hanheide Feb 16, 2026
b3e9a40
Update Docker build workflow to enable sequential builds and dynamic …
marc-hanheide Feb 16, 2026
7f2808b
Add CUDA Dockerfile and update build workflow for CUDA support
marc-hanheide Feb 16, 2026
6e0c408
Refactor Docker build configuration to use ROS_DISTRO variable for ta…
marc-hanheide Feb 16, 2026
a1fe98d
Add ROS installation and setup commands to CUDA Dockerfile
marc-hanheide Feb 16, 2026
a16011a
Add ROS_DISTRO argument and environment variables to CUDA Dockerfile
marc-hanheide Feb 16, 2026
71f257b
Add ARG declarations for BASE_IMAGE and ROS_DISTRO in Dockerfiles
marc-hanheide Feb 16, 2026
3f967cb
Add CUDA Dockerfile stages for base and desktop images with ROS support
marc-hanheide Feb 16, 2026
14e9331
Comment out cache-from and cache-to lines in Docker build configuration
marc-hanheide Feb 16, 2026
728dad1
Move python3-rosdep installation to the correct stage in Dockerfile
marc-hanheide Feb 16, 2026
3749deb
Add target specification for Docker build stage in workflow
marc-hanheide Feb 16, 2026
0d530ee
Add additional CUDA Dockerfile stages for base and desktop images wit…
marc-hanheide Feb 16, 2026
c55cbf2
Uncomment cache-from and cache-to lines in Docker build configuration
marc-hanheide Feb 16, 2026
ac535ef
Initialize rosdep before updating in Dockerfile
marc-hanheide Feb 16, 2026
1a5d2bf
Add support for ROS Jazzy in Docker build configuration
marc-hanheide Feb 16, 2026
37b628f
Refactor Docker build configuration by removing unused desktop stage …
marc-hanheide Feb 16, 2026
2e8ba15
Add reusable Docker image build workflow and CUDA desktop Dockerfile
marc-hanheide Feb 16, 2026
6a10ecd
Add outputs section for image digest in Docker build workflow
marc-hanheide Feb 16, 2026
8d66679
Reorder Docker build steps to ensure proper setup of buildx before bu…
marc-hanheide Feb 16, 2026
0591fb5
Fix Dockerfile syntax for ros installation
marc-hanheide Feb 16, 2026
7665cde
feat: add seperate display container
cooperj Feb 16, 2026
e9e2e9a
Merge branch 'main' into display
marc-hanheide Feb 16, 2026
940098f
ci: rename the container from `display` to `vnc` add CI building
cooperj Feb 17, 2026
2f6514f
ci: disable requirement for ros distro, allowing for non ros builds
cooperj Feb 17, 2026
21c932c
Merge branch 'main' into display
cooperj Feb 25, 2026
faa9021
fix: install turbovnc this time and fix ci
cooperj Feb 25, 2026
be348cd
feat: cleaned up the vnc container, added docker cli
cooperj Feb 25, 2026
cafb62e
chore: run linter
cooperj Feb 25, 2026
2b3873c
fix: restore wallpaper functionality
cooperj Mar 2, 2026
3afa5ca
chore: add back the old wallpaper as an option
cooperj Mar 2, 2026
9de3968
chore: update readme to force build
cooperj Mar 10, 2026
bc94c5c
ci: break the vnc + devtools into two separate containers
cooperj Mar 13, 2026
dba3a96
fix: rm the distro line
cooperj Mar 13, 2026
15994e0
Merge branch 'main' into display
cooperj Mar 13, 2026
f4049ed
fix: change context to inside docker folder matching ci actions
cooperj Mar 13, 2026
b788647
Apply suggestions from code review
cooperj Mar 13, 2026
a7b6e0e
Remove unused VNC_PORT env var from vnc.dockerfile (#7)
Copilot Mar 13, 2026
0eeb0a3
fix: rm the warning on contexts outside of a terminal inside vnc term…
cooperj Mar 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 5 additions & 13 deletions .github/workflows/_build-image.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@ on:
description: Image name on the LCAS registry
required: true
type: string
ros_distro:
required: true
type: string
dockerfile:
required: true
type: string
Expand Down Expand Up @@ -55,16 +52,12 @@ jobs:
with:
flavor: latest=false
labels: |
org.opencontainers.image.description=AOC Docker Image (${{ inputs.push_image }}, ${{ inputs.ros_distro }})
org.opencontainers.image.description=AOC Docker Image (${{ inputs.push_image }})
org.opencontainers.image.authors=L-CAS Team
images: lcas.lincoln.ac.uk/${{ inputs.push_image }}
tags: |
type=raw,value=${{ inputs.ros_distro }}-staging
type=raw,enable=${{ github.event_name != 'pull_request' }},value=${{ inputs.ros_distro }}-latest
type=ref,enable=${{ github.event_name != 'pull_request' }},event=branch,prefix=${{ inputs.ros_distro }}-
type=semver,pattern={{version}},prefix=${{ inputs.ros_distro }}-
type=semver,pattern={{major}}.{{minor}},prefix=${{ inputs.ros_distro }}-
type=semver,pattern={{major}},prefix=${{ inputs.ros_distro }}-
type=raw,value=staging
type=raw,enable=${{ github.event_name != 'pull_request' }},value=latest

- uses: docker/setup-buildx-action@v3

Expand All @@ -76,10 +69,9 @@ jobs:
file: ./${{ inputs.dockerfile }}
platforms: ${{ inputs.architectures }}
push: true
cache-from: type=registry,ref=lcas.lincoln.ac.uk/cache/${{ inputs.push_image }}:${{ inputs.ros_distro }}
cache-to: type=registry,ref=lcas.lincoln.ac.uk/cache/${{ inputs.push_image }}:${{ inputs.ros_distro }},mode=max
cache-from: type=registry,ref=lcas.lincoln.ac.uk/cache/${{ inputs.push_image }}:latest
cache-to: type=registry,ref=lcas.lincoln.ac.uk/cache/${{ inputs.push_image }}:latest,mode=max
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
BASE_IMAGE=${{ inputs.base_image }}
ROS_DISTRO=${{ inputs.ros_distro }}
82 changes: 82 additions & 0 deletions .github/workflows/_build-ros-image.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
name: Build a single ROS Docker image (reusable)

on:
workflow_call:
inputs:
base_image:
description: The FROM base image
required: true
type: string
push_image:
description: Image name on the LCAS registry
required: true
type: string
ros_distro:
required: true
type: string
dockerfile:
required: true
type: string
architectures:
required: true
type: string
outputs:
digest:
description: Image digest from the build
value: ${{ jobs.build.outputs.digest }}
secrets:
LCAS_REGISTRY_PUSHER:
required: true
LCAS_REGISTRY_TOKEN:
required: true

jobs:
build:
runs-on: [lcas, qemu]
outputs:
digest: ${{ steps.build.outputs.digest }}
steps:
- uses: actions/setup-node@v4
- uses: actions/checkout@v3
- run: echo "BRANCH=${GITHUB_REF##*/}" >> $GITHUB_ENV

- uses: docker/login-action@v3
with:
registry: lcas.lincoln.ac.uk
username: ${{ secrets.LCAS_REGISTRY_PUSHER }}
password: ${{ secrets.LCAS_REGISTRY_TOKEN }}

- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
flavor: latest=false
labels: |
org.opencontainers.image.description=AOC Docker Image (${{ inputs.push_image }}, ${{ inputs.ros_distro }})
org.opencontainers.image.authors=L-CAS Team
images: lcas.lincoln.ac.uk/${{ inputs.push_image }}
tags: |
type=raw,value=${{ inputs.ros_distro }}-staging
type=raw,enable=${{ github.event_name != 'pull_request' }},value=${{ inputs.ros_distro }}-latest
type=ref,enable=${{ github.event_name != 'pull_request' }},event=branch,prefix=${{ inputs.ros_distro }}-
type=semver,pattern={{version}},prefix=${{ inputs.ros_distro }}-
type=semver,pattern={{major}}.{{minor}},prefix=${{ inputs.ros_distro }}-
type=semver,pattern={{major}},prefix=${{ inputs.ros_distro }}-

- uses: docker/setup-buildx-action@v3

- name: Build and push
id: build
uses: docker/build-push-action@v6
with:
context: ./docker
file: ./${{ inputs.dockerfile }}
platforms: ${{ inputs.architectures }}
push: true
cache-from: type=registry,ref=lcas.lincoln.ac.uk/cache/${{ inputs.push_image }}:${{ inputs.ros_distro }}
cache-to: type=registry,ref=lcas.lincoln.ac.uk/cache/${{ inputs.push_image }}:${{ inputs.ros_distro }},mode=max
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
BASE_IMAGE=${{ inputs.base_image }}
ROS_DISTRO=${{ inputs.ros_distro }}
32 changes: 24 additions & 8 deletions .github/workflows/docker-build-and-push.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,18 @@ on:
workflow_dispatch:

jobs:

# ── Level 0: no dependencies ──────────────────────────────────────────────
vnc:
uses: ./.github/workflows/_build-image.yaml
with:
base_image: debian:trixie-slim
push_image: vnc
dockerfile: vnc.dockerfile
architectures: linux/amd64,linux/arm64
secrets: inherit

ros-humble:
uses: ./.github/workflows/_build-image.yaml
uses: ./.github/workflows/_build-ros-image.yaml
with:
base_image: ros:humble
push_image: ros
Expand All @@ -23,7 +30,7 @@ jobs:
secrets: inherit

ros-jazzy:
uses: ./.github/workflows/_build-image.yaml
uses: ./.github/workflows/_build-ros-image.yaml
with:
base_image: ros:jazzy
push_image: ros
Expand All @@ -33,7 +40,7 @@ jobs:
secrets: inherit

ros-cuda-humble:
uses: ./.github/workflows/_build-image.yaml
uses: ./.github/workflows/_build-ros-image.yaml
with:
base_image: nvidia/cuda:11.8.0-runtime-ubuntu22.04
push_image: ros_cuda
Expand All @@ -43,7 +50,7 @@ jobs:
secrets: inherit

ros-cuda-jazzy:
uses: ./.github/workflows/_build-image.yaml
uses: ./.github/workflows/_build-ros-image.yaml
with:
base_image: nvidia/cuda:12.9.1-runtime-ubuntu24.04
push_image: ros_cuda
Expand All @@ -53,10 +60,19 @@ jobs:
secrets: inherit

# ── Level 1: base_image is the exact digest from level 0 ─────────────────
vnc-devtools:
needs: vnc
uses: ./.github/workflows/_build-image.yaml
with:
base_image: lcas.lincoln.ac.uk/vnc@${{ needs.vnc.outputs.digest }}
push_image: vnc_devtools
dockerfile: vnc_devtools.dockerfile
architectures: linux/amd64,linux/arm64
secrets: inherit

ros-cuda-desktop-humble:
needs: ros-cuda-humble
uses: ./.github/workflows/_build-image.yaml
uses: ./.github/workflows/_build-ros-image.yaml
with:
# Digest is immutable — no staging tag, no race condition, no cleanup
base_image: lcas.lincoln.ac.uk/ros_cuda@${{ needs.ros-cuda-humble.outputs.digest }}
Expand All @@ -68,11 +84,11 @@ jobs:

ros-cuda-desktop-jazzy:
needs: ros-cuda-jazzy
uses: ./.github/workflows/_build-image.yaml
uses: ./.github/workflows/_build-ros-image.yaml
with:
base_image: lcas.lincoln.ac.uk/ros_cuda@${{ needs.ros-cuda-jazzy.outputs.digest }}
push_image: ros_cuda_desktop
ros_distro: jazzy
dockerfile: cuda_desktop.dockerfile
architectures: linux/amd64
secrets: inherit
secrets: inherit
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ A repository of verstile ROS-enabled Docker containers, orginally developed as a
| ------------------------------------- | --------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| `lcas.lincoln.ac.uk/ros` | { `humble`, `jazzy` } | Base ROS Container, the minimal environment you need for ROS |
| `lcas.lincoln.ac.uk/ros_cuda` | { `humble`, `jazzy` } | ROS + Nvidia. When you need to use a GPU in your ROS environment for either better quality simulation or AI workloads. |
| `lcas.lincoln.ac.uk/ros_cuda_desktop` | { `humble`, `jazzy` } | ROS + Nvidia + Packages. Installs the `ros-{distro}-desktop` varient so there is the full ROS stack available. |
| `lcas.lincoln.ac.uk/ros_cuda_desktop` | { `humble`, `jazzy` } | ROS + Nvidia + Packages. Installs the `ros-{distro}-desktop` varient so there is the full ROS stack available. |
| `lcas.lincoln.ac.uk/vnc` | { `latest` } | X11 destination accessible over a website using NoVNC. |
32 changes: 15 additions & 17 deletions base.dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,20 @@ ENV ROS_DISTRO=${ROS_DISTRO}
ENV DEBIAN_FRONTEND=noninteractive

RUN apt-get update \
&& apt-get upgrade -y && \
apt-get install -y --no-install-recommends \
build-essential \
ca-certificates \
gnupg \
cmake \
git \
curl \
wget \
unzip \
ros-${ROS_DISTRO}-ros-base \
ros-${ROS_DISTRO}-rmw-cyclonedds-cpp \
python3-colcon-common-extensions && \
rm -rf /var/lib/apt/lists/*
&& apt-get upgrade -y \
&& apt-get install -y --no-install-recommends \
build-essential \
ca-certificates \
gnupg \
cmake \
git \
curl \
wget \
unzip \
ros-${ROS_DISTRO}-ros-base \
ros-${ROS_DISTRO}-rmw-cyclonedds-cpp \
python3-colcon-common-extensions \
&& rm -rf /var/lib/apt/lists/*

ENV LANG=en_US.UTF-8

Expand All @@ -39,8 +39,7 @@ RUN groupadd --gid $USER_GID $USERNAME \
&& useradd -s /bin/bash --uid $USER_UID --gid $USER_GID -m $USERNAME \
&& apt-get update \
&& apt-get install -y --no-install-recommends sudo \
&& echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME\
&& chmod 0440 /etc/sudoers.d/$USERNAME \
&& echo $USERNAME ALL=\(root\) NOPASSWD:ALL >/etc/sudoers.d/$USERNAME && chmod 0440 /etc/sudoers.d/$USERNAME \
&& rm -rf /var/lib/apt/lists/*

# Cyclone DDS Config
Expand All @@ -60,4 +59,3 @@ ENV CYCLONEDDS_URI=file:///etc/cyclonedds.xml

USER ${USERNAME}
CMD ["bash", "-l"]

65 changes: 32 additions & 33 deletions cuda.dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,59 +12,58 @@ ENV ROS_DISTRO=${ROS_DISTRO}
ENV DEBIAN_FRONTEND=noninteractive

RUN apt-get update \
&& apt-get upgrade -y \
&& apt-get install -y --no-install-recommends \
locales \
curl \
wget \
ca-certificates \
gnupg2 \
lsb-release \
git \
nano \
python3-setuptools \
software-properties-common \
tzdata \
&& locale-gen en_US.UTF-8 \
&& update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8 \
&& rm -rf /var/lib/apt/lists/*
&& apt-get upgrade -y \
&& apt-get install -y --no-install-recommends \
locales \
curl \
wget \
ca-certificates \
gnupg2 \
lsb-release \
git \
nano \
python3-setuptools \
software-properties-common \
tzdata \
&& locale-gen en_US.UTF-8 \
&& update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8 \
&& rm -rf /var/lib/apt/lists/*

ENV LANG=en_US.UTF-8

# Prepare ROS2
RUN add-apt-repository universe \
&& curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg \
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu $(. /etc/os-release && echo $UBUNTU_CODENAME) main" | tee /etc/apt/sources.list.d/ros2.list > /dev/null
&& curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg \
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu $(. /etc/os-release && echo $UBUNTU_CODENAME) main" | tee /etc/apt/sources.list.d/ros2.list >/dev/null

RUN apt-get update && apt-get install -y --no-install-recommends \
ros-${ROS_DISTRO}-ros-base \
python3-rosdep \
ros-${ROS_DISTRO}-rmw-cyclonedds-cpp \
&& rm -rf /var/lib/apt/lists/*
ros-${ROS_DISTRO}-ros-base \
python3-rosdep \
ros-${ROS_DISTRO}-rmw-cyclonedds-cpp \
&& rm -rf /var/lib/apt/lists/*

# Cyclone DDS Config
COPY cyclonedds.xml /etc/cyclonedds.xml

RUN . /opt/ros/${ROS_DISTRO}/setup.sh && rosdep init && rosdep update

# Setup VirtualGL
RUN wget -q -O- https://packagecloud.io/dcommander/virtualgl/gpgkey | gpg --dearmor >/etc/apt/trusted.gpg.d/VirtualGL.gpg && \
echo "deb [signed-by=/etc/apt/trusted.gpg.d/VirtualGL.gpg] https://packagecloud.io/dcommander/virtualgl/any/ any main" >> /etc/apt/sources.list.d/virtualgl.list && \
apt update && apt install -y virtualgl libgl1 && rm -rf /var/lib/apt/lists/*
RUN wget -q -O- https://packagecloud.io/dcommander/virtualgl/gpgkey | gpg --dearmor >/etc/apt/trusted.gpg.d/VirtualGL.gpg \
&& echo "deb [signed-by=/etc/apt/trusted.gpg.d/VirtualGL.gpg] https://packagecloud.io/dcommander/virtualgl/any/ any main" >>/etc/apt/sources.list.d/virtualgl.list \
&& apt-get update && apt-get install -y virtualgl libgl1 && rm -rf /var/lib/apt/lists/*

# Create a non-root user
ARG USERNAME=ros
ARG USER_UID=1001
ARG USER_GID=$USER_UID

RUN groupadd --gid $USER_GID $USERNAME \
&& useradd -s /bin/bash --uid $USER_UID --gid $USER_GID -m $USERNAME \
# Add sudo support for the non-root user\
&& apt-get update \
&& apt-get install -y --no-install-recommends sudo \
&& echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME\
&& chmod 0440 /etc/sudoers.d/$USERNAME \
&& rm -rf /var/lib/apt/lists/*
&& useradd -s /bin/bash --uid $USER_UID --gid $USER_GID -m $USERNAME \
# Add sudo support for the non-root user\
&& apt-get update \
&& apt-get install -y --no-install-recommends sudo \
&& echo $USERNAME ALL=\(root\) NOPASSWD:ALL >/etc/sudoers.d/$USERNAME && chmod 0440 /etc/sudoers.d/$USERNAME \
&& rm -rf /var/lib/apt/lists/*

# Configure bash profile
RUN echo "if [ -f /etc/bash.bashrc ]; then source /etc/bash.bashrc; fi" >> /root/.bashrc && \
Expand All @@ -74,7 +73,7 @@ RUN echo "if [ -f /etc/bash.bashrc ]; then source /etc/bash.bashrc; fi" >> /root
echo "source /opt/ros/${ROS_DISTRO}/setup.bash" >> /etc/bash.bashrc && \
echo "alias t='tmux'" >> /etc/bash.bashrc && \
echo "alias cls='clear'" >> /etc/bash.bashrc

ENV RMW_IMPLEMENTATION=rmw_cyclonedds_cpp
ENV CYCLONEDDS_URI=file:///etc/cyclonedds.xml
ENV TVNC_VGL=1
Expand Down
1 change: 0 additions & 1 deletion cuda_desktop.dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
ARG BASE_IMAGE=lcas.lincoln.ac.uk/ros_cuda:humble-main

###########################################
FROM ${BASE_IMAGE} AS base

RUN sudo apt-get update && sudo apt-get install -y --no-install-recommends \
Expand Down
Loading