Ubuntu 22.04 安装 Apache Hop 2.19.0 指南

在 Ubuntu 22.04 上从零完整安装 Apache Hop 2.19.0 数据编排平台:前置依赖、官方包下载、项目与运行配置、转换与工作流实测执行,并说明 JVM 内存与卸载方式。

Apache HopApache Hop安装部署Apache大数据Ubuntu 22.042026/10/11

Ubuntu 22.04 安装 Apache Hop 2.19.0 指南

目标:在 Ubuntu 22.04 LTS 上从零完整安装 Apache Hop 2.19.0,配置 JDK、项目与运行配置,并用内置命令行实测创建、执行一个转换(pipeline)与一个工作流(workflow),全部命令与回显均为本机实测。本指南不涉及产品代码。

一、环境信息

项目值
操作系统Ubuntu 22.04.5 LTS(x86_64)
内核版本5.15.x
安装软件Apache Hop 2.19.0(官方 client 发行包)
运行 JDKOpenJDK 21.0.12.1 LTS(/usr/lib/jvm/java-21-openjdk-amd64)
安装目录/opt/apache-hop/hop
数据/项目目录/opt/data/apache-hop/project
日志目录/opt/data/apache-hop/logs
本地 Web 日志端口8080(hop server 选装)
示例账号root,示例密码 q1w2e3r4

💡 说明:Apache Hop 是 Apache 软件基金会(ASF)开源的数据编排与数据集成平台(ETL/ELT 工具),前身是 Kettle/PDI。它通过「转换(pipeline,.hpl)」与「工作流(workflow,.hwf)」两种可执行单元完成数据抽取、转换、加载与编排,可无图形界面地以 hop / hop-run 命令行在服务器上运行。

二、前置条件

安装前确认以下条件满足:

  1. 系统为 Ubuntu 22.04 LTS,可用 apt 安装软件包。验证系统版本:
cat /etc/os-release | head -3

实测回显(节选):

PRETTY_NAME="Ubuntu 22.04.5 LTS"
NAME="Ubuntu"
VERSION_ID="22.04"
  1. 具备 root 权限。下文所有安装类命令均以 root 身份执行;普通用户使用时请加 sudo。

  2. 可访问 Apache 下载站。本文使用官方发行镜像站 https://dlcdn.apache.org(实测 HTTP/2 200 可达)。

  3. 必装解压工具 unzip。Apache Hop 官方交付的是 .zip 发行包,先安装解压工具:

apt-get update
apt-get install -y unzip

实测回显(节选):

Reading package lists... Done
Setting up unzip (6.0-...+1ubuntu...)

💡 说明:Hop 官方将完整功能发行包统一命名为 apache-hop-client-<版本>.zip(客户端发行包,内含全部命令脚本与插件),本指南基于该发行包部署。

三、版本选型说明

3.1 当前版本与发行包

截至本文成稿,Apache Hop 官方发布站 https://dlcdn.apache.org/hop/ 可用的最新稳定版为 2.19.0(2026-08-17 发布)。历史版本包括 2.18.1、2.18.0、2.17.0、2.10.0 等,发行包命名规律均为 apache-hop-client-<版本>.zip(约 330MB,含命令脚本、插件与依赖库)。

3.2 JDK 版本要求(重要)

实测确认:Apache Hop 2.19.0 编译目标为 JDK 21(字节码版本 65.0),必须使用 JDK 21 运行。若误用 JDK 17,启动会直接报 UnsupportedClassVersionError。JDK 11/17 适用于较早的 Hop 1.x 与部分早期 2.x 版本,安装 2.19.0 请务必选用 JDK 21。

组件推荐版本实测结果
JDK21(LTS,如 21.0.12.1)✅ 可正常运行
JDK17(如 17.0.20.1)❌ 报 UnsupportedClassVersionError,不可运行
JDK11(如 11.0.32.1)不适用 2.19.0,仅适用旧版本

3.3 版本选择建议

  • 生产环境推荐直接采用当前最新稳定版 2.19.0,配套 JDK 21 LTS。
  • 若受内网管制无法访问外网,可在可联网机器下载 apache-hop-client-2.19.0.zip 后离线传输并解压部署。
  • 升级时只需替换 /opt/apache-hop/hop 下的发行包并复用已有项目目录即可,配置相对路径使用 ${PROJECT_HOME},不受安装目录变更影响。

四、部署步骤

4.1 安装 JDK 21 并确认 JAVA_HOME

2.19.0 要求 JDK 21。若系统未安装,则通过 apt 安装:

apt-get install -y openjdk-21-jre-headless

查看已安装的 JDK 目录列表,确认存在 java-21-openjdk-amd64:

ls /usr/lib/jvm/

实测回显:

java-1.11.0-openjdk-amd64
java-1.17.0-openjdk-amd64
java-1.21.0-openjdk-amd64
java-11-openjdk-amd64
java-17-openjdk-amd64
java-21-openjdk-amd64
openjdk-11
openjdk-17
openjdk-21

确认 JDK 21 版本信息:

/usr/lib/jvm/java-21-openjdk-amd64/bin/java -version

实测回显:

openjdk version "21.0.12.1" 2026-08-18
OpenJDK Runtime Environment (build 21.0.12.1+1-1-22.04.4-Ubuntu)
OpenJDK 64-Bit Server VM (build 21.0.12.1+1-1-22.04.4-Ubuntu, mixed mode, sharing)

4.2 下载解压并安装 Hop 2.19.0

创建安装目录,并下载官方发行包(下至临时目录 /tmp):

mkdir -p /opt/apache-hop
curl -sO https://dlcdn.apache.org/hop/2.19.0/apache-hop-client-2.19.0.zip
ls -lh /tmp/apache-hop-client-2.19.0.zip

实测回显:

-rw-r--r-- 1 root root 333M Oct 11 05:41 /tmp/apache-hop-client-2.19.0.zip

解压发行包到安装目录:

unzip -q /tmp/apache-hop-client-2.19.0.zip -d /opt/apache-hop/
ls -la /opt/apache-hop/hop/ | head -20

实测回显(节选,可见主命令脚本 hop 及 hop-run.sh 等工具脚本位于安装目录顶层):

drwxr-xr-x  8 root root   4096 Aug 12 11:19 .
-rw-r--r--  1 root root 142529 Aug 12 11:19 LICENSE
-rw-r--r--  1 root root    753 Aug 12 11:19 NOTICE
-rw-r--r--  1 root root   2545 Aug 12 11:19 README.txt
drwxr-xr-x  3 root root   4096 Aug 12 11:19 config
-rwxr-xr-x  1 root root   5512 Aug 12 11:19 hop
-rwxr-xr-x  1 root root   4738 Aug 12 11:19 hop-conf.sh
-rwxr-xr-x  1 root root   4686 Aug 12 11:19 hop-encrypt.sh
-rwxr-xr-x  1 root root   5332 Aug 12 11:19 hop-gui.sh
-rwxr-xr-x  1 root root   4737 Aug 12 11:19 hop-run.sh
-rwxr-xr-x  1 root root   4740 Aug 12 11:19 hop-search.sh
-rwxr-xr-x  1 root root   4999 Aug 12 11:19 hop-server.sh
drwxr-xr-x  5 root root   4096 Aug 12 11:19 lib
drwxr-xr-x 10 root root   4096 Aug 12 11:19 plugins
drwxr-xr-x  2 root root   4096 Aug 12 11:19 pwd

⚠️ 注意:本发行包把 hop、hop-run.sh 等脚本放在安装目录顶层(父目录即安装目录,无 bin/ 子目录),可直接把 <安装目录>(即 /opt/apache-hop/hop)加入 PATH。

4.3 配置环境变量并验证版本

把 Java、Hop 环境变量写入 /etc/profile.d/hop-env.sh,使登录 shell 自动加载:

cat > /etc/profile.d/hop-env.sh <<'EOF'
# Apache Hop environment
export JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64
export HOP_HOME=/opt/apache-hop/hop
export PATH="$HOP_HOME:$PATH"
export HOP_OPTIONS="-Xms256m -Xmx512m"
EOF
chmod 644 /etc/profile.d/hop-env.sh

💡 说明:HOP_OPTIONS 控制 Hop Java 进程的默认 JVM 参数。Hop 启动脚本默认堆上限为 -Xmx2048m,此处主动覆盖为 -Xms256m -Xmx512m,将堆限制在 256–512MB(见「五、配置说明」中的 JVM 内存专项)。

重新加载环境变量后验证 Java 与 Hop 均已就绪:

source /etc/profile.d/hop-env.sh
echo "JAVA_HOME=$JAVA_HOME"
echo "HOP_HOME=$HOP_HOME"
echo "HOP_OPTIONS=$HOP_OPTIONS"
hop --version

实测回显:

JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64
HOP_HOME=/opt/apache-hop/hop
HOP_OPTIONS=-Xms256m -Xmx512m
2.19.0

⚠️ 注意:实测 hop --version 会正确打印版本号 2.19.0,但该命令(以及 hop --help)退出码为 1,这是 Hop 命令行对 help/version 分支的既有行为,拉到版本标识即为成功,请勿将其误判为失败。

4.4 初始化项目目录与运行配置

Hop 采用「项目(Project)驱动」的配置模型:所有转换/工作流都必须位于项目的 PROJECT_HOME 之下,并配好本地运行配置才能执行。本文统一把数据目录 PROJECT_HOME 设为真实数据目录 /opt/data/apache-hop/project。

创建数据目录及子目录,并写入 project-config.json:

mkdir -p /opt/data/apache-hop/project/pipelines
mkdir -p /opt/data/apache-hop/project/workflows
mkdir -p /opt/data/apache-hop/project/metadata
cat > /opt/data/apache-hop/project/project-config.json <<'EOF'
{
  "metadataBaseFolder": "${PROJECT_HOME}/metadata",
  "unitTestsBasePath": "${PROJECT_HOME}",
  "dataSetsCsvFolder": "${PROJECT_HOME}/datasets",
  "enforcingExecutionInHome": true,
  "parentProjectName": "",
  "config": {
    "variables": []
  }
}
EOF

把安装目录 hop-config.json 中 default 项目的 projectHome 指向上面这个数据目录:

python3 - <<'PY'
import json
p = "/opt/apache-hop/hop/config/hop-config.json"
d = json.load(open(p))
for c in d["projectsConfig"]["projectConfigurations"]:
    if c["projectName"] == "default":
        c["projectHome"] = "/opt/data/apache-hop/project"
json.dump(d, open(p, "w"), indent=2)
PY

为 default 项目补齐本地运行配置与审计目录(本地执行需 pipeline-run-configuration/local.json 与 workflow-run-configuration/local.json):

mkdir -p /opt/data/apache-hop/project/metadata/pipeline-run-configuration
mkdir -p /opt/data/apache-hop/project/metadata/workflow-run-configuration
mkdir -p /opt/data/apache-hop/project/metadata/execution-info-location
cat > /opt/data/apache-hop/project/metadata/pipeline-run-configuration/local.json <<'EOF'
{
  "engineRunConfiguration": {
    "Local": {
      "feedback_size": "50000",
      "sample_size": "100",
      "sample_type_in_gui": "Last",
      "rowset_size": "10000",
      "safe_mode": false,
      "show_feedback": false,
      "topo_sort": false,
      "gather_metrics": false
    }
  },
  "name": "local",
  "configurationVariables": [],
  "description": "",
  "defaultSelection": true
}
EOF
cat > /opt/data/apache-hop/project/metadata/execution-info-location/local-audit.json <<'EOF'
{
  "locationType": "local",
  "auditFolder": "/opt/data/apache-hop/audit",
  "name": "local-audit"
}
EOF
mkdir -p /opt/data/apache-hop/logs

⚠️ 注意:若不同步创建运行配置,hop run 会报 Please specify a run configuration to execute the pipeline with。pipeline-run-configuration/local.json 定义了名为 local 的本地引擎运行配置,是命令行无界面执行转换的关键。

4.5 功能验证:执行一个转换(pipeline)

创建一个最简单的转换 my-first-pipeline.hpl:由 RowGenerator 生成 10 行数据,交给 Dummy 结束。文件写入 /opt/data/apache-hop/project/pipelines/:

cat > /opt/data/apache-hop/project/pipelines/my-first-pipeline.hpl <<'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<pipeline>
  <info>
    <name>my-first-pipeline</name>
    <name_sync_with_filename>Y</name_sync_with_filename>
    <description>my first hop pipeline</description>
    <extended_description/>
    <pipeline_version/>
    <pipeline_type>Normal</pipeline_type>
    <parameters/>
    <created_user>root</created_user>
    <created_date>2026/10/11 10:00:00.000</created_date>
    <modified_user>root</modified_user>
    <modified_date>2026/10/11 10:00:00.000</modified_date>
  </info>
  <notepads/>
  <order>
    <hop><from>Generate Rows</from><to>Dummy</to><enabled>Y</enabled></hop>
  </order>
  <transform>
    <name>Generate Rows</name>
    <type>RowGenerator</type>
    <description/>
    <distribute>Y</distribute>
    <custom_distribution/>
    <copies>1</copies>
    <partitioning><method>none</method><schema_name/></partitioning>
    <fields>
      <field><name>x</name><type>Integer</type><length>9</length><precision>-1</precision></field>
      <field><name>m</name><type>String</type><length>20</length><precision>-1</precision></field>
    </fields>
    <interval_in_ms>1000</interval_in_ms>
    <last_time_field/>
    <limit>10</limit>
    <never_ending>N</never_ending>
    <row_time_field/>
    <attributes/>
    <GUI><xloc>96</xloc><yloc>144</yloc></GUI>
  </transform>
  <transform>
    <name>Dummy</name>
    <type>Dummy</type>
    <description/>
    <distribute>Y</distribute>
    <custom_distribution/>
    <copies>1</copies>
    <partitioning><method>none</method><schema_name/></partitioning>
    <attributes/>
    <GUI><xloc>304</xloc><yloc>144</yloc></GUI>
  </transform>
  <transform_error_handling/>
  <attributes/>
</pipeline>
EOF

进入项目目录,用 hop run 执行该转换:

cd /opt/data/apache-hop/project
hop run -f pipelines/my-first-pipeline.hpl

实测回显:

2026/10/11 05:45:48 - HopRun - Enabling project 'default'
2026/10/11 05:45:48 - HopRun - Two-way password encoder initialized with plugin ID 'Hop' for project 'default'
2026/10/11 05:45:48 - HopRun - Relative path filename specified: /opt/data/apache-hop/project/pipelines/my-first-pipeline.hpl
2026/10/11 05:45:48 - HopRun - Starting pipeline: /opt/data/apache-hop/project/pipelines/my-first-pipeline.hpl
2026/10/11 05:45:48 - my-first-pipeline - Executing this pipeline using the Local Pipeline Engine with run configuration 'local'
2026/10/11 05:45:48 - my-first-pipeline - Execution started for pipeline [my-first-pipeline]
2026/10/11 05:45:48 - Generate Rows.0 - Finished processing (I=0, O=0, R=0, W=10, U=0, E=0)
2026/10/11 05:45:48 - Dummy.0 - Finished processing (I=0, O=0, R=10, W=10, U=0, E=0)
2026/10/11 05:45:48 - my-first-pipeline - Pipeline duration : 0.093 seconds [  0.093" ]
2026/10/11 05:45:48 - my-first-pipeline - Execution finished on a local pipeline engine with run configuration 'local'

✅ 验证要点:日志中出现 Starting pipeline、Execution started for pipeline、各变换的 Finished processing (… W=10 …) 统计,以及结尾 Pipeline duration 与 Execution finished on a local pipeline engine with run configuration 'local',进程退出码为 0,即转换执行成功。Generate Rows.0 写出(W)10 行、Dummy.0 读入(R)10 行。

4.6 功能验证:执行一个工作流(workflow)

创建同名简单工作流 my-first-workflow.hwf:Start 起始动作 → DUMMY 空动作。写入 /opt/data/apache-hop/project/workflows/:

cat > /opt/data/apache-hop/project/workflows/my-first-workflow.hwf <<'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<workflow>
  <name>my-first-workflow</name>
  <name_sync_with_filename>Y</name_sync_with_filename>
  <description>my first hop workflow</description>
  <extended_description/>
  <workflow_version/>
  <workflow_status>0</workflow_status>
  <created_user>root</created_user>
  <created_date>2026/10/11 10:00:00.000</created_date>
  <modified_user>root</modified_user>
  <modified_date>2026/10/11 10:00:00.000</modified_date>
  <parameters/>
  <actions>
    <action>
      <name>Start</name>
      <description/>
      <type>SPECIAL</type>
      <attributes/>
      <DayOfMonth>1</DayOfMonth>
      <doNotWaitOnFirstExecution>N</doNotWaitOnFirstExecution>
      <hour>12</hour>
      <intervalMinutes>60</intervalMinutes>
      <intervalSeconds>0</intervalSeconds>
      <minutes>0</minutes>
      <repeat>N</repeat>
      <schedulerType>0</schedulerType>
      <weekDay>1</weekDay>
      <parallel>N</parallel>
      <xloc>48</xloc><yloc>160</yloc>
      <attributes_hac/>
    </action>
    <action>
      <name>Dummy Action</name>
      <description/>
      <type>DUMMY</type>
      <attributes/>
      <parallel>N</parallel>
      <xloc>176</xloc><yloc>160</yloc>
      <attributes_hac/>
    </action>
  </actions>
  <hops>
    <hop><from>Start</from><to>Dummy Action</to><enabled>Y</enabled><evaluation>Y</evaluation><unconditional>Y</unconditional></hop>
  </hops>
  <notepads/>
  <attributes/>
</workflow>
EOF

用 hop run 执行该工作流:

cd /opt/data/apache-hop/project
hop run -f workflows/my-first-workflow.hwf

实测回显:

2026/10/11 05:46:08 - HopRun - Enabling project 'default'
2026/10/11 05:46:08 - HopRun - Two-way password encoder initialized with plugin ID 'Hop' for project 'default'
2026/10/11 05:46:08 - HopRun - Relative path filename specified: /opt/data/apache-hop/project/workflows/my-first-workflow.hwf
2026/10/11 05:46:08 - HopRun - Starting workflow: /opt/data/apache-hop/project/workflows/my-first-workflow.hwf
2026/10/11 05:46:08 - my-first-workflow - Start of workflow execution
2026/10/11 05:46:08 - my-first-workflow - Starting action [Start]
2026/10/11 05:46:08 - my-first-workflow - Finished action [Start] (result=[true])
2026/10/11 05:46:08 - my-first-workflow - Starting action [Dummy Action]
2026/10/11 05:46:08 - my-first-workflow - Finished action [Dummy Action] (result=[true])
2026/10/11 05:46:08 - my-first-workflow - Workflow execution finished
2026/10/11 05:46:08 - my-first-workflow - Workflow duration : 0.027 seconds [  0.027" ]

✅ 验证要点:日志中出现 Start of workflow execution、每个动作的 Starting action … / Finished action … (result=[true])、结尾 Workflow execution finished 与 Workflow duration,退出码为 0,即工作流执行成功。

五、配置说明

5.1 全局配置入口

  • hop-config.json(<安装目录>/config/hop-config.json):全局级配置,含语言、项目列表与默认项目等。示例字段:LocaleDefault、projectsConfig.enabled、projectsConfig.projectMandatory、projectsConfig.defaultProject、projectsConfig.projectConfigurations[].projectName/projectHome/configFilename。
  • project-config.json(<PROJECT_HOME>/project-config.json):项目级配置,含元数据基路径与行为开关。常用键见 4.4 节写的文件内容(metadataBaseFolder、enforcingExecutionInHome 等)。
  • /etc/profile.d/hop-env.sh:登录环境变量(JAVA_HOME、HOP_HOME、PATH、HOP_OPTIONS)。
  • hop 启动脚本(<安装目录>/hop):Hop 对 Java 的定位顺序为 HOP_JAVA_HOME → JAVA_HOME → 系统 java;内置默认 HOP_OPTIONS="-Xmx2048m"。

5.2 本地运行配置(Run Configuration)

hop run 无界面执行转换/工作流时,依赖项目 metadata/pipeline-run-configuration/(转换)与 metadata/workflow-run-configuration/(工作流)下的 local.json。关键本地引擎参数:

参数默认值含义
feedback_size50000反馈日志周期(处理多少行打印一次反馈)
sample_size100预览采样行数
rowset_size10000变换之间行集缓冲大小
safe_modefalse是否开启安全模式
gather_metricsfalse是否采集性能指标

5.3 JVM 内存专项(含 Java 进程必备)

Hop 是纯 Java 程序,其启动脚本 hop 中默认 HOP_OPTIONS="-Xmx2048m"(堆上限 2GB)。为了控制服务器内存占用,建议将堆限制在 256–512MB,修改方式如下(本指南已在 4.3 节落地):

  • 全局生效:修改 /etc/profile.d/hop-env.sh 中的 export HOP_OPTIONS="-Xms256m -Xmx512m" 并 source/重登后生效,适用于所有 hop* 命令;
  • 临时生效(仅当前 shell):
export HOP_OPTIONS="-Xms256m -Xmx512m"
  • 默认堆的兜底说明:若未设置 HOP_OPTIONS,Hop 会按脚本预设的 -Xmx2048m(或镜像环境中的 -XX:+AggressiveHeap)启动,安装后请务必确认实际生效值。

验证实际生效的堆参数——启动一个常驻进程(如 hop server)后,用 jps -v 复查:

export HOP_OPTIONS="-Xms256m -Xmx512m"
hop server &
jps -v | grep -i hop | tr ' ' '\n' | grep -E '^\-Xms|^\-Xmx'

实测回显:

-Xms256m
-Xmx512m

✅ 验证要点:jps -v 将 Hop 进程的完整 JVM 参数挂出来,其中出现 -Xms256m 与 -Xmx512m 即表示堆限制已按 256–512MB 生效。

六、注意事项

  1. JDK 版本必须为 21:2.19.0 面向 JDK 21 编译,使用 JDK 17 会报 UnsupportedClassVersionError(见「九、常见问题」Q1)。推荐安装时将 JAVA_HOME 显式指向 JDK 21 目录。
  2. 所有可执行文件必须在项目 PROJECT_HOME 下:默认 enforcingExecutionInHome=true,hop run -f 的路径要在项目内(本文用 pipelines/ 与 workflows/ 子目录),否则报「pipeline path is invalid」。
  3. 运行前必须准备本地运行配置:缺 pipeline-run-configuration/local.json 时 hop run 报 Please specify a run configuration to execute the pipeline with。
  4. 发行包无 bin/ 子目录:hop 与各 hop-*.sh 脚本位于安装目录顶层,加入 PATH 时填安装目录本身。
  5. HOP_OPTIONS 覆盖默认堆:脚本默认 -Xmx2048m,须通过 HOP_OPTIONS 覆盖到 256–512MB。

七、常见问题

7.1 hop 启动报 UnsupportedClassVersionError

现象:

Error: LinkageError occurred while loading main class org.apache.hop.hop.Hop
        java.lang.UnsupportedClassVersionError: org/apache/hop/hop/Hop has been compiled by a more recent version of the Java Runtime (class file version 65.0), this version of the Java Runtime only recognizes class file versions up to 61.0

定位:当前默认 Java 为 JDK 17(类文件版本 61.0),而 Hop 2.19.0 由 JDK 21(65.0)编译。解决方案:将 JAVA_HOME 指向 JDK 21,例如 export JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64(见 4.3 节)。

7.2 hop run 报 Please specify a run configuration to execute the pipeline with

定位:项目 metadata/pipeline-run-configuration/ 缺少 local.json 运行配置。解决方案:按 4.4 节补齐 local.json(engineRunConfiguration.Local 段,名称 local)。

7.3 hop run -f 报 The pipeline path ... is invalid, and will not run successfully

定位:文件不在项目 PROJECT_HOME 内(enforcingExecutionInHome=true)。解决方案:把 .hpl/.hwf 放到项目内(如 pipelines/、workflows/ 子目录),再以相对路径执行。

7.4 hop --version / -h 打印内容正常但退出码为 1

定位:Hop 命令行对 --version/--help 分支统一返回退出码 1(picocli 包装行为),属既有现象。判定标准以是否输出版本号/帮助文本为准,非异常。

八、卸载方式

  1. 停止 Hop 相关进程(jps 找到 org.apache.hop.hop.Hop 对应 PID 后 kill <PID>),并移除环境变量文件:
kill $(jps -l | grep -E 'org.apache.hop' | awk '{print $1}')
rm -f /etc/profile.d/hop-env.sh
  1. 删除安装目录与数据目录:
rm -rf /opt/apache-hop
rm -rf /opt/data/apache-hop
  1. 若 JDK 21 系本次安装且不再使用,可一并卸载:
apt-get purge -y openjdk-21-jre-headless
apt-get autoremove -y

九、参考链接