1. Kiến trúc và Vai trò của Iceberg REST Catalog
Mục đích: Hiểu rõ cách Iceberg REST Catalog đóng vai trò trung gian giữa các Client (Trino, Spark, Flink) và Storage Backend (S3/MinIO).
Giải thích: Iceberg REST Catalog là một server độc lập, chạy theo chuẩn HTTP/JSON. Nó không lưu trữ dữ liệu thực tế (data files) mà chỉ quản lý Metadata (Catalog, Namespace, Table Schema, Snapshot). Khi Client muốn truy cập bảng, nó gửi request lên Catalog, Catalog sẽ tương tác với Storage Backend để lấy thông tin vị trí file, sau đó trả về cho Client.
Lợi ích: Giải quyết bài toán "Single Catalog, Multiple Engines". Bạn chỉ cần duy trì một Catalog duy nhất, cho phép Trino đọc, Spark ghi, và Flink stream dữ liệu vào cùng một bảng Iceberg mà không cần chuyển đổi định dạng.
Verify: Đảm bảo bạn đã có môi trường Kubernetes (EKS/GKE/MicroK8s) và Helm đã cài đặt. Kiểm tra version Helm bằng lệnh sau:
helm version
Kết quả mong đợi: In ra phiên bản Helm (ví dụ: version.BuildInfo{Version:"v3.12.0", ...}).
2. Triển khai Iceberg REST Catalog bằng Helm Chart
Mục đích: Cài đặt Iceberg REST Catalog vào cluster Kubernetes dưới dạng một Pod và Service.
Giải thích: Apache Iceberg cung cấp Helm Chart chính thức. Chúng ta sẽ sử dụng repository của Apache để pull chart này. Việc triển khai qua Helm giúp quản lý lifecycle, versioning và scaling tự động.
Bước 1: Thêm repository của Apache Iceberg.
helm repo add apache-iceberg https://iceberg.apache.org/helm-charts/
helm repo update
Kết quả mong đợi: In ra thông báo "repository apache-iceberg added" và update thành công.
Bước 2: Tạo namespace riêng cho Iceberg.
kubectl create namespace iceberg-catalog
Kết quả mong đợi: In ra "namespace/iceberg-catalog created".
Bước 3: Cài đặt Iceberg REST Catalog với cấu hình mặc định (để kiểm tra nhanh).
helm install iceberg-rest-catalog apache-iceberg/iceberg-rest-catalog \
--namespace iceberg-catalog \
--set service.type=ClusterIP \
--set service.port=8181
Kết quả mong đợi: In ra thông báo "NAME: iceberg-rest-catalog" và trạng thái "STATUS: deployed".
Verify kết quả: Kiểm tra trạng thái Pod và Service.
kubectl get pods -n iceberg-catalog
kubectl get svc -n iceberg-catalog
Kết quả mong đợi: Pod có trạng thái "Running" và Service có endpoint nội bộ (ClusterIP).
3. Cấu hình kết nối Catalog với Backend Storage (S3/MinIO)
Mục đích: Cấu hình Catalog để biết cách truy cập vào nơi lưu trữ metadata và data files (ví dụ: MinIO trong local test hoặc S3 trong production).
Giải thích: Iceberg REST Catalog cần biết "nơi lưu trữ" (warehouse) là đâu. Nó cần một URI (ví dụ: s3://my-bucket/warehouse) và thông tin xác thực (Access Key, Secret Key). Trong môi trường Kubernetes, các thông tin nhạy cảm này được lưu trong Kubernetes Secret và được mount vào Pod dưới dạng biến môi trường.
Bước 1: Chuẩn bị Secret cho Storage Backend.
Giả sử bạn đang dùng MinIO với bucket tên là "iceberg-warehouse".
kubectl create secret generic iceberg-storage-credentials \
--from-literal=storage-access-key=MINIO_ACCESS_KEY \
--from-literal=storage-secret-key=MINIO_SECRET_KEY \
--namespace iceberg-catalog
Kết quả mong đợi: In ra "secret/iceberg-storage-credentials created".
Bước 2: Tạo file cấu hình values.yaml tùy chỉnh.
Tạo file iceberg-values.yaml trên máy local của bạn với nội dung đầy đủ như sau:
cat > iceberg-values.yaml
Kết quả mong đợi: File iceberg-values.yaml được tạo thành công.
Bước 3: Upgrade/Install lại Catalog với cấu hình mới.
Nếu bạn đã install ở phần 2, hãy dùng lệnh upgrade. Nếu chưa, dùng install.
helm upgrade --install iceberg-rest-catalog apache-iceberg/iceberg-rest-catalog \
--namespace iceberg-catalog \
-f iceberg-values.yaml
Kết quả mong đợi: In ra "Release "iceberg-rest-catalog" has been upgraded. Happy Helming!"
Verify kết quả: Kiểm tra log của Pod để đảm bảo Catalog đã khởi động và kết nối được với MinIO/S3.
kubectl logs -n iceberg-catalog -l app.kubernetes.io/name=iceberg-rest-catalog --tail=50
Kết quả mong đợi: Không thấy lỗi "Connection refused" hay "Access Denied". Thấy dòng log "Server started on port 8181".
4. Khởi tạo Catalog và Kiểm tra trạng thái
Mục đích: Xác nhận Catalog đã sẵn sàng nhận yêu cầu và kiểm tra sức khỏe của endpoint.
Giải thích: Sau khi Pod chạy, Catalog cần một khoảng thời gian để khởi tạo các connection pool và load cấu hình. Chúng ta sẽ dùng lệnh `curl` để gọi API `/v1/catalogs` của REST Catalog.
Bước 1: Port-forward để truy cập Catalog từ local.
Lệnh này tạo đường hầm mạng từ local machine (port 8181) đến Pod trong cluster.
kubectl port-forward -n iceberg-catalog svc/iceberg-rest-catalog 8181:8181 &
Kết quả mong đợi: In ra "Forwarding from 127.0.0.1:8181 -> 8181" và tiến trình chạy ở background (dấu &).
Bước 2: Gọi API kiểm tra danh sách Catalogs.
curl -s http://localhost:8181/v1/catalogs
Kết quả mong đợi: Trả về JSON chứa danh sách catalog đã cấu hình:
[{"name": "my-iceberg-catalog"}]
Bước 3: Kiểm tra Health check.
curl -s http://localhost:8181/v1/health
Kết quả mong đợi: Trả về {"status": "UP"}.
Verify kết quả: Nếu cả hai lệnh trên trả về JSON hợp lệ, Catalog đã hoạt động ổn định. Dừng port-forward khi không cần dùng nữa bằng `kill %1` hoặc `pkill -f port-forward`.
5. Tạo và quản lý Iceberg Table thông qua REST API
Mục đích: Thực hành tạo bảng Iceberg đầu tiên bằng cách gửi yêu cầu HTTP trực tiếp đến Catalog, thay vì dùng Spark/Trino.
Giải thích: Iceberg REST Catalog hỗ trợ API chuẩn để tạo bảng. Chúng ta cần gửi một request `POST` đến endpoint `/v1/namespaces/{namespace}/tables` với body JSON chứa định nghĩa Schema của bảng.
Bước 1: Tạo Namespace (Database) mới.
Trước khi tạo bảng, phải tạo namespace.
curl -X POST http://localhost:8181/v1/namespaces/my_db -H "Content-Type: application/json" -d '{}'
Kết quả mong đợi: Trả về {"name": "my_db"}.
Bước 2: Tạo Bảng Iceberg với Schema cụ thể.
Chúng ta sẽ tạo bảng `sales` với các cột: id (long), product (string), amount (double), created_at (timestamp).
curl -X POST http://localhost:8181/v1/namespaces/my_db/tables/sales \
-H "Content-Type: application/json" \
-d '{
"schema": {
"type": "struct",
"schema-id": 0,
"fields": [
{"id": 1, "name": "id", "type": "long", "required": true},
{"id": 2, "name": "product", "type": "string", "required": false},
{"id": 3, "name": "amount", "type": "double", "required": false},
{"id": 4, "name": "created_at", "type": "timestamp", "required": false}
]
},
"location": "s3://iceberg-warehouse/warehouse/my_db/sales",
"properties": {
"write.delete.default": "false",
"write.update.default": "false",
"write.merge.default": "false"
}
}'
Kết quả mong đợi: Trả về JSON chi tiết về bảng mới được tạo, bao gồm table name, namespace, location và schema-id.
Bước 3: Liệt kê các bảng trong namespace.
Kiểm tra xem bảng `sales` đã xuất hiện trong namespace `my_db` chưa.
curl -s http://localhost:8181/v1/namespaces/my_db/tables
Kết quả mong đợi: Trả về mảng JSON chứa tên bảng:
[{"name": "sales"}]
Bước 4: Lấy thông tin chi tiết của bảng (Table Metadata).
Lệnh này sẽ trả về toàn bộ metadata của bảng, bao gồm cả các snapshot (nếu có) và partition spec.
curl -s http://localhost:8181/v1/namespaces/my_db/tables/sales
Kết quả mong đợi: Trả về JSON lớn chứa thông tin định nghĩa bảng. Lưu ý trường "metadata-location" sẽ trỏ đến file metadata.json trong S3/MinIO.
Verify kết quả: Mở file iceberg-values.yaml hoặc log của Catalog để xác nhận cấu hình đã áp dụng đúng. Nếu bạn truy cập vào MinIO Console và vào bucket iceberg-warehouse, bạn sẽ thấy thư mục warehouse/my_db/sales/metadata chứa các file v0.metadata.json và current-manifest-list.
Điều hướng series:
Mục lục: Series: Xây dựng nền tảng Data Fabric hiện đại với Apache Iceberg, Trino và Kubernetes
« Phần 2: Triển khai Apache Iceberg trên Kubernetes với Iceberg REST Catalog
Phần 3: Triển khai Trino trên Kubernetes để truy vấn dữ liệu Iceberg »