From 8d8aa44f405c0e3df88d81f0571c264a3fabc8df Mon Sep 17 00:00:00 2001 From: Francesco Timperi Tiberi Date: Sun, 14 Dec 2025 17:08:37 +0100 Subject: [PATCH 1/6] fix: bump zookeeper to version 3.6.9 to OW2 usage with legacy LB --- core/invoker/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/invoker/build.gradle b/core/invoker/build.gradle index 2a4164cecb2..eaffa243e6c 100644 --- a/core/invoker/build.gradle +++ b/core/invoker/build.gradle @@ -48,7 +48,7 @@ dependencies { implementation ("org.apache.curator:curator-recipes:${gradle.curator.version}") { exclude group: 'org.apache.zookeeper', module:'zookeeper' } - implementation ("org.apache.zookeeper:zookeeper:3.4.14") { + implementation ("org.apache.zookeeper:zookeeper:3.5.9") { exclude group: 'org.slf4j' exclude group: 'log4j' exclude group: 'jline' From daacdd20e5eb8bae6122d60b99b8c5b4e6bb82e4 Mon Sep 17 00:00:00 2001 From: Francesco Timperi Tiberi Date: Sun, 14 Dec 2025 17:08:37 +0100 Subject: [PATCH 2/6] fix: bump zookeeper to version 3.6.9 to OW2 usage with legacy LB --- core/invoker/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/invoker/build.gradle b/core/invoker/build.gradle index 2a4164cecb2..eaffa243e6c 100644 --- a/core/invoker/build.gradle +++ b/core/invoker/build.gradle @@ -48,7 +48,7 @@ dependencies { implementation ("org.apache.curator:curator-recipes:${gradle.curator.version}") { exclude group: 'org.apache.zookeeper', module:'zookeeper' } - implementation ("org.apache.zookeeper:zookeeper:3.4.14") { + implementation ("org.apache.zookeeper:zookeeper:3.5.9") { exclude group: 'org.slf4j' exclude group: 'log4j' exclude group: 'jline' From 5b828bd6833121fa83213a5622788c1dec6500fd Mon Sep 17 00:00:00 2001 From: Francesco Timperi Tiberi Date: Fri, 17 Jul 2026 22:04:22 +0000 Subject: [PATCH 3/6] fix(tests): bumping elastic search to version 7.17.29 to allow proper test execution also on apple silicon based machine --- ansible/group_vars/all | 2 +- .../templates/elasticsearch.yml.j2 | 60 +++++++++++++++---- tools/macos/README.md | 6 ++ 3 files changed, 57 insertions(+), 11 deletions(-) diff --git a/ansible/group_vars/all b/ansible/group_vars/all index 301ce385692..9c63f2d9988 100644 --- a/ansible/group_vars/all +++ b/ansible/group_vars/all @@ -352,7 +352,7 @@ couchdb: version: 2.3 elasticsearch: - version: 6.7.2 + version: 7.17.29 elasticsearch_connect_string: "{% set ret = [] %}\ {% for host in groups['elasticsearch'] %}\ diff --git a/ansible/roles/elasticsearch/templates/elasticsearch.yml.j2 b/ansible/roles/elasticsearch/templates/elasticsearch.yml.j2 index 1cd491a8eee..5ec24f6fb3f 100644 --- a/ansible/roles/elasticsearch/templates/elasticsearch.yml.j2 +++ b/ansible/roles/elasticsearch/templates/elasticsearch.yml.j2 @@ -1,23 +1,63 @@ +# Elastic Search 6.7.2 setup (kept for reference) +#cluster.name: "{{ db.elasticsearch.cluster_name }}" +#node.name: "{{ elasticsearch_name }}" +#network.host: 0.0.0.0 +#network.publish_host: {{ ansible_default_ipv4.address | default(ansible_host | default('127.0.0.1')) }} + +#http.port: 9200 +#transport.tcp.port: {{ transport_port }} + +# minimum_master_nodes need to be explicitly set when bound on a public IP +# set to 1 to allow single node clusters +# Details: https://github.com/elastic/elasticsearch/pull/17282 +#discovery.zen.ping.unicast.hosts: +#{% for es in groups['elasticsearch'] %} +# - {{ hostvars[es].ansible_host }}:{{ db.elasticsearch.base_transport_port|int + host_group.index(es)|int }} +#{% endfor %} +#discovery.zen.minimum_master_nodes: {{ (host_group|length / 2 + 1) | int}} + +#gateway.recover_after_nodes: {{ (host_group|length / 2 + 1) | int }} +#gateway.expected_nodes: {{ host_group|length }} +#gateway.recover_after_time: 5m + +#xpack.security.enabled: false +#bootstrap.memory_lock: true + +# Elastic Search 7.17.29 setup + cluster.name: "{{ db.elasticsearch.cluster_name }}" node.name: "{{ elasticsearch_name }}" + network.host: 0.0.0.0 network.publish_host: {{ ansible_default_ipv4.address | default(ansible_host | default('127.0.0.1')) }} http.port: 9200 -transport.tcp.port: {{ transport_port }} -# minimum_master_nodes need to be explicitly set when bound on a public IP -# set to 1 to allow single node clusters -# Details: https://github.com/elastic/elasticsearch/pull/17282 -discovery.zen.ping.unicast.hosts: +# Elasticsearch 7.x transport port +transport.port: {{ transport_port }} + +{% if host_group|length == 1 %} + +# Single node deployment (local OpenWhisk tests) +discovery.type: single-node + +{% else %} + +# Multi-node Elasticsearch 7.x cluster +discovery.seed_hosts: {% for es in groups['elasticsearch'] %} - {{ hostvars[es].ansible_host }}:{{ db.elasticsearch.base_transport_port|int + host_group.index(es)|int }} {% endfor %} -discovery.zen.minimum_master_nodes: {{ (host_group|length / 2 + 1) | int}} -gateway.recover_after_nodes: {{ (host_group|length / 2 + 1) | int }} -gateway.expected_nodes: {{ host_group|length }} -gateway.recover_after_time: 5m +cluster.initial_master_nodes: +{% for es in groups['elasticsearch'] %} + - {{ hostvars[es].ansible_host }} +{% endfor %} +{% endif %} + +# Disable security for OpenWhisk xpack.security.enabled: false -bootstrap.memory_lock: true + +# Allow memory locking +bootstrap.memory_lock: true \ No newline at end of file diff --git a/tools/macos/README.md b/tools/macos/README.md index 658529f8caa..f214b4331a3 100644 --- a/tools/macos/README.md +++ b/tools/macos/README.md @@ -102,9 +102,12 @@ Bellow are the ansible commands required to prepare your machine: cd ./ansible ansible-playbook setup.yml -e mode=HA +ansible-playbook prereq.yml ansible-playbook couchdb.yml ansible-playbook initdb.yml ansible-playbook wipe.yml +ansible-playbook elasticsearch.yml +ansible-playbook etcd.yml ansible-playbook downloadcli-github.yml ansible-playbook properties.yml @@ -114,5 +117,8 @@ To run the unit tests execute the command bellow from the project's root folder: ```bash # go back to project's root folder cd ../ + +export TESTCONTAINERS_RYUK_DISABLED="true" + ./gradlew -PtestSetName="REQUIRE_ONLY_DB" :tests:testCoverageLean ``` From e4d89ef024bcf1d2989ac6567f4e3fa6afada8c6 Mon Sep 17 00:00:00 2001 From: Francesco Timperi Tiberi Date: Sun, 19 Jul 2026 11:38:00 +0200 Subject: [PATCH 4/6] fix(tests): ensure ansible deploys zookepeer 3.5.9 as this version deps are needed by hte invoker when working in LB mode chore(tests): update ubuntu docker script to fix docker version to 200~7.3.1-1~ubuntu.22.04~jammy fix(tests): fixes issues in failing Elastic Search and MongoDB databases tests fix(test): using temurin 21 JRE --- ansible/group_vars/all | 6 +- .../templates/elasticsearch.yml.j2 | 58 +++---------------- ansible/roles/kafka/tasks/deploy.yml | 9 ++- ansible/roles/zookeeper/tasks/deploy.yml | 17 ++++-- common/scala/Dockerfile | 1 + core/invoker/build.gradle | 15 +++-- gradle/docker.gradle | 6 ++ tests/build.gradle | 4 +- .../ElasticSearchActivationStoreTests.scala | 10 +++- .../MongoDBAsyncStreamGraphTests.scala | 17 ++++-- tools/macos/runUnitTests.sh | 40 +++++++++++++ tools/ubuntu-setup/docker.sh | 33 ++++++----- 12 files changed, 130 insertions(+), 86 deletions(-) create mode 100755 tools/macos/runUnitTests.sh diff --git a/ansible/group_vars/all b/ansible/group_vars/all index 9c63f2d9988..bab9bc3c201 100644 --- a/ansible/group_vars/all +++ b/ansible/group_vars/all @@ -187,8 +187,8 @@ kafka_protocol_for_setup: "{{ kafka_protocol | default('PLAINTEXT') }}" zookeeper: image: - amd64: zookeeper:3.4 - arm64: arm64v8/zookeeper:3.4 + amd64: zookeeper:3.5.9 + arm64: arm64v8/zookeeper:3.5.9 port: 2181 zookeeper_connect_string: "{% set ret = [] %}\ @@ -352,7 +352,7 @@ couchdb: version: 2.3 elasticsearch: - version: 7.17.29 + version: 6.7.2 elasticsearch_connect_string: "{% set ret = [] %}\ {% for host in groups['elasticsearch'] %}\ diff --git a/ansible/roles/elasticsearch/templates/elasticsearch.yml.j2 b/ansible/roles/elasticsearch/templates/elasticsearch.yml.j2 index 5ec24f6fb3f..02584bb914d 100644 --- a/ansible/roles/elasticsearch/templates/elasticsearch.yml.j2 +++ b/ansible/roles/elasticsearch/templates/elasticsearch.yml.j2 @@ -1,63 +1,23 @@ -# Elastic Search 6.7.2 setup (kept for reference) -#cluster.name: "{{ db.elasticsearch.cluster_name }}" -#node.name: "{{ elasticsearch_name }}" -#network.host: 0.0.0.0 -#network.publish_host: {{ ansible_default_ipv4.address | default(ansible_host | default('127.0.0.1')) }} - -#http.port: 9200 -#transport.tcp.port: {{ transport_port }} - -# minimum_master_nodes need to be explicitly set when bound on a public IP -# set to 1 to allow single node clusters -# Details: https://github.com/elastic/elasticsearch/pull/17282 -#discovery.zen.ping.unicast.hosts: -#{% for es in groups['elasticsearch'] %} -# - {{ hostvars[es].ansible_host }}:{{ db.elasticsearch.base_transport_port|int + host_group.index(es)|int }} -#{% endfor %} -#discovery.zen.minimum_master_nodes: {{ (host_group|length / 2 + 1) | int}} - -#gateway.recover_after_nodes: {{ (host_group|length / 2 + 1) | int }} -#gateway.expected_nodes: {{ host_group|length }} -#gateway.recover_after_time: 5m - -#xpack.security.enabled: false -#bootstrap.memory_lock: true - -# Elastic Search 7.17.29 setup - cluster.name: "{{ db.elasticsearch.cluster_name }}" node.name: "{{ elasticsearch_name }}" - network.host: 0.0.0.0 network.publish_host: {{ ansible_default_ipv4.address | default(ansible_host | default('127.0.0.1')) }} http.port: 9200 +transport.tcp.port: {{ transport_port }} -# Elasticsearch 7.x transport port -transport.port: {{ transport_port }} - -{% if host_group|length == 1 %} - -# Single node deployment (local OpenWhisk tests) -discovery.type: single-node - -{% else %} - -# Multi-node Elasticsearch 7.x cluster -discovery.seed_hosts: +# minimum_master_nodes need to be explicitly set when bound on a public IP +# set to 1 to allow single node clusters +# Details: https://github.com/elastic/elasticsearch/pull/17282 +discovery.zen.ping.unicast.hosts: {% for es in groups['elasticsearch'] %} - {{ hostvars[es].ansible_host }}:{{ db.elasticsearch.base_transport_port|int + host_group.index(es)|int }} {% endfor %} +discovery.zen.minimum_master_nodes: {{ (host_group|length / 2 + 1) | int}} -cluster.initial_master_nodes: -{% for es in groups['elasticsearch'] %} - - {{ hostvars[es].ansible_host }} -{% endfor %} +gateway.recover_after_nodes: {{ (host_group|length / 2 + 1) | int }} +gateway.expected_nodes: {{ host_group|length }} +gateway.recover_after_time: 5m -{% endif %} - -# Disable security for OpenWhisk xpack.security.enabled: false - -# Allow memory locking bootstrap.memory_lock: true \ No newline at end of file diff --git a/ansible/roles/kafka/tasks/deploy.yml b/ansible/roles/kafka/tasks/deploy.yml index 6406990ac3d..04f20fd9e66 100644 --- a/ansible/roles/kafka/tasks/deploy.yml +++ b/ansible/roles/kafka/tasks/deploy.yml @@ -100,11 +100,10 @@ pull: "{{ kafka.pull_kafka | default(true) }}" - name: wait until the kafka server started up - shell: - (echo dump; sleep 1) | - nc {{hostvars[groups['zookeepers']|first].ansible_host}} {{zookeeper.port}} | - grep /brokers/ids/{{ groups['kafkas'].index(inventory_hostname) }} + shell: | + docker exec zookeeper0 /bin/bash -c "echo dump | nc 127.0.0.1 2181" | + grep "/brokers/ids/{{ groups['kafkas'].index(inventory_hostname) }}" register: result until: (result.rc == 0) - retries: 10 + retries: 20 delay: 5 diff --git a/ansible/roles/zookeeper/tasks/deploy.yml b/ansible/roles/zookeeper/tasks/deploy.yml index ae038b8eb73..9b114431cfe 100644 --- a/ansible/roles/zookeeper/tasks/deploy.yml +++ b/ansible/roles/zookeeper/tasks/deploy.yml @@ -37,12 +37,21 @@ env: TZ: "{{ docker.timezone }}" ZOO_MY_ID: "{{ groups['zookeepers'].index(inventory_hostname) + 1 }}" + # CRITICAL FIX 1: Turn off standalone mode capabilities completely + ZOO_STANDALONE_ENABLED: "false" + # Disable the embedded Jetty AdminServer to prevent port 8080 conflicts globally + ZOO_ADMINSERVER_ENABLED: "false" + # Disable 3.5 dynamic reconfiguration to keep OpenWhisk's static host lists working + ZOO_RECONFIG_ENABLED: "false" + # Whitelist the health status command so the netcat step passes + ZOO_4LW_COMMANDS_WHITELIST: "ruok,dump" + # CRITICAL FIX 2: Append ';2181' client configuration suffix to server entries for 3.5 quorum rules ZOO_SERVERS: "{% set zhosts = [] %} {% for host in groups['zookeepers'] %} {% if host == inventory_hostname %} - {{ zhosts.append('server.' + (loop.index|string) + '=' + '0.0.0.0:2888:3888') }} + {{ zhosts.append('server.' + (loop.index|string) + '=0.0.0.0:2888:3888;2181') }} {% else %} - {{ zhosts.append('server.' + (loop.index|string) + '=' + hostvars[host].ansible_host + ':' + ((2888+loop.index-1)|string) + ':' + ((3888+loop.index-1)|string) ) }} + {{ zhosts.append('server.' + (loop.index|string) + '=' + hostvars[host].ansible_host + ':' + ((2888+loop.index-1)|string) + ':' + ((3888+loop.index-1)|string) + ';2181' ) }} {% endif %} {% endfor %} {{ zhosts | join(' ') }}" @@ -53,8 +62,8 @@ pull: "{{ zookeeper.pull_zookeeper | default(true) }}" - name: wait until the Zookeeper in this host is up and running - action: shell (echo ruok; sleep 1) | nc {{ ansible_host }} {{ zookeeper.port + groups['zookeepers'].index(inventory_hostname) }} + shell: docker exec zookeeper{{ groups['zookeepers'].index(inventory_hostname) }} zkServer.sh status register: result - until: (result.rc == 0) and (result.stdout == 'imok') + until: result.rc == 0 retries: 36 delay: 5 diff --git a/common/scala/Dockerfile b/common/scala/Dockerfile index 9886f18c39b..38d8f4018b4 100644 --- a/common/scala/Dockerfile +++ b/common/scala/Dockerfile @@ -18,6 +18,7 @@ # 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) +# Use Eclipse Temurin 17 JRE FROM eclipse-temurin:21-jre ENV LANG=en_US.UTF-8 diff --git a/core/invoker/build.gradle b/core/invoker/build.gradle index eaffa243e6c..1493c55112e 100644 --- a/core/invoker/build.gradle +++ b/core/invoker/build.gradle @@ -48,10 +48,17 @@ dependencies { implementation ("org.apache.curator:curator-recipes:${gradle.curator.version}") { exclude group: 'org.apache.zookeeper', module:'zookeeper' } - implementation ("org.apache.zookeeper:zookeeper:3.5.9") { - exclude group: 'org.slf4j' - exclude group: 'log4j' - exclude group: 'jline' + + // Force absolute isolation so ZooKeeper cannot impact Elasticsearch client configurations globally + implementation("org.apache.zookeeper:zookeeper:3.5.9") { + transitive = false + exclude group: 'io.netty' + exclude group: 'com.fasterxml.jackson.core' + } + + // Manually add only the companion Jute data framework if the Invoker fails class lookups for it + implementation("org.apache.zookeeper:zookeeper-jute:3.5.9") { + transitive = false } } diff --git a/gradle/docker.gradle b/gradle/docker.gradle index 7621254d97f..fb53859cd32 100644 --- a/gradle/docker.gradle +++ b/gradle/docker.gradle @@ -69,6 +69,10 @@ if( !project.hasProperty('dockerBuildArgs') && dockerMultiArchBuild ) { dockerBuildArg += ['--build-arg','BASE='+scalaBaseImageName] } +if( project.hasProperty('dockerTargetPlatformsArgs') ) { + dockerBuildArg += ['--build-arg','TARGETPLATFORM='+project.dockerTargetPlatformsArgs] +} + def builDockerCommand(dockerFile) { def cmd = dockerBinary @@ -134,12 +138,14 @@ task distDockerCoverage() { def prepareBuildArgs(List buildArgs) { def result = ['build'] + if(project.hasProperty('dockerBuildArgs')) { buildArgs.addAll(dockerBuildArgs) } buildArgs.each {arg -> result += ['--build-arg', arg] } + result } diff --git a/tests/build.gradle b/tests/build.gradle index 3500d025016..d94a9728d5c 100644 --- a/tests/build.gradle +++ b/tests/build.gradle @@ -256,8 +256,8 @@ dependencies { implementation "software.amazon.awssdk:s3:2.46.17" implementation "com.microsoft.azure:azure-cosmos:3.7.6" - implementation 'org.testcontainers:elasticsearch:1.17.6' - implementation 'org.testcontainers:mongodb:1.17.1' + implementation 'org.testcontainers:elasticsearch:1.19.8' + implementation 'org.testcontainers:mongodb:1.19.8' implementation project(':common:scala') implementation project(':core:controller') implementation project(':core:scheduler') diff --git a/tests/src/test/scala/org/apache/openwhisk/core/database/elasticsearch/ElasticSearchActivationStoreTests.scala b/tests/src/test/scala/org/apache/openwhisk/core/database/elasticsearch/ElasticSearchActivationStoreTests.scala index e7ad5f16d32..44f4f8ae661 100644 --- a/tests/src/test/scala/org/apache/openwhisk/core/database/elasticsearch/ElasticSearchActivationStoreTests.scala +++ b/tests/src/test/scala/org/apache/openwhisk/core/database/elasticsearch/ElasticSearchActivationStoreTests.scala @@ -52,7 +52,10 @@ class ElasticSearchActivationStoreTests upto: Option[Instant] = None, context: UserContext, expected: IndexedSeq[WhiskActivation])(implicit transid: TransactionId): Unit = { - retry(super.checkQueryActivations(namespace, name, skip, limit, includeDocs, since, upto, context, expected), 10) + retry( + super.checkQueryActivations(namespace, name, skip, limit, includeDocs, since, upto, context, expected), + 10, + Some(500.milliseconds)) } override def checkCountActivations(namespace: String, @@ -62,6 +65,9 @@ class ElasticSearchActivationStoreTests upto: Option[Instant] = None, context: UserContext, expected: Long)(implicit transid: TransactionId): Unit = { - retry(super.checkCountActivations(namespace, name, skip, since, upto, context, expected), 10) + retry( + super.checkCountActivations(namespace, name, skip, since, upto, context, expected), + 10, + Some(500.milliseconds)) } } diff --git a/tests/src/test/scala/org/apache/openwhisk/core/database/mongodb/MongoDBAsyncStreamGraphTests.scala b/tests/src/test/scala/org/apache/openwhisk/core/database/mongodb/MongoDBAsyncStreamGraphTests.scala index 6320ac94376..b05bae4a76c 100644 --- a/tests/src/test/scala/org/apache/openwhisk/core/database/mongodb/MongoDBAsyncStreamGraphTests.scala +++ b/tests/src/test/scala/org/apache/openwhisk/core/database/mongodb/MongoDBAsyncStreamGraphTests.scala @@ -59,15 +59,16 @@ class MongoDBAsyncStreamGraphTests it should "close the stream when done" in { val bytes = randomBytes(4000) - val inputStream = new ByteArrayInputStream(bytes) - val spiedStream = spy(inputStream) - val asyncStream = AsyncStreamHelper.toAsyncInputStream(spiedStream) + // Replace the mockito spy with our safe native recording stream + val safeStream = new CloseRecordingInputStream(bytes) + val asyncStream = AsyncStreamHelper.toAsyncInputStream(safeStream) val readStream = MongoDBAsyncStreamSource(asyncStream, 42).runWith(StreamConverters.asInputStream()) val readBytes = IOUtils.toByteArray(readStream) bytes shouldBe readBytes - verify(spiedStream).close() + // Replace mockito verify() with a bulletproof boolean assertion + safeStream.closed shouldBe true } it should "onError with failure and return a failed IOResult when reading from failed stream" in { @@ -132,4 +133,12 @@ class MongoDBAsyncStreamGraphTests var closed: Boolean = _ override def close() = { super.close(); closed = true } } + + private class CloseRecordingInputStream(bytes: Array[Byte]) extends ByteArrayInputStream(bytes) { + @volatile var closed: Boolean = false + override def close(): Unit = { + super.close() + closed = true + } + } } diff --git a/tools/macos/runUnitTests.sh b/tools/macos/runUnitTests.sh new file mode 100755 index 00000000000..cd2a0822448 --- /dev/null +++ b/tools/macos/runUnitTests.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash + +# +# 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. +# + +set -e + +SCRIPTDIR=$(cd $(dirname "$0") && pwd) +ROOTDIR="$SCRIPTDIR/../.." + +cd $ROOTDIR/ansible + +ansible-playbook setup.yml -e mode=HA +ansible-playbook prereq.yml +ansible-playbook couchdb.yml +ansible-playbook initdb.yml +ansible-playbook wipe.yml +ansible-playbook elasticsearch.yml +ansible-playbook etcd.yml +ansible-playbook properties.yml + + +cd $ROOTDIR +# ./gradlew distDocker + +./gradlew -PtestSetName="REQUIRE_ONLY_DB" :tests:testCoverageLean diff --git a/tools/ubuntu-setup/docker.sh b/tools/ubuntu-setup/docker.sh index 702dd38e672..d2e84847cf9 100755 --- a/tools/ubuntu-setup/docker.sh +++ b/tools/ubuntu-setup/docker.sh @@ -19,24 +19,31 @@ set -e set -x -sudo sudo apt-get install -y apt-transport-https ca-certificates curl gnupg-agent software-properties-common -curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - -sudo apt-key fingerprint 0EBFCD88 +sudo apt-get update +sudo apt-get install -y ca-certificates curl gnupg -sudo add-apt-repository \ - "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" +# Add the GPG key signatures +sudo install -m 0755 -d /etc/apt/keyrings +curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg +sudo chmod a+r /etc/apt/keyrings/docker.gpg -sudo add-apt-repository \ - "deb [arch=$(uname -m | sed -e 's/x86_64/amd64/g')] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" -sudo apt-get -y update +# Register the stable Ubuntu Jammy APT source line channel +echo \ + "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ + $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \ + sudo tee /etc/apt/sources.list.d/docker.list > /dev/null -# AUFS -# Use '-virtual' package to support docker tests of the script -sudo apt-get --no-install-recommends -y install linux-image-extra-virtual +sudo apt-get update # DOCKER -sudo apt-get install -y docker-ce=18.06.3~ce~3-0~ubuntu containerd.io -sudo apt-mark hold docker-ce +# Force the exact target version +sudo apt-get install -y \ + docker-ce=5:27.3.1-1~ubuntu.22.04~jammy \ + docker-ce-cli=5:27.3.1-1~ubuntu.22.04~jammy \ + containerd.io + +# CRITICAL: Lock the packages so 'apt upgrade' cannot update them automatically later +sudo apt-mark hold docker-ce docker-ce-cli # enable (security - use 127.0.0.1) sudo -E bash -c 'echo '\''DOCKER_OPTS="-H unix:///var/run/docker.sock --storage-driver=aufs"'\'' >> /etc/default/docker' From bb1342c490a231da2d3e61bb2e99b2ed5a08cb47 Mon Sep 17 00:00:00 2001 From: Francesco Timperi Tiberi Date: Sun, 19 Jul 2026 19:15:46 +0200 Subject: [PATCH 5/6] chore(common): using eclipse-temurin:21-jre-alpine as baseimage --- common/scala/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/scala/Dockerfile b/common/scala/Dockerfile index 38d8f4018b4..f81ddd37831 100644 --- a/common/scala/Dockerfile +++ b/common/scala/Dockerfile @@ -19,7 +19,7 @@ # 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) # Use Eclipse Temurin 17 JRE -FROM eclipse-temurin:21-jre +FROM eclipse-temurin:21-jre-alpine ENV LANG=en_US.UTF-8 ENV LANGUAGE=en_US:en From 89634bc3802290ffc49ae4845edc32411b1866f1 Mon Sep 17 00:00:00 2001 From: Francesco Timperi Tiberi Date: Sun, 19 Jul 2026 19:19:59 +0200 Subject: [PATCH 6/6] chore: sticking to JRE 21 as common OW runtime --- common/scala/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/scala/Dockerfile b/common/scala/Dockerfile index f81ddd37831..38d8f4018b4 100644 --- a/common/scala/Dockerfile +++ b/common/scala/Dockerfile @@ -19,7 +19,7 @@ # 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) # Use Eclipse Temurin 17 JRE -FROM eclipse-temurin:21-jre-alpine +FROM eclipse-temurin:21-jre ENV LANG=en_US.UTF-8 ENV LANGUAGE=en_US:en