feat: compiles over Jdk17 with multiarch based images (#5542)

* feat: multiplatform base image for common:scala
* feat: jdk17-scala 2.12.10-gradle 7.6.2 build
* fix: wsk CLI requires a glibc based image, using eclipse-temurin:21-jre
* fix: trailspaces in common Dockerfiles
* fix: ensure elasticsearch hostname is resolved
diff --git a/.scalafmt.conf b/.scalafmt.conf
index cc0159a..96771bf 100644
--- a/.scalafmt.conf
+++ b/.scalafmt.conf
@@ -15,6 +15,7 @@
 # limitations under the License.
 #
 
+version = 1.5.1
 style = intellij
 danglingParentheses = false
 maxColumn = 120
diff --git a/ansible/elasticsearch.yml b/ansible/elasticsearch.yml
index ed05e3d..a782837 100644
--- a/ansible/elasticsearch.yml
+++ b/ansible/elasticsearch.yml
@@ -18,6 +18,7 @@
 # This playbook deploys a ElasticSearch cluster
 
 - hosts: elasticsearch
+  gather_facts: yes
   vars:
     #
     # host_group - usually "{{ groups['...'] }}" where '...' is what was used
diff --git a/ansible/roles/elasticsearch/templates/elasticsearch.yml.j2 b/ansible/roles/elasticsearch/templates/elasticsearch.yml.j2
index c300a5b..1cd491a 100644
--- a/ansible/roles/elasticsearch/templates/elasticsearch.yml.j2
+++ b/ansible/roles/elasticsearch/templates/elasticsearch.yml.j2
@@ -1,7 +1,7 @@
 cluster.name: "{{ db.elasticsearch.cluster_name }}"
 node.name: "{{ elasticsearch_name }}"
 network.host: 0.0.0.0
-network.publish_host: {{ ansible_default_ipv4.address }}
+network.publish_host: {{ ansible_default_ipv4.address | default(ansible_host | default('127.0.0.1')) }}
 
 http.port: 9200
 transport.tcp.port: {{ transport_port }}
diff --git a/build.gradle b/build.gradle
index 7eca2c46..9987d43 100644
--- a/build.gradle
+++ b/build.gradle
@@ -17,7 +17,8 @@
 
 buildscript {
     repositories {
-        jcenter()
+        gradlePluginPortal()
+        mavenCentral()
     }
     dependencies {
         classpath "gradle.plugin.cz.alenkacz:gradle-scalafmt:${gradle.scalafmt.version}"
@@ -26,6 +27,7 @@
 
 plugins {
     id "org.scoverage" version "7.0.0" apply false
+    id "cz.alenkacz.gradle.scalafmt" version "1.16.2" apply false
 }
 
 subprojects {
@@ -41,16 +43,21 @@
         // ./gradlew :test:dependencies | grep -o 'akka-.*_' | cut -c 6- | rev | cut -c 2- | rev | sort -u
         def cons = project.getDependencies().getConstraints()
         def akka = ['akka-actor', 'akka-cluster', 'akka-cluster-metrics', 'akka-cluster-tools', 'akka-coordination',
-                    'akka-discovery', 'akka-distributed-data', 'akka-protobuf', 'akka-remote', 'akka-slf4j',
-                    'akka-stream', 'akka-stream-testkit', 'akka-testkit', 'akka-persistence', 'akka-cluster-sharding']
+                    'akka-discovery', 'discovery-kubernetes-api', 'discovery-marathon-api', 'akka-distributed-data','grpc-runtime','akka-protobuf', 'akka-remote', 'akka-slf4j',
+                    'akka-stream', 'akka-stream-testkit', 'akka-testkit', 'akka-persistence', 'akka-cluster-sharding','akka-protobuf-v3','akka-pki','akka-parsing','akka-management-cluster-bootstrap','akka-management',
+                    'akka-kryo-serialization']
         def akkaHttp = ['akka-http', 'akka-http-core', 'akka-http-spray-json', 'akka-http-testkit', 'akka-http-xml',
                         'akka-parsing', 'akka-http2-support']
+        def akkaKafka = ['akka-stream-kafka-testkit','akka-stream-kafka','akka-stream-alpakka-s3','akka-stream-alpakka-file']
 
         akka.forEach {
-            cons.add('compile', "com.typesafe.akka:${it}_${gradle.scala.depVersion}:${gradle.akka.version}")
+            cons.add('implementation', "com.typesafe.akka:${it}_${gradle.scala.depVersion}:${gradle.akka.version}")
         }
         akkaHttp.forEach {
-            cons.add('compile', "com.typesafe.akka:${it}_${gradle.scala.depVersion}:${gradle.akka_http.version}")
+            cons.add('implementation', "com.typesafe.akka:${it}_${gradle.scala.depVersion}:${gradle.akka_http.version}")
+        }
+        akkaKafka.forEach{
+            cons.add('implementation', "com.typesafe.akka:${it}_${gradle.scala.depVersion}:${gradle.akka_kafka.version}")
         }
     }
 
@@ -72,9 +79,17 @@
                     }
                 }
             }
+
+            configurations {
+                implementationResolvable {
+                    canBeResolved = true
+                    canBeConsumed = false
+                    extendsFrom configurations.implementation
+                }
+            }
         }
 
-        if (project.plugins.hasPlugin('maven')) {
+        if (project.plugins.hasPlugin('maven-publish')) {
             task sourcesJar(type: Jar, dependsOn: classes) {
                 classifier = 'sources'
                 from sourceSets.main.allSource
@@ -90,18 +105,12 @@
                 classifier = 'tests'
                 from sourceSets.test.output
             }
-
-            artifacts {
-                archives sourcesJar
-                archives testSourcesJar
-                archives testClassesJar
-            }
         }
 
         if (project.plugins.hasPlugin('application')) {
             //Ensure that dist archive name does not contain version
             distTar {
-                archiveName = "${project.name}.tar"
+                archiveFileName = "${project.name}.tar"
             }
 
             //Avoid generating the zip files from maven installations
diff --git a/common/scala/Dockerfile b/common/scala/Dockerfile
index c7ebd2b..9886f18 100644
--- a/common/scala/Dockerfile
+++ b/common/scala/Dockerfile
@@ -14,16 +14,21 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-# if you change version of openjsk, also update tools/github/setup.sh to download the corresponding jdk
-FROM adoptopenjdk/openjdk11-openj9:x86_64-alpine-jdk-11.0.12_7_openj9-0.27.0
+# if you change version of openjdk, also update tools/github/setup.sh to download the corresponding jdk
+# NOTE:
+# OpenWhisk will use a 21-jre multi arch image, compilation will be done with a jdk 17 temurin based image.
+# as wsk CLI is compiled against glibc we need touse a GLIBC based JRE Image (alpine it is not GLIBC based)
+FROM eclipse-temurin:21-jre
 
-ENV LANG en_US.UTF-8
-ENV LANGUAGE en_US:en
-ENV LC_ALL en_US.UTF-8
+ENV LANG=en_US.UTF-8
+ENV LANGUAGE=en_US:en
+ENV LC_ALL=en_US.UTF-8
 
-# Switch to the HTTPS endpoint for the apk repositories as per https://github.com/gliderlabs/docker-alpine/issues/184
-RUN sed -i 's/http\:\/\/dl-cdn.alpinelinux.org/https\:\/\/alpine.global.ssl.fastly.net/g' /etc/apk/repositories
-RUN apk add --update sed curl bash && apk update && apk upgrade
+# Install curl, bash, sed
+RUN apt-get update && \
+    apt-get install -y curl bash sed openssl && \
+    apt-get clean && \
+    rm -rf /var/lib/apt/lists/*
 
 RUN mkdir /logs
 
diff --git a/common/scala/Dockerfile.arm b/common/scala/Dockerfile.arm
deleted file mode 100644
index feac234..0000000
--- a/common/scala/Dockerfile.arm
+++ /dev/null
@@ -1,34 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License.  You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# if you change version of openjsk, also update tools/github/setup.sh to download the corresponding jdk
-FROM arm64v8/eclipse-temurin:21.0.4_7-jdk-alpine
-
-ENV LANG en_US.UTF-8
-ENV LANGUAGE en_US:en
-ENV LC_ALL en_US.UTF-8
-
-# Switch to the HTTPS endpoint for the apk repositories as per https://github.com/gliderlabs/docker-alpine/issues/184
-RUN sed -i 's/http\:\/\/dl-cdn.alpinelinux.org/https\:\/\/alpine.global.ssl.fastly.net/g' /etc/apk/repositories
-RUN apk add --update sed curl bash && apk update && apk upgrade
-
-RUN mkdir /logs
-
-COPY transformEnvironment.sh /
-RUN chmod +x transformEnvironment.sh
-
-COPY copyJMXFiles.sh /
-RUN chmod +x copyJMXFiles.sh
diff --git a/common/scala/build.gradle b/common/scala/build.gradle
index f9be938..bb0311d 100644
--- a/common/scala/build.gradle
+++ b/common/scala/build.gradle
@@ -17,16 +17,19 @@
 
 plugins {
     id 'eclipse'
-    id 'maven'
+    id 'maven-publish'
     id 'org.scoverage'
     id 'scala'
     id 'java-library'
 }
 
 ext.dockerImageName = 'scala'
-if(System.getProperty("os.arch").toLowerCase(Locale.ENGLISH).startsWith("aarch")) {
-    ext.dockerDockerfileSuffix = ".arm"
-}
+
+// Using a multiarch base image should make this supefluous
+//if(System.getProperty("os.arch").toLowerCase(Locale.ENGLISH).startsWith("aarch")) {
+//    ext.dockerDockerfileSuffix = ".arm"
+//}
+
 apply from: '../../gradle/docker.gradle'
 
 project.archivesBaseName = "openwhisk-common"
@@ -56,7 +59,7 @@
     api "com.typesafe.akka:akka-http-core_${gradle.scala.depVersion}:${gradle.akka_http.version}"
     api "com.typesafe.akka:akka-http-spray-json_${gradle.scala.depVersion}:${gradle.akka_http.version}"
 
-    api "com.lightbend.akka:akka-stream-alpakka-file_${gradle.scala.depVersion}:1.1.2"
+    api "com.lightbend.akka:akka-stream-alpakka-file_${gradle.scala.depVersion}:2.0.2"
 
     api "ch.qos.logback:logback-classic:1.2.11"
     api "org.slf4j:jcl-over-slf4j:1.7.25"
@@ -141,10 +144,12 @@
     api "io.netty:netty-codec-http2:${gradle.netty.version}"
     api "io.netty:netty-transport-native-epoll:${gradle.netty.version}"
     api "io.netty:netty-transport-native-unix-common:${gradle.netty.version}"
+    api "com.lightbend.akka.grpc:akka-grpc-runtime_${gradle.scala.depVersion}:${gradle.akka_gprc.version}"
+    api "com.typesafe.akka:akka-stream_${gradle.scala.depVersion}:${gradle.akka.version}"
 }
 
 configurations {
-    compile {
+    api {
         exclude group: 'commons-logging'
         exclude group: 'log4j'
     }
diff --git a/core/controller/Dockerfile b/core/controller/Dockerfile
index 670c0db..6331cc2 100644
--- a/core/controller/Dockerfile
+++ b/core/controller/Dockerfile
@@ -15,7 +15,8 @@
 # limitations under the License.
 #
 
-FROM scala
+ARG BASE=scala
+FROM ${BASE}
 
 ENV UID=1001 \
     NOT_ROOT_USER=owuser
@@ -30,8 +31,6 @@
 # If this cannot be guaranteed, set `invoker_use_runc: false` in the ansible env.
 ENV DOCKER_VERSION=23.0.6
 
-RUN apk add --update openssl
-
 # Uncomment to fetch latest version of docker instead: RUN wget -qO- https://get.docker.com | sh
 # Install docker client
 RUN curl -sSL -o docker-${DOCKER_VERSION}.tgz https://download.docker.com/linux/static/stable/x86_64/docker-${DOCKER_VERSION}.tgz && \
@@ -56,7 +55,7 @@
 COPY init.sh /
 RUN chmod +x init.sh
 
-RUN adduser -D -u ${UID} -h /home/${NOT_ROOT_USER} -s /bin/bash ${NOT_ROOT_USER}
+RUN useradd -m -u 1001 -d /home/${NOT_ROOT_USER} -s /bin/bash ${NOT_ROOT_USER}
 
 # It is possible to run as non root if you dont need invoker capabilities out of the controller today
 # When running it as a non-root user this has implications on the standard directory where runc stores its data.
diff --git a/core/controller/build.gradle b/core/controller/build.gradle
index eb6ec97..9a8cc3a 100644
--- a/core/controller/build.gradle
+++ b/core/controller/build.gradle
@@ -18,7 +18,7 @@
 plugins {
     id 'application'
     id 'eclipse'
-    id 'maven'
+    id 'maven-publish'
     id 'org.scoverage'
     id 'scala'
 }
diff --git a/core/cosmosdb/cache-invalidator/Dockerfile b/core/cosmosdb/cache-invalidator/Dockerfile
index e8df857..3af25a8 100644
--- a/core/cosmosdb/cache-invalidator/Dockerfile
+++ b/core/cosmosdb/cache-invalidator/Dockerfile
@@ -15,7 +15,8 @@
 # limitations under the License.
 #
 
-FROM scala
+ARG BASE=scala
+FROM ${BASE}
 
 ENV UID=1001 \
     NOT_ROOT_USER=owuser
@@ -27,7 +28,7 @@
 COPY init.sh /
 RUN chmod +x init.sh
 
-RUN adduser -D -u ${UID} -h /home/${NOT_ROOT_USER} -s /bin/bash ${NOT_ROOT_USER}
+RUN useradd -m -u 1001 -d /home/${NOT_ROOT_USER} -s /bin/bash ${NOT_ROOT_USER}
 USER ${NOT_ROOT_USER}
 
 EXPOSE 8080
diff --git a/core/cosmosdb/cache-invalidator/build.gradle b/core/cosmosdb/cache-invalidator/build.gradle
index fef96af..5fe4c83 100644
--- a/core/cosmosdb/cache-invalidator/build.gradle
+++ b/core/cosmosdb/cache-invalidator/build.gradle
@@ -18,7 +18,7 @@
 plugins {
     id 'application'
     id 'eclipse'
-    id 'maven'
+    id 'maven-publish'
     id 'org.scoverage'
     id 'scala'
 }
diff --git a/core/invoker/Dockerfile b/core/invoker/Dockerfile
index 36581e4..7ca0554 100644
--- a/core/invoker/Dockerfile
+++ b/core/invoker/Dockerfile
@@ -15,7 +15,8 @@
 # limitations under the License.
 #
 
-FROM scala
+ARG BASE=scala
+FROM ${BASE}
 
 ENV UID=1001 \
     NOT_ROOT_USER=owuser \
@@ -24,9 +25,6 @@
 # Docker server version and the invoker docker version must be the same to enable runc usage.
 # If this cannot be guaranteed, set `invoker_use_runc: false` in the ansible env.
 
-
-RUN apk add --update openssl
-
 # Uncomment to fetch latest version of docker instead: RUN wget -qO- https://get.docker.com | sh
 # Install docker client
 RUN curl -sSL -o docker-${DOCKER_VERSION}.tgz https://download.docker.com/linux/static/stable/x86_64/docker-${DOCKER_VERSION}.tgz && \
@@ -43,7 +41,7 @@
 
 # When running the invoker as a non-root user this has implications on the standard directory where runc stores its data.
 # The non-root user should have access on the directory and corresponding permission to make changes on it.
-RUN adduser -D -u ${UID} -h /home/${NOT_ROOT_USER} -s /bin/bash ${NOT_ROOT_USER}
+RUN useradd -m -u 1001 -d /home/${NOT_ROOT_USER} -s /bin/bash ${NOT_ROOT_USER}
 
 EXPOSE 8080
 CMD ["./init.sh", "0"]
diff --git a/core/invoker/build.gradle b/core/invoker/build.gradle
index c97c8a7..2a4164c 100644
--- a/core/invoker/build.gradle
+++ b/core/invoker/build.gradle
@@ -18,7 +18,7 @@
 plugins {
     id 'application'
     id 'eclipse'
-    id 'maven'
+    id 'maven-publish'
     id 'org.scoverage'
     id 'scala'
 }
diff --git a/core/monitoring/user-events/Dockerfile b/core/monitoring/user-events/Dockerfile
index 95b06ae..ee4b729 100644
--- a/core/monitoring/user-events/Dockerfile
+++ b/core/monitoring/user-events/Dockerfile
@@ -15,7 +15,8 @@
 # limitations under the License.
 #
 
-FROM scala
+ARG BASE=scala
+FROM ${BASE}
 
 ENV UID=1001 \
     NOT_ROOT_USER=owuser
@@ -26,7 +27,7 @@
 COPY init.sh /
 RUN chmod +x init.sh
 
-RUN adduser -D -u ${UID} -h /home/${NOT_ROOT_USER} -s /bin/bash ${NOT_ROOT_USER}
+RUN useradd -m -u 1001 -d /home/${NOT_ROOT_USER} -s /bin/bash ${NOT_ROOT_USER}
 USER ${NOT_ROOT_USER}
 
 # Prometheus port
diff --git a/core/monitoring/user-events/build.gradle b/core/monitoring/user-events/build.gradle
index 42269d1..f771e25 100644
--- a/core/monitoring/user-events/build.gradle
+++ b/core/monitoring/user-events/build.gradle
@@ -18,7 +18,7 @@
 plugins {
     id 'application'
     id 'eclipse'
-    id 'maven'
+    id 'maven-publish'
     id 'org.scoverage'
     id 'scala'
 }
diff --git a/core/scheduler/Dockerfile b/core/scheduler/Dockerfile
index 244d80d..33af8e9 100644
--- a/core/scheduler/Dockerfile
+++ b/core/scheduler/Dockerfile
@@ -15,7 +15,8 @@
 # limitations under the License.
 #
 
-FROM scala
+ARG BASE=scala
+FROM ${BASE}
 
 ENV UID=1001 \
     NOT_ROOT_USER=owuser
@@ -26,7 +27,7 @@
 COPY init.sh /
 RUN chmod +x init.sh
 
-RUN adduser -D -u ${UID} -h /home/${NOT_ROOT_USER} -s /bin/bash ${NOT_ROOT_USER}
+RUN useradd -m -u 1001 -d /home/${NOT_ROOT_USER} -s /bin/bash ${NOT_ROOT_USER}
 USER ${NOT_ROOT_USER}
 
 EXPOSE 8080
diff --git a/core/scheduler/build.gradle b/core/scheduler/build.gradle
index 101a361..cca0dd8 100644
--- a/core/scheduler/build.gradle
+++ b/core/scheduler/build.gradle
@@ -18,7 +18,7 @@
 apply plugin: 'scala'
 apply plugin: 'application'
 apply plugin: 'eclipse'
-apply plugin: 'maven'
+apply plugin: 'maven-publish'
 apply plugin: 'org.scoverage'
 apply plugin: 'com.lightbend.akka.grpc.gradle'
 
@@ -48,16 +48,16 @@
     dependencies {
         // see https://plugins.gradle.org/plugin/com.lightbend.akka.grpc.gradle
         // for the currently latest version.
-        classpath 'com.lightbend.akka.grpc:akka-grpc-gradle-plugin:1.0.0'
+        classpath 'com.lightbend.akka.grpc:akka-grpc-gradle-plugin:1.0.2'
     }
 }
 
 protobuf {
     protoc {
         if (osdetector.os == "osx") {
-            artifact = 'com.google.protobuf:protoc:3.4.0:osx-x86_64'
+            artifact = 'com.google.protobuf:protoc:3.11.4:osx-x86_64'
         } else {
-            artifact = 'com.google.protobuf:protoc:3.4.0'
+            artifact = 'com.google.protobuf:protoc:3.11.4'
         }
     }
 }
@@ -101,3 +101,13 @@
 
 mainClassName = "org.apache.openwhisk.core.scheduler.Scheduler"
 applicationDefaultJvmArgs = ["-Djava.security.egd=file:/dev/./urandom"]
+
+// Explictly declare task dependencies
+tasks.named("processResources") {
+    dependsOn tasks.named("extractProto")
+}
+
+tasks.named("processScoverageResources") {
+    dependsOn tasks.named("extractScoverageProto")
+}
+
diff --git a/core/standalone/Dockerfile b/core/standalone/Dockerfile
index 676b1eb..92df97d 100644
--- a/core/standalone/Dockerfile
+++ b/core/standalone/Dockerfile
@@ -14,19 +14,34 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-FROM scala
+ARG BASE=scala
+FROM ${BASE}
 ARG OPENWHISK_JAR
+ARG TARGETPLATFORM
+
 ENV DOCKER_VERSION=18.06.3-ce
-ENV WSK_VERSION=1.0.0
+ENV WSK_VERSION=1.2.0
+
 ADD bin/init /
 ADD bin/stop bin/waitready /bin/
-RUN chmod +x /bin/stop /bin/waitready ;\
-  curl -sL \
-  https://download.docker.com/linux/static/stable/x86_64/docker-${DOCKER_VERSION}.tgz \
-  | tar xzvf -  -C /usr/bin --strip 1 docker/docker ;\
-  curl -sL \
-  https://github.com/apache/openwhisk-cli/releases/download/${WSK_VERSION}/OpenWhisk_CLI-${WSK_VERSION}-linux-amd64.tgz \
-  | tar xzvf - -C /usr/bin wsk
+
+RUN chmod +x /bin/stop /bin/waitready ;
+
+RUN if [ "$TARGETPLATFORM" = "linux/arm64" ]; then \
+      curl -sL https://download.docker.com/linux/static/stable/aarch64/docker-${DOCKER_VERSION}.tgz \
+      | tar xzvf -  -C /usr/bin --strip 1 docker/docker ; \
+      curl -sL https://github.com/apache/openwhisk-cli/releases/download/${WSK_VERSION}/OpenWhisk_CLI-${WSK_VERSION}-linux-arm64.tgz \
+      | tar xzvf - -C /usr/bin wsk; \
+    elif [ "$TARGETPLATFORM" = "linux/amd64" ]; then \
+      curl -sL https://download.docker.com/linux/static/stable/x86_64/docker-${DOCKER_VERSION}.tgz \
+      | tar xzvf -  -C /usr/bin --strip 1 docker/docker ; \
+      curl -sL https://github.com/apache/openwhisk-cli/releases/download/${WSK_VERSION}/OpenWhisk_CLI-${WSK_VERSION}-linux-amd64.tgz \
+      | tar xzvf - -C /usr/bin wsk; \
+    else \
+        echo "Unsupported platform: $TARGETPLATFORM"; \
+        exit 1; \
+    fi
+
 ADD ${OPENWHISK_JAR} /openwhisk-standalone.jar
 WORKDIR /
 EXPOSE 8080
diff --git a/core/standalone/build.gradle b/core/standalone/build.gradle
index 25d94d1..0718647 100644
--- a/core/standalone/build.gradle
+++ b/core/standalone/build.gradle
@@ -18,9 +18,9 @@
 import org.apache.tools.ant.taskdefs.condition.Os
 
 plugins {
-    id 'maven'
+    id 'maven-publish'
     id 'org.scoverage'
-    id 'org.springframework.boot' version '2.1.6.RELEASE'
+    id 'org.springframework.boot' version '2.7.18'
     id 'scala'
     id 'com.gorylenko.gradle-git-properties' version '2.4.2'
 }
@@ -147,7 +147,7 @@
 }
 
 bootJar {
-    mainClassName = 'org.apache.openwhisk.standalone.StandaloneOpenWhisk'
+    mainClass = 'org.apache.openwhisk.standalone.StandaloneOpenWhisk'
     finalizedBy copyBootJarToBin
 }
 
@@ -159,7 +159,7 @@
 // Gradle boot disables the default jar task. So need to now make
 // install task depend on bootJar such that it finds the required jar file
 // https://github.com/spring-projects/spring-boot/issues/13187
-install.dependsOn(bootJar)
+// install.dependsOn(bootJar)
 
 dependencies {
     implementation "org.scala-lang:scala-library:${gradle.scala.version}"
@@ -192,3 +192,12 @@
         }
     }
 }
+
+task copyRuntimeLibs(type:Copy) {
+    from configurations.runtimeClasspath
+    into "$buildDir/dependency-libs"
+}
+
+tasks.named("copyBootJarToBin") {
+    dependsOn tasks.named("jar")
+}
diff --git a/gradle/docker.gradle b/gradle/docker.gradle
index d4eb572..7621254 100644
--- a/gradle/docker.gradle
+++ b/gradle/docker.gradle
@@ -47,8 +47,10 @@
     dockerBinary = project.hasProperty('dockerBinary') ? [dockerBinary] : ['docker']
     dockerBuildArg = ['build']
     dockerDockerfileSuffix = project.hasProperty('dockerDockerfileSuffix') ? dockerDockerfileSuffix : ""
+    dockerMultiArchBuild = project.hasProperty('dockerMultiArchBuild') ? dockerMultiArchBuild.toBoolean() : false
 }
 ext.dockerTaggedImageName = dockerRegistry + dockerImagePrefix + '/' + dockerImageName + ':' + dockerImageTag
+ext.scalaBaseImageName = dockerRegistry + dockerImagePrefix + '/scala:' + dockerImageTag
 
 if(project.hasProperty('dockerHost')) {
     dockerBinary += ['--host', project.dockerHost]
@@ -58,6 +60,29 @@
     dockerBuildArgs.each { arg  ->
         dockerBuildArg += ['--build-arg', arg]
     }
+    if( dockerMultiArchBuild ){
+        dockerBuildArg += ['--build-arg','BASE='+scalaBaseImageName]
+    }
+}
+
+if( !project.hasProperty('dockerBuildArgs') && dockerMultiArchBuild ) {
+    dockerBuildArg += ['--build-arg','BASE='+scalaBaseImageName]
+}
+
+def builDockerCommand(dockerFile) {
+    def cmd = dockerBinary
+
+    if(dockerMultiArchBuild) {
+        cmd += ['buildx']
+    }
+
+    cmd +=  dockerBuildArg + ['-f', dockerFile] + ['-t', dockerImageName, project.buildscript.sourceFile.getParentFile().getAbsolutePath()]
+
+    if(dockerMultiArchBuild) {
+        cmd += ['--load']
+    }
+
+    return cmd
 }
 
 task distDocker {
@@ -70,8 +95,9 @@
             dockerFile = dockerFileDir + "/Dockerfile"
         }
 
-        def cmd = dockerBinary + dockerBuildArg + ['-f', dockerFile] + ['-t', dockerImageName, project.buildscript.sourceFile.getParentFile().getAbsolutePath()]
+        def cmd = builDockerCommand(dockerFile)
         retry(cmd, dockerRetries, dockerTimeout)
+
         println("Building '${dockerImageName}' took ${TimeCategory.minus(new Date(), start)}")
     }
 }
@@ -80,7 +106,7 @@
     doLast {
         def start = new Date()
         //Copy the scoverage runtime jars
-        copy {from configurations.scoverage - configurations.compile; into "build/tmp/docker-coverage/ext-lib"}
+        copy {from configurations.scoverage - configurations.implementationResolvable; into "build/tmp/docker-coverage/ext-lib"}
         //Copy the scoverage prepared jars
         coverageDirs.each {dir ->
             copy {from file(dir); into "build/tmp/docker-coverage/classes"}
@@ -140,6 +166,7 @@
         retry(cmd, dockerRetries, dockerTimeout)
     }
 }
+
 pushImage.dependsOn tagImage
 pushImage.onlyIf { dockerRegistry != '' }
 distDocker.finalizedBy pushImage
@@ -165,3 +192,4 @@
         }
     }
 }
+
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index c441f28..8391417 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -17,6 +17,6 @@
 
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.9.1-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.2-bin.zip
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
diff --git a/settings.gradle b/settings.gradle
index b372c9b..8d63ca5 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -99,9 +99,10 @@
 ]
 
 gradle.ext.akka = [version : '2.6.12']
-gradle.ext.akka_kafka = [version : '2.0.5']
-gradle.ext.akka_http = [version : '10.2.4']
-gradle.ext.akka_management = [version : '1.0.5']
+gradle.ext.akka_kafka = [version : '2.0.7']
+gradle.ext.akka_http = [version : '10.2.3']
+gradle.ext.akka_management = [version : '1.0.10']
+gradle.ext.akka_gprc = [version : '1.0.2']
 
 gradle.ext.curator = [version : '4.3.0']
 gradle.ext.kube_client = [version: '4.10.3']
diff --git a/tests/build.gradle b/tests/build.gradle
index 30906ac..2307da2 100644
--- a/tests/build.gradle
+++ b/tests/build.gradle
@@ -20,16 +20,13 @@
 
 plugins {
     id 'eclipse'
-    id 'maven'
-    id 'org.hidetake.swagger.generator' version '2.18.1'
+    id 'maven-publish'
+    id 'org.hidetake.swagger.generator' version '2.19.2'
     id 'org.scoverage'
     id 'scala'
 }
 
 compileTestScala.options.encoding = 'UTF-8'
-
-install.dependsOn ':tools:admin:install'
-
 project.archivesBaseName = "openwhisk-tests"
 
 scoverage {
@@ -337,6 +334,7 @@
         dependentTasks << copyMeasurementFiles
         projectsWithCoverage.forEach {
             dependentTasks << it + ':reportScoverage'
+            dependentTasks << it + ':processScoverageResources'
         }
         dependentTasks << 'compileScoverageScala'
         dependsOn(dependentTasks)
@@ -438,5 +436,5 @@
 }
 
 def getStandaloneJarFilePath(){
-    project(":core:standalone").jar.archivePath
+    project(":core:standalone").tasks.named("bootJar").get().archiveFile.get().asFile
 }
diff --git a/tests/dat/actions/unicode.tests/src/java/unicode/build.gradle b/tests/dat/actions/unicode.tests/src/java/unicode/build.gradle
index c6df5f6..7c718ff 100644
--- a/tests/dat/actions/unicode.tests/src/java/unicode/build.gradle
+++ b/tests/dat/actions/unicode.tests/src/java/unicode/build.gradle
@@ -26,5 +26,5 @@
 }
 
 dependencies {
-    compile "com.google.code.gson:gson:2.6.2"
+    implementation "com.google.code.gson:gson:2.6.2"
 }
diff --git a/tests/performance/gatling_tests/src/gatling/resources/data/src/java/build.gradle b/tests/performance/gatling_tests/src/gatling/resources/data/src/java/build.gradle
index 390d17d..de380a7 100644
--- a/tests/performance/gatling_tests/src/gatling/resources/data/src/java/build.gradle
+++ b/tests/performance/gatling_tests/src/gatling/resources/data/src/java/build.gradle
@@ -31,5 +31,5 @@
 }
 
 dependencies {
-    compile "com.google.code.gson:gson:2.6.2"
+    implementation "com.google.code.gson:gson:2.6.2"
 }
diff --git a/tests/src/test/resources/templates/build.gradle.mustache b/tests/src/test/resources/templates/build.gradle.mustache
index 99a5a63..312f0e1 100644
--- a/tests/src/test/resources/templates/build.gradle.mustache
+++ b/tests/src/test/resources/templates/build.gradle.mustache
@@ -76,16 +76,35 @@
 } else {
 
     apply plugin: 'java'
-    apply plugin: 'maven'
+    apply plugin: 'maven-publish'
 
     sourceCompatibility = JavaVersion.VERSION_1_8
     targetCompatibility = JavaVersion.VERSION_1_8
 
+    /*
     install {
         repositories.mavenInstaller {
             pom.artifactId = 'swagger-java-client'
         }
     }
+    */
+    publishing {
+        publications {
+            mavenJava(MavenPublication) {
+                from components.java
+                groupId = 'com.example'
+                artifactId = 'swagger-java-client'
+                version = '1.0.0'
+            }
+        }
+        repositories {
+            maven {
+                name = "localRepo"
+                url = uri("${buildDir}/repo") // or mavenLocal() or remote repo
+            }
+        }
+    }
+
 
     task execute(type:JavaExec) {
        main = System.getProperty('mainClass')
@@ -94,10 +113,10 @@
 }
 
 dependencies {
-    compile 'io.swagger:swagger-annotations:1.5.17'
-    compile 'com.squareup.okhttp:okhttp:2.7.5'
-    compile 'com.squareup.okhttp:logging-interceptor:2.7.5'
-    compile 'com.google.code.gson:gson:2.8.1'
-    compile 'io.gsonfire:gson-fire:1.8.0'
-    testCompile 'junit:junit:4.12'
+    implementation 'io.swagger:swagger-annotations:1.5.17'
+    implementation 'com.squareup.okhttp:okhttp:2.7.5'
+    implementation 'com.squareup.okhttp:logging-interceptor:2.7.5'
+    implementation 'com.google.code.gson:gson:2.8.1'
+    implementation 'io.gsonfire:gson-fire:1.8.0'
+    testImplementation 'junit:junit:4.12'
 }
diff --git a/tools/admin/build.gradle b/tools/admin/build.gradle
index 064a5ed..016a27c 100644
--- a/tools/admin/build.gradle
+++ b/tools/admin/build.gradle
@@ -18,7 +18,7 @@
 plugins {
     id 'org.springframework.boot' version '2.0.2.RELEASE'
     id 'scala'
-    id 'maven'
+    id 'maven-publish'
     id 'org.scoverage'
 }
 
diff --git a/tools/dev/build.gradle b/tools/dev/build.gradle
index 2eb3e18..9d8b308 100644
--- a/tools/dev/build.gradle
+++ b/tools/dev/build.gradle
@@ -33,28 +33,28 @@
 
 task couchdbViews(type: JavaExec) {
     description 'Dumps CouchDB views as js files'
-    main = 'couchdbViews'
+    mainClass = 'couchdbViews'
     args owHome.absolutePath
     classpath = sourceSets.main.runtimeClasspath
 }
 
 task intellij(type: JavaExec) {
     description 'Generates Intellij run config for Controller and Invoker'
-    main = 'intellijRunConfig'
+    mainClass = 'intellijRunConfig'
     args owHome.absolutePath
     classpath = sourceSets.main.runtimeClasspath
 }
 
 task listRepos(type: JavaExec) {
     description 'Generates a list of all OpenWhisk related Git repos'
-    main = 'listRepos'
+    mainClass = 'listRepos'
     args owHome.absolutePath
     classpath = sourceSets.main.runtimeClasspath
 }
 
 task renderModuleDetails(type: JavaExec) {
     description 'Renders modules details'
-    main = 'renderModuleDetails'
+    mainClass = 'renderModuleDetails'
     args owHome.absolutePath
     classpath = sourceSets.main.runtimeClasspath
 }
diff --git a/tools/github/setup.sh b/tools/github/setup.sh
index 80536d4..7bef49d 100755
--- a/tools/github/setup.sh
+++ b/tools/github/setup.sh
@@ -45,8 +45,8 @@
 sudo systemctl daemon-reload
 sudo systemctl start docker
 
-# installing right version of jdk
-JDK=https://github.com/ibmruntimes/semeru11-binaries/releases/download/jdk-11.0.12%2B7_openj9-0.27.0/ibm-semeru-open-jdk_x64_linux_11.0.12_7_openj9-0.27.0.tar.gz
+# compiles with eclipse temurin jdk 17
+JDK=https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.9%2B9/OpenJDK17U-jdk_x64_linux_hotspot_17.0.9_9.tar.gz
 curl -sL $JDK | sudo tar xzvf - -C /usr/local
 JAVA="$(which java)"
 sudo mv "$JAVA" "$JAVA"."$(date +%s)"
diff --git a/tools/jenkins/apache/dockerhub.groovy b/tools/jenkins/apache/dockerhub.groovy
index 6573495..df5d294 100644
--- a/tools/jenkins/apache/dockerhub.groovy
+++ b/tools/jenkins/apache/dockerhub.groovy
@@ -30,7 +30,10 @@
       withCredentials([usernamePassword(credentialsId: 'openwhisk_dockerhub', passwordVariable: 'DOCKER_PASSWORD', usernameVariable: 'DOCKER_USER')]) {
           sh 'HOME="$WORKSPACE/local-docker-cfg" docker login -u ${DOCKER_USER} -p ${DOCKER_PASSWORD}'
       }
-      def PUSH_CMD = "./gradlew :core:controller:distDocker :core:scheduler:distDocker :core:invoker:distDocker :core:standalone:distDocker :core:monitoring:user-events:distDocker :tools:ow-utils:distDocker :core:cosmos:cache-invalidator:distDocker -PdockerRegistry=docker.io -PdockerImagePrefix=openwhisk"
+      sh "docker run -it --rm --userns=host --privileged tonistiigi/binfmt --install all"
+      sh "docker buildx create --name owbuilder"
+      sh "docker buildx use owbuilder"
+      def PUSH_CMD = "./gradlew :core:controller:distDocker :core:scheduler:distDocker :core:invoker:distDocker :core:standalone:distDocker :core:monitoring:user-events:distDocker :tools:ow-utils:distDocker :core:cosmos:cache-invalidator:distDocker -PdockerRegistry=docker.io -PdockerImagePrefix=openwhisk -PdockerMultiArchBuild=true"
       def gitCommit = sh(returnStdout: true, script: 'git rev-parse HEAD').trim()
       def shortCommit = gitCommit.take(7)
       sh "./gradlew clean"
@@ -40,6 +43,7 @@
   }
 
   stage("Clean") {
+    sh "docker buildx rm owbuilder"
     sh "docker images"
     sh 'docker rmi -f $(docker images -f "reference=openwhisk/*" -q) || true'
     sh "docker images"
diff --git a/tools/macos/README.md b/tools/macos/README.md
index 964bb94..658529f 100644
--- a/tools/macos/README.md
+++ b/tools/macos/README.md
@@ -105,6 +105,7 @@
 ansible-playbook couchdb.yml
 ansible-playbook initdb.yml
 ansible-playbook wipe.yml
+ansible-playbook downloadcli-github.yml
 
 ansible-playbook properties.yml
 ```
diff --git a/tools/ow-utils/Dockerfile b/tools/ow-utils/Dockerfile
index b6eb7de..75f9fe4 100644
--- a/tools/ow-utils/Dockerfile
+++ b/tools/ow-utils/Dockerfile
@@ -17,10 +17,10 @@
 
 FROM adoptopenjdk/openjdk8:jdk8u262-b10
 
-ENV DOCKER_VERSION 1.12.0
-ENV KUBECTL_VERSION v1.16.3
-ENV WHISK_CLI_VERSION latest
-ENV WHISKDEPLOY_CLI_VERSION latest
+ENV DOCKER_VERSION=1.12.0
+ENV KUBECTL_VERSION=v1.16.3
+ENV WHISK_CLI_VERSION=latest
+ENV WHISKDEPLOY_CLI_VERSION=latest
 
 RUN apt-get update && apt-get install -y \
   git \
diff --git a/tools/ow-utils/Dockerfile.arm b/tools/ow-utils/Dockerfile.arm
index f319c9c..44d1ac0 100644
--- a/tools/ow-utils/Dockerfile.arm
+++ b/tools/ow-utils/Dockerfile.arm
@@ -17,10 +17,10 @@
 
 FROM arm64v8/eclipse-temurin:8u422-b05-jdk-noble
 
-ENV DOCKER_VERSION 1.12.0
-ENV KUBECTL_VERSION v1.16.3
-ENV WHISK_CLI_VERSION latest
-ENV WHISKDEPLOY_CLI_VERSION latest
+ENV DOCKER_VERSION=1.12.0
+ENV KUBECTL_VERSION=v1.16.3
+ENV WHISK_CLI_VERSION=latest
+ENV WHISKDEPLOY_CLI_VERSION=latest
 
 RUN apt-get update && apt-get install -y \
   git \