From 4f1424f256fa367091e47bf3baf6d237572c7557 Mon Sep 17 00:00:00 2001 From: Michael Wrock Date: Fri, 15 Jul 2022 02:02:30 -0700 Subject: [PATCH] Test docker (#3) * renamed cartesian limits file (#472) * Tutorial dockerfiles (#463) Build and push docker images for tutorials * fixed clang complaints * removed dockerhub pushes * successfully ran htmlproofer * removed chomp tutorial commits * removed accidental commits * Update CMakeLists.txt * renamed mtc tutorial cpp file * updated cmakelists * updated cmakelists * removed vscode * refactored docker * skipping base image * added conditions on building base image * added conditions on building base image * added conditions on building base image * ran pre commit * Update .docker/Dockerfile Co-authored-by: Robert Haschke * Update .docker/Dockerfile Co-authored-by: Robert Haschke * resolved comments * updated location to check for changes * test change to dockerfile * test change to dockerfile * test change to dockerfile * updated scripts to run only when dockerfile changes * fixed syntax * chaged to ros base image * chaged to ros base image * update * removed ccache and change repo names * removed ccache and change repo names Co-authored-by: Henry Moore <44307180+henrygerardmoore@users.noreply.github.com> Co-authored-by: Robert Haschke --- .docker/Dockerfile | 106 +++++++++++++ .docker/README.md | 4 + .docker/gui-docker | 147 ++++++++++++++++++ .github/workflows/docker-base.yml | 72 +++++++++ .github/workflows/docker-images.yml | 82 ++++++++++ .github/workflows/docker.yml | 53 +++++++ ...limits.yaml => pilz_cartesian_limits.yaml} | 0 .../CMakeLists.txt | 2 +- .../src/{main.cpp => mtc_node.cpp} | 0 package.xml | 1 + 10 files changed, 466 insertions(+), 1 deletion(-) create mode 100644 .docker/Dockerfile create mode 100644 .docker/README.md create mode 100755 .docker/gui-docker create mode 100644 .github/workflows/docker-base.yml create mode 100644 .github/workflows/docker-images.yml create mode 100644 .github/workflows/docker.yml rename doc/examples/dual_arms/dual_arm_panda_moveit_config/config/{cartesian_limits.yaml => pilz_cartesian_limits.yaml} (100%) rename doc/tutorials/pick_and_place_with_moveit_task_constructor/src/{main.cpp => mtc_node.cpp} (100%) diff --git a/.docker/Dockerfile b/.docker/Dockerfile new file mode 100644 index 0000000000..a73a8a2d5e --- /dev/null +++ b/.docker/Dockerfile @@ -0,0 +1,106 @@ +# syntax = docker/dockerfile:1.3 + +# ghcr.io/ros-planning/moveit2:${ROS_DISTRO}-source +# Downloads the moveit source code and install remaining debian dependencies + +ARG ROS_DISTRO=rolling +ARG BASE_BRANCH= + +######################### Base Tutorial Image ################################################# + +FROM ros:${ROS_DISTRO}-ros-base as base_image +ENV ROS_UNDERLAY /root/ws_moveit/ +WORKDIR $ROS_UNDERLAY + +# Copy MoveIt sources from docker context +COPY . src/moveit2_tutorials + +# Commands are combined in single RUN statement with "apt/lists" folder removal to reduce image size +# https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#minimize-the-number-of-layers +RUN --mount=type=cache,target=/root/.ccache/ \ + # Enable ccache + PATH=/usr/lib/ccache:$PATH && \ + # Fetch required upstream sources for building + vcs import src < /root/ws_moveit/src/moveit2_tutorials/moveit2_tutorials.repos && \ + . "/opt/ros/${ROS_DISTRO}/setup.sh" &&\ + sudo apt update && rosdep install -r --from-paths src --ignore-src --rosdistro $ROS_DISTRO -y && \ + colcon build \ + --cmake-args -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=OFF -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ + --ament-cmake-args -DCMAKE_BUILD_TYPE=Debug \ + --event-handlers desktop_notification- status- + +# Update /ros_entrypoint.sh to source our new workspace +RUN sed -i "s#/opt/ros/\$ROS_DISTRO/setup.bash#$ROS_UNDERLAY/install/setup.bash#g" /ros_entrypoint.sh + +######################### Hello World Tutorial Image ######################################### + +FROM ghcr.io/mikewrock/moveit2_tutorials:${ROS_DISTRO}${BASE_BRANCH} as hello_world_image + +#Make a new package using the command in the tutorial +RUN . "/opt/ros/${ROS_DISTRO}/setup.sh" &&\ + . "install/setup.sh" &&\ + cd "src" &&\ + ros2 pkg create \ + --build-type ament_cmake \ + --dependencies moveit_ros_planning_interface rclcpp \ + --node-name hello_moveit hello_moveit + +#Remove the empty cpp file and replace it with the example file +RUN rm src/hello_moveit/src/hello_moveit.cpp +COPY ./doc/tutorials/your_first_project/hello_moveit.cpp src/hello_moveit/src/hello_moveit.cpp +#Build the tutorial +RUN --mount=type=cache,target=/root/.ccache/ \ + . "/opt/ros/${ROS_DISTRO}/setup.sh" &&\ + . "install/setup.sh" &&\ + sudo apt update && rosdep install -r --from-paths src --ignore-src --rosdistro $ROS_DISTRO -y && \ + colcon build \ + --cmake-args -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=OFF -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ + --ament-cmake-args -DCMAKE_BUILD_TYPE=Debug \ + --event-handlers desktop_notification- status- + +######################### Planning Around Objects Image ####################################### + +FROM hello_world_image as planning_around_objects_image + +#Remove the hellow_world tutorial cpp file and replace it with the planning_around_objects file +RUN rm src/hello_moveit/src/hello_moveit.cpp +COPY ./doc/tutorials/planning_around_objects/hello_moveit.cpp src/hello_moveit/src/hello_moveit.cpp +#Build the tutorial +RUN --mount=type=cache,target=/root/.ccache/ \ + . "/opt/ros/${ROS_DISTRO}/setup.sh" &&\ + . "install/setup.sh" &&\ + sudo apt update && rosdep install -r --from-paths src --ignore-src --rosdistro $ROS_DISTRO -y && \ + colcon build \ + --cmake-args -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=OFF -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ + --ament-cmake-args -DCMAKE_BUILD_TYPE=Debug \ + --event-handlers desktop_notification- status- + +######################### Pick and Place (MTC) Image ######################################### + +FROM planning_around_objects_image as pick_and_place_image + +#Make a new package using the command in the tutorial +RUN . "/opt/ros/${ROS_DISTRO}/setup.sh" &&\ + . "install/setup.sh" &&\ + ros2 pkg create \ + --build-type ament_cmake \ + --destination-directory src \ + --dependencies moveit_task_constructor_core rclcpp \ + --node-name mtc_node mtc_tutorial +#Remove the empty cpp file and replace it with the example file +RUN rm src/mtc_tutorial/src/mtc_node.cpp +COPY ./doc/tutorials/pick_and_place_with_moveit_task_constructor/src/mtc_node.cpp src/mtc_tutorial/src/mtc_node.cpp +#Add the launch folder to the tutorial package and CMakeLists.txt +COPY ./doc/tutorials/pick_and_place_with_moveit_task_constructor/launch src/mtc_tutorial/launch +RUN sed -i "s|ament_package()|install(DIRECTORY launch DESTINATION share/\${PROJECT_NAME})\nament_package()|g" src/mtc_tutorial/CMakeLists.txt +#Build the tutorial +RUN --mount=type=cache,target=/root/.ccache/ \ + # Enable ccache + PATH=/usr/lib/ccache:$PATH && \ + . "/opt/ros/${ROS_DISTRO}/setup.sh" &&\ + . "install/setup.sh" &&\ + sudo apt update && rosdep install -r --from-paths src --ignore-src --rosdistro $ROS_DISTRO -y && \ + colcon build \ + --cmake-args -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=OFF -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ + --ament-cmake-args -DCMAKE_BUILD_TYPE=Debug \ + --event-handlers desktop_notification- status- diff --git a/.docker/README.md b/.docker/README.md new file mode 100644 index 0000000000..d250ee12a1 --- /dev/null +++ b/.docker/README.md @@ -0,0 +1,4 @@ +# MoveIt Docker Containers + + +For more information see the pages [Continuous Integration and Docker](http://moveit.ros.org/documentation/contributing/continuous_integration.html) and [Using Docker Containers with MoveIt](https://moveit.ros.org/install/docker/). diff --git a/.docker/gui-docker b/.docker/gui-docker new file mode 100755 index 0000000000..898af879af --- /dev/null +++ b/.docker/gui-docker @@ -0,0 +1,147 @@ +#!/bin/bash -u + +# This script is used to run a docker container with graphics support. +# All arguments to this script except "-c " will be appended to a docker run command. +# If a container name is specified, and this container already exists, the container is re-entered, +# which easily allows entering the same persistent container from multiple terminals. +# See documentation for detailed examples: https://moveit.ros.org/install/docker/ + +# Example commands: +# ./gui-docker --rm -it moveit/moveit:foxy-source /bin/bash # Run a (randomly named) container that is removed on exit +# ./gui-docker -v ~/ros_ws:/root/ros_ws --rm -it moveit/moveit:foxy-source /bin/bash # Same, but also link host volume ~/ros_ws to /root/ros_ws in the container +# ./gui-docker -c container_name # Start (or continue) an interactive bash in a moveit/moveit:foxy-source container +# ./gui-docker # Same, but use the default container name "default_moveit_container" + +function check_nvidia2() { + # If we don't have an NVIDIA graphics card, bail out + lspci | grep -qi "vga .*nvidia" || return 1 + # If we don't have the nvidia runtime, bail out + if ! docker -D info | grep -qi "runtimes.* nvidia" ; then + echo "nvidia-docker v2 not installed (see https://github.com/NVIDIA/nvidia-docker/wiki)" + return 2 + fi + echo "found nvidia-docker v2" + DOCKER_PARAMS="\ + --runtime=nvidia \ + --env=NVIDIA_VISIBLE_DEVICES=${NVIDIA_VISIBLE_DEVICES:-all} \ + --env=NVIDIA_DRIVER_CAPABILITIES=${NVIDIA_DRIVER_CAPABILITIES:+$NVIDIA_DRIVER_CAPABILITIES,}all" + return 0 +} + +function check_nvidia1() { + # If we don't have an NVIDIA graphics card, bail out + lspci | grep -qi "vga .*nvidia" || return 1 + # Check whether nvidia-docker is available + if ! which nvidia-docker > /dev/null ; then + echo "nvidia-docker v1 not installed either" + return 2 + fi + # Check that nvidia-modprobe is installed + if ! which nvidia-modprobe > /dev/null ; then + echo "nvidia-docker-plugin requires nvidia-modprobe. Please install it!" + return 3 + fi + # Retrieve device parameters from nvidia-docker-plugin + if ! DOCKER_PARAMS=$(curl -s http://localhost:3476/docker/cli) ; then + echo "nvidia-docker-plugin not responding on http://localhost:3476/docker/cli" + echo "See https://github.com/NVIDIA/nvidia-docker/wiki/Installation-(version-1.0)" + return 3 + fi + echo "found nvidia-docker v1" + DOCKER_EXECUTABLE=nvidia-docker +} + +function check_dri() { + # If there is no /dev/dri, bail out + test -d /dev/dri || return 1 + DOCKER_PARAMS="--device=/dev/dri --group-add video" +} + +function transfer_x11_permissions() { + # store X11 access rights in temp file to be passed into docker container + XAUTH=/tmp/.docker.xauth + touch $XAUTH + xauth nlist $DISPLAY | sed -e 's/^..../ffff/' | xauth -f $XAUTH nmerge - +} + +function count_positional_args() { + while true ; do + case "${1:-}" in + # Skip common options with a subsequent positional argument + # This list is not exhaustive! Augment as you see fit. + -v|--volume) shift ;; + -w) shift ;; + -e) shift ;; + # Skip all other options + -*) ;; + *) break ;; + esac + shift + done + # Return remaining number of arguments + echo $# +} + +if [ $# -eq 0 ] ; then + # If no options are specified at all, use the name "default_moveit_container" + CONTAINER_NAME=default_moveit_container +else + # Check for option -c or --container in first position + case "$1" in + -c|--container) + shift + # If next argument is not an option, use it as the container name + if [[ "${1:-}" != -* ]] ; then + CONTAINER_NAME="${1:-}" + shift + fi + # Set default container name if still undefined + CONTAINER_NAME="${CONTAINER_NAME:-default_moveit_container}" + ;; + esac +fi + +transfer_x11_permissions + +# Probe for nvidia-docker (version 2 or 1) +check_nvidia2 || check_nvidia1 || check_dri || echo "No supported graphics card found" + +DOCKER_EXECUTABLE=${DOCKER_EXECUTABLE:-docker} + +# If CONTAINER_NAME was specified and this container already exists, continue it +if [ -n "${CONTAINER_NAME:-}" ] ; then + if [ -z "$($DOCKER_EXECUTABLE ps -aq --filter name=^$CONTAINER_NAME\$)" ] ; then + # container not yet existing: add an option to name the container when running docker below + NAME_OPTION="--name=$CONTAINER_NAME" + if [ "$(count_positional_args $@)" == "0" ] ; then + # If no further (positional) arguments were provided, start a bash in the default image (for dummy users) + DUMMY_DEFAULTS="-it moveit/moveit:foxy-source bash" + fi + else + if [ -z "$($DOCKER_EXECUTABLE ps -q --filter name=^$CONTAINER_NAME\$)" ] ; then + echo -n "Start existing, but stopped container: " + docker start $CONTAINER_NAME + fi + echo "Entering container: $CONTAINER_NAME" + if [ $# -eq 0 ] ; then + docker exec -it $CONTAINER_NAME bash + else + docker exec $CONTAINER_NAME $@ + fi + rm $XAUTH + exit 0 + fi +fi + +${DOCKER_EXECUTABLE:-docker} run \ + --env="DISPLAY=$DISPLAY" \ + --env="QT_X11_NO_MITSHM=1" \ + --env="XAUTHORITY=$XAUTH" \ + --volume="/tmp/.X11-unix:/tmp/.X11-unix:rw" \ + --volume="$XAUTH:$XAUTH" \ + ${NAME_OPTION:-} \ + ${DOCKER_PARAMS:-} \ + $@ ${DUMMY_DEFAULTS:-} + +# cleanup +rm $XAUTH diff --git a/.github/workflows/docker-base.yml b/.github/workflows/docker-base.yml new file mode 100644 index 0000000000..3949ab5da2 --- /dev/null +++ b/.github/workflows/docker-base.yml @@ -0,0 +1,72 @@ +name: Build Basic Tutorial Image + +on: + workflow_call: + +jobs: + build-base: + strategy: + fail-fast: false + matrix: + ROS_DISTRO: [humble, rolling] + runs-on: ubuntu-latest + permissions: + packages: write + contents: read + env: + GH_IMAGE: ghcr.io/mikewrock/moveit2_tutorials:${{ matrix.ROS_DISTRO }} + DH_IMAGE: moveit/moveit2_tutorials:${{ matrix.ROS_DISTRO }} + PUSH: ${{ (github.event_name != 'pull_request') && (github.repository == 'mikewrock/moveit2_tutorials') }} + + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Get changed files + id: changed-files + uses: tj-actions/changed-files@v23.1 + with: + since_last_remote_commit: true + files: | + .docker/Dockerfile + moveit2_tutorials.repos + doc/tutorials/* + - name: Set up Docker Buildx + if: steps.changed-files.outputs.any_changed == 'true' + uses: docker/setup-buildx-action@v2 + - name: Login to Github Container Registry + if: steps.changed-files.outputs.any_changed == 'true' + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + # - name: Login to DockerHub + # if: env.PUSH == 'true' + # uses: docker/login-action@v2 + # with: + # username: ${{ secrets.DOCKERHUB_USERNAME }} + # password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Build and Push Basic Tutorial Image + uses: docker/build-push-action@v3 + if: steps.changed-files.outputs.any_changed == 'true' && env.PUSH == 'true' + with: + file: .docker/Dockerfile + build-args: ROS_DISTRO=${{ matrix.ROS_DISTRO }} + target: base_image + push: ${{ env.PUSH }} + no-cache: false + tags: | + ${{ env.GH_IMAGE }} +# ${{ env.DH_IMAGE }} + - name: Build and Push PR Image + uses: docker/build-push-action@v3 + if: steps.changed-files.outputs.any_changed == 'true' && env.PUSH == 'false' && github.event_name == 'pull_request' + with: + file: .docker/Dockerfile + build-args: ROS_DISTRO=${{ matrix.ROS_DISTRO }} + target: base_image + push: true + no-cache: false + tags: | + ${{ env.GH_IMAGE }}-PR-${{ github.head_ref }} diff --git a/.github/workflows/docker-images.yml b/.github/workflows/docker-images.yml new file mode 100644 index 0000000000..f3e09351a4 --- /dev/null +++ b/.github/workflows/docker-images.yml @@ -0,0 +1,82 @@ +name: Build Tutorial Images + +on: + workflow_call: + +jobs: + build-images: + strategy: + fail-fast: false + matrix: + ROS_DISTRO: [humble, rolling] + runs-on: ubuntu-latest + permissions: + packages: write + contents: read + env: + GH_IMAGE: ghcr.io/mikewrock/moveit2_tutorials:${{ matrix.ROS_DISTRO }} + DH_IMAGE: moveit/moveit2_tutorials:${{ matrix.ROS_DISTRO }} + PUSH: ${{ (github.event_name != 'pull_request') && (github.repository == 'mikewrock/moveit2_tutorials') }} + BASE_IMAGE_BRANCH: + + steps: + - name: Add -PR- to base image if this is a PR + if: github.event_name == 'pull_request' + run: | + echo "BASE_IMAGE_BRANCH=-PR-${{ github.head_ref }}" >> $GITHUB_ENV + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + - name: Login to Github Container Registry + if: env.PUSH == 'true' + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + # - name: Login to DockerHub + # if: env.PUSH == 'true' + # uses: docker/login-action@v2 + # with: + # username: ${{ secrets.DOCKERHUB_USERNAME }} + # password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Build and Push Hello World + uses: docker/build-push-action@v3 + with: + file: .docker/Dockerfile + build-args: | + ROS_DISTRO=${{ matrix.ROS_DISTRO }} + BASE_BRANCH=${{ env.BASE_IMAGE_BRANCH }} + target: hello_world_image + push: ${{ env.PUSH }} + no-cache: false + tags: | + ${{ env.GH_IMAGE }}-hello-world +# ${{ env.DH_IMAGE }}-hello-world + - name: Build and Push Planning Around Objects + uses: docker/build-push-action@v3 + with: + file: .docker/Dockerfile + build-args: | + ROS_DISTRO=${{ matrix.ROS_DISTRO }} + BASE_BRANCH=${{ env.BASE_IMAGE_BRANCH }} + target: planning_around_objects_image + push: ${{ env.PUSH }} + no-cache: false + tags: | + ${{ env.GH_IMAGE }}-planning +# ${{ env.DH_IMAGE }}-planning + - name: Build and Push MTC (All) + uses: docker/build-push-action@v3 + with: + file: .docker/Dockerfile + build-args: | + ROS_DISTRO=${{ matrix.ROS_DISTRO }} + BASE_BRANCH=${{ env.BASE_IMAGE_BRANCH }} + target: pick_and_place_image + push: ${{ env.PUSH }} + no-cache: false + tags: | + ${{ env.GH_IMAGE }}-pick-and-place + ${{ env.GH_IMAGE }}-all +# ${{ env.DH_IMAGE }}-pick-and-place +# ${{ env.DH_IMAGE }}-all diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml new file mode 100644 index 0000000000..2fe3071ad1 --- /dev/null +++ b/.github/workflows/docker.yml @@ -0,0 +1,53 @@ +name: Build Docker Images + +on: + schedule: + # 5 PM UTC every Sunday + - cron: '0 17 * * 6' + workflow_dispatch: + push: + branches: + - main + pull_request: + paths: + - moveit2_tutorials.repos + - .docker/** + - doc/tutorials/** + +jobs: + call-docker-base: + uses: ./.github/workflows/docker-base.yml + secrets: inherit + + call-docker-images: + needs: + - call-docker-base + uses: ./.github/workflows/docker-images.yml + secrets: inherit + + + delete-untagged: + runs-on: ubuntu-latest + needs: + - call-docker-images + steps: + - name: Delete Untagged Images + if: (github.event_name != 'pull_request') && (github.repository == 'mikewrock/moveit2_tutorials') + uses: actions/github-script@v6 + with: + github-token: ${{ secrets.DELETE_PACKAGES_TOKEN }} + script: | + const response = await github.request("GET /orgs/${{ env.OWNER }}/packages/container/${{ env.PACKAGE_NAME }}/versions", { + per_page: ${{ env.PER_PAGE }} + }); + for(version of response.data) { + if (version.metadata.container.tags.length == 0) { + console.log("delete " + version.id) + const deleteResponse = await github.request("DELETE /orgs/${{ env.OWNER }}/packages/container/${{ env.PACKAGE_NAME }}/versions/" + version.id, { }); + console.log("status " + deleteResponse.status) + } + } + env: + OWNER: mikewrock + PACKAGE_NAME: moveit2_tutorials + PER_PAGE: 100 diff --git a/doc/examples/dual_arms/dual_arm_panda_moveit_config/config/cartesian_limits.yaml b/doc/examples/dual_arms/dual_arm_panda_moveit_config/config/pilz_cartesian_limits.yaml similarity index 100% rename from doc/examples/dual_arms/dual_arm_panda_moveit_config/config/cartesian_limits.yaml rename to doc/examples/dual_arms/dual_arm_panda_moveit_config/config/pilz_cartesian_limits.yaml diff --git a/doc/tutorials/pick_and_place_with_moveit_task_constructor/CMakeLists.txt b/doc/tutorials/pick_and_place_with_moveit_task_constructor/CMakeLists.txt index ed69a5fe74..0bea18f8c2 100644 --- a/doc/tutorials/pick_and_place_with_moveit_task_constructor/CMakeLists.txt +++ b/doc/tutorials/pick_and_place_with_moveit_task_constructor/CMakeLists.txt @@ -1,4 +1,4 @@ -add_executable(mtc_tutorial src/main.cpp) +add_executable(mtc_tutorial src/mtc_node.cpp) target_compile_options(mtc_tutorial PUBLIC -g -O0) ament_target_dependencies(mtc_tutorial ${THIS_PACKAGE_INCLUDE_DEPENDS}) diff --git a/doc/tutorials/pick_and_place_with_moveit_task_constructor/src/main.cpp b/doc/tutorials/pick_and_place_with_moveit_task_constructor/src/mtc_node.cpp similarity index 100% rename from doc/tutorials/pick_and_place_with_moveit_task_constructor/src/main.cpp rename to doc/tutorials/pick_and_place_with_moveit_task_constructor/src/mtc_node.cpp diff --git a/package.xml b/package.xml index d6957cdf32..6cafbee536 100644 --- a/package.xml +++ b/package.xml @@ -26,6 +26,7 @@ moveit_servo moveit_hybrid_planning moveit_visual_tools + moveit_msgs pluginlib