From 9295ca12e54d287c3ec9a54448a2e399103688e1 Mon Sep 17 00:00:00 2001 From: Alex Chapin Date: Tue, 4 Aug 2026 17:49:46 -0400 Subject: [PATCH 1/8] Enhance multi-architecture support in Docker setup and CI workflows - Update GitHub Actions to support both amd64 and arm64 architectures. - Modify Dockerfile to use geckodriver version 0.35.0 for arm64 compatibility. - Refactor deployment scripts to handle arch-suffixed image tagging and merging. - Introduce new scripts for image tagging and merging multi-arch manifests. --- .github/workflows/openstudio-server-tests.yml | 55 ++++++++++++++- Dockerfile | 16 +++-- .../scripts/deploy_docker_github_actions.sh | 67 ++++++++----------- docker/deployment/scripts/get_image_tag.sh | 27 ++++++++ .../scripts/merge_manifests_github_actions.sh | 35 ++++++++++ 5 files changed, 153 insertions(+), 47 deletions(-) create mode 100755 docker/deployment/scripts/get_image_tag.sh create mode 100755 docker/deployment/scripts/merge_manifests_github_actions.sh diff --git a/.github/workflows/openstudio-server-tests.yml b/.github/workflows/openstudio-server-tests.yml index 3fa925e40..938273057 100644 --- a/.github/workflows/openstudio-server-tests.yml +++ b/.github/workflows/openstudio-server-tests.yml @@ -101,7 +101,20 @@ jobs: name: openstudio-server-gems-darwin path: build/NREL/export/*.tar.gz docker: - runs-on: ubuntu-24.04 + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + include: + - arch: amd64 + os: ubuntu-24.04 + platform: linux/amd64 + - arch: arm64 + os: ubuntu-24.04-arm + platform: linux/arm64 + env: + DEPLOY_ARCH: ${{ matrix.arch }} + DOCKER_PLATFORM: ${{ matrix.platform }} steps: - name: Delete huge unnecessary tools folder run: rm -rf /opt/hostedtoolcache @@ -121,7 +134,14 @@ jobs: docker images --all docker --version docker-compose --version - docker-compose -f docker-compose.test.yml pull + if [ "${DEPLOY_ARCH}" = "arm64" ]; then + # The first arm64 run may predate an arm64 entry in the :latest + # manifests, so tolerate pull failure and build from scratch. + # BuildKit also skips missing cache_from images without failing. + docker-compose -f docker-compose.test.yml pull || echo "arm64 pull skipped/failed; building from scratch" + else + docker-compose -f docker-compose.test.yml pull + fi # Rebuild the rserve image only when its inputs changed. PR runs otherwise reuse # the pulled nrel/openstudio-rserve:latest (kept fresh by docker-upload on # develop/master pushes): rebuilding R packages on every run cost ~10 min and @@ -136,7 +156,7 @@ jobs: echo "docker/R is unchanged by this PR: reusing pulled nrel/openstudio-rserve:latest instead of rebuilding it" BUILD_SERVICES="web" fi - docker-compose -f docker-compose.test.yml build --build-arg OPENSTUDIO_VERSION=$OPENSTUDIO_TAG $BUILD_SERVICES + docker-compose -f docker-compose.test.yml build --build-arg OPENSTUDIO_VERSION=$OPENSTUDIO_TAG --build-arg DOCKER_PLATFORM=$DOCKER_PLATFORM $BUILD_SERVICES docker-compose -f docker-compose.test.yml up -d #set SKIP_URBANOPT_ALGO=true to skip UrbanOpt algo tests docker-compose exec -e SKIP_URBANOPT_ALGO=true -T web /usr/local/bin/run-server-tests @@ -167,3 +187,32 @@ jobs: # https://docs.github.com/en/actions/reference/encrypted-secrets DOCKER_PASS: ${{ secrets.DOCKER_PASS }} DOCKER_USER: ${{ secrets.DOCKER_USER }} + docker-manifest: + # Merge the per-arch images pushed by the docker job into canonical + # multi-arch manifests. Runs after BOTH matrix legs (amd64 + arm64) push. + needs: docker + runs-on: ubuntu-24.04 + if: | + github.ref == 'refs/heads/master' || + github.ref == 'refs/heads/develop' || + github.ref == 'refs/heads/3.10.0' || + github.ref == 'refs/heads/179' || + github.ref == 'refs/heads/fix/zip-read-only-extract' + steps: + - name: Check out repository + uses: actions/checkout@v4 + - name: setup + shell: bash + run: ./ci/github-actions/setup.sh + env: + BUILD_TYPE: docker + - name: merge multi-arch manifests + shell: bash + run: ./docker/deployment/scripts/merge_manifests_github_actions.sh + env: + CI: true + BUILD_TYPE: docker + # On forked Pull Requests secrets will not be sent to the runner. See more info here: + # https://docs.github.com/en/actions/reference/encrypted-secrets + DOCKER_PASS: ${{ secrets.DOCKER_PASS }} + DOCKER_USER: ${{ secrets.DOCKER_USER }} diff --git a/Dockerfile b/Dockerfile index c4fe012d2..7241353fa 100644 --- a/Dockerfile +++ b/Dockerfile @@ -159,8 +159,13 @@ EXPOSE 8080 9090 # Multistage build includes test library. To build without testing run # docker build --target base -t some-tag . FROM base -ENV GECKODRIVER_VERSION=v0.21.0 +# geckodriver >= v0.30.0 ships linux-aarch64 builds (v0.21.0 was linux64-only). +# The test suite no longer drives Firefox through geckodriver (see +# run-server-tests.sh), so this is mainly for manual/legacy test runs. +ENV GECKODRIVER_VERSION=v0.35.0 # Install vfb and firefox requirement if docker-test env +# Automatically populated by BuildKit (amd64 / arm64). +ARG TARGETARCH RUN echo "Running in testing environment - Installing Firefox and Gecko Driver" && \ apt-get update && \ apt-get install -y xvfb \ @@ -172,10 +177,11 @@ RUN echo "Running in testing environment - Installing Firefox and Gecko Driver" firefox && \ rm -rf /var/lib/apt/lists/* && \ cd /usr/local/bin && \ - wget http://github.com/mozilla/geckodriver/releases/download/${GECKODRIVER_VERSION}/geckodriver-${GECKODRIVER_VERSION}-linux64.tar.gz && \ - tar -xvzf geckodriver-${GECKODRIVER_VERSION}-linux64.tar.gz && \ - rm geckodriver-${GECKODRIVER_VERSION}-linux64.tar.gz && \ - chmod +x geckodriver; + if [ "${TARGETARCH}" = "arm64" ]; then GECKODRIVER_ARCH="linux-aarch64"; else GECKODRIVER_ARCH="linux64"; fi && \ + wget http://github.com/mozilla/geckodriver/releases/download/${GECKODRIVER_VERSION}/geckodriver-${GECKODRIVER_VERSION}-${GECKODRIVER_ARCH}.tar.gz && \ + tar -xvzf geckodriver-${GECKODRIVER_VERSION}-${GECKODRIVER_ARCH}.tar.gz && \ + rm geckodriver-${GECKODRIVER_VERSION}-${GECKODRIVER_ARCH}.tar.gz && \ + chmod +x geckodriver COPY /docker/server/run-server-tests.sh /usr/local/bin/run-server-tests RUN chmod +x /usr/local/bin/run-server-tests diff --git a/docker/deployment/scripts/deploy_docker_github_actions.sh b/docker/deployment/scripts/deploy_docker_github_actions.sh index fbb6333ec..f303773a6 100755 --- a/docker/deployment/scripts/deploy_docker_github_actions.sh +++ b/docker/deployment/scripts/deploy_docker_github_actions.sh @@ -1,47 +1,36 @@ #!/usr/bin/env bash +# Tags the locally-built images with an arch suffix and pushes them. +# The canonical (multi-arch) tags are created later by +# merge_manifests_github_actions.sh. +# +# Required env: DOCKER_USER, DOCKER_PASS +# Optional env: DEPLOY_ARCH (amd64|arm64, default amd64) +set -euo pipefail -# Default set IMAGETAG to skip. -IMAGETAG="skip" +source "$(dirname "$0")/get_image_tag.sh" +DEPLOY_ARCH=${DEPLOY_ARCH:-amd64} -if [ "${GITHUB_REF}" == "refs/heads/develop" ]; then - IMAGETAG="develop" -elif [ "${GITHUB_REF}" == "refs/heads/2.9.X-LTS" ]; then - IMAGETAG="2.9.X-LTS" -elif [ "${GITHUB_REF}" == "refs/heads/master" ]; then - # Retrieve the version number from rails - IMAGETAG="$(ruby -e "load 'server/app/lib/openstudio_server/version.rb'; print OpenstudioServer::Version+OpenstudioServer::VERSION_EXT")" -# Uncomment and set branch name for custom builds. -# Currently setting this to setup_github_actions to test upload. -elif [ "${GITHUB_REF}" == "refs/heads/setup_github_actions" ]; then - IMAGETAG=experimental -elif [ "${GITHUB_REF}" == "refs/heads/3.10.0" ]; then - IMAGETAG="3.10.0-rc2" -elif [ "${GITHUB_REF}" == "refs/heads/179" ]; then - IMAGETAG="3.10.0-179" -# issue-857 zip-corruption fix candidate for cluster testing; remove mapping once merged into 179 -elif [ "${GITHUB_REF}" == "refs/heads/fix/zip-read-only-extract" ]; then - IMAGETAG="179-flock" +if [ "${IMAGETAG}" == "skip" ]; then + echo "Not on a deployable branch [master/develop/179/...] or this is a pull request" + exit 0 fi -if [ "${IMAGETAG}" != "skip" ]; then - echo "$DOCKER_PASS" | docker login -u "$DOCKER_USER" --password-stdin +echo "$DOCKER_PASS" | docker login -u "$DOCKER_USER" --password-stdin - echo "Tagging image as $IMAGETAG" - docker tag nrel/openstudio-server nrel/openstudio-server:$IMAGETAG; (( exit_status = exit_status || $? )) - docker tag nrel/openstudio-rserve nrel/openstudio-rserve:$IMAGETAG; (( exit_status = exit_status || $? )) - docker push nrel/openstudio-server:$IMAGETAG; (( exit_status = exit_status || $? )) - docker push nrel/openstudio-rserve:$IMAGETAG; (( exit_status = exit_status || $? )) +# Push arch-suffixed images. The canonical tags are assembled by the manifest +# job so that parallel amd64/arm64 pushes never clobber each other. +for IMAGE in nrel/openstudio-server nrel/openstudio-rserve; do + echo "Tagging image as ${IMAGE}:${IMAGETAG}-${DEPLOY_ARCH}" + docker tag "${IMAGE}" "${IMAGE}:${IMAGETAG}-${DEPLOY_ARCH}" + docker push "${IMAGE}:${IMAGETAG}-${DEPLOY_ARCH}" +done - if [ "${GITHUB_REF}" == "refs/heads/master" ]; then - # Deploy master as the latest. - docker tag nrel/openstudio-server nrel/openstudio-server:latest; (( exit_status = exit_status || $? )) - docker tag nrel/openstudio-rserve nrel/openstudio-rserve:latest; (( exit_status = exit_status || $? )) - - docker push nrel/openstudio-server:latest; (( exit_status = exit_status || $? )) - docker push nrel/openstudio-rserve:latest; (( exit_status = exit_status || $? )) - fi - - exit $exit_status -else - echo "Not on a deployable branch [master/nrcan-master/develop] or this is a pull request" +if [ "${GITHUB_REF}" == "refs/heads/master" ]; then + # Deploy master as the latest. + for IMAGE in nrel/openstudio-server nrel/openstudio-rserve; do + docker tag "${IMAGE}" "${IMAGE}:latest-${DEPLOY_ARCH}" + docker push "${IMAGE}:latest-${DEPLOY_ARCH}" + done fi + +echo "Done pushing ${DEPLOY_ARCH} artifacts for ${IMAGETAG}" diff --git a/docker/deployment/scripts/get_image_tag.sh b/docker/deployment/scripts/get_image_tag.sh new file mode 100755 index 000000000..c84fb93ef --- /dev/null +++ b/docker/deployment/scripts/get_image_tag.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +# Determines the image tag based on the branch. Sourced by +# deploy_docker_github_actions.sh and merge_manifests_github_actions.sh. +# Sets IMAGETAG (or "skip" when nothing should be deployed/merged). +set -euo pipefail + +IMAGETAG="skip" + +if [ "${GITHUB_REF}" == "refs/heads/develop" ]; then + IMAGETAG="develop" +elif [ "${GITHUB_REF}" == "refs/heads/2.9.X-LTS" ]; then + IMAGETAG="2.9.X-LTS" +elif [ "${GITHUB_REF}" == "refs/heads/master" ]; then + # Retrieve the version number from rails + IMAGETAG="$(ruby -e "load 'server/app/lib/openstudio_server/version.rb'; print OpenstudioServer::Version+OpenstudioServer::VERSION_EXT")" +# Uncomment and set branch name for custom builds. +# Currently setting this to setup_github_actions to test upload. +elif [ "${GITHUB_REF}" == "refs/heads/setup_github_actions" ]; then + IMAGETAG=experimental +elif [ "${GITHUB_REF}" == "refs/heads/3.10.0" ]; then + IMAGETAG="3.10.0-rc2" +elif [ "${GITHUB_REF}" == "refs/heads/179" ]; then + IMAGETAG="3.10.0-179" +# issue-857 zip-corruption fix candidate for cluster testing; remove mapping once merged into 179 +elif [ "${GITHUB_REF}" == "refs/heads/fix/zip-read-only-extract" ]; then + IMAGETAG="179-flock" +fi diff --git a/docker/deployment/scripts/merge_manifests_github_actions.sh b/docker/deployment/scripts/merge_manifests_github_actions.sh new file mode 100755 index 000000000..415a2be17 --- /dev/null +++ b/docker/deployment/scripts/merge_manifests_github_actions.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash +# Merges the arch-suffixed images pushed by deploy_docker_github_actions.sh +# into canonical multi-arch manifests (e.g. +# nrel/openstudio-server:3.10.0-179-amd64 + -arm64 -> :3.10.0-179). +# Requires docker buildx (bundled with Docker CLI 19.03+). +# +# Required env: DOCKER_USER, DOCKER_PASS +set -euo pipefail + +source "$(dirname "$0")/get_image_tag.sh" + +if [ "${IMAGETAG}" == "skip" ]; then + echo "Nothing to merge — not on a deployable branch" + exit 0 +fi + +echo "$DOCKER_PASS" | docker login -u "$DOCKER_USER" --password-stdin + +merge_image() { + local image=$1 canonical=$2 + echo "Creating multi-arch manifest ${image}:${canonical}" + docker buildx imagetools create \ + -t "${image}:${canonical}" \ + "${image}:${canonical}-amd64" \ + "${image}:${canonical}-arm64" +} + +for IMAGE in nrel/openstudio-server nrel/openstudio-rserve; do + merge_image "${IMAGE}" "${IMAGETAG}" + if [ "${GITHUB_REF}" == "refs/heads/master" ]; then + merge_image "${IMAGE}" "latest" + fi +done + +echo "Done merging multi-arch manifests for ${IMAGETAG}" From f8ccfe4801ac042c7490140fbd3ba493b30b91a5 Mon Sep 17 00:00:00 2001 From: Alex Chapin Date: Tue, 4 Aug 2026 17:56:10 -0400 Subject: [PATCH 2/8] Update GECKODRIVER_VERSION to v0.35.0 in Dockerfile-dev --- docker/development/Dockerfile-dev | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/development/Dockerfile-dev b/docker/development/Dockerfile-dev index cd7d0e363..f56e67112 100644 --- a/docker/development/Dockerfile-dev +++ b/docker/development/Dockerfile-dev @@ -71,7 +71,7 @@ ENV PERL_EXE_PATH /usr/bin # Set the rails env var ENV RAILS_ENV $rails_env -ENV GECKODRIVER_VERSION v0.15.0 +ENV GECKODRIVER_VERSION v0.35.0 ### ADD Gemfile to cache the installation of Gems. If you change the Gemfile, then you will need to rebuild ### your docker containers From c7bbffc6aae802a2e00fd500524d9efce923c62b Mon Sep 17 00:00:00 2001 From: Alex Chapin Date: Tue, 4 Aug 2026 19:14:46 -0400 Subject: [PATCH 3/8] Enhance Docker installation condition for multi-architecture support --- ci/github-actions/setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/github-actions/setup.sh b/ci/github-actions/setup.sh index 65199d1f0..ae066f090 100755 --- a/ci/github-actions/setup.sh +++ b/ci/github-actions/setup.sh @@ -2,7 +2,7 @@ set -euo pipefail echo "The build architecture is ${ImageOS}" -if [ "${ImageOS}" == "ubuntu24" ] && [ "${BUILD_TYPE}" == "docker" ]; then +if { [ "${ImageOS}" == "ubuntu24" ] || [ "${ImageOS}" == "ubuntu24-arm64" ]; } && [ "${BUILD_TYPE}" == "docker" ]; then echo "Installing docker compose" sudo rm -f /usr/local/bin/docker-compose curl -L https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` > docker-compose From b628b73b491a4456529501b7c8f155dc32990394 Mon Sep 17 00:00:00 2001 From: Alex Chapin Date: Tue, 4 Aug 2026 19:23:34 -0400 Subject: [PATCH 4/8] Update DOCKER_COMPOSE_VERSION to 5.4.0 in workflow files --- .github/workflows/openstudio-server-tests.yml | 2 +- .github/workflows/security-scan.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/openstudio-server-tests.yml b/.github/workflows/openstudio-server-tests.yml index 938273057..b92222f3a 100644 --- a/.github/workflows/openstudio-server-tests.yml +++ b/.github/workflows/openstudio-server-tests.yml @@ -23,7 +23,7 @@ env: OPENSTUDIO_VERSION: 3.10.0 OPENSTUDIO_VERSION_SHA: 86d7e215a1 OPENSTUDIO_VERSION_EXT: "" - DOCKER_COMPOSE_VERSION: 1.29.2 + DOCKER_COMPOSE_VERSION: 5.4.0 BUNDLE_WITHOUT: native_ext diff --git a/.github/workflows/security-scan.yml b/.github/workflows/security-scan.yml index f05e1d728..ca4bffd96 100644 --- a/.github/workflows/security-scan.yml +++ b/.github/workflows/security-scan.yml @@ -22,7 +22,7 @@ env: OPENSTUDIO_VERSION: 3.10.0 OPENSTUDIO_VERSION_SHA: 86d7e215a1 OPENSTUDIO_VERSION_EXT: "" - DOCKER_COMPOSE_VERSION: 1.29.2 + DOCKER_COMPOSE_VERSION: 5.4.0 BUNDLE_WITHOUT: native_ext From 05c0f42642a86c788a06961ac80b076d2c2006eb Mon Sep 17 00:00:00 2001 From: Alex Chapin Date: Tue, 4 Aug 2026 20:09:28 -0400 Subject: [PATCH 5/8] update docker compose so it works on arm, now it is a docker plugin 'docker compose' --- .github/workflows/security-scan.yml | 4 ++-- Dockerfile | 2 +- README.md | 24 +++++++++---------- ci/github-actions/setup.sh | 2 +- docker-compose.test.yml | 2 +- docker-compose.yml | 2 +- docker/R/Dockerfile | 2 +- docker/development/Dockerfile-dev | 2 +- docker/development/docker-compose.yml | 2 +- local_setup_scripts/win64/command.sh | 2 +- .../spec/features/docker_stack_algo_spec.rb | 2 +- .../spec/features/docker_stack_custom_gems.rb | 2 +- .../features/docker_stack_requeue_spec.rb | 2 +- .../docker_stack_urbanopt_algo_spec.rb | 2 +- 14 files changed, 26 insertions(+), 26 deletions(-) diff --git a/.github/workflows/security-scan.yml b/.github/workflows/security-scan.yml index ca4bffd96..d64aca3fa 100644 --- a/.github/workflows/security-scan.yml +++ b/.github/workflows/security-scan.yml @@ -45,8 +45,8 @@ jobs: docker volume create --name=osdata docker images --all docker --version - docker-compose --version - docker-compose -f docker-compose.test.yml build --build-arg OPENSTUDIO_VERSION=$OPENSTUDIO_TAG web + docker compose --version + docker compose -f docker-compose.test.yml build --build-arg OPENSTUDIO_VERSION=$OPENSTUDIO_TAG web env: CI: true OS_SERVER_NUMBER_OF_WORKERS: 4 diff --git a/Dockerfile b/Dockerfile index 7241353fa..e53ad1275 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ # AUTHOR: Nicholas Long # DESCRIPTION: OpenStudio Server Docker Container -# TO_BUILD_AND_RUN: docker-compose up +# TO_BUILD_AND_RUN: docker compose up # NOTES: Currently this is one big dockerfile and non-optimal. # may include suffix diff --git a/README.md b/README.md index cce7fa7d8..d2111d585 100644 --- a/README.md +++ b/README.md @@ -60,25 +60,25 @@ To develop locally the following dependency stack is recommended. #### Docker Compose ```bash -docker-compose build +docker compose build ``` ... [be patient](https://www.youtube.com/watch?v=f4hkPn0Un_Q) ... If the containers build successfully start them by -running `docker volume create --name=osdata && docker volume create --name=dbdata && OS_SERVER_NUMBER_OF_WORKERS=4 docker-compose up --scale worker=4` +running `docker volume create --name=osdata && docker volume create --name=dbdata && OS_SERVER_NUMBER_OF_WORKERS=4 docker compose up --scale worker=4` where 4 is equal to the number of worker nodes you wish to run. For single node servers this should not be greater than the total number of available cores minus 4. Resetting the containers can be accomplished by running: ```bash -docker-compose rm -f +docker compose rm -f docker volume rm osdata dbdata docker volume create --name=osdata docker volume create --name=dbdata -OS_SERVER_NUMBER_OF_WORKERS=N docker-compose up -d --scale worker=N +OS_SERVER_NUMBER_OF_WORKERS=N docker compose up -d --scale worker=N # Or one line -docker-compose rm -f && docker-compose build && docker volume rm osdata dbdata && docker volume create --name=osdata && docker volume create --name=dbdata && OS_SERVER_NUMBER_OF_WORKERS=N docker-compose up -d --scale worker=N +docker compose rm -f && docker compose build && docker volume rm osdata dbdata && docker volume create --name=osdata && docker volume create --name=dbdata && OS_SERVER_NUMBER_OF_WORKERS=N docker compose up -d --scale worker=N ``` Congratulations! Visit `http://localhost:8080` to see the OpenStudio Server Management Console. @@ -89,17 +89,17 @@ Congratulations! Visit `http://localhost:8080` to see the OpenStudio Server Mana export OPENSTUDIO_TAG=develop export RAILS_ENV=docker-test -docker-compose rm -f +docker compose rm -f docker volume rm osdata sed -i -E "s/.git//g" .dockerignore docker volume create --name=osdata -docker-compose -f docker-compose.test.yml pull -docker-compose -f docker-compose.test.yml build --build-arg OPENSTUDIO_VERSION=$OPENSTUDIO_TAG -docker-compose -f docker-compose.test.yml up -d -docker-compose exec -T web /usr/local/bin/run-server-tests -docker-compose stop +docker compose -f docker-compose.test.yml pull +docker compose -f docker-compose.test.yml build --build-arg OPENSTUDIO_VERSION=$OPENSTUDIO_TAG +docker compose -f docker-compose.test.yml up -d +docker compose exec -T web /usr/local/bin/run-server-tests +docker compose stop git checkout -- .dockerignore && git checkout -- Dockerfile -docker-compose rm -f +docker compose rm -f ``` ### Local Docker Swarm Deployment diff --git a/ci/github-actions/setup.sh b/ci/github-actions/setup.sh index ae066f090..f546fd142 100755 --- a/ci/github-actions/setup.sh +++ b/ci/github-actions/setup.sh @@ -7,7 +7,7 @@ if { [ "${ImageOS}" == "ubuntu24" ] || [ "${ImageOS}" == "ubuntu24-arm64" ]; } & sudo rm -f /usr/local/bin/docker-compose curl -L https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` > docker-compose chmod +x docker-compose - sudo mv docker-compose /usr/local/bin + sudo mv docker-compose /usr/local/lib/docker/cli-plugins # install pipeviewer sudo apt-get update sudo apt-get install -y pv ruby diff --git a/docker-compose.test.yml b/docker-compose.test.yml index d3e075bf3..d55fea3a6 100644 --- a/docker-compose.test.yml +++ b/docker-compose.test.yml @@ -1,5 +1,5 @@ # Docker Compose creates multiple containers on a single machine. -# run `docker-compose up` to create and run/link the containers +# run `docker compose up` to create and run/link the containers services: db: image: mongo:8.0.12 diff --git a/docker-compose.yml b/docker-compose.yml index fe8ec2d2c..f85637242 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,5 @@ # Docker Compose creates multiple containers on a single machine. -# run `docker-compose up` to create and run/link the containers +# run `docker compose up` to create and run/link the containers services: db: image: mongo:8.0.12 diff --git a/docker/R/Dockerfile b/docker/R/Dockerfile index 96d54500a..26a522503 100644 --- a/docker/R/Dockerfile +++ b/docker/R/Dockerfile @@ -1,6 +1,6 @@ # AUTHOR: Nicholas Long # DESCRIPTION: OpenStudio Server R Container -# TO_BUILD_AND_RUN: docker-compose up +# TO_BUILD_AND_RUN: docker compose up ARG DOCKER_PLATFORM=linux/amd64 FROM --platform=${DOCKER_PLATFORM} nrel/openstudio-r:4.4.0 diff --git a/docker/development/Dockerfile-dev b/docker/development/Dockerfile-dev index f56e67112..8e6234a05 100644 --- a/docker/development/Dockerfile-dev +++ b/docker/development/Dockerfile-dev @@ -1,6 +1,6 @@ # AUTHOR: Nicholas Long # DESCRIPTION: OpenStudio Server Docker Container -# TO_BUILD_AND_RUN: docker-compose up +# TO_BUILD_AND_RUN: docker compose up # NOTES: Currently this is one big dockerfile and non-optimal. FROM nrel/openstudio:2.5.2 diff --git a/docker/development/docker-compose.yml b/docker/development/docker-compose.yml index e4ba4c757..c2a4b537e 100644 --- a/docker/development/docker-compose.yml +++ b/docker/development/docker-compose.yml @@ -1,5 +1,5 @@ # Docker Compose creates multiple containers on a single machine. -# run `docker-compose up` to create and run/link the containers +# run `docker compose up` to create and run/link the containers services: db: image: mongo:latest diff --git a/local_setup_scripts/win64/command.sh b/local_setup_scripts/win64/command.sh index f3d0e8fe7..3d0b11be4 100644 --- a/local_setup_scripts/win64/command.sh +++ b/local_setup_scripts/win64/command.sh @@ -3,7 +3,7 @@ docker volume create --name=osdata docker volume create --name=dbdata #start the oss -docker-compose -f docker-compose.yml up --scale worker=8 +docker compose -f docker-compose.yml up --scale worker=8 #cleanup if you finished the work docker container rm -f $(docker container ls -aq) diff --git a/server/spec/features/docker_stack_algo_spec.rb b/server/spec/features/docker_stack_algo_spec.rb index af7f2cf8c..72c011ce2 100644 --- a/server/spec/features/docker_stack_algo_spec.rb +++ b/server/spec/features/docker_stack_algo_spec.rb @@ -38,7 +38,7 @@ puts "Project folder is: #{PROJECT}" puts "META_CLI is: #{META_CLI}" puts "App host is: http://#{HOST}" -#docker_ps = system('docker-compose ps') +#docker_ps = system('docker compose ps') #puts "Docker ps: #{docker_ps.to_s}" # the actual tests diff --git a/server/spec/features/docker_stack_custom_gems.rb b/server/spec/features/docker_stack_custom_gems.rb index e430c5601..e0da58e3f 100644 --- a/server/spec/features/docker_stack_custom_gems.rb +++ b/server/spec/features/docker_stack_custom_gems.rb @@ -67,7 +67,7 @@ puts "Project folder is: #{PROJECT}" puts "META_CLI is: #{META_CLI}" puts "App host is: http://#{HOST}" -#docker_ps = system('docker-compose ps') +#docker_ps = system('docker compose ps') #puts "Docker ps: #{docker_ps.to_s}" # the actual tests diff --git a/server/spec/features/docker_stack_requeue_spec.rb b/server/spec/features/docker_stack_requeue_spec.rb index db3523dc0..a72be1ba1 100644 --- a/server/spec/features/docker_stack_requeue_spec.rb +++ b/server/spec/features/docker_stack_requeue_spec.rb @@ -39,7 +39,7 @@ puts "Project folder is: #{PROJECT}" puts "META_CLI is: #{META_CLI}" puts "App host is: http://#{HOST}" -#docker_ps = system('docker-compose ps') +#docker_ps = system('docker compose ps') #puts "Docker ps: #{docker_ps.to_s}" # the actual tests diff --git a/server/spec/features/docker_stack_urbanopt_algo_spec.rb b/server/spec/features/docker_stack_urbanopt_algo_spec.rb index 58961ea99..26b0cdcd0 100644 --- a/server/spec/features/docker_stack_urbanopt_algo_spec.rb +++ b/server/spec/features/docker_stack_urbanopt_algo_spec.rb @@ -38,7 +38,7 @@ puts "Project folder is: #{PROJECT}" puts "META_CLI is: #{META_CLI}" puts "App host is: http://#{HOST}" -#docker_ps = system('docker-compose ps') +#docker_ps = system('docker compose ps') #puts "Docker ps: #{docker_ps.to_s}" # the actual tests From d16d85a0161f8370bb0d7b2c857507654dfb1684 Mon Sep 17 00:00:00 2001 From: Alex Chapin Date: Tue, 4 Aug 2026 20:27:15 -0400 Subject: [PATCH 6/8] Update Docker Compose commands to use the new 'docker compose' syntax --- .github/workflows/openstudio-server-tests.yml | 14 +++++++------- ci/github-actions/setup.sh | 7 +++++++ docker-compose.local.yml | 2 +- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/.github/workflows/openstudio-server-tests.yml b/.github/workflows/openstudio-server-tests.yml index b92222f3a..2a0d14a91 100644 --- a/.github/workflows/openstudio-server-tests.yml +++ b/.github/workflows/openstudio-server-tests.yml @@ -133,14 +133,14 @@ jobs: docker volume create --name=osdata docker images --all docker --version - docker-compose --version + docker compose --version if [ "${DEPLOY_ARCH}" = "arm64" ]; then # The first arm64 run may predate an arm64 entry in the :latest # manifests, so tolerate pull failure and build from scratch. # BuildKit also skips missing cache_from images without failing. - docker-compose -f docker-compose.test.yml pull || echo "arm64 pull skipped/failed; building from scratch" + docker compose -f docker-compose.test.yml pull || echo "arm64 pull skipped/failed; building from scratch" else - docker-compose -f docker-compose.test.yml pull + docker compose -f docker-compose.test.yml pull fi # Rebuild the rserve image only when its inputs changed. PR runs otherwise reuse # the pulled nrel/openstudio-rserve:latest (kept fresh by docker-upload on @@ -156,11 +156,11 @@ jobs: echo "docker/R is unchanged by this PR: reusing pulled nrel/openstudio-rserve:latest instead of rebuilding it" BUILD_SERVICES="web" fi - docker-compose -f docker-compose.test.yml build --build-arg OPENSTUDIO_VERSION=$OPENSTUDIO_TAG --build-arg DOCKER_PLATFORM=$DOCKER_PLATFORM $BUILD_SERVICES - docker-compose -f docker-compose.test.yml up -d + docker compose -f docker-compose.test.yml build --build-arg OPENSTUDIO_VERSION=$OPENSTUDIO_TAG --build-arg DOCKER_PLATFORM=$DOCKER_PLATFORM $BUILD_SERVICES + docker compose -f docker-compose.test.yml up -d #set SKIP_URBANOPT_ALGO=true to skip UrbanOpt algo tests - docker-compose exec -e SKIP_URBANOPT_ALGO=true -T web /usr/local/bin/run-server-tests - docker-compose stop + docker compose exec -e SKIP_URBANOPT_ALGO=true -T web /usr/local/bin/run-server-tests + docker compose stop git checkout -- .dockerignore && git checkout -- Dockerfile env: CI: true diff --git a/ci/github-actions/setup.sh b/ci/github-actions/setup.sh index f546fd142..e36196bfd 100755 --- a/ci/github-actions/setup.sh +++ b/ci/github-actions/setup.sh @@ -4,6 +4,13 @@ echo "The build architecture is ${ImageOS}" if { [ "${ImageOS}" == "ubuntu24" ] || [ "${ImageOS}" == "ubuntu24-arm64" ]; } && [ "${BUILD_TYPE}" == "docker" ]; then echo "Installing docker compose" + echo "Check if docker compose is already installed" + if command -v docker-compose &> /dev/null; then + echo "docker-compose is already installed" + docker-compose --version + exit 0 + fi + # install docker compose v2 sudo rm -f /usr/local/bin/docker-compose curl -L https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` > docker-compose chmod +x docker-compose diff --git a/docker-compose.local.yml b/docker-compose.local.yml index a47e1dd9f..490e510e1 100644 --- a/docker-compose.local.yml +++ b/docker-compose.local.yml @@ -1,5 +1,5 @@ # Docker Compose creates multiple containers on a single machine. -# run `docker-compose up` to create and run/link the containers +# run `docker compose up` to create and run/link the containers services: db: image: mongo:8.0.12 From a710272b2e68d0d25cb65a98675f499d98b1e069 Mon Sep 17 00:00:00 2001 From: Alex Chapin Date: Tue, 4 Aug 2026 20:31:00 -0400 Subject: [PATCH 7/8] Update DOCKER_COMPOSE_VERSION to 2.38.2 in workflow files for compatibility --- .github/workflows/openstudio-server-tests.yml | 15 ++++++++++++++- .github/workflows/security-scan.yml | 2 +- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/.github/workflows/openstudio-server-tests.yml b/.github/workflows/openstudio-server-tests.yml index 2a0d14a91..278f1a107 100644 --- a/.github/workflows/openstudio-server-tests.yml +++ b/.github/workflows/openstudio-server-tests.yml @@ -23,7 +23,7 @@ env: OPENSTUDIO_VERSION: 3.10.0 OPENSTUDIO_VERSION_SHA: 86d7e215a1 OPENSTUDIO_VERSION_EXT: "" - DOCKER_COMPOSE_VERSION: 5.4.0 + DOCKER_COMPOSE_VERSION: 2.38.2 BUNDLE_WITHOUT: native_ext @@ -120,6 +120,19 @@ jobs: run: rm -rf /opt/hostedtoolcache - name: Check out repository uses: actions/checkout@v4 + - name: Fix Docker Path for ARM64 Runner + run: | + if [ -f /usr/bin/docker ]; then + echo "Docker already exists in /usr/bin" + elif [ -f /usr/local/bin/docker ]; then + sudo ln -s /usr/local/bin/docker /usr/bin/docker + else + # If not found in common locations, explicitly locate and export it + DOCKER_BIN=$(which docker || find / -name docker -type f -perm -o+x 2>/dev/null | head -n 1) + if [ ! -z "$DOCKER_BIN" ]; then + sudo ln -s "$DOCKER_BIN" /usr/bin/docker + fi + fi - name: setup shell: bash run: ./ci/github-actions/setup.sh diff --git a/.github/workflows/security-scan.yml b/.github/workflows/security-scan.yml index d64aca3fa..08e19c7b9 100644 --- a/.github/workflows/security-scan.yml +++ b/.github/workflows/security-scan.yml @@ -22,7 +22,7 @@ env: OPENSTUDIO_VERSION: 3.10.0 OPENSTUDIO_VERSION_SHA: 86d7e215a1 OPENSTUDIO_VERSION_EXT: "" - DOCKER_COMPOSE_VERSION: 5.4.0 + DOCKER_COMPOSE_VERSION: 2.38.2 BUNDLE_WITHOUT: native_ext From f2ebdebb2ef084dacc09a833a10cdc9a93046e29 Mon Sep 17 00:00:00 2001 From: Alex Chapin Date: Tue, 4 Aug 2026 20:37:56 -0400 Subject: [PATCH 8/8] Fix docker-compose installation path in setup script for consistency --- ci/github-actions/setup.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ci/github-actions/setup.sh b/ci/github-actions/setup.sh index e36196bfd..fd3b8d659 100755 --- a/ci/github-actions/setup.sh +++ b/ci/github-actions/setup.sh @@ -11,10 +11,10 @@ if { [ "${ImageOS}" == "ubuntu24" ] || [ "${ImageOS}" == "ubuntu24-arm64" ]; } & exit 0 fi # install docker compose v2 - sudo rm -f /usr/local/bin/docker-compose + sudo rm -f /usr/bin/docker-compose curl -L https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` > docker-compose chmod +x docker-compose - sudo mv docker-compose /usr/local/lib/docker/cli-plugins + sudo mv docker-compose /usr/bin/ # install pipeviewer sudo apt-get update sudo apt-get install -y pv ruby