# MinIO + Apache Iceberg lakehouse

Source: https://docs.quake.ai/resources/iac-templates/minio-iceberg
Markdown: https://docs.quake.ai/resources/iac-templates/minio-iceberg.md

---

# MinIO + Apache Iceberg lakehouse

This [validated OpenTofu template](/docs/platform/validation#how-infrastructure-templates-are-checked) composes Compute, Network, and Block Storage into a self-hosted open lakehouse catalog you run on infrastructure you control.

## What this template does

Provisions a single instance running [MinIO](https://min.io) (S3-compatible object storage) and an [Apache Iceberg](https://iceberg.apache.org) REST catalog via Docker Compose:

- MinIO stores table data files; the REST catalog tracks Iceberg metadata with schema evolution and time travel
- Default sizing: `m2a.large` (2 vCPU / 8 GiB RAM) and a 50 GiB data volume at `/var/lib/docker`
- Private network, security group, and floating IP; S3 API (9000), MinIO console (9001), and REST catalog (8181) restricted to `api_allowed_cidr` by default
- cloud-init installs Docker Engine, generates MinIO credentials on first boot, creates the warehouse bucket, and starts both services

No credential ships with this template. MinIO root credentials are generated on first boot and written to `/opt/lakehouse/.bootstrap-credentials` on the instance.

For a durable lake that outlives this VM, use Quake AI [Object Storage](/docs/storage/object) as the warehouse target in production. The bundled MinIO instance suits development, integration testing, and the raw or curated layers on a single host.

## Parameters

| Parameter | Description | Default |
| --- | --- | --- |
| `key_name` | SSH keypair name (must already exist) | No default |
| `flavor_name` | Instance size (MinIO plus REST catalog on 2 vCPU / 8 GiB) | `m2a.large` |
| `image_name` | Operating system image | `Ubuntu-24.04` |
| `app_name` | Display name prefix for resources | `lakehouse` |
| `volume_size` | Block volume size in GiB, mounted at `/var/lib/docker` | `50` |
| `external_network` | External network for floating IP allocation | `PublicStatic` |
| `private_cidr` | CIDR for the private subnet | `10.52.0.0/24` |
| `api_allowed_cidr` | CIDR allowed to reach MinIO and the REST catalog | `10.52.0.0/24` |
| `warehouse_bucket` | S3 bucket name for the Iceberg warehouse root | `warehouse` |

## API access and security

MinIO exposes the S3 API on port 9000 and the web console on 9001. The Iceberg REST catalog listens on 8181. The security group restricts all three to `api_allowed_cidr`, which defaults to the private network only.

Reach the endpoints one of two ways:

- Set `api_allowed_cidr` to `YOUR_IP/32` during setup.
- Tunnel over SSH: `ssh -L 9000:localhost:9000 -L 9001:localhost:9001 -L 8181:localhost:8181 ubuntu@FLOATING_IP`, then use `http://localhost:9000` and `http://localhost:8181`.


Bootstrap credentials live in `/opt/lakehouse/.bootstrap-credentials` on the instance. Snapshot the data volume before you resize or rebuild the host; object data and catalog state both live on the attached volume.


## Object lake target

The template stores table files on MinIO backed by the attached block volume. For production lake workloads, create an Object Storage bucket and S3 credentials in the Console, then repoint the REST catalog warehouse URI at that bucket. Object Storage gives you a durable, S3-compatible target that other compute instances (for example a [Trino](/resources/iac-templates/trino) query host) can reach without routing through this VM's floating IP.

## When to use this pattern

Run an open table format over object storage when you want schema evolution, partition evolution, and time travel without a proprietary warehouse. Iceberg tables registered through the REST catalog work with Spark, Flink, Trino, and other engines that speak the Iceberg REST protocol.

For object storage without table metadata, use [S3 storage with ACLs](/resources/iac-templates/s3-storage-acl). For federated SQL over Iceberg tables, add a [Trino](/resources/iac-templates/trino) query host that points at the same warehouse URI.

## Estimated cost

<PricingCompanion
  components={[
    { kind: "template", slug: "minio-iceberg", required: true },
  ]}
/>

## Template source

<TemplateSource slug="minio-iceberg" />

<TemplateResourceMap template="minio-iceberg" format="opentofu" />

## Customize this pattern

- [Customize a template's image and flavor](/docs/automation/how-to/customize-template-image-flavor)
- [Add a block volume to a template](/docs/automation/how-to/add-volume-to-template)
- [Parameterize a template with a tfvars file](/docs/automation/how-to/parameterize-template-tfvars)

## See also

- [S3 storage with ACLs](/resources/iac-templates/s3-storage-acl)
- [Trino query engine](/resources/iac-templates/trino)
- [Object Storage overview](/docs/storage/object)
