diff --git a/.github/workflows/docker-build-opengl.yaml b/.github/workflows/docker-build-opengl.yaml new file mode 100644 index 0000000..15535e1 --- /dev/null +++ b/.github/workflows/docker-build-opengl.yaml @@ -0,0 +1,56 @@ +name: Build Docker Images + +on: + push: + branches: [ main ] + tags: + - '*' + pull_request: + branches: [ main ] + + schedule: + - cron: '30 2 * * 0,2,4,6' + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + include: + - base_image: ubuntu:jammy + ros_distro: humble + push_tag: lcas.lincoln.ac.uk/lcas/ros:jammy-humble + - base_image: nvidia/cuda:11.8.0-runtime-ubuntu22.04 + ros_distro: humble + push_tag: lcas.lincoln.ac.uk/lcas/ros:jammy-humble-cuda-opengl + + steps: + - uses: actions/checkout@v3 + - name: What + run: echo "BRANCH=${GITHUB_REF##*/}" >> $GITHUB_ENV + - name: Docker Login LCAS + if: ${{ github.event_name != 'pull_request' }} + # You may pin to the exact commit or the version. + # uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9 + uses: docker/login-action@v3 + with: + # Server address of Docker registry. If not set then will default to Docker Hub + registry: lcas.lincoln.ac.uk + # Username used to log against the Docker registry + username: ${{ secrets.LCAS_REGISTRY_PUSHER }} + # Password or personal access token used to log against the Docker registry + password: ${{ secrets.LCAS_REGISTRY_TOKEN }} + + - name: Build Docker Image + uses: docker/build-push-action@v5 + with: + context: . + file: ./Dockerfile.opengl + platforms: linux/amd64 + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ matrix.push_tag }} + build-args: | + BASE_IMAGE=ros:${{ matrix.base_image }} + BRANCH=${{ env.BRANCH }} + ROS_DISTRO=${{ matrix.ros_distro }} diff --git a/Dockerfile.kasm b/Dockerfile.kasm new file mode 100644 index 0000000..b0e7267 --- /dev/null +++ b/Dockerfile.kasm @@ -0,0 +1,22 @@ +ARG BASE_IMAGE=lcas.lincoln.ac.uk/lcas/ros:humble + +FROM ${BASE_IMAGE} as installer + +ENV DEBIAN_FRONTEND=noninteractive + + +RUN apt-get update && \ + wget -O /tmp/vncserver.deb https://github.com/kasmtech/KasmVNC/releases/download/v1.2.0/kasmvncserver_focal_1.2.0_amd64.deb && apt-get install -y /tmp/vncserver.deb && \ + apt-get install -y xfce4-session xfce4-panel && \ + apt-get clean + +#RUN sh -c 'echo "deb https://lcas.lincoln.ac.uk/apt/lcas $(lsb_release -sc) lcas" > /etc/apt/sources.list.d/lcas-latest.list' && \ +# curl -s https://lcas.lincoln.ac.uk/apt/repo_signing.gpg | tee /etc/apt/trusted.gpg.d/lcas-latest.gpg + +# RUN rosdep init || true +# RUN curl -o /etc/ros/rosdep/sources.list.d/20-default.list https://raw.githubusercontent.com/LCAS/rosdistro/master/rosdep/sources.list.d/20-default.list && \ +# curl -o /etc/ros/rosdep/sources.list.d/50-lcas.list https://raw.githubusercontent.com/LCAS/rosdistro/master/rosdep/sources.list.d/50-lcas.list + +# ENV ROSDISTRO_INDEX_URL=https://raw.github.com/LCAS/rosdistro/master/index-v4.yaml + +# RUN mkdir -p ~/.config/rosdistro && echo "index_url: https://raw.github.com/LCAS/rosdistro/master/index-v4.yaml" > ~/.config/rosdistro/config.yaml diff --git a/Dockerfile.opengl b/Dockerfile.opengl new file mode 100644 index 0000000..46dcd07 --- /dev/null +++ b/Dockerfile.opengl @@ -0,0 +1,221 @@ +ARG BASE_IMAGE=nvidia/cuda:11.8.0-runtime-ubuntu22.04 + +########################################### +FROM ${BASE_IMAGE} as base +ARG ROS_DISTRO=humble + +ENV ROS_DISTRO=${ROS_DISTRO} +ENV DEBIAN_FRONTEND=noninteractive + +# Install language +RUN apt-get update && apt-get install -y \ + locales \ + && 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 + +# Install timezone +RUN ln -fs /usr/share/zoneinfo/UTC /etc/localtime \ + && export DEBIAN_FRONTEND=noninteractive \ + && apt-get update \ + && apt-get install -y tzdata \ + && dpkg-reconfigure --frontend noninteractive tzdata \ + && rm -rf /var/lib/apt/lists/* + +RUN apt-get update && apt-get -y upgrade \ + && rm -rf /var/lib/apt/lists/* + +# Install common programs +RUN apt-get update && apt-get install -y --no-install-recommends \ + curl \ + gnupg2 \ + lsb-release \ + sudo \ + software-properties-common \ + wget \ + && rm -rf /var/lib/apt/lists/* + +# Install 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 \ + && apt-get update && apt-get install -y --no-install-recommends \ + ros-${ROS_DISTRO}-ros-base \ + python3-argcomplete \ + && rm -rf /var/lib/apt/lists/* + +################ +# Expose the nvidia driver to allow opengl +# Dependencies for glvnd and X11. +################ +RUN apt-get update \ + && apt-get install -y -qq --no-install-recommends \ + libglvnd0 \ + libgl1 \ + libglx0 \ + libegl1 \ + libxext6 \ + libx11-6 + +# Env vars for the nvidia-container-runtime. +ENV NVIDIA_VISIBLE_DEVICES all +ENV NVIDIA_DRIVER_CAPABILITIES graphics,utility,compute +ENV QT_X11_NO_MITSHM 1 + +ENV AMENT_PREFIX_PATH=/opt/ros/${ROS_DISTRO} +ENV COLCON_PREFIX_PATH=/opt/ros/${ROS_DISTRO} +ENV LD_LIBRARY_PATH=/opt/ros/${ROS_DISTRO}/lib +ENV PATH=/opt/ros/${ROS_DISTRO}/bin:$PATH +ENV PYTHONPATH=/opt/ros/${ROS_DISTRO}/local/lib/python3.10/dist-packages:/opt/ros/${ROS_DISTRO}/lib/python3.10/site-packages +ENV ROS_PYTHON_VERSION=3 +ENV ROS_VERSION=2 +ENV DEBIAN_FRONTEND= + +########################################### +# Develop image +########################################### +FROM base AS dev + +ENV DEBIAN_FRONTEND=noninteractive +RUN apt-get update && apt-get install -y --no-install-recommends \ + bash-completion \ + build-essential \ + cmake \ + gdb \ + git \ + openssh-client \ + python3-argcomplete \ + python3-pip \ + ros-dev-tools \ + ros-${ROS_DISTRO}-ament-* \ + vim \ + && rm -rf /var/lib/apt/lists/* + +RUN rosdep init || echo "rosdep already initialized" + +ARG USERNAME=ros +ARG USER_UID=1000 +ARG USER_GID=$USER_UID + +# Create a non-root user +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 sudo \ + && echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME\ + && chmod 0440 /etc/sudoers.d/$USERNAME \ + && rm -rf /var/lib/apt/lists/* + +# Set up autocompletion for user +RUN apt-get update && apt-get install -y git-core bash-completion \ + && echo "if [ -f /opt/ros/${ROS_DISTRO}/setup.bash ]; then source /opt/ros/${ROS_DISTRO}/setup.bash; fi" >> /home/$USERNAME/.bashrc \ + && echo "if [ -f /usr/share/colcon_argcomplete/hook/colcon-argcomplete.bash ]; then source /usr/share/colcon_argcomplete/hook/colcon-argcomplete.bash; fi" >> /home/$USERNAME/.bashrc \ + && rm -rf /var/lib/apt/lists/* + +ENV DEBIAN_FRONTEND= +ENV AMENT_CPPCHECK_ALLOW_SLOW_VERSIONS=1 + +########################################### +# Full image +########################################### +FROM dev AS full + +ENV DEBIAN_FRONTEND=noninteractive +# Install the full release +RUN apt-get update && apt-get install -y --no-install-recommends \ + ros-${ROS_DISTRO}-desktop \ + && rm -rf /var/lib/apt/lists/* +ENV DEBIAN_FRONTEND= +ENV LD_LIBRARY_PATH=/opt/ros/${ROS_DISTRO}/lib + + +########################################### +FROM dev as lcas + +ENV DEBIAN_FRONTEND=noninteractive + +RUN apt-get update && \ + apt-get install -y lsb-release curl software-properties-common apt-transport-https && \ + apt-get clean + +RUN sh -c 'echo "deb https://lcas.lincoln.ac.uk/apt/lcas $(lsb_release -sc) lcas" > /etc/apt/sources.list.d/lcas-latest.list' && \ + curl -s https://lcas.lincoln.ac.uk/apt/repo_signing.gpg | tee /etc/apt/trusted.gpg.d/lcas-latest.gpg + +RUN rosdep init || true +RUN curl -o /etc/ros/rosdep/sources.list.d/20-default.list https://raw.githubusercontent.com/LCAS/rosdistro/master/rosdep/sources.list.d/20-default.list && \ + curl -o /etc/ros/rosdep/sources.list.d/50-lcas.list https://raw.githubusercontent.com/LCAS/rosdistro/master/rosdep/sources.list.d/50-lcas.list + +ENV ROSDISTRO_INDEX_URL=https://raw.github.com/LCAS/rosdistro/master/index-v4.yaml + +ENV DEBIAN_FRONTEND= + +########################################### +FROM lcas as openglvnc + +ARG ENTRY_POINT=/opt/entrypoint.sh +ENV ENTRY_POINT=${ENTRY_POINT} + +ENV DEBIAN_FRONTEND=noninteractive +RUN curl -L -O https://github.com/VirtualGL/virtualgl/releases/download/3.1.1/virtualgl_3.1.1_amd64.deb && \ + apt-get -y install ./virtualgl_3.1.1_amd64.deb && \ + rm virtualgl_3.1.1_amd64.deb +RUN curl -L -O https://github.com/TurboVNC/turbovnc/releases/download/3.1.1/turbovnc_3.1.1_amd64.deb && \ + apt-get -y install ./turbovnc_3.1.1_amd64.deb && \ + rm turbovnc_3.1.1_amd64.deb +RUN addgroup --gid 1002 vglusers && adduser ros video && adduser ros vglusers +RUN apt-get update && apt-get -y install xfce4-session xfce4-terminal xfce4-panel python3-minimal python3-pip python3-numpy unzip less tmux screen +ENV DEBIAN_FRONTEND= + +# Install noVNC + +ENV NOVNC_VERSION=1.4.0 +ENV WEBSOCKETIFY_VERSION=0.10.0 + +RUN mkdir -p /usr/local/novnc && \ + curl -sSL https://github.com/novnc/noVNC/archive/v${NOVNC_VERSION}.zip -o /tmp/novnc-install.zip && \ + unzip /tmp/novnc-install.zip -d /usr/local/novnc && \ + cp /usr/local/novnc/noVNC-${NOVNC_VERSION}/vnc.html /usr/local/novnc/noVNC-${NOVNC_VERSION}/index.html && \ + curl -sSL https://github.com/novnc/websockify/archive/v${WEBSOCKETIFY_VERSION}.zip -o /tmp/websockify-install.zip && \ + unzip /tmp/websockify-install.zip -d /usr/local/novnc && \ + ln -s /usr/local/novnc/websockify-${WEBSOCKETIFY_VERSION} /usr/local/novnc/noVNC-${NOVNC_VERSION}/utils/websockify && \ + rm -f /tmp/websockify-install.zip /tmp/novnc-install.zip && \ + sed -i -E 's/^python /python3 /' /usr/local/novnc/websockify-${WEBSOCKETIFY_VERSION}/run + +RUN cat < /usr/share/glvnd/egl_vendor.d/10_nvidia.json + { + "file_format_version" : "1.0.0", + "ICD" : { + "library_path" : "libEGL_nvidia.so.0" + } + } +EOF + +COPY start-turbovnc.sh /opt/nvidia/entrypoint.d/90-turbovnc.sh +RUN echo "source /opt/ros/${ROS_DISTRO}/setup.bash" > /opt/nvidia/entrypoint.d/91-ros.sh + +COPY entrypoint.sh /opt/entrypoint.sh +RUN chmod +x /opt/entrypoint.sh +COPY start-turbovnc.sh /opt/entrypoint.d/90-turbovnc.sh +RUN echo "source /opt/ros/${ROS_DISTRO}/setup.bash" > /opt/entrypoint.d/91-ros.sh + +ENTRYPOINT ["/opt/entrypoint.sh"] + +########################################### +FROM openglvnc as user +USER ros + +RUN mkdir -p ~/.config/rosdistro && echo "index_url: https://raw.github.com/LCAS/rosdistro/master/index-v4.yaml" > ~/.config/rosdistro/config.yaml +RUN sudo apt-get purge -y xfce4-screensaver + +ENV DISPLAY=:1 +ENV TVNC_VGL=1 +ENV VGL_ISACTIVE=1 +ENV VGL_FPS=30 +ENV VGL_COMPRESS=0 +ENV VGL_DISPLAY=egl +ENV VGL_WM=1 +ENV VGL_PROBEGLX=0 +ENV LD_PRELOAD=libdlfaker.so:libvglfaker.so + diff --git a/entrypoint.sh b/entrypoint.sh new file mode 100644 index 0000000..f9e8990 --- /dev/null +++ b/entrypoint.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +# hand over to nvidia if present +if [ -r /opt/nvidia/nvidia_entrypoint.sh ]; then + exec /opt/nvidia/nvidia_entrypoint.sh "$@" +fi + +set -xe + +export VGL_FPS=30 +export VGL_DISPLAY=egl +/opt/TurboVNC/bin/vncserver -vgl -depth 24 -securitytypes TLSNone,X509None,None -wm xfce4-session > /tmp/vnc.log 2>&1 +/usr/local/novnc/noVNC-1.4.0/utils/novnc_proxy --vnc localhost:5901 --listen 5801 > /tmp/novnc.log 2>&1 & + +exec "$@" diff --git a/start-turbovnc.sh b/start-turbovnc.sh new file mode 100644 index 0000000..27dba0d --- /dev/null +++ b/start-turbovnc.sh @@ -0,0 +1,5 @@ +#!/bin/bash +export VGL_FPS=30 +export VGL_DISPLAY=egl +/opt/TurboVNC/bin/vncserver -vgl -depth 24 -securitytypes TLSNone,X509None,None -wm xfce4-session > /tmp/vnc.log 2>&1 +/usr/local/novnc/noVNC-1.4.0/utils/novnc_proxy --vnc localhost:5901 --listen 5801 > /tmp/novnc.log 2>&1 &