Selama satu dekade, banyak tim data terjebak di antara dua pilihan: data warehouse yang cepat tetapi mahal dan tertutup, atau data lake ...
Selama satu dekade, banyak tim data terjebak di antara dua pilihan: data warehouse yang cepat tetapi mahal dan tertutup, atau data lake berbasis file Parquet di S3 yang murah tetapi rapuh. File bisa tertimpa saat dua job menulis bersamaan, skema berubah tanpa jejak, dan menghapus satu baris saja berarti menulis ulang satu partisi penuh.
Apache Iceberg menyelesaikan masalah itu dengan menambahkan lapisan table format di atas object storage. Lapisan ini menyediakan transaksi ACID, snapshot yang bisa di-time travel, evolusi skema dan partisi tanpa menulis ulang data, serta metadata yang bisa dibaca banyak engine sekaligus (Trino, Spark, Flink, DuckDB, ClickHouse). Ekosistem kini juga mengerucut ke Iceberg REST Catalog sebagai antarmuka katalog standar, dengan Apache Polaris sebagai implementasi open source yang dikelola Apache Software Foundation.
Artikel ini membangun lakehouse kecil yang sepenuhnya self-hosted: Polaris sebagai katalog, object storage kompatibel S3, dan Trino sebagai SQL engine. Semuanya berjalan di Docker, cocok ditempatkan di satu VM Proxmox untuk lab atau POC sebelum naik ke Kubernetes.
1. Arsitektur Komponen
- Object storage S3 (RustFS, MinIO, atau Ceph RGW): menyimpan file data Parquet beserta file metadata Iceberg (
metadata.json, manifest list, manifest). - Apache Polaris: Iceberg REST Catalog yang menyimpan pointer ke metadata terbaru setiap tabel, mengelola RBAC (principal, principal role, catalog role), dan dapat memberikan vended credentials S3 berumur pendek ke engine.
- Trino: SQL engine MPP yang membaca dan menulis tabel Iceberg melalui konektor
icebergdenganiceberg.catalog.type=rest.
Keuntungan pola ini adalah decoupling. Besok Anda bisa menambahkan Spark untuk batch ETL atau DuckDB di laptop analis, dan semua engine melihat tabel yang sama lewat katalog yang sama, tanpa menyalin data.
2. Menyiapkan VM di Proxmox
Untuk lab, satu VM Ubuntu Server 24.04 dengan 4 vCPU, RAM 16 GB, dan disk data terpisah sudah cukup. Trino adalah aplikasi JVM yang boros memori, jadi alokasikan RAM yang longgar.
# Di host Proxmox: buat VM dari template cloud-init (contoh ID 9000)
qm clone 9000 410 --name lakehouse-lab --full
qm set 410 --cores 4 --memory 16384 --scsi1 local-lvm:200
qm start 410
# Di dalam VM: pasang Docker Engine + plugin compose
curl -fsSL https://get.docker.com | sudo sh
sudo usermod -aG docker $USER
docker compose version
3. Menjalankan Polaris dan Object Storage
Proyek Polaris menyediakan docker compose quickstart yang otomatis membuat katalog quickstart_catalog dan principal quickstart_user. Repo resmi juga memuat compose khusus Trino (direktori site/content/guides/trino). Untuk evaluasi cepat:
git clone https://github.com/apache/polaris.git && cd polaris
# Polaris (metastore in-memory) + RustFS sebagai storage S3
curl -s https://raw.githubusercontent.com/apache/polaris/refs/heads/main/site/content/guides/quickstart/docker-compose.yml \
| docker compose -p polaris-quickstart -f - up -d
# Kredensial principal dan contoh perintah dicetak di log bootstrap
docker compose -p polaris-quickstart logs | grep -iE "client|secret|catalog"
# Uji REST API (port default 8181)
curl -s http://localhost:8181/api/catalog/v1/config?warehouse=quickstart_catalog
client_secret di secret manager, dan aktifkan TLS di depan endpoint 8181. Jangan pernah meng-commit kredensial principal ke Git.
4. Menghubungkan Trino ke Polaris
Di Trino, setiap katalog didefinisikan sebagai file properties di /etc/trino/catalog/. Berikut konfigurasi konektor Iceberg yang memakai REST catalog dengan autentikasi OAuth2 client credentials:
# etc/trino/catalog/lakehouse.properties
connector.name=iceberg
iceberg.catalog.type=rest
iceberg.rest-catalog.uri=http://polaris:8181/api/catalog
iceberg.rest-catalog.warehouse=quickstart_catalog
iceberg.rest-catalog.security=OAUTH2
iceberg.rest-catalog.oauth2.credential=${ENV:POLARIS_CLIENT_ID}:${ENV:POLARIS_CLIENT_SECRET}
iceberg.rest-catalog.oauth2.scope=PRINCIPAL_ROLE:ALL
iceberg.rest-catalog.vended-credentials-enabled=true
# Akses S3 native (path-style untuk RustFS/MinIO)
fs.native-s3.enabled=true
s3.endpoint=http://rustfs:9000
s3.region=us-east-1
s3.path-style-access=true
# Jalankan Trino di network compose yang sama dengan Polaris
docker run -d --name trino --network polaris-quickstart_default \
-e POLARIS_CLIENT_ID -e POLARIS_CLIENT_SECRET \
-v $PWD/etc/trino/catalog:/etc/trino/catalog:ro \
-p 8080:8080 trinodb/trino:latest
docker exec -it trino trino --catalog lakehouse
fs.native-s3.enabled vs. fs.s3.enabled pada distribusi tertentu). Selalu cocokkan dengan dokumentasi versi Trino yang Anda jalankan, dan periksa log startup jika katalog gagal dimuat.
5. Operasi Tabel Iceberg dengan SQL
5.1 Membuat Skema dan Tabel Terpartisi
Iceberg memakai hidden partitioning. Partisi didefinisikan dengan transformasi kolom (misalnya day(event_ts)), sehingga pengguna cukup memfilter event_ts dan tidak perlu tahu struktur folder.
CREATE SCHEMA IF NOT EXISTS lakehouse.web;
CREATE TABLE lakehouse.web.access_log (
event_ts timestamp(6) with time zone,
host varchar,
client_ip varchar,
status integer,
bytes_sent bigint,
latency_ms double
)
WITH (
format = 'PARQUET',
partitioning = ARRAY['day(event_ts)', 'bucket(client_ip, 16)']
);
INSERT INTO lakehouse.web.access_log VALUES
(TIMESTAMP '2026-11-08 10:00:01 +08:00', 'simpeg', '10.10.10.21', 200, 5120, 12.4),
(TIMESTAMP '2026-11-08 10:00:02 +08:00', 'simpeg', '10.10.10.35', 502, 0, 3001.0);
5.2 Time Travel dan Audit Snapshot
Setiap commit menghasilkan snapshot baru. Tabel metadata $snapshots dan $history memungkinkan audit perubahan, sedangkan klausa FOR VERSION AS OF / FOR TIMESTAMP AS OF membaca kondisi tabel di masa lalu. Fitur ini sangat berguna untuk investigasi insiden atau reproduksi model ML.
SELECT snapshot_id, committed_at, operation, summary['added-records'] AS added
FROM lakehouse.web."access_log$snapshots"
ORDER BY committed_at DESC;
-- Baca isi tabel pada snapshot tertentu
SELECT count(*) FROM lakehouse.web.access_log FOR VERSION AS OF 7340215689123456789;
-- Atau berdasarkan waktu
SELECT status, count(*)
FROM lakehouse.web.access_log FOR TIMESTAMP AS OF TIMESTAMP '2026-11-08 12:00:00 +08:00'
GROUP BY status;
5.3 Evolusi Skema dan Partisi Tanpa Rewrite
Menambah kolom atau mengubah granularitas partisi hanyalah operasi metadata. Data lama tetap memakai spesifikasi partisi lama, data baru memakai spesifikasi baru, dan query planner menangani keduanya secara transparan.
ALTER TABLE lakehouse.web.access_log ADD COLUMN user_agent varchar;
-- Trafik meningkat: ganti partisi harian menjadi per jam untuk data baru
ALTER TABLE lakehouse.web.access_log
SET PROPERTIES partitioning = ARRAY['hour(event_ts)', 'bucket(client_ip, 16)'];
6. Maintenance: Compaction, Expire Snapshot, dan Orphan Files
Ingest streaming atau micro-batch menghasilkan banyak file kecil yang memperlambat query. Snapshot lama juga terus menumpuk dan memakan kapasitas S3. Jadwalkan tiga prosedur berikut, misalnya lewat cron atau Airflow:
-- Gabungkan file kecil (< 128MB) menjadi file yang lebih besar
ALTER TABLE lakehouse.web.access_log EXECUTE optimize(file_size_threshold => '128MB');
-- Hapus snapshot lebih tua dari 7 hari (time travel di luar jendela ini hilang)
ALTER TABLE lakehouse.web.access_log EXECUTE expire_snapshots(retention_threshold => '7d');
-- Bersihkan file yang tidak lagi direferensikan metadata
ALTER TABLE lakehouse.web.access_log EXECUTE remove_orphan_files(retention_threshold => '7d');
retention_threshold di bawah batas iceberg.expire-snapshots.min-retention (default 7 hari). Jangan menurunkannya sembarangan: remove_orphan_files dengan retensi terlalu pendek dapat menghapus file milik transaksi yang sedang berjalan dari engine lain, sehingga tabel menjadi korup.
7. Hardening untuk Produksi
- Backend katalog persisten: PostgreSQL dengan backup terjadwal. Katalog adalah sumber kebenaran pointer metadata; jika hilang, tabel harus didaftarkan ulang.
- RBAC granular: buat principal terpisah per engine/aplikasi (misalnya
trino-biread-only,spark-etlread-write) dan batasi grant di level namespace. - Jaringan: letakkan Polaris dan S3 di VLAN/bridge Proxmox internal, dan ekspos hanya Trino (port 8443 dengan TLS + autentikasi password/OAuth2) ke jaringan analis.
- Observabilitas: Polaris menyediakan metrik Prometheus, dan Trino mengekspos metrik JMX/OpenMetrics. Pantau latensi commit katalog dan jumlah file per partisi.
- Skala: ketika beban naik, pindahkan Trino ke Kubernetes (Helm chart
trino/trino) dengan worker autoscaling, sementara katalog dan data tetap tidak berubah.
Kesimpulan
Kombinasi Iceberg + Polaris + Trino memberikan kapabilitas warehouse modern (ACID, time travel, evolusi skema) di atas infrastruktur milik sendiri dan format terbuka. Tidak ada vendor lock-in: data tetap berupa Parquet di S3 Anda, dan engine bisa diganti atau ditambah kapan saja. Mulailah dari satu VM Proxmox, disiplinkan maintenance snapshot sejak hari pertama, lalu skalakan engine secara horizontal saat kebutuhan analitik tumbuh.
COMMENTS