diff --git a/.github/actions/docker-build-and-push-openadkit/action.yaml b/.github/actions/docker-build-and-push-openadkit/action.yaml new file mode 100644 index 00000000000..638bcf2c034 --- /dev/null +++ b/.github/actions/docker-build-and-push-openadkit/action.yaml @@ -0,0 +1,197 @@ +name: docker-build-and-push-openadkit +description: "" + +inputs: + bake-target: + description: "" + required: true + bake-images: + description: "" + required: false + build-args: + description: "" + required: false + tag-prefix: + description: "" + required: false + tag-suffix: + description: "" + required: false + tag-arch: + description: "" + required: false + allow-push: + description: "" + default: "true" + required: false + +runs: + using: composite + steps: + - name: Setup Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Set Docker tags + id: set-docker-tags + run: | + tags=() + if [ "${{ github.event_name }}" == "push" ] && [ "${{ github.ref_type }}" == "tag" ]; then + tags+=("$(echo "${{ github.ref }}" | sed -E 's/.*([vV][0-9]+\.[0-9]+\.[0-9]+).*/\1/')") + fi + + tags+=("{{date 'YYYYMMDD'}}") + tags+=("latest") + tags+=("latest-${{ inputs.tag-prefix }}") + + # Output multiline strings: https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#multiline-strings + EOF=$(dd if=/dev/urandom bs=15 count=1 status=none | base64) + echo "tags<<$EOF" >> $GITHUB_OUTPUT + echo "$(printf "%s\n" "${tags[@]}")" >> $GITHUB_OUTPUT + echo "$EOF" >> $GITHUB_OUTPUT + shell: bash + + # openadkit modular images metadata + - name: Docker meta for openadkit:planning-control + id: meta-planning-control + uses: docker/metadata-action@v4 + with: + images: ghcr.io/${{ github.repository_owner }}/${{ inputs.bake-target }} + tags: ${{ steps.set-docker-tags.outputs.tags }} + bake-target: docker-metadata-action-planning-control + flavor: | + latest=false + suffix=-planning-control${{ inputs.tag-arch }} + + - name: Docker meta for openadkit:visualizer + id: meta-visualizer + uses: docker/metadata-action@v4 + with: + images: ghcr.io/${{ github.repository_owner }}/${{ inputs.bake-target }} + tags: ${{ steps.set-docker-tags.outputs.tags }} + bake-target: docker-metadata-action-visualizer + flavor: | + latest=false + suffix=-visualizer${{ inputs.tag-arch }} + + - name: Docker meta for openadkit:simulator + id: meta-simulator + uses: docker/metadata-action@v4 + with: + images: ghcr.io/${{ github.repository_owner }}/${{ inputs.bake-target }} + tags: ${{ steps.set-docker-tags.outputs.tags }} + bake-target: docker-metadata-action-simulator + flavor: | + latest=false + suffix=-simulator${{ inputs.tag-arch }} + + - name: Login to GitHub Container Registry + if: ${{ github.event_name != 'pull_request' }} + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ github.token }} + + - name: Build and Push to GitHub Container Registry + if: ${{ github.event_name == 'push' || github.event_name == 'schedule' || ( github.event_name == 'workflow_dispatch' && github.event.inputs.artifacts-destination == 'registry') }} + uses: docker/bake-action@v3 + with: + push: ${{ inputs.allow-push == 'true' }} + files: | + docker/${{ inputs.bake-target }}/docker-bake.hcl + ${{ steps.meta-planning-control.outputs.bake-file }} + ${{ steps.meta-visualizer.outputs.bake-file }} + ${{ steps.meta-simulator.outputs.bake-file }} + provenance: false + targets: | + ${{ inputs.bake-images }} + set: | + ${{ inputs.build-args }} + + - name: Build only + if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.artifacts-destination == 'tarball' }} + uses: docker/bake-action@v3 + with: + push: false + files: | + docker/${{ inputs.bake-target }}/docker-bake.hcl + ${{ steps.meta-planning-control.outputs.bake-file }} + ${{ steps.meta-visualizer.outputs.bake-file }} + ${{ steps.meta-simulator.outputs.bake-file }} + provenance: false + targets: | + ${{ inputs.bake-images }} + set: | + ${{ inputs.build-args }} + + - name: Output artifact URLs + if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.artifacts-destination == 'tarball' }} + id: warn-no-artifacts + run: | + echo 'No artifacts uploaded because of disk space issue' + shell: bash + + # TODO:Enable after solving the issue with the disk space + # - name: Build and Save Artifacts + # if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.artifacts-destination == 'tarball' }} + # uses: docker/bake-action@v3 + # with: + # push: false + # files: | + # docker/${{ inputs.bake-target }}/docker-bake.hcl + # ${{ steps.meta-planning-control.outputs.bake-file }} + # ${{ steps.meta-visualizer.outputs.bake-file }} + # ${{ steps.meta-simulator.outputs.bake-file }} + # provenance: false + # targets: | + # ${{ inputs.bake-images }} + # set: | + # ${{ inputs.build-args }} + # planning-control.output=type=docker,dest=/tmp/planning-control.tar + # visualizer.output=type=docker,dest=/tmp/visualizer.tar + # simulator.output=type=docker,dest=/tmp/simulator.tar + + # - name: Upload Artifact - planning-control + # if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.artifacts-destination == 'tarball' }} + # id: artifact-upload-step-planning-control + # uses: actions/upload-artifact@v4 + # with: + # name: planning-control-image${{ inputs.tag-suffix }} + # path: /tmp/planning-control.tar + # retention-days: 7 + # compression-level: 6 + # overwrite: true + # if-no-files-found: warn + + # - name: Upload Artifact - visualizer + # if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.artifacts-destination == 'tarball' }} + # id: artifact-upload-step-visualizer + # uses: actions/upload-artifact@v4 + # with: + # name: visualizer-image${{ inputs.tag-suffix }} + # path: /tmp/visualizer.tar + # retention-days: 7 + # compression-level: 6 + # overwrite: true + # if-no-files-found: warn + + # - name: Upload Artifact - simulator + # if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.artifacts-destination == 'tarball' }} + # id: artifact-upload-step-simulator + # uses: actions/upload-artifact@v4 + # with: + # name: simulator-image${{ inputs.tag-suffix }} + # path: /tmp/simulator.tar + # retention-days: 7 + # compression-level: 6 + # overwrite: true + # if-no-files-found: warn + + # - name: Output artifact URLs + # if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.artifacts-destination == 'tarball' }} + # id: output-artifact-urls + # run: | + # echo 'planning-control URL ${{ steps.artifact-upload-step-planning-control.outputs.artifact-url }}' + # echo 'visualizer URL ${{ steps.artifact-upload-step-visualizer.outputs.artifact-url }}' + # echo 'simulator URL ${{ steps.artifact-upload-step-simulator.outputs.artifact-url }}' + # shell: bash diff --git a/.github/actions/docker-build-and-push/action.yaml b/.github/actions/docker-build-and-push/action.yaml index 2afd706e66a..c08dba3c356 100644 --- a/.github/actions/docker-build-and-push/action.yaml +++ b/.github/actions/docker-build-and-push/action.yaml @@ -5,6 +5,9 @@ inputs: bake-target: description: "" required: true + bake-images: + description: "" + required: false build-args: description: "" required: false @@ -14,6 +17,9 @@ inputs: tag-suffix: description: "" required: false + tag-arch: + description: "" + required: false allow-push: description: "" default: "true" @@ -25,12 +31,6 @@ runs: - name: Setup Docker Buildx uses: docker/setup-buildx-action@v2 - - name: Install jq - run: | - sudo apt-get -y update - sudo apt-get -y install jq - shell: bash - - name: Set Docker tags id: set-docker-tags run: | @@ -50,6 +50,17 @@ runs: echo "$EOF" >> $GITHUB_OUTPUT shell: bash + - name: Docker meta for base + id: meta-base + uses: docker/metadata-action@v4 + with: + images: ghcr.io/${{ github.repository_owner }}/${{ inputs.bake-target }} + tags: ${{ steps.set-docker-tags.outputs.tags }} + bake-target: docker-metadata-action-base + flavor: | + latest=false + suffix=-base${{ inputs.tag-arch }} + - name: Docker meta for prebuilt id: meta-prebuilt uses: docker/metadata-action@v4 @@ -59,7 +70,7 @@ runs: bake-target: docker-metadata-action-prebuilt flavor: | latest=false - suffix=-prebuilt${{ inputs.tag-suffix }} + suffix=-prebuilt${{ inputs.tag-suffix }}${{ inputs.tag-arch }} - name: Docker meta for devel id: meta-devel @@ -70,10 +81,9 @@ runs: bake-target: docker-metadata-action-devel flavor: | latest=false - suffix=-devel${{ inputs.tag-suffix }} + suffix=-devel${{ inputs.tag-suffix }}${{ inputs.tag-arch }} - name: Docker meta for runtime - if: ${{ github.event_name == 'workflow_dispatch' }} || ${{ (github.event_name == 'push' && github.ref_type == 'tag') }} id: meta-runtime uses: docker/metadata-action@v4 with: @@ -82,7 +92,7 @@ runs: bake-target: docker-metadata-action-runtime flavor: | latest=${{ github.event_name == 'push' && github.ref_type == 'tag' }} - suffix=-runtime${{ inputs.tag-suffix }} + suffix=-runtime${{ inputs.tag-suffix }}${{ inputs.tag-arch }} - name: Login to GitHub Container Registry if: ${{ github.event_name != 'pull_request' }} @@ -99,23 +109,29 @@ runs: push: ${{ inputs.allow-push == 'true' }} files: | docker/docker-bake.hcl + ${{ steps.meta-base.outputs.bake-file }} ${{ steps.meta-prebuilt.outputs.bake-file }} ${{ steps.meta-devel.outputs.bake-file }} ${{ steps.meta-runtime.outputs.bake-file }} provenance: false + targets: | + ${{ inputs.bake-images }} set: | ${{ inputs.build-args }} - - name: Build only + - name: Build Only if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.artifacts-destination == 'tarball' }} uses: docker/bake-action@v3 with: push: false files: | docker/docker-bake.hcl + ${{ steps.meta-base.outputs.bake-file }} ${{ steps.meta-prebuilt.outputs.bake-file }} ${{ steps.meta-devel.outputs.bake-file }} ${{ steps.meta-runtime.outputs.bake-file }} provenance: false + targets: | + ${{ inputs.bake-images }} set: | ${{ inputs.build-args }} diff --git a/.github/workflows/docker-build-and-push-main-self-hosted.yaml b/.github/workflows/docker-build-and-push-main-self-hosted.yaml index 772ba389e82..227f6b54752 100644 --- a/.github/workflows/docker-build-and-push-main-self-hosted.yaml +++ b/.github/workflows/docker-build-and-push-main-self-hosted.yaml @@ -43,10 +43,12 @@ jobs: lib_dir: aarch64 setup-args: --no-nvidia additional-tag-suffix: "" + bake-images: default - name: cuda base_image_env: base_image lib_dir: aarch64 additional-tag-suffix: -cuda + bake-images: default steps: # https://github.com/actions/checkout/issues/211 - name: Change permission of workspace @@ -85,10 +87,31 @@ jobs: *.args.BASE_IMAGE=${{ needs.load-env.outputs[format('{0}', matrix.base_image_env)] }} *.args.SETUP_ARGS=${{ matrix.setup-args }} *.args.LIB_DIR=${{ matrix.lib_dir }} + *.args.ARCH=arm64 *.cache-from=type=registry,ref=ghcr.io/${{ github.repository }}:buildcache-${{ matrix.name }} *.cache-to=type=registry,ref=ghcr.io/${{ github.repository }}:buildcache-${{ matrix.name }},mode=max - tag-suffix: ${{ matrix.additional-tag-suffix }}-arm64 + tag-suffix: ${{ matrix.additional-tag-suffix }} + tag-arch: -arm64 tag-prefix: ${{ needs.load-env.outputs.rosdistro }} + bake-images: ${{ matrix.bake-images }} + allow-push: true + + - name: Build 'Open AD Kit' + if: ${{ matrix.name == 'no-cuda' }} + uses: ./.github/actions/docker-build-and-push-openadkit + with: + bake-target: openadkit + build-args: | + *.platform=linux/arm64 + *.args.ROS_DISTRO=${{ needs.load-env.outputs.rosdistro }} + *.args.BASE_IMAGE=${{ needs.load-env.outputs[format('{0}', matrix.base_image_env)] }} + *.args.SETUP_ARGS=${{ matrix.setup-args }} + *.args.LIB_DIR=${{ matrix.lib_dir }} + *.args.ARCH=arm64 + tag-suffix: ${{ matrix.additional-tag-suffix }} + tag-arch: -arm64 + tag-prefix: ${{ needs.load-env.outputs.rosdistro }} + bake-images: ${{ matrix.bake-images }} allow-push: true - name: Show disk space diff --git a/.github/workflows/docker-build-and-push-main.yaml b/.github/workflows/docker-build-and-push-main.yaml index 118ba5413e5..a5c4ae036ef 100644 --- a/.github/workflows/docker-build-and-push-main.yaml +++ b/.github/workflows/docker-build-and-push-main.yaml @@ -43,10 +43,12 @@ jobs: lib_dir: x86_64 setup-args: --no-nvidia additional-tag-suffix: "" + bake-images: default - name: cuda base_image_env: base_image lib_dir: x86_64 additional-tag-suffix: -cuda + bake-images: default steps: - name: Check out repository uses: actions/checkout@v4 @@ -80,10 +82,31 @@ jobs: *.args.BASE_IMAGE=${{ needs.load-env.outputs[format('{0}', matrix.base_image_env)] }} *.args.SETUP_ARGS=${{ matrix.setup-args }} *.args.LIB_DIR=${{ matrix.lib_dir }} + *.args.ARCH=amd64 *.cache-from=type=registry,ref=ghcr.io/${{ github.repository }}:buildcache-${{ matrix.name }} *.cache-to=type=registry,ref=ghcr.io/${{ github.repository }}:buildcache-${{ matrix.name }},mode=max - tag-suffix: ${{ matrix.additional-tag-suffix }}-amd64 + tag-suffix: ${{ matrix.additional-tag-suffix }} + tag-arch: -amd64 tag-prefix: ${{ needs.load-env.outputs.rosdistro }} + bake-images: ${{ matrix.bake-images }} + allow-push: true + + - name: Build 'Open AD Kit' + if: ${{ matrix.name == 'no-cuda' }} + uses: ./.github/actions/docker-build-and-push-openadkit + with: + bake-target: openadkit + build-args: | + *.platform=linux/amd64 + *.args.ROS_DISTRO=${{ needs.load-env.outputs.rosdistro }} + *.args.BASE_IMAGE=${{ needs.load-env.outputs[format('{0}', matrix.base_image_env)] }} + *.args.SETUP_ARGS=${{ matrix.setup-args }} + *.args.LIB_DIR=${{ matrix.lib_dir }} + *.args.ARCH=amd64 + tag-suffix: ${{ matrix.additional-tag-suffix }} + tag-arch: -amd64 + tag-prefix: ${{ needs.load-env.outputs.rosdistro }} + bake-images: ${{ matrix.bake-images }} allow-push: true - name: Show disk space diff --git a/.github/workflows/update-docker-manifest.yaml b/.github/workflows/update-docker-manifest.yaml index a0539b037ed..a8097dafda7 100644 --- a/.github/workflows/update-docker-manifest.yaml +++ b/.github/workflows/update-docker-manifest.yaml @@ -16,3 +16,8 @@ jobs: uses: ./.github/actions/combine-multi-arch-images with: package-name: autoware + + - name: Combine multi arch images for 'Open AD Kit' + uses: ./.github/actions/combine-multi-arch-images + with: + package-name: openadkit diff --git a/.yamllint.yaml b/.yamllint.yaml index 2c7bd088e26..0788c113194 100644 --- a/.yamllint.yaml +++ b/.yamllint.yaml @@ -10,6 +10,7 @@ rules: comments: level: error min-spaces-from-content: 1 # To be compatible with C++ and Python + comments-indentation: disable # Disable as it's sometimes fails to detect vscode auto-commenting https://github.com/adrienverge/yamllint/issues/384 document-start: level: error present: false # Don't need document start markers diff --git a/ansible/playbooks/openadkit.yaml b/ansible/playbooks/openadkit.yaml index f343d9cef55..46a8757229f 100644 --- a/ansible/playbooks/openadkit.yaml +++ b/ansible/playbooks/openadkit.yaml @@ -24,6 +24,8 @@ when: module == 'base' - role: autoware.dev_env.kisak_mesa when: module == 'base' + - role: autoware.dev_env.pacmod + when: module == 'base' - role: autoware.dev_env.build_tools when: module == 'all' and install_devel=='y' @@ -34,8 +36,6 @@ when: (module == 'perception-localization' or module == 'all') and prompt_install_nvidia=='y' - role: autoware.dev_env.tensorrt when: (module == 'perception-localization' or module == 'all') and prompt_install_nvidia=='y' - - role: autoware.dev_env.pacmod - when: module == 'planning-control' or module == 'perception-localization' or module == 'all' # Development environment - role: autoware.dev_env.dev_tools diff --git a/docker/Dockerfile b/docker/Dockerfile index b1374e5fad6..1f6cadcad86 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -72,11 +72,9 @@ ENV CXX="/usr/lib/ccache/g++" # cspell: ignore libcu libnv # Set up development environment RUN --mount=type=ssh \ - ./setup-dev-env.sh -y --module all ${SETUP_ARGS} --no-cuda-drivers openadkit \ + ./setup-dev-env.sh -y --module all ${SETUP_ARGS} --download-artifacts --no-cuda-drivers openadkit \ && pip uninstall -y ansible ansible-core \ - && apt-get autoremove -y && apt-get clean -y && rm -rf /var/lib/apt/lists/* "$HOME"/.cache \ - && find / -name 'libcu*.a' -delete \ - && find / -name 'libnv*.a' -delete + && apt-get autoremove -y && apt-get clean -y && rm -rf /var/lib/apt/lists/* "$HOME"/.cache # Install rosdep dependencies COPY --from=src-imported /rosdep-all-depend-packages.txt /tmp/rosdep-all-depend-packages.txt @@ -125,7 +123,7 @@ ARG SETUP_ARGS COPY --from=src-imported /rosdep-exec-depend-packages.txt /tmp/rosdep-exec-depend-packages.txt # hadolint ignore=SC2002 RUN --mount=type=ssh \ - ./setup-dev-env.sh -y --module all ${SETUP_ARGS} --no-cuda-drivers --runtime openadkit \ + ./setup-dev-env.sh -y --module all ${SETUP_ARGS} --download-artifacts --no-cuda-drivers --runtime openadkit \ && pip uninstall -y ansible ansible-core \ && apt-get update \ && cat /tmp/rosdep-exec-depend-packages.txt | xargs apt-get install -y --no-install-recommends \ diff --git a/docker/README.md b/docker/README.md index a569443bf01..067ebd970ed 100644 --- a/docker/README.md +++ b/docker/README.md @@ -1,5 +1,5 @@ -# Open AD Kit: containerized workloads for Autoware +## 🐳 Open AD Kit: containerized workloads for Autoware -[Open AD Kit](https://autoware.org/open-ad-kit/) offers containers for Autoware to simplify the development and deployment of Autoware and its dependencies. This directory contains scripts to build and run the containers. +This directory contains scripts to build and run the containers for Autoware both for development(devel image) and deployment(runtime image). Detailed instructions on how to use the containers can be found in the [Open AD Kit documentation](https://autowarefoundation.github.io/autoware-documentation/main/installation/autoware/docker-installation/). -Detailed instructions on how to use the containers can be found in the [Open AD Kit documentation](https://autowarefoundation.github.io/autoware-documentation/main/installation/autoware/docker-installation/). +> ℹ️ [Open AD Kit](https://autoware.org/open-ad-kit/) also offers a set of modular workloads designed to enable scalable deployment of Autoware. This initiative is part of the Autoware Foundation's efforts to transition Autoware into a software-defined and cloud-native solution . Currently, the project is in progress, with its first official release targeted for Q3/2024. We welcome contributions and feedback, please join our discussions on the [Autoware Foundation Discord](https://discord.com/channels/953808765935816715/953877118415151205). diff --git a/docker/build.sh b/docker/build.sh index 3d0a417c952..a9104f5920f 100755 --- a/docker/build.sh +++ b/docker/build.sh @@ -58,10 +58,9 @@ set_cuda_options() { # Set build options set_build_options() { + targets=() if [ "$option_devel_only" = "true" ]; then targets=("devel") - else - targets=() fi } @@ -97,6 +96,13 @@ load_env() { fi } +# Clone repositories +clone_repositories() { + cd "$WORKSPACE_ROOT" + mkdir src + vcs import src >/etc/sudoers - # Source ROS2 + # Source ROS 2 # hadolint ignore=SC1090 source "/opt/ros/$ROS_DISTRO/setup.bash" source /autoware/install/setup.bash diff --git a/docker/openadkit/build.sh b/docker/openadkit/build.sh new file mode 100755 index 00000000000..c0faf717396 --- /dev/null +++ b/docker/openadkit/build.sh @@ -0,0 +1,120 @@ +#!/usr/bin/env bash + +set -e + +# Function to print help message +print_help() { + echo "Usage: build.sh [OPTIONS]" + echo "Options:" + echo " --help Display this help message" + echo " -h Display this help message" + echo " --no-cuda Disable CUDA support" + echo " --platform Specify the platform (default: current platform)" + echo "" + echo "Note: The --platform option should be one of 'linux/amd64' or 'linux/arm64'." +} + +SCRIPT_DIR=$(readlink -f "$(dirname "$0")") +WORKSPACE_ROOT="$SCRIPT_DIR/../.." + +# Parse arguments +parse_arguments() { + while [ "$1" != "" ]; do + case "$1" in + --help | -h) + print_help + exit 1 + ;; + --no-cuda) + option_no_cuda=true + ;; + --platform) + option_platform="$2" + shift + ;; + *) + echo "Unknown option: $1" + print_help + exit 1 + ;; + esac + shift + done +} + +# Set platform +set_platform() { + if [ -n "$option_platform" ]; then + platform="$option_platform" + else + platform="linux/amd64" + if [ "$(uname -m)" = "aarch64" ]; then + platform="linux/arm64" + fi + fi +} + +# Set arch lib dir +set_arch_lib_dir() { + if [ "$platform" = "linux/arm64" ]; then + lib_dir="aarch64" + elif [ "$platform" = "linux/amd64" ]; then + lib_dir="x86_64" + else + echo "Unsupported platform: $platform" + exit 1 + fi +} + +# Load env +load_env() { + source "$WORKSPACE_ROOT/amd64.env" + if [ "$platform" = "linux/arm64" ]; then + source "$WORKSPACE_ROOT/arm64.env" + fi +} + +# Set CUDA options +set_cuda_options() { + if [ "$option_no_cuda" = "true" ]; then + setup_args="--no-nvidia" + image_name_suffix="" + else + image_name_suffix="-cuda" + fi +} + +# Build images +build_images() { + # https://github.com/docker/buildx/issues/484 + export BUILDKIT_STEP_LOG_MAX_SIZE=10000000 + + echo "Building images for platform: $platform" + echo "ROS distro: $rosdistro" + echo "Base image: $base_image" + echo "Setup args: $setup_args" + echo "Lib dir: $lib_dir" + echo "Image name suffix: $image_name_suffix" + + set -x + docker buildx bake --load --progress=plain -f "$SCRIPT_DIR/docker-bake.hcl" \ + --set "*.context=$WORKSPACE_ROOT" \ + --set "*.ssh=default" \ + --set "*.platform=$platform" \ + --set "*.args.ROS_DISTRO=$rosdistro" \ + --set "*.args.BASE_IMAGE=$base_image" \ + --set "*.args.SETUP_ARGS=$setup_args" \ + --set "*.args.LIB_DIR=$lib_dir" \ + --set "planning-control.tags=ghcr.io/autowarefoundation/openadkit:latest-planning-control" \ + --set "visualizer.tags=ghcr.io/autowarefoundation/openadkit:latest-visualizer" \ + --set "simulator.tags=ghcr.io/autowarefoundation/openadkit:latest-simulator" + set +x +} + +# Main script execution +parse_arguments "$@" +set_cuda_options +set_platform +set_arch_lib_dir +load_env +build_images diff --git a/docker/openadkit/docker-bake.hcl b/docker/openadkit/docker-bake.hcl new file mode 100644 index 00000000000..eb589d9872d --- /dev/null +++ b/docker/openadkit/docker-bake.hcl @@ -0,0 +1,27 @@ +group "default" { + targets = ["planning-control", "simulator", "visualizer"] +} + +// For docker/metadata-action +target "docker-metadata-action-planning-control" {} +target "docker-metadata-action-visualizer" {} +target "docker-metadata-action-simulator" {} + +// Autoware openadkit modules +target "planning-control" { + inherits = ["docker-metadata-action-planning-control"] + dockerfile = "docker/openadkit/modules/planning-control/Dockerfile" + target = "planning-control" +} + +target "visualizer" { + inherits = ["docker-metadata-action-visualizer"] + dockerfile = "docker/openadkit/modules/visualizer/Dockerfile" + target = "visualizer" +} + +target "simulator" { + inherits = ["docker-metadata-action-simulator"] + dockerfile = "docker/openadkit/modules/simulator/Dockerfile" + target = "simulator" +} diff --git a/docker/openadkit/etc/ros_entrypoint.sh b/docker/openadkit/etc/ros_entrypoint.sh new file mode 100644 index 00000000000..40dbbee02e9 --- /dev/null +++ b/docker/openadkit/etc/ros_entrypoint.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash +# shellcheck disable=SC1090,SC1091 + +# Get the user ID and group ID of the local user +USER_ID=${LOCAL_UID} +USER_NAME=${LOCAL_USER} +GROUP_ID=${LOCAL_GID} +GROUP_NAME=${LOCAL_GROUP} + +# Check if any of the variables are empty +if [[ -z $USER_ID || -z $USER_NAME || -z $GROUP_ID || -z $GROUP_NAME ]]; then + source "/opt/ros/$ROS_DISTRO/setup.bash" + source /autoware/install/setup.bash + exec "$@" +else + echo "Starting with user: $USER_NAME >> UID $USER_ID, GID: $GROUP_ID" + + # Create group and user with GID/UID + groupadd -g "$GROUP_ID" "$GROUP_NAME" + useradd -u "$USER_ID" -g "$GROUP_ID" -s /bin/bash -m -d /home/"$USER_NAME" "$USER_NAME" + + # Add sudo privileges to the user + echo "$USER_NAME ALL=(ALL) NOPASSWD:ALL" >>/etc/sudoers + + # Source ROS 2 + # hadolint ignore=SC1090 + source "/opt/ros/$ROS_DISTRO/setup.bash" + source /autoware/install/setup.bash + + # Execute the command as the user + exec /usr/sbin/gosu "$USER_NAME" "$@" +fi diff --git a/docker/openadkit/modules/planning-control/Dockerfile b/docker/openadkit/modules/planning-control/Dockerfile new file mode 100644 index 00000000000..b3d3f3dcd1f --- /dev/null +++ b/docker/openadkit/modules/planning-control/Dockerfile @@ -0,0 +1,32 @@ +ARG ARCH +FROM ghcr.io/autowarefoundation/autoware:latest-base-${ARCH} as planning-control +SHELL ["/bin/bash", "-o", "pipefail", "-c"] +ARG ROS_DISTRO +ARG LIB_DIR + +# Copy install folder from prebuilt +COPY --from=ghcr.io/autowarefoundation/autoware:latest-prebuilt /autoware/install/ /autoware/install/ +COPY autoware.repos /autoware/ + +# Dependencies +RUN --mount=type=ssh \ + mkdir src \ + && vcs import src < autoware.repos \ + && apt-get update \ + && rosdep update \ + && DEBIAN_FRONTEND=noninteractive rosdep install -y -t exec --ignore-src --from-paths src --rosdistro "$ROS_DISTRO" \ + && apt-get autoremove -y && apt-get clean -y && rm -rf /var/lib/apt/lists/* "$HOME"/.cache \ + && find /usr/lib/$LIB_DIR-linux-gnu -name "*.a" -type f -delete \ + && find / -name "*.o" -type f -delete \ + && find / -name "*.h" -type f -delete \ + && find / -name "*.hpp" -type f -delete \ + && rm -rf /autoware/src /autoware/ansible /autoware/autoware.repos \ + /root/.local/pipx /opt/ros/"$ROS_DISTRO"/include /etc/apt/sources.list.d/cuda*.list \ + /etc/apt/sources.list.d/docker.list /etc/apt/sources.list.d/nvidia-docker.list \ + /usr/include /usr/share/doc /usr/lib/gcc /usr/lib/jvm /usr/lib/llvm* + +# Create entrypoint +COPY docker/openadkit/etc/ros_entrypoint.sh /ros_entrypoint.sh +RUN chmod +x /ros_entrypoint.sh +ENTRYPOINT ["/ros_entrypoint.sh"] +CMD ["bash"] diff --git a/docker/openadkit/modules/simulator/Dockerfile b/docker/openadkit/modules/simulator/Dockerfile new file mode 100644 index 00000000000..494390e52c4 --- /dev/null +++ b/docker/openadkit/modules/simulator/Dockerfile @@ -0,0 +1,42 @@ +ARG ARCH +FROM ghcr.io/autowarefoundation/autoware:latest-base-${ARCH} as simulator +SHELL ["/bin/bash", "-o", "pipefail", "-c"] +ARG PLATFORM +ARG LIB_DIR +ARG ROS_DISTRO + +COPY simulator.repos /autoware/ +COPY autoware.repos /autoware/ + +RUN --mount=type=ssh \ + mkdir src \ + && vcs import src < simulator.repos \ + && vcs import src/simulator/scenario_simulator/external < src/simulator/scenario_simulator/dependency_humble.repos \ + && apt-get update \ + && rosdep update \ + && source /opt/ros/"$ROS_DISTRO"/setup.bash \ + && DEBIAN_FRONTEND=noninteractive rosdep install -y -t exec --rosdistro "$ROS_DISTRO" --from-paths src --ignore-src \ + && colcon build --cmake-args -DCMAKE_BUILD_TYPE=Release \ + && find /autoware/install -type d -exec chmod -R 777 {} \; \ + && rm -rf src/* \ + && vcs import src < autoware.repos \ + && apt-get update \ + && rosdep update \ + && DEBIAN_FRONTEND=noninteractive rosdep install -y --rosdistro "$ROS_DISTRO" --from-paths src --ignore-src \ + && apt-get autoremove -y && apt-get clean -y && rm -rf /var/lib/apt/lists/* "$HOME"/.cache \ + && find /usr/lib/$LIB_DIR-linux-gnu -name "*.a" -type f -delete \ + && find / -name "*.o" -type f -delete \ + && find / -name "*.h" -type f -delete \ + && find / -name "*.hpp" -type f -delete \ + && rm -rf /autoware/src /autoware/ansible /autoware/simulator.repos \ + /root/.local/pipx /opt/ros/"$ROS_DISTRO"/include /etc/apt/sources.list.d/cuda*.list \ + /etc/apt/sources.list.d/docker.list /etc/apt/sources.list.d/nvidia-docker.list \ + /usr/include /usr/share/doc /usr/lib/gcc /usr/lib/jvm /usr/lib/llvm* + +COPY --from=ghcr.io/autowarefoundation/autoware:latest-prebuilt /autoware/install /autoware/install + +# Create entrypoint +COPY docker/openadkit/etc/ros_entrypoint.sh /ros_entrypoint.sh +RUN chmod +x /ros_entrypoint.sh +ENTRYPOINT ["/ros_entrypoint.sh"] +CMD ["bash"] diff --git a/docker/openadkit/modules/visualizer/Dockerfile b/docker/openadkit/modules/visualizer/Dockerfile new file mode 100644 index 00000000000..5223f2cac99 --- /dev/null +++ b/docker/openadkit/modules/visualizer/Dockerfile @@ -0,0 +1,32 @@ +ARG ARCH +FROM ghcr.io/autowarefoundation/autoware:latest-base-${ARCH} as visualizer +SHELL ["/bin/bash", "-o", "pipefail", "-c"] +ARG ROS_DISTRO +ARG LIB_DIR + +# Copy install folder from prebuilt +COPY --from=ghcr.io/autowarefoundation/autoware:latest-prebuilt /autoware/install/ /autoware/install/ +COPY autoware.repos /autoware/ + +# Dependencies +RUN --mount=type=ssh \ + mkdir src \ + && vcs import src < autoware.repos \ + && apt-get update \ + && rosdep update \ + && DEBIAN_FRONTEND=noninteractive rosdep install -y -t exec --ignore-src --from-paths src --rosdistro "$ROS_DISTRO" \ + && apt-get autoremove -y && apt-get clean -y && rm -rf /var/lib/apt/lists/* "$HOME"/.cache \ + && find /usr/lib/$LIB_DIR-linux-gnu -name "*.a" -type f -delete \ + && find / -name "*.o" -type f -delete \ + && find / -name "*.h" -type f -delete \ + && find / -name "*.hpp" -type f -delete \ + && rm -rf /autoware/src /autoware/ansible /autoware/autoware.repos \ + /root/.local/pipx /opt/ros/"$ROS_DISTRO"/include /etc/apt/sources.list.d/cuda*.list \ + /etc/apt/sources.list.d/docker.list /etc/apt/sources.list.d/nvidia-docker.list \ + /usr/include /usr/share/doc /usr/lib/gcc /usr/lib/jvm /usr/lib/llvm* + +# Create entrypoint +COPY docker/openadkit/etc/ros_entrypoint.sh /ros_entrypoint.sh +RUN chmod +x /ros_entrypoint.sh +ENTRYPOINT ["/ros_entrypoint.sh"] +CMD ["bash"] diff --git a/docker/openadkit/test/run-test-scenario.sh b/docker/openadkit/test/run-test-scenario.sh new file mode 100755 index 00000000000..5fa04497401 --- /dev/null +++ b/docker/openadkit/test/run-test-scenario.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +set -e + +# download test artifacts from google drive +if [ ! -d ~/autoware_artifacts/test-artifacts ]; then + echo "Downloading test artifacts from google drive..." + gdown -O ~/autoware_artifacts/ 'https://drive.google.com/uc?export=download&id=1gTCWcye4JxqR7rSxl2b-iiLqgya6ShBR' + unzip -d ~/autoware_artifacts ~/autoware_artifacts/test-artifacts.zip + rm ~/autoware_artifacts/test-artifacts.zip +else + echo "Test artifacts are already downloaded." +fi + +# enable xhost +xhost + + +# start containers +echo "Starting containers..." +docker compose -f test-scenario.docker-compose.yaml up diff --git a/docker/openadkit/test/test-scenario.docker-compose.yaml b/docker/openadkit/test/test-scenario.docker-compose.yaml new file mode 100644 index 00000000000..f3aca988c59 --- /dev/null +++ b/docker/openadkit/test/test-scenario.docker-compose.yaml @@ -0,0 +1,36 @@ +version: "2.17" + +services: + planning-control: + image: ghcr.io/autowarefoundation/openadkit:latest-planning-control + volumes: + - /dev/shm:/dev/shm + - /home/${USER}/autoware_artifacts/test-artifacts:/autoware/test-scenario/ + network_mode: host + environment: + - ROS_LOCALHOST_ONLY=1 + command: ros2 launch autoware_launch planning_simulator.launch.xml map_path:=/autoware/test-scenario/map/ vehicle_model:=sample_vehicle sensor_model:=sample_sensor_kit scenario_simulation:=true use_foa:=false perception/enable_traffic_light:=false rviz:=false + + simulator: + image: ghcr.io/autowarefoundation/openadkit:latest-simulator + volumes: + - /dev/shm:/dev/shm + - /home/${USER}/autoware_artifacts/test-artifacts:/autoware/test-scenario/ + network_mode: host + environment: + - ROS_LOCALHOST_ONLY=1 + command: ros2 launch scenario_test_runner scenario_test_runner.launch.py architecture_type:=awf/universe record:=false scenario:=/autoware/test-scenario/yield_maneuver_demo.yaml sensor_model:=sample_sensor_kit vehicle_model:=sample_vehicle map_path:=/autoware/test-scenario/map launch_autoware:=False initialize_duration:=60 global_frame_rate:=12 + + visualizer: + image: ghcr.io/autowarefoundation/openadkit:latest-visualizer + volumes: + - /dev/shm:/dev/shm + - /tmp/.X11-unix:/tmp/.X11-unix + - /home/${USER}/autoware_artifacts/test-artifacts:/autoware/test-scenario/ + network_mode: host + environment: + - DISPLAY=$DISPLAY + - ROS_LOCALHOST_ONLY=1 + depends_on: + - simulator + command: /autoware/test-scenario/rviz/launch_rviz.sh diff --git a/docker/run.sh b/docker/run.sh index e26bd5c4a37..17be654d8cc 100755 --- a/docker/run.sh +++ b/docker/run.sh @@ -6,7 +6,7 @@ set -e # Define terminal colors RED='\033[0;31m' GREEN='\033[0;32m' -# BLUE='\033[0;34m' +BLUE='\033[0;34m' NC='\033[0m' # No Color SCRIPT_DIR=$(readlink -f "$(dirname "$0")") @@ -20,28 +20,26 @@ fi option_no_nvidia=false option_devel=false option_headless=false -DATA_PATH="${HOME}/autoware_data" MAP_PATH="" WORKSPACE_PATH="" USER_ID="" WORKSPACE="" -DEFAULT_LAUNCH_CMD="ros2 launch autoware_launch autoware.launch.xml data_path:=/autoware_data map_path:=/autoware_map vehicle_model:=sample_vehicle sensor_model:=sample_sensor_kit" +DEFAULT_LAUNCH_CMD="ros2 launch autoware_launch autoware.launch.xml map_path:=/autoware_map vehicle_model:=sample_vehicle sensor_model:=sample_sensor_kit" # Function to print help message print_help() { echo -e "\n------------------------------------------------------------" - echo -e "${RED}Note:${NC} The --map-path option is mandatory if not custom launch command given. Please provide exact path to the map files." + echo -e "${RED}Note:${NC} The --map-path option is mandatory for the runtime. For development environment with shell access, use --devel option." echo -e " Default launch command: ${GREEN}${DEFAULT_LAUNCH_CMD}${NC}" echo -e "------------------------------------------------------------" echo -e "${RED}Usage:${NC} run.sh [OPTIONS] [LAUNCH_CMD](optional)" echo -e "Options:" echo -e " ${GREEN}--help/-h${NC} Display this help message" - echo -e " ${GREEN}--data-path${NC} Specify to mount data files into /autoware_data" - echo -e " ${GREEN}--map-path${NC} Specify to mount map files into /autoware_map (mandatory if no custom launch command is provided)" + echo -e " ${GREEN}--map-path${NC} Specify to mount map files into /autoware_map (mandatory for runtime)" + echo -e " ${GREEN}--devel${NC} Launch the latest Autoware development environment with shell access" + echo -e " ${GREEN}--workspace${NC} (--devel only)Specify the directory to mount into /workspace, by default it uses current directory (pwd)" echo -e " ${GREEN}--no-nvidia${NC} Disable NVIDIA GPU support" - echo -e " ${GREEN}--devel${NC} Use the latest development version of Autoware" echo -e " ${GREEN}--headless${NC} Run Autoware in headless mode (default: false)" - echo -e " ${GREEN}--workspace${NC} Specify to mount the workspace into /workspace" echo "" } @@ -66,10 +64,6 @@ parse_arguments() { WORKSPACE_PATH="$2" shift ;; - --data-path) - DATA_PATH="$2" - shift - ;; --map-path) MAP_PATH="$2" shift @@ -93,40 +87,48 @@ parse_arguments() { done } -# Set image and workspace variables +# Set the docker image and workspace variables set_variables() { - # Check if map path is provided for default launch command - if [ "$MAP_PATH" == "" ] && [ "$LAUNCH_CMD" == "" ]; then - print_help - exit 1 - fi - - # Mount data path - DATA="-v ${DATA_PATH}:/autoware_data:ro" + if [ "$option_devel" = "true" ]; then + # Set image based on option + IMAGE="ghcr.io/autowarefoundation/autoware:latest-devel" - # Mount map path if provided - MAP="-v ${MAP_PATH}:/autoware_map:ro" + # Set workspace path, if not provided use the current directory + if [ "$WORKSPACE_PATH" = "" ]; then + WORKSPACE_PATH=$(pwd) + fi + WORKSPACE="-v ${WORKSPACE_PATH}:/workspace" - # Set workspace path if provided and login with local user - if [ "$WORKSPACE_PATH" != "" ]; then + # Set user ID and group ID to match the local user USER_ID="-e LOCAL_UID=$(id -u) -e LOCAL_GID=$(id -g) -e LOCAL_USER=$(id -un) -e LOCAL_GROUP=$(id -gn)" - WORKSPACE="-v ${WORKSPACE_PATH}:/workspace" - fi - # Set default launch command if not provided - if [ "$LAUNCH_CMD" == "" ]; then - if [ "$WORKSPACE_PATH" != "" ]; then - LAUNCH_CMD="/bin/bash" - else - LAUNCH_CMD=${DEFAULT_LAUNCH_CMD} + # Set map path + if [ "$MAP_PATH" != "" ]; then + MAP="-v ${MAP_PATH}:/autoware_map:ro" fi - fi - # Set image based on option - if [ "$option_devel" == "true" ]; then - IMAGE="ghcr.io/autowarefoundation/autoware:latest-devel" + # Set launch command + if [ "$LAUNCH_CMD" = "" ]; then + LAUNCH_CMD="/bin/bash" + fi else + # Set image based on option IMAGE="ghcr.io/autowarefoundation/autoware:latest-runtime" + + # Set map path + if [ "$MAP_PATH" = "" ]; then + echo -e "\n------------------------------------------------------------" + echo -e "${RED}Note:${NC} The --map-path option is mandatory for the runtime. For development environment with shell access, use --devel option." + echo -e "------------------------------------------------------------" + exit 1 + else + MAP="-v ${MAP_PATH}:/autoware_map:ro" + fi + + # Set default launch command if not provided + if [ "$LAUNCH_CMD" = "" ]; then + LAUNCH_CMD=${DEFAULT_LAUNCH_CMD} + fi fi } @@ -157,11 +159,20 @@ main() { set_gpu_flag set_x_display - echo -e "${GREEN}\n-----------------------LAUNCHING CONTAINER-----------------------" + if [ "$option_devel" = "true" ]; then + echo -e "${GREEN}-----------------------------------------------------------------${NC}" + echo -e "${BLUE}Launching Autoware development environment${NC}" + else + echo -e "${GREEN}-----------------------------------------------------------------${NC}" + echo -e "${GREEN}Launching Autoware${NC}" + fi echo -e "${GREEN}IMAGE:${NC} ${IMAGE}" - echo -e "${GREEN}DATA PATH(mounted):${NC} ${DATA_PATH}:/autoware_data" - echo -e "${GREEN}MAP PATH(mounted):${NC} ${MAP_PATH}:/autoware_map" - echo -e "${GREEN}WORKSPACE(mounted):${NC} ${WORKSPACE_PATH}:/workspace" + if [ "$option_devel" = "true" ]; then + echo -e "${GREEN}WORKSPACE PATH(mounted):${NC} ${WORKSPACE_PATH}:/workspace" + fi + if [ "$MAP_PATH" != "" ]; then + echo -e "${GREEN}MAP PATH(mounted):${NC} ${MAP_PATH}:/autoware_map" + fi echo -e "${GREEN}LAUNCH CMD:${NC} ${LAUNCH_CMD}" echo -e "${GREEN}-----------------------------------------------------------------${NC}" @@ -169,7 +180,7 @@ main() { set -x docker run -it --rm --net=host ${GPU_FLAG} ${USER_ID} ${MOUNT_X} \ -e XAUTHORITY=${XAUTHORITY} -e XDG_RUNTIME_DIR=$XDG_RUNTIME_DIR -e NVIDIA_DRIVER_CAPABILITIES=all -v /etc/localtime:/etc/localtime:ro \ - ${WORKSPACE} ${DATA} ${MAP} ${IMAGE} \ + ${WORKSPACE} ${MAP} ${IMAGE} \ ${LAUNCH_CMD} } diff --git a/setup-dev-env.sh b/setup-dev-env.sh index 48afecc4444..0c5cf960165 100755 --- a/setup-dev-env.sh +++ b/setup-dev-env.sh @@ -133,7 +133,7 @@ if [ "$option_yes" = "true" ] || [ "$option_download_artifacts" = "true" ]; then fi # Check downloading artifacts -if [ "$target_playbook" = "autoware.dev_env.docker" ] || [ "$target_playbook" = "autoware.dev_env.openadk" ]; then +if [ "$target_playbook" = "autoware.dev_env.openadkit" ]; then if [ "$option_download_artifacts" = "true" ]; then echo -e "\e[36mArtifacts will be downloaded to $option_data_dir\e[m" ansible_args+=("--extra-vars" "prompt_download_artifacts=y")