Créer une image Docker pour exécuter des taches Pentaho Data Integration
Introduction
Pentaho Data Integration (PDI), aussi connu sous le nom de Kettle, est l’ETL que j’ai utilisé pendant plusieurs années avant de migrer progressivement vers Apache Hop et DBT.
Malgré cette transition, on conserve encore un volume important de legacy qui s’exécute sur des serveurs Carte via l’API REST comme je l'expliquais dans un précédent article.
Pour garder de la souplesse et paradoxalement, préparer l’avenir, j’ai décidé de créer un container Docker personnalisé capable d’exécuter des tâches PDI de manière autonome dans un environnement maitrisé en cas de besoin. Comme il n’existe pas d’image officielle de PDI, nous allons construire la nôtre à partir de la dernière version open source, la 9.4.
On pourrait bien sûr faire de même pour d’autres versions (9.3, 9.1, 8.2, etc.) ou les combiner dans une même image. Mais ce n’est pas l’objectif ici. Et pour terminer, nous verrons comment utiliser cette image dans Apache Airflow grâce au DockerOperator.

Dockerfile
L’image est basée sur openjdk:8-jre.
- On configure les locales en fr_FR.UTF-8 et la timezone Europe/Paris.
- On copie le dossier contenant tous les fichiers de PDI dans /opt/pdi.
- On définit /app comme répertoire de travail, qui servira de point de montage pour nos jobs et transformations.
- Aucune commande par défaut.
Cette image n'a pas pour vocation de répondre à tous les usages qu'on pourrait avoir de pdi mais c'est une bonne base de travail !
FROM openjdk:8-jre
ENV DEBIAN_FRONTEND=noninteractive
# Variables d'environnement
ENV LANG=fr_FR.UTF-8 \
LANGUAGE=fr_FR:fr \
LC_ALL=fr_FR.UTF-8 \
TZ=Europe/Paris \
PDI_HOME=/opt/pdi
# Installer tzdata, locales et unzip, configurer timezone et locale
RUN apt-get update && \
apt-get install -y locales tzdata unzip && \
ln -fs /usr/share/zoneinfo/${TZ} /etc/localtime && \
dpkg-reconfigure -f noninteractive tzdata && \
sed -i '/fr_FR.UTF-8/s/^# //g' /etc/locale.gen && \
locale-gen fr_FR.UTF-8 && \
update-locale LANG=fr_FR.UTF-8 && \
rm -rf /var/lib/apt/lists/*
# Copier les fichiers de PDI 9.4 dans le container
COPY pdi94/ ${PDI_HOME}/
RUN chmod +x ${PDI_HOME}/*.sh
#COPY pdi93/ /opt/pdi93/
#COPY pdi82/ /opt/pdi82/
#RUN chmod +x /opt/pdi93/*.sh
#RUN chmod +x /opt/pdi82/*.sh
# Définir le répertoire de travail
WORKDIR /app


Build de l'image
Dans un terminal :

docker build -t pdi:pdi94_v1 .
Test du container
Ajouter les options : --dns "ip de votre dns" --dns-search "votre-domaine.xx" si la résolution des hostnames ne fonctionne pas dans le container.
On peut lancer le container en mode bash en montant un dossier local contenant nos taches et transformations PDI dans le répertoire de travail /app :
docker run -it --rm -v "C:/Users/tonuser/Documents/Docker/Image_Personnalisee/pdi:/app" pdi:pdi94_v1 bash
Vérifiez que :
- les fichiers de PDI 9.4 sont bien présents dans /opt/pdi (ls /opt/pdi),
- vos jobs de test sont bien accessibles dans /app (ls /app).
Puis exécutez une tache(.kjb) PDI avec kitchen.sh (pan.sh pour une transformation):
/opt/pdi/kitchen.sh -file=/app/test_pdi_docker.kjb -level=Basic
Tout fonctionne correctement :

Docker Hub
Pour rendre l'image accessible et réutilisable depuis n’importe quel environnement, il est possible de la publier sur un dépôt Docker. À défaut, il reste possible de la construire localement sur chaque machine qui devra l’exécuter à l'aide du Dockerfile et de la commande build.
Avant de pousser une image vers un dépôt, il est indispensable de taguer correctement l'image, sans quoi l’opération de push échouera.
docker login
docker tag pdi:pdi94_v1 account/repo:pdi94_v1
docker push account/repo:pdi94_v1
Apache Airflow
Dans Airflow, on utilise le DockerOperator pour lancer nos taches PDI directement dans un container.
⚠️ Attention à bien gérer les deux niveaux de mémoire :
- la RAM allouée au container (mem_limit),
- la RAM maximum de la JVM pdi (PENTAHO_DI_JAVA_OPTIONS).
Pour ce test, les jobs et transformations PDI sont stockés sur l’instance Airflow dans le répertoire /mnt/DossierTachePdi/test. Ce répertoire doit être monté dans le conteneur Docker sous /app afin que les fichiers soient accessibles à l’exécution.
Dag
from datetime import datetime, timedelta
import pendulum
from airflow import DAG
from airflow.operators.docker_operator import DockerOperator
from docker.types import Mount
from airflow.operators.dummy_operator import DummyOperator
##########################################################################
# DEFINITION GLOBALE DU DAG #
DAG_ID = 'test_pdi_docker'
DAG_NAME = 'Test Pdi Docker'
DAG_TAG = ["pdi","test",'docker']
DAG_TIMEOUT = 20
DAG_RETRY_DELAY = 1
DAG_RETRIES = 0
default_args = {
'owner' : 'nicodl',
'description' : DAG_NAME,
'depend_on_past' : False,
'start_date' : datetime(2025, 9, 3),
'email_on_failure' : False,
'email_on_retry' : False,
'retries' : DAG_RETRIES,
'retry_delay' : timedelta(minutes=DAG_RETRY_DELAY),
}
##########################################################################
# DECLARATION DU DAG #
with DAG(DAG_ID,
dag_display_name = DAG_NAME,
default_args = default_args,
catchup = False,
tags= DAG_TAG,
schedule_interval = None, # https://crontab.cronhub.io/
is_paused_upon_creation = True,
max_active_runs=1,
on_failure_callback=None,
on_success_callback=None,
dagrun_timeout=timedelta(minutes=DAG_TIMEOUT),
) as dag:
##########################################################################
# DECLARATION DES TASKS #
#---------------------------------------------------------------
# Task 1 => test pdi 9.4 dans un container docker
tache_pdi_docker = DockerOperator(
task_id='tache_pdi_docker',
image = 'account/repo:pdi94_v1',
api_version='auto',
mount_tmp_dir=False,
auto_remove=True,
command = 'bash -c "/opt/pdi/kitchen.sh -file=/app/test_pdi_docker.kjb -level=Basic"',
cpus= 1, #cpu du container a modifier selon use case
mem_limit= '1g', #ram du container a modifier selon use case
priority_weight= 1,
execution_timeout= timedelta(minutes=10),
environment= {"PENTAHO_DI_JAVA_OPTIONS": "-Xms512m -Xmx512m"}, #ram pour la jvm a modifier selon use case
docker_url='unix://var/run/docker.sock',
network_mode="bridge",
mounts=[Mount(source="/mnt/DossierTachePdi/test", target='/app', type='bind')],
force_pull=False
)
#task
start_dag = DummyOperator(task_id='start')
#task
end_dag = DummyOperator( task_id='end')
start_dag >> tache_pdi_docker >> end_dag
Résultat
- Le job PDI s’exécute correctement dans notre image Docker personnalisée.
- On peut ajuster la mémoire au niveau du container et de la JVM selon les besoins.

Résumé
Même si Pentaho Data Integration community edition appartient désormais au passé, il reste fréquent d’avoir à maintenir et exécuter un legacy important basé sur cet ETL. La mise en place d’une image Docker personnalisée apporte une alternative flexible et portable pour exécuter des taches pdi.
Cette image Docker n’a pas vocation à remplacer les serveurs Carte dans tous les cas d’usage, mais elle constitue un outil supplémentaire, pratique et moderne, pour exécuter des taches PDI.
Vous trouverez sur mon github tous les fichiers.