Kettle 9.1 Docker Compose 部署指南
基于 Docker Compose 部署 Pentaho Data Integration 9.1:同镜像编排 Kitchen 作业与 Carte 服务,含 Dockerfile、编排全文、构建启动输出、status 接口验证与常见问题。
Kettle 9.1 Docker Compose 部署指南
目标:在一台装有 Docker 的 Linux 服务器上,使用 Docker Compose 一键部署 Pentaho Data Integration(Kettle,下称 PDI)9.1 社区版:用同一个自建镜像同时编排「Kitchen 一次性作业」与「Carte 常驻 Web 服务」两个服务,完成构建、启动、作业执行与接口验证的完整闭环。全文命令与回显已在 Linux x86_64(Docker 29.8.0 + Compose v5.5.1)实测通过。
一、方案说明
1.1 服务组成与端口
PDI 9.1 解压目录内含完整的命令行执行器与 Web 服务组件,本方案用同一份程序目录构建一个镜像,编排两个服务:
| 服务 | 定位 | 命令 | 端口 | restart 策略 |
|---|---|---|---|---|
| pdi-kitchen | 一次性作业执行器,跑完即退出 | ./kitchen.sh -file=<作业.kjb> -level=Basic | 无 | no |
| pdi-carte | 常驻 Web 服务(内嵌 Jetty),提供 HTTP 管理接口 | ./carte.sh 0.0.0.0 8081 | 8081 对外映射 | unless-stopped |
1.2 实测环境版本
| 项目 | 版本 |
|---|---|
| PDI | 9.1.0.0-324(build date 2020-09-07) |
| 基础镜像 | eclipse-temurin:8-jre-jammy(JDK 8,见第八节 8.1 的 JDK 版本要求) |
| Docker | 29.8.0 |
| Docker Compose | v5.5.1(插件版 docker compose) |
二、前置条件
2.1 安装 Docker Engine
服务器需已安装 Docker Engine(19.03+,含 buildkit)。CentOS 8 参考安装:
dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
systemctl enable --now docker
Ubuntu 22.04 参考安装:
apt-get update
apt-get install -y ca-certificates curl gnupg
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" > /etc/apt/sources.list.d/docker.list
apt-get update
apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
systemctl enable --now docker
💡 说明:若服务器已装有可用的 Docker Engine 与 Compose 插件,跳过本节即可。
2.2 版本验证
docker --version
docker compose version
实测输出:
Docker version 29.8.0, build 88096ef
Docker Compose version v5.5.1
三、准备 PDI 程序目录
3.1 获取 data-integration 目录
PDI 9.1 社区版发行包 pdi-ce-9.1.0.0-324.zip(约 1749 MB)解压后得到 data-integration 目录,这就是构建镜像的全部程序文件。历史官方下载地址:
wget https://sourceforge.net/projects/pentaho/files/Pentaho%209.1/client-tools/pdi-ce-9.1.0.0-324.zip
unzip -q pdi-ce-9.1.0.0-324.zip
⚠️ 注意(渠道变迁):Hitachi Vantara 已清空 SourceForge 上 pentaho 项目的文件区,上述历史直链可能返回 404。替代获取方式:从企业内部留存的安装包解压,或从可信的第三方 Docker Hub 镜像(内含完整 PDI 目录结构)中提取
data-integration目录。安装包 SHA256(以本文实测包为准):0f3c031d6d0a2d6f7eedd918a4f3d44a02006d1c8ccca9b99f7ceded3bb07ad8。
3.2 程序目录内容确认
ls data-integration | head -12
实测输出(节选):
ADDITIONAL-FILES
Carte.bat
carte.sh
classes
Data Integration.app
Data Service JDBC Driver
docs
drivers
Encr.bat
encr.sh
import.sh
kitchen.bat
kitchen.sh
四、编写编排文件
4.1 项目目录结构
在服务器上规划项目目录 /opt/kettle-compose,结构如下:
/opt/kettle-compose/
├── Dockerfile
├── docker-compose.yml
├── jobs/ # 作业与转换文件(只读挂入 pdi-kitchen)
│ ├── test_gen_log.ktr
│ └── test_gen_log_job.kjb
└── src/
└── data-integration/ # 第三步解压得到的 PDI 程序目录
mkdir -p /opt/kettle-compose/jobs /opt/kettle-compose/src
cp -a data-integration /opt/kettle-compose/src/
cd /opt/kettle-compose
4.2 Dockerfile
FROM eclipse-temurin:8-jre-jammy
COPY src/data-integration /opt/pentaho/data-integration
ENV PENTAHO_DI_JAVA_OPTIONS="-Xms256m -Xmx512m"
WORKDIR /opt/pentaho/data-integration
要点说明:
- 基础镜像必须为 JDK 8(
eclipse-temurin:8-jre-jammy):PDI 9.1 启动脚本硬编码-Djava.endorsed.dirs,JDK 11+ 直接拒绝启动(详见第八节 8.1)。 PENTAHO_DI_JAVA_OPTIONS是 PDI 启动脚本读取的专用 JVM 变量,-Xms256m -Xmx512m将堆限制在 256–512 MB。WORKDIR指向程序目录,compose 的command才能用./kitchen.sh相对路径。
4.3 docker-compose.yml
services:
pdi-kitchen:
build: .
container_name: pdi-kitchen
command: ["./kitchen.sh", "-file=/opt/pentaho/jobs/test_gen_log_job.kjb", "-level=Basic"]
volumes:
- ./jobs:/opt/pentaho/jobs:ro
restart: "no"
pdi-carte:
build: .
container_name: pdi-carte
command: ["./carte.sh", "0.0.0.0", "8081"]
ports:
- "8081:8081"
restart: unless-stopped
要点说明:
pdi-kitchen挂载宿主机jobs/目录为只读,作业文件改动无需重建镜像,下次运行即生效。pdi-carte以命令行方式启动(接口地址 + 端口),默认监听账号为cluster/cluster(详见第六节 6.3 与第八节 8.3)。- 两个服务
build: .共用一个镜像,首次up时自动构建。
4.4 作业与转换文件
写入一个最小可验证的示例作业:START → 执行转换(生成 3 行数据写入日志)。先写转换文件 /opt/kettle-compose/jobs/test_gen_log.ktr:
<?xml version="1.0" encoding="UTF-8"?>
<transformation>
<info>
<name>gen_log_test</name>
<trans_type>Normal</trans_type>
<directory>/</directory>
<size_rowset>10000</size_rowset>
<created_user>-</created_user>
<created_date>2026/10/12 12:00:00.000</created_date>
<modified_user>-</modified_user>
<modified_date>2026/10/12 12:00:00.000</modified_date>
</info>
<order>
<hop><from>gen</from><to>log</to><enabled>Y</enabled></hop>
</order>
<notepads></notepads>
<step>
<name>gen</name>
<type>RowGenerator</type>
<distribute>Y</distribute>
<copies>1</copies>
<partitioning><method>none</method><schema_name/></partitioning>
<fields>
<field>
<name>msg</name>
<type>String</type>
<nullif>hello-kettle</nullif>
<length>-1</length>
<precision>-1</precision>
<set_empty_string>N</set_empty_string>
</field>
</fields>
<limit>3</limit>
<never_ending>N</never_ending>
<cluster_schema/>
<GUI><xloc>100</xloc><yloc>100</yloc><draw>Y</draw></GUI>
</step>
<step>
<name>log</name>
<type>WriteToLog</type>
<distribute>Y</distribute>
<copies>1</copies>
<partitioning><method>none</method><schema_name/></partitioning>
<log_level>log_level_basic</log_level>
<displayHeader>Y</displayHeader>
<limitRows>N</limitRows>
<limitRowsNumber>0</limitRowsNumber>
<logmessage>msg</logmessage>
<byname>Y</byname>
<cluster_schema/>
<GUI><xloc>300</xloc><yloc>100</yloc><draw>Y</draw></GUI>
</step>
<step_error_handling></step_error_handling>
<slave_transformation>N</slave_transformation>
<attributes/>
</transformation>
再写作业文件 /opt/kettle-compose/jobs/test_gen_log_job.kjb(注意其中引用的转换路径必须是容器内挂载路径 /opt/pentaho/jobs/test_gen_log.ktr):
<?xml version="1.0" encoding="UTF-8"?>
<job>
<name>run_ktr_job</name>
<directory>/</directory>
<created_user>-</created_user>
<created_date>2026/10/12 12:00:00.000</created_date>
<modified_user>-</modified_user>
<modified_date>2026/10/12 12:00:00.000</modified_date>
<parameters></parameters>
<slaveservers></slaveservers>
<entries>
<entry>
<name>START</name>
<type>SPECIAL</type>
<start>Y</start>
<dummy>N</dummy>
<repeat>N</repeat>
<schedulerType>0</schedulerType>
<intervalSeconds>60</intervalSeconds>
<intervalMinutes>60</intervalMinutes>
<hour>12</hour>
<minutes>0</minutes>
<weekDay>1</weekDay>
<DayOfMonth>1</DayOfMonth>
<parallel>N</parallel>
<draw>Y</draw>
<nr>0</nr>
<xloc>100</xloc>
<yloc>100</yloc>
</entry>
<entry>
<name>run trans</name>
<type>TRANS</type>
<filename>/opt/pentaho/jobs/test_gen_log.ktr</filename>
<arg_from_previous>N</arg_from_previous>
<exec_local>Y</exec_local>
<exec_remote>N</exec_remote>
<clear_rows>N</clear_rows>
<wait_until_finished>Y</wait_until_finished>
<parameters><pass_all_parameters>Y</pass_all_parameters></parameters>
<parallel>N</parallel>
<draw>Y</draw>
<nr>0</nr>
<xloc>300</xloc>
<yloc>100</yloc>
</entry>
</entries>
<hops>
<hop>
<from>START</from><to>run trans</to>
<from_nr>0</from_nr><to_nr>0</to_nr><nr>0</nr>
<enabled>Y</enabled><evaluation>Y</evaluation><unconditional>N</unconditional>
</hop>
</hops>
<notepads></notepads>
</job>
五、构建与启动
5.1 构建镜像
cd /opt/kettle-compose
docker compose build
实测输出(尾部,首次构建约 1–2 分钟,COPY 1.8 GB 程序目录占大头):
#10 unpacking to docker.io/library/kettle-compose-pdi-carte:latest 11.1s done
#10 DONE 71.1s
#9 [pdi-kitchen] exporting to image
#9 unpacking to docker.io/library/kettle-compose-pdi-kitchen:latest 11.1s done
#9 DONE 71.1s
#11 [pdi-kitchen] resolving provenance for metadata file
#11 DONE 0.0s
#12 [pdi-carte] resolving provenance for metadata file
#12 DONE 0.0s
Image kettle-compose-pdi-kitchen Built
Image kettle-compose-pdi-carte Built
5.2 启动服务
docker compose up -d
实测输出:
Network kettle-compose_default Creating
Network kettle-compose_default Created
Container pdi-kitchen Creating
Container pdi-carte Creating
Container pdi-kitchen Created
Container pdi-carte Created
Container pdi-carte Starting
Container pdi-kitchen Starting
Container pdi-carte Started
Container pdi-kitchen Started
5.3 查看服务状态
docker compose ps
实测输出:
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
pdi-carte kettle-compose-pdi-carte "/__cacert_entrypoin…" pdi-carte 5 seconds ago Up 3 seconds 0.0.0.0:8081->8081/tcp, [::]:8081->8081/tcp
pdi-kitchen kettle-compose-pdi-kitchen "/__cacert_entrypoin…" pdi-kitchen 5 seconds ago Up 3 seconds
pdi-kitchen 是一次性作业,执行完会自动退出。稍候约 1 分钟后再看完整状态:
docker compose ps -a
实测输出:
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
pdi-carte kettle-compose-pdi-carte "/__cacert_entrypoin…" pdi-carte About a minute ago Up About a minute 0.0.0.0:8081->8081/tcp, [::]:8081->8081/tcp
pdi-kitchen kettle-compose-pdi-kitchen "/__cacert_entrypoin…" pdi-kitchen About a minute ago Exited (0) About a minute ago
Exited (0) 表示作业正常执行完毕退出。
六、运行验证
6.1 作业执行日志
docker logs pdi-kitchen
实测输出(尾部;开头的 Karaf/OSGI 初始化日志略):
14:31:29,019 INFO [DriverManager] 0 drivers will be installed.
14:31:29,020 INFO [DriverManager] Finished installing drivers kars.
2026/10/12 14:31:29 - run_ktr_job - Start of job execution
2026/10/12 14:31:29 - run_ktr_job - Job execution finished
2026/10/12 14:31:29 - Carte - Installing timer to purge stale objects after 1440 minutes.
2026/10/12 14:31:29 - Finished!
2026/10/12 14:31:29 - Start=2026/10/12 14:31:29.126, Stop=2026/10/12 14:31:29.175
2026/10/12 14:31:29 - Processing ended after 0 seconds.
Job execution finished + Finished! + Exited (0) 三者齐备,说明作业链路(kitchen → kjb → ktr)在镜像内完整跑通。
6.2 Carte 服务启动确认
docker logs pdi-carte 2>&1 | tail -3
实测输出:
14:31:31,839 INFO [DriverManager] Finished installing drivers kars.
14:31:31 - Carte - Installing timer to purge stale objects after 1440 minutes.
14:31:32 - Carte - Created listener for webserver @ address : 0.0.0.0:8081
6.3 status 接口验证
在服务器本机访问映射出的 8081 端口:
curl -s -o /dev/null -w '%{http_code}\n' -u cluster:cluster http://localhost:8081/kettle/status/
实测输出:
200
⚠️ 注意(默认凭据):
carte.sh 接口地址 端口这种命令行方式启动的 Carte 使用内置默认账号cluster/cluster,本文docker-compose.yml正是这种方式,因此验证用cluster:cluster。若用配置文件方式启动(carte.sh <配置.xml>),账号密码以配置文件中的username/password为准。错误凭据返回 401。
七、日常运维
7.1 查看 Carte 实时日志
docker logs -f pdi-carte
按 Ctrl+C 退出跟踪(不影响服务)。
7.2 停止与清理
cd /opt/kettle-compose
docker compose down
实测输出:
Container pdi-carte Stopping
Container pdi-kitchen Stopping
Container pdi-kitchen Stopped
Container pdi-kitchen Removing
Container pdi-kitchen Removed
Container pdi-carte Stopped
Container pdi-carte Removing
Container pdi-carte Removed
Network kettle-compose_default Removing
Network kettle-compose_default Removed
如需连镜像一并删除:
docker compose down --rmi local
7.3 更新作业文件
作业与转换文件通过 volumes 只读挂载,直接修改宿主机 /opt/kettle-compose/jobs/ 下的文件后重新运行作业即可,无需重建镜像:
docker compose run --rm pdi-kitchen
docker compose run 会按服务定义的 command 新起一个一次性实例执行作业,跑完自动清理。
7.4 程序目录变更后重建镜像
若替换了 src/data-integration(例如升级 PDI 版本),需要重新构建并滚动重启 Carte:
cd /opt/kettle-compose
docker compose build
docker compose up -d --force-recreate pdi-carte
八、常见问题
8.1 启动脚本与 JDK 11+ 不兼容
现象:容器启动即退出,日志中出现:
-Djava.endorsed.dirs=... is not supported. Endorsed standards and standalone APIs
in modular form will be supported via the concept of upgradeable modules.
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.
原因:PDI 9.1 启动脚本(kitchen/pan/carte/spoon 共用)固定拼接非空的 -Djava.endorsed.dirs,JDK 9+ 已移除该机制并直接拒绝启动。解决:基础镜像锁定 JDK 8(本文使用 eclipse-temurin:8-jre-jammy)。
8.2 宿主机 8081 端口被占用
现象:pdi-carte 反复重启,docker logs pdi-carte 尾部出现:
Caused by: java.net.BindException: Address already in use
排查占用并释放端口(或修改 docker-compose.yml 的端口映射为其他宿主机端口,如 "18081:8081"):
ss -lntp | grep 8081
8.3 status 接口返回 401
本文编排的 Carte 以命令行方式启动,默认账号为 cluster/cluster;用 admin:q1w2e3r4 等其他凭据访问会得到 401:
HTTP/1.1 401 Unauthorized
解决:使用 cluster:cluster 访问,或改用配置文件方式启动并自定义账号(在配置文件的 slaveserver 节点设置 username/password)。
8.4 内存控制
Dockerfile 中 PENTAHO_DI_JAVA_OPTIONS="-Xms256m -Xmx512m" 已将 JVM 堆限制在 256–512 MB。实测 Carte 常驻内存约 500 MB 上下。若服务器内存紧张,可将两值对齐为 -Xms256m -Xmx256m。
九、参考链接
- Pentaho Data Integration 官方产品页:https://www.hitachivantara.com/en-us/products/data-management-analytics/pentaho-data-integration.html
- Docker 官方安装文档:https://docs.docker.com/engine/install/
- Docker Compose 官方文档:https://docs.docker.com/compose/
- Eclipse Temurin JDK 8 镜像:https://hub.docker.com/_/eclipse-temurin