diff --git a/.github/workflows/docker-cbdb-build-containers.yml b/.github/workflows/docker-cbdb-build-containers.yml
index dd9ea9acd27..a3b2e42782e 100644
--- a/.github/workflows/docker-cbdb-build-containers.yml
+++ b/.github/workflows/docker-cbdb-build-containers.yml
@@ -60,6 +60,7 @@ on:
paths:
- 'devops/deploy/docker/build/rocky8/**'
- 'devops/deploy/docker/build/rocky9/**'
+ - 'devops/deploy/docker/build/rocky10/**'
- 'devops/deploy/docker/build/ubuntu22.04/**'
- 'devops/deploy/docker/build/ubuntu24.04/**'
pull_request:
@@ -81,7 +82,7 @@ jobs:
# Matrix strategy to build for both Rocky Linux 8 and 9, Ubuntu 22.04 and 24.04
strategy:
matrix:
- platform: ['rocky8', 'rocky9', 'ubuntu22.04', 'ubuntu24.04']
+ platform: ['rocky8', 'rocky9', 'rocky10', 'ubuntu22.04', 'ubuntu24.04']
steps:
# Checkout repository code with full history
@@ -108,6 +109,8 @@ jobs:
- 'devops/deploy/docker/build/rocky8/**'
rocky9:
- 'devops/deploy/docker/build/rocky9/**'
+ rocky10:
+ - 'devops/deploy/docker/build/rocky10/**'
ubuntu22.04:
- 'devops/deploy/docker/build/ubuntu22.04/**'
ubuntu24.04:
diff --git a/.github/workflows/docker-cbdb-test-containers.yml b/.github/workflows/docker-cbdb-test-containers.yml
index 1c8e1c8a9a2..b80c66aa748 100644
--- a/.github/workflows/docker-cbdb-test-containers.yml
+++ b/.github/workflows/docker-cbdb-test-containers.yml
@@ -49,6 +49,7 @@ on:
paths:
- 'devops/deploy/docker/test/rocky8/**'
- 'devops/deploy/docker/test/rocky9/**'
+ - 'devops/deploy/docker/test/rocky10/**'
- 'devops/deploy/docker/test/ubuntu22.04/**'
- 'devops/deploy/docker/test/ubuntu24.04/**'
pull_request:
@@ -68,7 +69,7 @@ jobs:
strategy:
matrix:
# Build for Rocky Linux 8 and 9, Ubuntu 22.04 and 24.04
- platform: ['rocky8', 'rocky9', 'ubuntu22.04', 'ubuntu24.04']
+ platform: ['rocky8', 'rocky9', 'rocky10', 'ubuntu22.04', 'ubuntu24.04']
steps:
# Checkout repository code
@@ -92,6 +93,8 @@ jobs:
- 'devops/deploy/docker/test/rocky8/**'
rocky9:
- 'devops/deploy/docker/test/rocky9/**'
+ rocky10:
+ - 'devops/deploy/docker/test/rocky10/**'
ubuntu22.04:
- 'devops/deploy/docker/test/ubuntu22.04/**'
ubuntu24.04:
diff --git a/devops/deploy/docker/build/rocky10/Dockerfile b/devops/deploy/docker/build/rocky10/Dockerfile
new file mode 100644
index 00000000000..63b16b4ff20
--- /dev/null
+++ b/devops/deploy/docker/build/rocky10/Dockerfile
@@ -0,0 +1,216 @@
+# --------------------------------------------------------------------
+#
+# 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.
+#
+# --------------------------------------------------------------------
+#
+# Apache Cloudberry (Incubating) is an effort undergoing incubation at
+# the Apache Software Foundation (ASF), sponsored by the Apache
+# Incubator PMC.
+#
+# Incubation is required of all newly accepted projects until a
+# further review indicates that the infrastructure, communications,
+# and decision making process have stabilized in a manner consistent
+# with other successful ASF projects.
+#
+# While incubation status is not necessarily a reflection of the
+# completeness or stability of the code, it does indicate that the
+# project has yet to be fully endorsed by the ASF.
+#
+# --------------------------------------------------------------------
+# Dockerfile for Apache Cloudberry Build Environment
+# --------------------------------------------------------------------
+# This Dockerfile sets up a Rocky Linux 9-based container for building
+# and developing Apache Cloudberry. It installs necessary system
+# utilities, development tools, and configures the environment for SSH
+# access and systemd support.
+#
+# Key Features:
+# - Locale setup for en_US.UTF-8
+# - SSH daemon setup for remote access
+# - Essential development tools and libraries installation
+# - User configuration for 'gpadmin' with sudo privileges
+#
+# Usage:
+# docker build -t cloudberry-db-env .
+# docker run -h cdw -it cloudberry-db-env
+# --------------------------------------------------------------------
+
+# Base image: Rocky Linux 10
+FROM rockylinux/rockylinux:10
+
+# Argument for configuring the timezone
+ARG TIMEZONE_VAR="America/Los_Angeles"
+
+# Environment variables for locale and user
+ENV container=docker
+ENV LANG=en_US.UTF-8
+ENV USER=gpadmin
+
+# --------------------------------------------------------------------
+# Install Development Tools and Utilities
+# --------------------------------------------------------------------
+# Install various development tools, system utilities, and libraries
+# required for building and running Apache Cloudberry.
+# - EPEL repository is enabled for additional packages.
+# - Cleanup steps are added to reduce image size after installation.
+# --------------------------------------------------------------------
+RUN dnf makecache && \
+ dnf install -y \
+ epel-release \
+ git && \
+ dnf makecache && \
+ dnf config-manager --disable epel && \
+ dnf install -y --enablerepo=epel \
+ bat \
+ libssh2-devel \
+ python3-devel \
+ htop && \
+ dnf install -y \
+ bison \
+ cmake3 \
+ ed \
+ file \
+ flex \
+ gcc \
+ gcc-c++ \
+ gdb \
+ glibc-langpack-en \
+ glibc-locale-source \
+ initscripts \
+ iproute \
+ less \
+ lsof \
+ m4 \
+ net-tools \
+ openssh-clients \
+ openssh-server \
+ perl \
+ rpm-build \
+ rpmdevtools \
+ rsync \
+ sudo \
+ tar \
+ unzip \
+ util-linux-ng \
+ wget \
+ sshpass \
+ which && \
+ dnf install -y \
+ apr-devel \
+ bzip2-devel \
+ java-21-openjdk \
+ java-21-openjdk-devel \
+ krb5-devel \
+ libcurl-devel \
+ libevent-devel \
+ libxml2-devel \
+ libuuid-devel \
+ libzstd-devel \
+ lz4 \
+ lz4-devel \
+ openldap-devel \
+ openssl-devel \
+ pam-devel \
+ perl-ExtUtils-Embed \
+ perl-Test-Simple \
+ perl-core \
+ python3-setuptools \
+ readline-devel \
+ zlib-devel && \
+ dnf install -y --enablerepo=crb \
+ liburing-devel \
+ libuv-devel \
+ libyaml-devel \
+ perl-IPC-Run \
+ python3-wheel \
+ protobuf-devel && \
+ dnf clean all && \
+ cd && XERCES_LATEST_RELEASE=3.3.0 && \
+ wget -nv "https://archive.apache.org/dist/xerces/c/3/sources/xerces-c-${XERCES_LATEST_RELEASE}.tar.gz" && \
+ echo "$(curl -sL https://archive.apache.org/dist/xerces/c/3/sources/xerces-c-${XERCES_LATEST_RELEASE}.tar.gz.sha256)" | sha256sum -c - && \
+ tar xf "xerces-c-${XERCES_LATEST_RELEASE}.tar.gz"; rm "xerces-c-${XERCES_LATEST_RELEASE}.tar.gz" && \
+ cd xerces-c-${XERCES_LATEST_RELEASE} && \
+ ./configure --prefix=/usr/local && \
+ make -j$(nproc) && \
+ make install -C ~/xerces-c-${XERCES_LATEST_RELEASE} && \
+ rm -rf ~/xerces-c* && \
+ cd && GO_VERSION="go1.23.4" && \
+ ARCH=$(uname -m) && \
+ if [ "${ARCH}" = "aarch64" ]; then \
+ GO_ARCH="arm64" && \
+ GO_SHA256="16e5017863a7f6071363782b1b8042eb12c6ca4f4cd71528b2123f0a1275b13e"; \
+ elif [ "${ARCH}" = "x86_64" ]; then \
+ GO_ARCH="amd64" && \
+ GO_SHA256="6924efde5de86fe277676e929dc9917d466efa02fb934197bc2eba35d5680971"; \
+ else \
+ echo "Unsupported architecture: ${ARCH}" && exit 1; \
+ fi && \
+ GO_URL="https://go.dev/dl/${GO_VERSION}.linux-${GO_ARCH}.tar.gz" && \
+ wget -nv "${GO_URL}" && \
+ echo "${GO_SHA256} ${GO_VERSION}.linux-${GO_ARCH}.tar.gz" | sha256sum -c - && \
+ tar xf "${GO_VERSION}.linux-${GO_ARCH}.tar.gz" && \
+ mv go "/usr/local/${GO_VERSION}" && \
+ ln -s "/usr/local/${GO_VERSION}" /usr/local/go && \
+ rm -f "${GO_VERSION}.linux-${GO_ARCH}.tar.gz" && \
+ echo 'export PATH=$PATH:/usr/local/go/bin' | tee -a /etc/profile.d/go.sh > /dev/null
+
+# --------------------------------------------------------------------
+# Copy Configuration Files and Setup the Environment
+# --------------------------------------------------------------------
+# - Copy custom configuration files from the build context to /tmp/.
+# - Apply custom system limits and timezone.
+# - Create and configure the 'gpadmin' user with sudo privileges.
+# - Set up SSH for password-based authentication.
+# - Generate locale and set the default locale to en_US.UTF-8.
+# --------------------------------------------------------------------
+
+# Copy configuration files from their respective locations
+COPY ./configs/* /tmp/
+
+RUN cp /tmp/90-cbdb-limits /etc/security/limits.d/90-cbdb-limits && \
+ sed -i.bak -r 's/^(session\s+required\s+pam_limits.so)/#\1/' /etc/pam.d/* && \
+ cat /usr/share/zoneinfo/${TIMEZONE_VAR} > /etc/localtime && \
+ chmod 777 /tmp/init_system.sh && \
+ /usr/sbin/groupadd gpadmin && \
+ /usr/sbin/useradd gpadmin -g gpadmin -G wheel && \
+ setcap cap_net_raw+ep /usr/bin/ping && \
+ echo 'gpadmin ALL=(ALL) NOPASSWD: ALL' > /etc/sudoers.d/90-gpadmin && \
+ echo -e '\n# Add Cloudberry entries\nif [ -f /usr/local/cbdb/cloudberry-env.sh ]; then\n source /usr/local/cbdb/cloudberry-env.sh\nfi' >> /home/gpadmin/.bashrc && \
+ ssh-keygen -A && \
+ echo "PasswordAuthentication yes" >> /etc/ssh/sshd_config && \
+ localedef -i en_US -f UTF-8 en_US.UTF-8 && \
+ echo "LANG=en_US.UTF-8" | tee /etc/locale.conf && \
+ dnf clean all # Final cleanup to remove unnecessary files
+
+# Install testinfra via pip
+RUN pip3 install pytest-testinfra
+
+# Copying test files into the container
+COPY ./tests /tests
+
+# --------------------------------------------------------------------
+# Set the Default User and Command
+# --------------------------------------------------------------------
+# The default user is set to 'gpadmin', and the container starts by
+# running the init_system.sh script. The container also mounts the
+# /sys/fs/cgroup volume for systemd compatibility.
+# --------------------------------------------------------------------
+USER gpadmin
+
+VOLUME [ "/sys/fs/cgroup" ]
+CMD ["bash","-c","/tmp/init_system.sh"]
diff --git a/devops/deploy/docker/build/rocky10/configs/90-cbdb-limits b/devops/deploy/docker/build/rocky10/configs/90-cbdb-limits
new file mode 100644
index 00000000000..474957c42f6
--- /dev/null
+++ b/devops/deploy/docker/build/rocky10/configs/90-cbdb-limits
@@ -0,0 +1,32 @@
+# /etc/security/limits.d/90-db-limits
+# --------------------------------------------------------------------
+#
+# 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.
+#
+# --------------------------------------------------------------------
+
+# Core dump file size limits for gpadmin
+gpadmin soft core unlimited
+gpadmin hard core unlimited
+
+# Open file limits for gpadmin
+gpadmin soft nofile 524288
+gpadmin hard nofile 524288
+
+# Process limits for gpadmin
+gpadmin soft nproc 131072
+gpadmin hard nproc 131072
diff --git a/devops/deploy/docker/build/rocky10/configs/gpinitsystem.conf b/devops/deploy/docker/build/rocky10/configs/gpinitsystem.conf
new file mode 100644
index 00000000000..d4d312231c5
--- /dev/null
+++ b/devops/deploy/docker/build/rocky10/configs/gpinitsystem.conf
@@ -0,0 +1,89 @@
+# --------------------------------------------------------------------
+#
+# 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.
+#
+# --------------------------------------------------------------------
+
+# --------------------------------------------------------------------
+# gpinitsystem Configuration File for Apache Cloudberry
+# --------------------------------------------------------------------
+# This configuration file is used to initialize an Apache Cloudberry
+# cluster. It defines the settings for the coordinator, primary segments,
+# and mirrors, as well as other important configuration options.
+# --------------------------------------------------------------------
+
+# Segment prefix - This prefix is used for naming the segment directories.
+# For example, the primary segment directories will be named gpseg0, gpseg1, etc.
+SEG_PREFIX=gpseg
+
+# Coordinator port - The port number where the coordinator will listen.
+# This is the port used by clients to connect to the database.
+COORDINATOR_PORT=5432
+
+# Coordinator hostname - The hostname of the machine where the coordinator
+# will be running. The $(hostname) command will automatically insert the
+# hostname of the current machine.
+COORDINATOR_HOSTNAME=$(hostname)
+
+# Coordinator data directory - The directory where the coordinator's data
+# will be stored. This directory should have enough space to store metadata
+# and system catalogs.
+COORDINATOR_DIRECTORY=/data1/coordinator
+
+# Base port for primary segments - The starting port number for the primary
+# segments. Each primary segment will use a unique port number starting from
+# this base.
+PORT_BASE=6000
+
+# Primary segment data directories - An array specifying the directories where
+# the primary segment data will be stored. Each directory corresponds to a
+# primary segment. In this case, two primary segments will be created in the
+# same directory.
+declare -a DATA_DIRECTORY=(/data1/primary /data1/primary)
+
+# Base port for mirror segments - The starting port number for the mirror
+# segments. Each mirror segment will use a unique port number starting from
+# this base.
+MIRROR_PORT_BASE=7000
+
+# Mirror segment data directories - An array specifying the directories where
+# the mirror segment data will be stored. Each directory corresponds to a
+# mirror segment. In this case, two mirror segments will be created in the
+# same directory.
+declare -a MIRROR_DATA_DIRECTORY=(/data1/mirror /data1/mirror)
+
+# Trusted shell - The shell program used for remote execution. Cloudberry uses
+# SSH to run commands on other machines in the cluster. 'ssh' is the default.
+TRUSTED_SHELL=ssh
+
+# Database encoding - The character set encoding to be used by the database.
+# 'UNICODE' is a common choice, especially for internationalization.
+ENCODING=UNICODE
+
+# Default database name - The name of the default database to be created during
+# initialization. This is also the default database that the gpadmin user will
+# connect to.
+DATABASE_NAME=gpadmin
+
+# Machine list file - A file containing the list of hostnames where the primary
+# segments will be created. Each line in the file represents a different machine.
+# This file is critical for setting up the cluster across multiple nodes.
+MACHINE_LIST_FILE=/home/gpadmin/hostfile_gpinitsystem
+
+# --------------------------------------------------------------------
+# End of gpinitsystem Configuration File
+# --------------------------------------------------------------------
diff --git a/devops/deploy/docker/build/rocky10/configs/init_system.sh b/devops/deploy/docker/build/rocky10/configs/init_system.sh
new file mode 100755
index 00000000000..d8c4a00b035
--- /dev/null
+++ b/devops/deploy/docker/build/rocky10/configs/init_system.sh
@@ -0,0 +1,192 @@
+#!/bin/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.
+#
+# --------------------------------------------------------------------
+## Container Initialization Script
+# --------------------------------------------------------------------
+## This script sets up the environment inside the Docker container for
+## the Apache Cloudberry Build Environment. It performs the following
+## tasks:
+##
+## 1. Verifies that the container is running with the expected hostname.
+## 2. Starts the SSH daemon to allow SSH access to the container.
+## 3. Configures passwordless SSH access for the 'gpadmin' user.
+## 4. Displays a welcome banner and system information.
+## 5. Starts an interactive bash shell.
+##
+## This script is intended to be used as an entrypoint or initialization
+## script for the Docker container.
+# --------------------------------------------------------------------
+
+# --------------------------------------------------------------------
+# Check if the hostname is 'cdw'
+# --------------------------------------------------------------------
+# The script checks if the container's hostname is set to 'cdw'. This is
+# a requirement for this environment, and if the hostname does not match,
+# the script will exit with an error message. This ensures consistency
+# across different environments.
+# --------------------------------------------------------------------
+if [ "$(hostname)" != "cdw" ]; then
+ echo "Error: This container must be run with the hostname 'cdw'."
+ echo "Use the following command: docker run -h cdw ..."
+ exit 1
+fi
+
+# --------------------------------------------------------------------
+# Start SSH daemon and setup for SSH access
+# --------------------------------------------------------------------
+# The SSH daemon is started to allow remote access to the container via
+# SSH. This is useful for development and debugging purposes. If the SSH
+# daemon fails to start, the script exits with an error.
+# --------------------------------------------------------------------
+if ! sudo /usr/sbin/sshd; then
+ echo "Failed to start SSH daemon" >&2
+ exit 1
+fi
+
+# --------------------------------------------------------------------
+# Remove /run/nologin to allow logins
+# --------------------------------------------------------------------
+# The /run/nologin file, if present, prevents users from logging into
+# the system. This file is removed to ensure that users can log in via SSH.
+# --------------------------------------------------------------------
+sudo rm -rf /run/nologin
+
+# --------------------------------------------------------------------
+# Configure passwordless SSH access for 'gpadmin' user
+# --------------------------------------------------------------------
+# The script sets up SSH key-based authentication for the 'gpadmin' user,
+# allowing passwordless SSH access. It generates a new SSH key pair if one
+# does not already exist, and configures the necessary permissions.
+# --------------------------------------------------------------------
+mkdir -p /home/gpadmin/.ssh
+chmod 700 /home/gpadmin/.ssh
+
+if [ ! -f /home/gpadmin/.ssh/id_rsa ]; then
+ ssh-keygen -t rsa -b 4096 -C gpadmin -f /home/gpadmin/.ssh/id_rsa -P "" > /dev/null 2>&1
+fi
+
+cat /home/gpadmin/.ssh/id_rsa.pub >> /home/gpadmin/.ssh/authorized_keys
+chmod 600 /home/gpadmin/.ssh/authorized_keys
+
+# Add the container's hostname to the known_hosts file to avoid SSH warnings
+ssh-keyscan -t rsa cdw > /home/gpadmin/.ssh/known_hosts 2>/dev/null
+
+# Change to the home directory of the current user
+cd $HOME
+
+# --------------------------------------------------------------------
+# Display a Welcome Banner
+# --------------------------------------------------------------------
+# The following ASCII art and welcome message are displayed when the
+# container starts. This banner provides a visual indication that the
+# container is running in the Apache Cloudberry Build Environment.
+# --------------------------------------------------------------------
+cat <<-'EOF'
+
+======================================================================
+
+ ++++++++++ ++++++
+ ++++++++++++++ +++++++
+ ++++ +++++ ++++
+ ++++ +++++++++
+ =+==== =============+
+ ======== =====+ =====
+ ==== ==== ==== ====
+ ==== === === ====
+ ==== === === ====
+ ==== === ==-- ===
+ ===== ===== -- ====
+ ===================== ======
+ ============================
+ =-----=
+ ____ _ _ _
+ / ___|| | ___ _ _ __| || |__ ___ _ __ _ __ _ _
+ | | | | / _ \ | | | | / _` || '_ \ / _ \| '__|| '__|| | | |
+ | |___ | || (_) || |_| || (_| || |_) || __/| | | | | |_| |
+ \____||_| \____ \__,_| \__,_||_.__/ \___||_| |_| \__, |
+ |___/
+----------------------------------------------------------------------
+
+EOF
+
+# --------------------------------------------------------------------
+# Display System Information
+# --------------------------------------------------------------------
+# The script sources the /etc/os-release file to retrieve the operating
+# system name and version. It then displays the following information:
+# - OS name and version
+# - Current user
+# - Container hostname
+# - IP address
+# - CPU model name and number of cores
+# - Total memory available
+# This information is useful for users to understand the environment they
+# are working in.
+# --------------------------------------------------------------------
+source /etc/os-release
+
+# First, create the CPU info detection function
+get_cpu_info() {
+ ARCH=$(uname -m)
+ if [ "$ARCH" = "x86_64" ]; then
+ lscpu | grep 'Model name:' | awk '{print substr($0, index($0,$3))}'
+ elif [ "$ARCH" = "aarch64" ]; then
+ VENDOR=$(lscpu | grep 'Vendor ID:' | awk '{print $3}')
+ if [ "$VENDOR" = "Apple" ] || [ "$VENDOR" = "0x61" ]; then
+ echo "Apple Silicon ($ARCH)"
+ else
+ if [ -f /proc/cpuinfo ]; then
+ IMPL=$(grep "CPU implementer" /proc/cpuinfo | head -1 | awk '{print $3}')
+ PART=$(grep "CPU part" /proc/cpuinfo | head -1 | awk '{print $3}')
+ if [ ! -z "$IMPL" ] && [ ! -z "$PART" ]; then
+ echo "ARM $ARCH (Implementer: $IMPL, Part: $PART)"
+ else
+ echo "ARM $ARCH"
+ fi
+ else
+ echo "ARM $ARCH"
+ fi
+ fi
+ else
+ echo "Unknown architecture: $ARCH"
+ fi
+}
+
+cat <<-EOF
+Welcome to the Apache Cloudberry Build Environment!
+
+Container OS ........ : $NAME $VERSION
+User ................ : $(whoami)
+Container hostname .. : $(hostname)
+IP Address .......... : $(hostname -I | awk '{print $1}')
+CPU Info ............ : $(get_cpu_info)
+CPU(s) .............. : $(nproc)
+Memory .............. : $(free -h | grep Mem: | awk '{print $2}') total
+======================================================================
+
+EOF
+
+# --------------------------------------------------------------------
+# Start an interactive bash shell
+# --------------------------------------------------------------------
+# Finally, the script starts an interactive bash shell to keep the
+# container running and allow the user to interact with the environment.
+# --------------------------------------------------------------------
+/bin/bash
diff --git a/devops/deploy/docker/build/rocky10/tests/requirements.txt b/devops/deploy/docker/build/rocky10/tests/requirements.txt
new file mode 100644
index 00000000000..b9711eddac5
--- /dev/null
+++ b/devops/deploy/docker/build/rocky10/tests/requirements.txt
@@ -0,0 +1,3 @@
+testinfra
+pytest-testinfra
+paramiko
diff --git a/devops/deploy/docker/build/rocky10/tests/testinfra/test_cloudberry_db_env.py b/devops/deploy/docker/build/rocky10/tests/testinfra/test_cloudberry_db_env.py
new file mode 100644
index 00000000000..9da7929ff98
--- /dev/null
+++ b/devops/deploy/docker/build/rocky10/tests/testinfra/test_cloudberry_db_env.py
@@ -0,0 +1,129 @@
+# --------------------------------------------------------------------
+#
+# 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.
+#
+# --------------------------------------------------------------------
+
+import testinfra
+
+def test_installed_packages(host):
+ """
+ Test if the essential packages are installed.
+ """
+ packages = [
+ "epel-release",
+ "git",
+ "the_silver_searcher",
+ "bat",
+ "htop",
+ "bison",
+ "cmake",
+ "gcc",
+ "gcc-c++",
+ "glibc-langpack-en",
+ "glibc-locale-source",
+ "openssh-clients",
+ "openssh-server",
+ "sudo",
+ "rsync",
+ "wget",
+ "openssl-devel",
+ "python3-devel",
+ "python3-pytest",
+ "readline-devel",
+ "zlib-devel",
+ "libcurl-devel",
+ "libevent-devel",
+ "libxml2-devel",
+ "libuuid-devel",
+ "libzstd-devel",
+ "lz4",
+ "openldap-devel",
+ "libuv-devel",
+ "libyaml-devel"
+ ]
+ for package in packages:
+ pkg = host.package(package)
+ assert pkg.is_installed
+
+
+def test_user_gpadmin_exists(host):
+ """
+ Test if the gpadmin user exists and is configured properly.
+ """
+ user = host.user("gpadmin")
+ assert user.exists
+ assert "wheel" in user.groups
+
+
+def test_ssh_service(host):
+ """
+ Test if SSH service is configured correctly.
+ """
+ sshd_config = host.file("/etc/ssh/sshd_config")
+ assert sshd_config.exists
+
+
+def test_locale_configured(host):
+ """
+ Test if the locale is configured correctly.
+ """
+ locale_conf = host.file("/etc/locale.conf")
+ assert locale_conf.exists
+ assert locale_conf.contains("LANG=en_US.UTF-8")
+
+
+def test_timezone(host):
+ """
+ Test if the timezone is configured correctly.
+ """
+ localtime = host.file("/etc/localtime")
+ assert localtime.exists
+
+
+def test_system_limits_configured(host):
+ """
+ Test if the custom system limits are applied.
+ """
+ limits_file = host.file("/etc/security/limits.d/90-cbdb-limits")
+ assert limits_file.exists
+
+
+def test_init_system_script(host):
+ """
+ Test if the init_system.sh script is present and executable.
+ """
+ script = host.file("/tmp/init_system.sh")
+ assert script.exists
+ assert script.mode == 0o777
+
+
+def test_custom_configuration_files(host):
+ """
+ Test if custom configuration files are correctly copied.
+ """
+ config_file = host.file("/tmp/90-cbdb-limits")
+ assert config_file.exists
+
+
+def test_locale_generated(host):
+ """
+ Test if the en_US.UTF-8 locale is correctly generated.
+ """
+ locale = host.run("locale -a | grep en_US.utf8")
+ assert locale.exit_status == 0
+ assert "en_US.utf8" in locale.stdout
diff --git a/devops/deploy/docker/test/rocky10/Dockerfile b/devops/deploy/docker/test/rocky10/Dockerfile
new file mode 100644
index 00000000000..aab580ce7d8
--- /dev/null
+++ b/devops/deploy/docker/test/rocky10/Dockerfile
@@ -0,0 +1,135 @@
+# --------------------------------------------------------------------
+#
+# 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.
+#
+# --------------------------------------------------------------------
+#
+# Apache Cloudberry (Incubating) is an effort undergoing incubation at
+# the Apache Software Foundation (ASF), sponsored by the Apache
+# Incubator PMC.
+#
+# Incubation is required of all newly accepted projects until a
+# further review indicates that the infrastructure, communications,
+# and decision making process have stabilized in a manner consistent
+# with other successful ASF projects.
+#
+# While incubation status is not necessarily a reflection of the
+# completeness or stability of the code, it does indicate that the
+# project has yet to be fully endorsed by the ASF.
+#
+# --------------------------------------------------------------------
+# Dockerfile for Apache Cloudberry Base Environment
+# --------------------------------------------------------------------
+# This Dockerfile sets up a Rocky Linux 9-based container to serve as
+# a base environment for evaluating the Apache Cloudberry. It installs
+# necessary system utilities, configures the environment for SSH access,
+# and sets up a 'gpadmin' user with sudo privileges. The Cloudberry
+# Database RPM can be installed into this container for testing and
+# functional verification.
+#
+# Key Features:
+# - Locale setup for en_US.UTF-8
+# - SSH daemon setup for remote access
+# - Essential system utilities installation
+# - Separate user creation and configuration steps
+#
+# Security Considerations:
+# - This Dockerfile prioritizes ease of use for functional testing and
+# evaluation. It includes configurations such as passwordless sudo access
+# for the 'gpadmin' user and SSH access with password authentication.
+# - These configurations are suitable for testing and development but
+# should NOT be used in a production environment due to potential security
+# risks.
+#
+# Usage:
+# docker build -t cloudberry-db-base-env .
+# docker run -h cdw -it cloudberry-db-base-env
+# --------------------------------------------------------------------
+
+# Base image: Rocky Linux 10
+FROM rockylinux/rockylinux:10
+
+# Argument for configuring the timezone
+ARG TIMEZONE_VAR="America/Los_Angeles"
+
+# Environment variables for locale
+ENV LANG=en_US.UTF-8
+
+# --------------------------------------------------------------------
+# System Update and Installation
+# --------------------------------------------------------------------
+# Update the system and install essential system utilities required for
+# running and testing Apache Cloudberry. Cleanup the DNF cache afterward
+# to reduce the image size.
+# --------------------------------------------------------------------
+RUN dnf install -y \
+ file \
+ gdb \
+ glibc-locale-source \
+ make \
+ openssh \
+ openssh-clients \
+ openssh-server \
+ procps-ng \
+ sudo \
+ which \
+ && \
+ dnf clean all # Clean up DNF cache after package installations
+
+# --------------------------------------------------------------------
+# User Creation and Configuration
+# --------------------------------------------------------------------
+# - Create the 'gpadmin' user and group.
+# - Configure the 'gpadmin' user with passwordless sudo privileges.
+# - Add Cloudberry-specific entries to the gpadmin's .bashrc.
+# --------------------------------------------------------------------
+RUN /usr/sbin/groupadd gpadmin && \
+ /usr/sbin/useradd gpadmin -g gpadmin -G wheel && \
+ echo 'gpadmin ALL=(ALL) NOPASSWD: ALL' > /etc/sudoers.d/90-gpadmin && \
+ echo -e '\n# Add Cloudberry entries\nif [ -f /usr/local/cloudberry/cloudberry-env.sh ]; then\n source /usr/local/cloudberry/cloudberry-env.sh\n export COORDINATOR_DATA_DIRECTORY=/data1/coordinator/gpseg-1\nfi' >> /home/gpadmin/.bashrc
+
+# --------------------------------------------------------------------
+# Copy Configuration Files and Setup the Environment
+# --------------------------------------------------------------------
+# - Copy custom configuration files from the build context to /tmp/.
+# - Apply custom system limits and timezone.
+# - Set up SSH for password-based authentication.
+# - Generate locale and set the default locale to en_US.UTF-8.
+# --------------------------------------------------------------------
+COPY ./configs/* /tmp/
+
+RUN cp /tmp/90-cbdb-limits /etc/security/limits.d/90-cbdb-limits && \
+ sed -i.bak -r 's/^(session\s+required\s+pam_limits.so)/#\1/' /etc/pam.d/* && \
+ cat /usr/share/zoneinfo/${TIMEZONE_VAR} > /etc/localtime && \
+ chmod 777 /tmp/init_system.sh && \
+ setcap cap_net_raw+ep /usr/bin/ping && \
+ ssh-keygen -A && \
+ echo "PasswordAuthentication yes" >> /etc/ssh/sshd_config && \
+ localedef -i en_US -f UTF-8 en_US.UTF-8 && \
+ echo "LANG=en_US.UTF-8" | tee /etc/locale.conf
+
+# --------------------------------------------------------------------
+# Set the Default User and Command
+# --------------------------------------------------------------------
+# The default user is set to 'gpadmin', and the container starts by
+# running the init_system.sh script. This container serves as a base
+# environment, and the Apache Cloudberry RPM can be installed for
+# testing and functional verification.
+# --------------------------------------------------------------------
+USER gpadmin
+
+CMD ["bash","-c","/tmp/init_system.sh"]
diff --git a/devops/deploy/docker/test/rocky10/configs/90-cbdb-limits b/devops/deploy/docker/test/rocky10/configs/90-cbdb-limits
new file mode 100644
index 00000000000..474957c42f6
--- /dev/null
+++ b/devops/deploy/docker/test/rocky10/configs/90-cbdb-limits
@@ -0,0 +1,32 @@
+# /etc/security/limits.d/90-db-limits
+# --------------------------------------------------------------------
+#
+# 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.
+#
+# --------------------------------------------------------------------
+
+# Core dump file size limits for gpadmin
+gpadmin soft core unlimited
+gpadmin hard core unlimited
+
+# Open file limits for gpadmin
+gpadmin soft nofile 524288
+gpadmin hard nofile 524288
+
+# Process limits for gpadmin
+gpadmin soft nproc 131072
+gpadmin hard nproc 131072
diff --git a/devops/deploy/docker/test/rocky10/configs/gpinitsystem.conf b/devops/deploy/docker/test/rocky10/configs/gpinitsystem.conf
new file mode 100644
index 00000000000..bb8f38d4f2d
--- /dev/null
+++ b/devops/deploy/docker/test/rocky10/configs/gpinitsystem.conf
@@ -0,0 +1,87 @@
+# --------------------------------------------------------------------
+#
+# 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.
+#
+# ----------------------------------------------------------------------
+# gpinitsystem Configuration File for Apache Cloudberry
+# ----------------------------------------------------------------------
+# This configuration file is used to initialize a Apache Cloudberry
+# cluster. It defines the settings for the coordinator, primary segments,
+# and mirrors, as well as other important configuration options.
+# ----------------------------------------------------------------------
+
+# Segment prefix - This prefix is used for naming the segment directories.
+# For example, the primary segment directories will be named gpseg0, gpseg1, etc.
+SEG_PREFIX=gpseg
+
+# Coordinator port - The port number where the coordinator will listen.
+# This is the port used by clients to connect to the database.
+COORDINATOR_PORT=5432
+
+# Coordinator hostname - The hostname of the machine where the coordinator
+# will be running. The $(hostname) command will automatically insert the
+# hostname of the current machine.
+COORDINATOR_HOSTNAME=$(hostname)
+
+# Coordinator data directory - The directory where the coordinator's data
+# will be stored. This directory should have enough space to store metadata
+# and system catalogs.
+COORDINATOR_DIRECTORY=/data1/coordinator
+
+# Base port for primary segments - The starting port number for the primary
+# segments. Each primary segment will use a unique port number starting from
+# this base.
+PORT_BASE=6000
+
+# Primary segment data directories - An array specifying the directories where
+# the primary segment data will be stored. Each directory corresponds to a
+# primary segment. In this case, two primary segments will be created in the
+# same directory.
+declare -a DATA_DIRECTORY=(/data1/primary /data1/primary)
+
+# Base port for mirror segments - The starting port number for the mirror
+# segments. Each mirror segment will use a unique port number starting from
+# this base.
+MIRROR_PORT_BASE=7000
+
+# Mirror segment data directories - An array specifying the directories where
+# the mirror segment data will be stored. Each directory corresponds to a
+# mirror segment. In this case, two mirror segments will be created in the
+# same directory.
+declare -a MIRROR_DATA_DIRECTORY=(/data1/mirror /data1/mirror)
+
+# Trusted shell - The shell program used for remote execution. Cloudberry uses
+# SSH to run commands on other machines in the cluster. 'ssh' is the default.
+TRUSTED_SHELL=ssh
+
+# Database encoding - The character set encoding to be used by the database.
+# 'UNICODE' is a common choice, especially for internationalization.
+ENCODING=UNICODE
+
+# Default database name - The name of the default database to be created during
+# initialization. This is also the default database that the gpadmin user will
+# connect to.
+DATABASE_NAME=gpadmin
+
+# Machine list file - A file containing the list of hostnames where the primary
+# segments will be created. Each line in the file represents a different machine.
+# This file is critical for setting up the cluster across multiple nodes.
+MACHINE_LIST_FILE=/home/gpadmin/hostfile_gpinitsystem
+
+# ----------------------------------------------------------------------
+# End of gpinitsystem Configuration File
+# ----------------------------------------------------------------------
diff --git a/devops/deploy/docker/test/rocky10/configs/init_system.sh b/devops/deploy/docker/test/rocky10/configs/init_system.sh
new file mode 100755
index 00000000000..3ea7e34b0ff
--- /dev/null
+++ b/devops/deploy/docker/test/rocky10/configs/init_system.sh
@@ -0,0 +1,221 @@
+#!/bin/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.
+#
+# --------------------------------------------------------------------
+# Container Initialization Script
+# --------------------------------------------------------------------
+# This script sets up the environment inside the Docker container for
+# the Apache Cloudberry Build Environment. It performs the following
+# tasks:
+#
+# 1. Verifies that the container is running with the expected hostname.
+# 2. Starts the SSH daemon to allow SSH access to the container.
+# 3. Configures passwordless SSH access for the 'gpadmin' user.
+# 4. Sets up the necessary directories and configuration files for
+# Apache Cloudberry.
+# 5. Displays a welcome banner and system information.
+# 6. Starts an interactive bash shell.
+#
+# This script is intended to be used as an entrypoint or initialization
+# script for the Docker container.
+# --------------------------------------------------------------------
+
+# --------------------------------------------------------------------
+# Check if the hostname is 'cdw'
+# --------------------------------------------------------------------
+# The script checks if the container's hostname is set to 'cdw'. This is
+# a requirement for this environment, and if the hostname does not match,
+# the script will exit with an error message. This ensures consistency
+# across different environments.
+# --------------------------------------------------------------------
+if [ "$(hostname)" != "cdw" ]; then
+ echo "Error: This container must be run with the hostname 'cdw'."
+ echo "Use the following command: docker run -h cdw ..."
+ exit 1
+fi
+
+# --------------------------------------------------------------------
+# Start SSH daemon and setup for SSH access
+# --------------------------------------------------------------------
+# The SSH daemon is started to allow remote access to the container via
+# SSH. This is useful for development and debugging purposes. If the SSH
+# daemon fails to start, the script exits with an error.
+# --------------------------------------------------------------------
+if ! sudo /usr/sbin/sshd; then
+ echo "Failed to start SSH daemon" >&2
+ exit 1
+fi
+
+# --------------------------------------------------------------------
+# Remove /run/nologin to allow logins
+# --------------------------------------------------------------------
+# The /run/nologin file, if present, prevents users from logging into
+# the system. This file is removed to ensure that users can log in via SSH.
+# --------------------------------------------------------------------
+sudo rm -rf /run/nologin
+
+# --------------------------------------------------------------------
+# Configure passwordless SSH access for 'gpadmin' user
+# --------------------------------------------------------------------
+# The script sets up SSH key-based authentication for the 'gpadmin' user,
+# allowing passwordless SSH access. It generates a new SSH key pair if one
+# does not already exist, and configures the necessary permissions.
+# --------------------------------------------------------------------
+mkdir -p /home/gpadmin/.ssh
+chmod 700 /home/gpadmin/.ssh
+
+if [ ! -f /home/gpadmin/.ssh/id_rsa ]; then
+ ssh-keygen -t rsa -b 4096 -C gpadmin -f /home/gpadmin/.ssh/id_rsa -P "" > /dev/null 2>&1
+fi
+
+cat /home/gpadmin/.ssh/id_rsa.pub >> /home/gpadmin/.ssh/authorized_keys
+chmod 600 /home/gpadmin/.ssh/authorized_keys
+
+# Add the container's hostname to the known_hosts file to avoid SSH warnings
+ssh-keyscan -t rsa cdw > /home/gpadmin/.ssh/known_hosts 2>/dev/null
+
+# --------------------------------------------------------------------
+# Cloudberry Data Directories Setup
+# --------------------------------------------------------------------
+# The script sets up the necessary directories for Apache Cloudberry,
+# including directories for the coordinator, standby coordinator, primary
+# segments, and mirror segments. It also sets up the configuration files
+# required for initializing the database.
+# --------------------------------------------------------------------
+sudo rm -rf /data1/*
+sudo mkdir -p /data1/coordinator /data1/standby_coordinator /data1/primary /data1/mirror
+sudo chown -R gpadmin.gpadmin /data1
+
+# Copy the gpinitsystem configuration file to the home directory
+cp /tmp/gpinitsystem.conf /home/gpadmin
+
+# Set up the hostfile for cluster initialization
+echo $(hostname) > /home/gpadmin/hostfile_gpinitsystem
+
+# Change to the home directory of the current user
+cd $HOME
+
+# --------------------------------------------------------------------
+# Display a Welcome Banner
+# --------------------------------------------------------------------
+# The following ASCII art and welcome message are displayed when the
+# container starts. This banner provides a visual indication that the
+# container is running in the Apache Cloudberry Build Environment.
+# --------------------------------------------------------------------
+cat <<-'EOF'
+
+======================================================================
+
+ ++++++++++ ++++++
+ ++++++++++++++ +++++++
+ ++++ +++++ ++++
+ ++++ +++++++++
+ =+==== =============+
+ ======== =====+ =====
+ ==== ==== ==== ====
+ ==== === === ====
+ ==== === === ====
+ ==== === ==-- ===
+ ===== ===== -- ====
+ ===================== ======
+ ============================
+ =-----=
+ ____ _ _ _
+ / ___|| | ___ _ _ __| || |__ ___ _ __ _ __ _ _
+ | | | | / _ \ | | | | / _` || '_ \ / _ \| '__|| '__|| | | |
+ | |___ | || (_) || |_| || (_| || |_) || __/| | | | | |_| |
+ \____||_| \____ \__,_| \__,_||_.__/ \___||_| |_| \__, |
+ |___/
+----------------------------------------------------------------------
+
+EOF
+
+# --------------------------------------------------------------------
+# Display System Information
+# --------------------------------------------------------------------
+# The script sources the /etc/os-release file to retrieve the operating
+# system name and version. It then displays the following information:
+# - OS name and version
+# - Current user
+# - Container hostname
+# - IP address
+# - CPU model name and number of cores
+# - Total memory available
+# - Cloudberry version (if installed)
+# This information is useful for users to understand the environment they
+# are working in.
+# --------------------------------------------------------------------
+source /etc/os-release
+
+# First, create the CPU info detection function
+get_cpu_info() {
+ ARCH=$(uname -m)
+ if [ "$ARCH" = "x86_64" ]; then
+ lscpu | grep 'Model name:' | awk '{print substr($0, index($0,$3))}'
+ elif [ "$ARCH" = "aarch64" ]; then
+ VENDOR=$(lscpu | grep 'Vendor ID:' | awk '{print $3}')
+ if [ "$VENDOR" = "Apple" ] || [ "$VENDOR" = "0x61" ]; then
+ echo "Apple Silicon ($ARCH)"
+ else
+ if [ -f /proc/cpuinfo ]; then
+ IMPL=$(grep "CPU implementer" /proc/cpuinfo | head -1 | awk '{print $3}')
+ PART=$(grep "CPU part" /proc/cpuinfo | head -1 | awk '{print $3}')
+ if [ ! -z "$IMPL" ] && [ ! -z "$PART" ]; then
+ echo "ARM $ARCH (Implementer: $IMPL, Part: $PART)"
+ else
+ echo "ARM $ARCH"
+ fi
+ else
+ echo "ARM $ARCH"
+ fi
+ fi
+ else
+ echo "Unknown architecture: $ARCH"
+ fi
+}
+
+# Check if Apache Cloudberry is installed and display its version
+if rpm -q apache-cloudberry-db-incubating > /dev/null 2>&1; then
+ CBDB_VERSION=$(/usr/local/cbdb/bin/postgres --gp-version)
+else
+ CBDB_VERSION="Not installed"
+fi
+
+cat <<-EOF
+Welcome to the Apache Cloudberry Test Environment!
+
+Cloudberry version .. : $CBDB_VERSION
+Container OS ........ : $NAME $VERSION
+User ................ : $(whoami)
+Container hostname .. : $(hostname)
+IP Address .......... : $(hostname -I | awk '{print $1}')
+CPU Info ............ : $(get_cpu_info)
+CPU(s) .............. : $(nproc)
+Memory .............. : $(free -h | grep Mem: | awk '{print $2}') total
+======================================================================
+
+EOF
+
+# --------------------------------------------------------------------
+# Start an interactive bash shell
+# --------------------------------------------------------------------
+# Finally, the script starts an interactive bash shell to keep the
+# container running and allow the user to interact with the environment.
+# --------------------------------------------------------------------
+/bin/bash
diff --git a/pom.xml b/pom.xml
index bf1bd47b22d..a02fe3098bd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1748,7 +1748,8 @@ code or new licensing patterns.
devops/deploy/docker/build/rocky8/tests/requirements.txt
devops/deploy/docker/build/rocky9/tests/requirements.txt
- devops/deploy/docker/build/ubuntu22.04/tests/requirements.txt
+ devops/deploy/docker/build/rocky10/tests/requirements.txt
+ devops/deploy/docker/build/ubuntu22.04/tests/requirements.txt
devops/deploy/docker/build/ubuntu24.04/tests/requirements.txt