Skip to content

Commit e2f3b9a

Browse files
authored
Build and host docker images of the tutorials (#533)
1 parent 70f5b29 commit e2f3b9a

File tree

16 files changed

+934
-34
lines changed

16 files changed

+934
-34
lines changed

.docker/Dockerfile

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# syntax = docker/dockerfile:1.3
2+
3+
ARG ROS_DISTRO=rolling
4+
5+
######################### Tutorial Image #################################################
6+
7+
FROM moveit/moveit2:${ROS_DISTRO}-source as tutorial_image
8+
9+
LABEL org.opencontainers.image.description "This container has working versions of the tutorials discussed here: https://moveit.picknik.ai/main/doc/tutorials/tutorials.html"
10+
11+
# Copy MoveIt sources from docker context
12+
COPY . src/moveit2_tutorials
13+
14+
# Commands are combined in single RUN statement with "apt/lists" folder removal to reduce image size
15+
# https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#minimize-the-number-of-layers
16+
RUN --mount=type=cache,target=/root/.ccache/ \
17+
# Fetch required upstream sources for building
18+
vcs import src < /root/ws_moveit/src/moveit2_tutorials/.github/upstream.repos
19+
20+
######################### Hello World Tutorial #########################################
21+
22+
#Create a new package using the command from the tutorial
23+
RUN . "/opt/ros/${ROS_DISTRO}/setup.sh" &&\
24+
. "install/setup.sh" &&\
25+
cd "src" &&\
26+
ros2 pkg create \
27+
--build-type ament_cmake \
28+
--dependencies moveit_ros_planning_interface moveit_visual_tools rclcpp \
29+
--node-name hello_moveit hello_moveit
30+
31+
######################### Planning Around Objects #######################################
32+
33+
#Remove the hello_world tutorial cpp file and replace it with the planning_around_objects file
34+
RUN rm src/hello_moveit/src/hello_moveit.cpp
35+
COPY ./doc/tutorials/planning_around_objects/hello_moveit.cpp src/hello_moveit/src/hello_moveit.cpp
36+
37+
######################### Pick and Place (MTC) Image #########################################
38+
39+
#Create a new package using the command from the tutorial
40+
RUN . "/opt/ros/${ROS_DISTRO}/setup.sh" &&\
41+
. "install/setup.sh" &&\
42+
ros2 pkg create \
43+
--build-type ament_cmake \
44+
--destination-directory src \
45+
--dependencies moveit_task_constructor_core rclcpp \
46+
--node-name mtc_node mtc_tutorial
47+
48+
#Remove the empty cpp file and replace it with the example file
49+
RUN rm src/mtc_tutorial/src/mtc_node.cpp
50+
COPY ./doc/tutorials/pick_and_place_with_moveit_task_constructor/src/mtc_node.cpp src/mtc_tutorial/src/mtc_node.cpp
51+
52+
#Add the launch folder to the tutorial package and CMakeLists.txt
53+
COPY ./doc/tutorials/pick_and_place_with_moveit_task_constructor/launch src/mtc_tutorial/launch
54+
55+
#Add install(DIRECTORY launch DESTINATION share/${PROJECT_NAME}) to CMakeLists.txt
56+
RUN sed -i "s|ament_package()|install(DIRECTORY launch DESTINATION share/\${PROJECT_NAME})\nament_package()|g" src/mtc_tutorial/CMakeLists.txt
57+
#Build the tutorials and set up the entrypoint/bashrc
58+
RUN --mount=type=cache,target=/root/.ccache/ \
59+
# Enable ccache
60+
. "/opt/ros/${ROS_DISTRO}/setup.sh" &&\
61+
. "install/setup.sh" &&\
62+
sudo apt update && rosdep install -r --from-paths src --ignore-src --rosdistro $ROS_DISTRO -y && \
63+
sudo apt install -y ros-${ROS_DISTRO}-rmw-cyclonedds-cpp && \
64+
colcon build \
65+
--cmake-args -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTING=OFF -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
66+
--ament-cmake-args -DCMAKE_BUILD_TYPE=Release \
67+
--event-handlers desktop_notification- status- && \
68+
ccache -s && \
69+
rm -rf /var/lib/apt/lists/* && \
70+
# Update /ros_entrypoint.sh to source our new workspace
71+
sed -i "s#/opt/ros/\$ROS_DISTRO/setup.bash#$ROS_UNDERLAY/install/setup.bash#g" /ros_entrypoint.sh && \
72+
echo "export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp" >> /root/.bashrc && \
73+
echo "source /opt/ros/${ROS_DISTRO}/setup.bash" >> /root/.bashrc && \
74+
echo "source /root/ws_moveit/install/setup.bash" >> /root/.bashrc

.docker/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# MoveIt Docker Containers
2+
3+
4+
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.picknik.ai/main/doc/how_to_guides/how_to_setup_docker_containers_in_ubuntu.html).

.docker/docker-compose.yml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Example command:
2+
# Humble on a Nvidia system:
3+
# DOCKER_IMAGE=humble-tutorial docker compose run gpu
4+
# Rolling without discrete graphics:
5+
# DOCKER_IMAGE=rolling-tutorial docker compose run cpu
6+
7+
services:
8+
cpu:
9+
image: ghcr.io/ros-planning/moveit2_tutorials:$DOCKER_IMAGE
10+
container_name: moveit2_container
11+
privileged: true
12+
network_mode: host
13+
command: /bin/bash
14+
volumes:
15+
- /tmp/.X11-unix:/tmp/.X11-unix
16+
- $XAUTHORITY:/root/.Xauthority
17+
environment:
18+
QT_X11_NO_MITSHM: 1
19+
DISPLAY: $DISPLAY
20+
gpu:
21+
image: ghcr.io/ros-planning/moveit2_tutorials:$DOCKER_IMAGE
22+
container_name: moveit2_container
23+
privileged: true
24+
network_mode: host
25+
command: /bin/bash
26+
deploy:
27+
resources:
28+
reservations:
29+
devices:
30+
- driver: nvidia
31+
count: 1
32+
capabilities: [gpu]
33+
volumes:
34+
- /tmp/.X11-unix:/tmp/.X11-unix
35+
- $XAUTHORITY:/root/.Xauthority
36+
environment:
37+
QT_X11_NO_MITSHM: 1
38+
DISPLAY: $DISPLAY
39+
NVIDIA_VISIBLE_DEVICES: all
40+
NVIDIA_DRIVER_CAPABILITIES: all

.docker/gui-docker

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
#!/bin/bash -u
2+
3+
# This script is used to run a docker container with graphics support.
4+
# All arguments to this script except "-c <container_name>" will be appended to a docker run command.
5+
# If a container name is specified, and this container already exists, the container is re-entered,
6+
# which easily allows entering the same persistent container from multiple terminals.
7+
# See documentation for detailed examples: https://moveit.ros.org/install/docker/
8+
9+
# Example commands:
10+
# ./gui-docker --rm -it moveit/moveit:foxy-source /bin/bash # Run a (randomly named) container that is removed on exit
11+
# ./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
12+
# ./gui-docker -c container_name # Start (or continue) an interactive bash in a moveit/moveit:foxy-source container
13+
# ./gui-docker # Same, but use the default container name "default_moveit_container"
14+
15+
function check_nvidia2() {
16+
# If we don't have an NVIDIA graphics card, bail out
17+
lspci | grep -qi "vga .*nvidia" || return 1
18+
# If we don't have the nvidia runtime, bail out
19+
if ! docker -D info | grep -qi "runtimes.* nvidia" ; then
20+
echo "nvidia-docker v2 not installed (see https://github.com/NVIDIA/nvidia-docker/wiki)"
21+
return 2
22+
fi
23+
echo "found nvidia-docker v2"
24+
DOCKER_PARAMS="\
25+
--runtime=nvidia \
26+
--env=NVIDIA_VISIBLE_DEVICES=${NVIDIA_VISIBLE_DEVICES:-all} \
27+
--env=NVIDIA_DRIVER_CAPABILITIES=${NVIDIA_DRIVER_CAPABILITIES:+$NVIDIA_DRIVER_CAPABILITIES,}all"
28+
return 0
29+
}
30+
31+
function check_nvidia1() {
32+
# If we don't have an NVIDIA graphics card, bail out
33+
lspci | grep -qi "vga .*nvidia" || return 1
34+
# Check whether nvidia-docker is available
35+
if ! which nvidia-docker > /dev/null ; then
36+
echo "nvidia-docker v1 not installed either"
37+
return 2
38+
fi
39+
# Check that nvidia-modprobe is installed
40+
if ! which nvidia-modprobe > /dev/null ; then
41+
echo "nvidia-docker-plugin requires nvidia-modprobe. Please install it!"
42+
return 3
43+
fi
44+
# Retrieve device parameters from nvidia-docker-plugin
45+
if ! DOCKER_PARAMS=$(curl -s http://localhost:3476/docker/cli) ; then
46+
echo "nvidia-docker-plugin not responding on http://localhost:3476/docker/cli"
47+
echo "See https://github.com/NVIDIA/nvidia-docker/wiki/Installation-(version-1.0)"
48+
return 3
49+
fi
50+
echo "found nvidia-docker v1"
51+
DOCKER_EXECUTABLE=nvidia-docker
52+
}
53+
54+
function check_dri() {
55+
# If there is no /dev/dri, bail out
56+
test -d /dev/dri || return 1
57+
DOCKER_PARAMS="--device=/dev/dri --group-add video"
58+
}
59+
60+
function transfer_x11_permissions() {
61+
# store X11 access rights in temp file to be passed into docker container
62+
XAUTH=/tmp/.docker.xauth
63+
touch $XAUTH
64+
xauth nlist $DISPLAY | sed -e 's/^..../ffff/' | xauth -f $XAUTH nmerge -
65+
}
66+
67+
function count_positional_args() {
68+
while true ; do
69+
case "${1:-}" in
70+
# Skip common options with a subsequent positional argument
71+
# This list is not exhaustive! Augment as you see fit.
72+
-v|--volume) shift ;;
73+
-w) shift ;;
74+
-e) shift ;;
75+
# Skip all other options
76+
-*) ;;
77+
*) break ;;
78+
esac
79+
shift
80+
done
81+
# Return remaining number of arguments
82+
echo $#
83+
}
84+
85+
if [ $# -eq 0 ] ; then
86+
# If no options are specified at all, use the name "default_moveit_container"
87+
CONTAINER_NAME=default_moveit_container
88+
else
89+
# Check for option -c or --container in first position
90+
case "$1" in
91+
-c|--container)
92+
shift
93+
# If next argument is not an option, use it as the container name
94+
if [[ "${1:-}" != -* ]] ; then
95+
CONTAINER_NAME="${1:-}"
96+
shift
97+
fi
98+
# Set default container name if still undefined
99+
CONTAINER_NAME="${CONTAINER_NAME:-default_moveit_container}"
100+
;;
101+
esac
102+
fi
103+
104+
transfer_x11_permissions
105+
106+
# Probe for nvidia-docker (version 2 or 1)
107+
check_nvidia2 || check_nvidia1 || check_dri || echo "No supported graphics card found"
108+
109+
DOCKER_EXECUTABLE=${DOCKER_EXECUTABLE:-docker}
110+
111+
# If CONTAINER_NAME was specified and this container already exists, continue it
112+
if [ -n "${CONTAINER_NAME:-}" ] ; then
113+
if [ -z "$($DOCKER_EXECUTABLE ps -aq --filter name=^$CONTAINER_NAME\$)" ] ; then
114+
# container not yet existing: add an option to name the container when running docker below
115+
NAME_OPTION="--name=$CONTAINER_NAME"
116+
if [ "$(count_positional_args $@)" == "0" ] ; then
117+
# If no further (positional) arguments were provided, start a bash in the default image (for dummy users)
118+
DUMMY_DEFAULTS="-it moveit/moveit:foxy-source bash"
119+
fi
120+
else
121+
if [ -z "$($DOCKER_EXECUTABLE ps -q --filter name=^$CONTAINER_NAME\$)" ] ; then
122+
echo -n "Start existing, but stopped container: "
123+
docker start $CONTAINER_NAME
124+
fi
125+
echo "Entering container: $CONTAINER_NAME"
126+
if [ $# -eq 0 ] ; then
127+
docker exec -it $CONTAINER_NAME bash
128+
else
129+
docker exec $CONTAINER_NAME $@
130+
fi
131+
rm $XAUTH
132+
exit 0
133+
fi
134+
fi
135+
136+
${DOCKER_EXECUTABLE:-docker} run \
137+
--env="DISPLAY=$DISPLAY" \
138+
--env="QT_X11_NO_MITSHM=1" \
139+
--env="XAUTHORITY=$XAUTH" \
140+
--volume="/tmp/.X11-unix:/tmp/.X11-unix:rw" \
141+
--volume="$XAUTH:$XAUTH" \
142+
${NAME_OPTION:-} \
143+
${DOCKER_PARAMS:-} \
144+
$@ ${DUMMY_DEFAULTS:-}
145+
146+
# cleanup
147+
rm $XAUTH
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
name: Build Tutorial Image
2+
3+
on:
4+
workflow_call:
5+
workflow_dispatch:
6+
7+
jobs:
8+
build-images:
9+
strategy:
10+
fail-fast: false
11+
matrix:
12+
ROS_DISTRO: [humble, rolling]
13+
runs-on: ubuntu-latest
14+
permissions:
15+
packages: write
16+
contents: read
17+
env:
18+
GH_IMAGE: ghcr.io/${{ github.repository }}:${{ matrix.ROS_DISTRO }}
19+
PUSH: ${{ (github.ref_name == 'main') }}
20+
21+
steps:
22+
- name: Set lower case for container name
23+
run: |
24+
echo "GH_IMAGE_LC=${GH_IMAGE,,}" >>${GITHUB_ENV}
25+
- name: Set up Docker Buildx
26+
uses: docker/setup-buildx-action@v2
27+
- name: Login to Github Container Registry
28+
uses: docker/login-action@v2
29+
with:
30+
registry: ghcr.io
31+
username: ${{ github.repository_owner }}
32+
password: ${{ secrets.GITHUB_TOKEN }}
33+
- name: Build Tutorial Image
34+
uses: docker/build-push-action@v3
35+
with:
36+
file: .docker/Dockerfile
37+
build-args: |
38+
ROS_DISTRO=${{ matrix.ROS_DISTRO }}
39+
BASE_BRANCH=${{ env.BASE_IMAGE_BRANCH }}
40+
target: tutorial_image
41+
push: ${{ env.PUSH }}
42+
no-cache: false
43+
tags: |
44+
${{ env.GH_IMAGE_LC }}-tutorial

.github/workflows/docker.yml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
name: Update Tutorial Images
2+
3+
on:
4+
schedule:
5+
# 5 PM UTC every Sunday
6+
- cron: '0 17 * * 6'
7+
workflow_dispatch:
8+
push:
9+
branches:
10+
- main
11+
12+
jobs:
13+
call-docker-images:
14+
uses: ./.github/workflows/docker-images.yml
15+
secrets: inherit
16+
17+
delete-untagged:
18+
runs-on: ubuntu-latest
19+
needs:
20+
- call-docker-images
21+
steps:
22+
- name: Delete Untagged Images
23+
if: (github.event_name == 'schedule')
24+
uses: actions/github-script@v6
25+
with:
26+
github-token: ${{ secrets.DELETE_PACKAGES_TOKEN }}
27+
script: |
28+
const response = await github.request("GET /orgs/${{ env.OWNER }}/packages/container/${{ env.PACKAGE_NAME }}/versions", {
29+
per_page: ${{ env.PER_PAGE }}
30+
});
31+
for(version of response.data) {
32+
if (version.metadata.container.tags.length == 0) {
33+
console.log("delete " + version.id)
34+
const deleteResponse = await github.request("DELETE /orgs/${{ env.OWNER }}/packages/container/${{ env.PACKAGE_NAME }}/versions/" + version.id, { });
35+
console.log("status " + deleteResponse.status)
36+
}
37+
}
38+
env:
39+
OWNER: ${{ github.repository_owner }}
40+
PACKAGE_NAME: moveit2_tutorials
41+
PER_PAGE: 100

_static/videos/mtc-demo.webm

1.07 MB
Binary file not shown.

0 commit comments

Comments
 (0)