diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml new file mode 100644 index 0000000..d5d197d --- /dev/null +++ b/.github/workflows/docker.yml @@ -0,0 +1,62 @@ +name: Docker + +on: + push: + branches: + - master + pull_request: + release: + types: + - released + +jobs: + ci: + name: ${{ matrix.distro }} + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + distro: [foxy, humble, rolling] + env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + PUSH_DOCKER_IMAGE: ${{ github.ref == 'refs/heads/master' || github.event_name == 'release' }} + permissions: + contents: read + packages: write + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Log in to the Container registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract Docker meta-information + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + flavor: | + latest=false + prefix= + suffix= + tags: | + type=ref,event=branch,prefix=${{ matrix.distro }}- + type=ref,event=pr,prefix=${{ matrix.distro }}- + type=semver,pattern={{major}}.{{minor}},prefix=${{ matrix.distro }}- + + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: . + file: docker/Dockerfile + build-args: | + TAG=${{ matrix.distro }}-master + ROS_DISTRO=${{ matrix.distro }} + push: ${{ env.PUSH_DOCKER_IMAGE }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 0000000..025e2a9 --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,30 @@ +ARG TAG +FROM ghcr.io/ros-industrial-consortium/scan_n_plan_workshop:${TAG} + +SHELL ["/bin/bash", "-c"] + +ENV DEBIAN_FRONTEND noninteractivej + +USER root + + +# Run apt update and install useful utilities like sudo +RUN apt update -y -qq && apt install -y -qq sudo + +# Bind mount the source directory so as not to unnecessarily copy source code into the docker image +ARG WORKSPACE_DIR=/opt/snp_automate_2022 +RUN --mount=type=bind,target=${WORKSPACE_DIR}/src/snp_automate_2022 \ + apt update -y -qq \ + && source /opt/snp/install/setup.bash \ + && vcs import ${WORKSPACE_DIR}/src < ${WORKSPACE_DIR}/src/snp_automate_2022/dependencies.repos --shallow \ + && rosdep install \ + --from-paths ${WORKSPACE_DIR}/src \ + -iry + +# Build the repository +# Bind mount the source directory so as not to unnecessarily copy source code into the docker image +RUN --mount=type=bind,target=${WORKSPACE_DIR}/src/snp_automate_2022 \ + source /opt/snp/install/setup.bash \ + && cd ${WORKSPACE_DIR} \ + && colcon build --cmake-args \ + && rm -rf build log diff --git a/docker/README.md b/docker/README.md new file mode 100644 index 0000000..e33f6e3 --- /dev/null +++ b/docker/README.md @@ -0,0 +1,28 @@ +# SNP Automate 2022 Docker + +## Create the Docker image +### Download +Download a pre-built Docker image from the container registry: + +``` +docker login ghcr.io +docker pull ghcr.io/ros-industrial-consortium/scan_n_plan_workshop: +``` + +### Build +Build the Docker image using `docker-compose`: + +```commandLine +cd docker +docker compose build +``` + +## Run the docker image +Run the Docker image using `docker-compose`: + +```commandLine +cd docker +CURRENT_UID=$(id -u):$(id -g) docker compose up +``` + +> Note: by default the docker image runs as a non-root user, so the environment variable `CURRENT_UID` must be supplied as shown above diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml new file mode 100644 index 0000000..72a6844 --- /dev/null +++ b/docker/docker-compose.yml @@ -0,0 +1,66 @@ +version: '3' +services: + snp_automate_2022: + build: + context: .. + dockerfile: docker/Dockerfile + args: + - TAG=foxy-master + environment: + DISPLAY: $DISPLAY + XAUTHORITY: $XAUTHORITY + # NVIDIA_DRIVER_CAPABILITIES: all + ROS_LOG_DIR: /tmp/.ros + ROS_LOCALHOST_ONLY: $ROS_LOCALHOST_ONLY + ROS_DOMAIN_ID: $ROS_DOMAIN_ID + container_name: snp_automate_2022 + image: ghcr.io/ros-industrial-consortium/snp_automate_2022:foxy-master + stdin_open: true + tty: true + network_mode: host + privileged: true + user: ${CURRENT_UID} # CURRENT_UID=$(id -u):$(id -g) + group_add: + - sudo + volumes: + - /tmp/.X11-unix:/tmp/.X11-unix + - /etc/hosts:/etc/hosts + - /etc/passwd:/etc/passwd:ro + - /etc/group:/etc/group:ro + - /etc/shadow:/etc/shadow:ro + - /dev:/dev + # deploy: + # resources: + # reservations: + # devices: + # - driver: nvidia + # count: 1 + # capabilities: [gpu] + + # ROS1 bridge + ros1-bridge: + environment: + ROS_LOCALHOST_ONLY: $ROS_LOCALHOST_ONLY + ROS_DOMAIN_ID: $ROS_DOMAIN_ID + ROS_LOG_DIR: /tmp/.ros + volumes: + # Mount DDS shared memory location; see https://stackoverflow.com/questions/65900201/troubles-communicating-with-ros2-node-in-docker-container + - /dev/shm:/dev/shm + - /etc/hosts:/etc/hosts + - /etc/passwd:/etc/passwd:ro + - /etc/group:/etc/group:ro + - /etc/shadow:/etc/shadow:ro + stdin_open: true + tty: true + container_name: ros1-bridge + image: ghcr.io/ros-industrial/ros1_bridge:noetic-foxy + privileged: true + + # Run as the same user as the other system + # CURRENT_UID=$(id -u):$(id -g) + user: ${CURRENT_UID} + + # Share the network with the host PC + network_mode: host + ipc: host + pid: host \ No newline at end of file