MLflow experiment tracking
MLflow experiment tracking
This pattern composes Compute, Network, Block Storage, and Object Storage into a self-hosted experiment-tracking and model-registry server you run on infrastructure you control.
What this template does#
Provisions a single instance running MLflow, an open-source experiment-tracking and model-registry platform (a self-hosted alternative to Weights & Biases or Neptune). You log parameters, metrics, and artifacts from notebooks or training jobs, compare runs in the UI, and promote models through the registry:
- Compute instance that runs the MLflow tracking server in Docker, sized for moderate concurrent logging (2 vCPU and 2 GiB RAM)
- Private network, subnet, router, port, and security group; a floating IP for public access
- A block volume mounted at
/var/lib/docker, so Docker state lives on a volume you can grow rather than on the boot disk - cloud-init installs Docker Engine and writes the MLflow compose stack on first boot
- External PostgreSQL for experiment metadata and Object Storage for run artifacts (models, plots, files)
MLflow is the tracking layer for ML platform teams. It records experiments and hosts the model registry on a VM you own, which keeps metadata and artifact paths on your infrastructure.
No credential ships with this template. You add the PostgreSQL password and Object Storage credentials to /opt/mlflow/.env on the instance after apply.
Parameters#
| Parameter | Description | Default |
|---|---|---|
key_name | SSH keypair name (must already exist) | No default |
postgres_host | PostgreSQL host for metadata (for example a self-managed PostgreSQL private IP) | No default |
artifact_bucket | Object Storage bucket for run artifacts | No default |
s3_endpoint | S3-compatible endpoint URL for Object Storage | No default |
flavor_name | Instance size (tracking server runs on 2 vCPU / 2 GiB) | s1a.small |
image_name | Operating system image | Ubuntu-24.04 |
app_name | Display name prefix for resources | mlflow |
volume_size | Block volume size in GiB, mounted at /var/lib/docker | 20 |
external_network | External network for floating IP allocation | PublicStatic |
private_cidr | CIDR for the private subnet | 10.40.0.0/24 |
ui_allowed_cidr | CIDR allowed to reach the UI on port 5000 | 10.40.0.0/24 |
postgres_db | PostgreSQL database name | mlflow |
postgres_user | PostgreSQL user | mlflow |
artifact_prefix | Key prefix inside the artifact bucket | mlflow |
UI access and security#
The tracking UI listens on port 5000 over plain HTTP. The security group restricts 5000 to ui_allowed_cidr, which defaults to the private network only, so the raw UI stays off the public internet. Reach the UI one of three ways:
- Put a reverse proxy (Caddy or Nginx) in front of MLflow and serve the UI over HTTPS on 443. Point the domain's DNS A record at the floating IP. This is the recommended path for routine access.
- Tunnel over SSH:
ssh -L 5000:localhost:5000 ubuntu@FLOATING_IP, then openhttp://localhost:5000. - Set
ui_allowed_cidrtoYOUR_IP/32to reach port 5000 directly from one address.
Ports 80 and 443 stay open for the reverse proxy you put in front; they carry no traffic until you add one.
Metadata and artifacts#
The tracking server splits storage by role:
- PostgreSQL: run metadata, parameters, metrics, and registry entries. Point
postgres_host,postgres_db, andpostgres_userat an external database, then addPOSTGRES_PASSWORDto/opt/mlflow/.envon the instance and rundocker compose up -d --build. - Object Storage: models, plots, and other run artifacts. Set
artifact_bucket,artifact_prefix, ands3_endpoint, then addAWS_ACCESS_KEY_IDandAWS_SECRET_ACCESS_KEYto/opt/mlflow/.env. Provision the bucket with the S3 Storage with ACLs template or use an existing container.
Passwords and S3 credentials stay out of tfvars and the repo.
CPU-only boundary#
This template hosts the MLflow tracking server and model registry only. It does not provision GPUs, CUDA drivers, or training workers. Quake AI compute flavors are CPU-only AMD EPYC; experiment tracking fits that tier cleanly because logging metadata and artifacts is not training.
GPU training, fine-tuning, and heavy inference run on an external backend you operate. Point training jobs at that backend and set MLFLOW_TRACKING_URI to this server so runs still land in your registry. For GPU inference and RAG serving on Quake AI, see the inference gateway template.
When to use this pattern#
Run experiment tracking and a model registry on a VM you operate. MLflow suits notebook-driven exploration, batch training jobs that emit metrics, and teams that want a self-hosted alternative to SaaS experiment trackers.
For multi-user notebooks that log to MLflow, pair this template with JupyterHub. For the PostgreSQL metadata store, see self-managed PostgreSQL. For the artifact bucket, see S3 Storage with ACLs.
Estimated cost#
Monthly cost estimate
Pricing calculator ↗Sized as a custom package on shared vCPU.
Monthly total for the required template above. Use the configurator below to add optional pieces and see the total update.
What each resource is for
MLflow tracking server
s1a.small · 2 shared vCPU, 2 GiB RAM, 0.5 Gbps
Runs the MLflow tracking server in Docker with PostgreSQL metadata and Object Storage artifacts.
The tracking server runs on 2 vCPU and 2 GiB RAM. This template hosts experiment tracking and the model registry only; GPU training runs elsewhere.
Compute shown per role at custom-package rates ($29/dedicated vCPU, $7.25/shared vCPU, $1/GiB RAM). The headline above is the billed total: the cheaper of a named plan and the custom package, plus add-ons.
Included in baseline
s1a.small
2 shared vCPU, 2 GiB RAM, 0.5 Gbps
Compute + RAM rate basis
2 vCPU + 2 GiB RAM at $29/dedicated vCPU, $7.25/shared vCPU, $1/GiB RAM (regular). Totals apply the flat −$5/mo package promotion.
Block storage (50 GiB)
50 GiB at $0.08/GiB/mo
Public IP (included)
1 included with the custom package
Package promotional discount
Flat −$5.00/mo on the custom package (same promotion as named plans).
Included at no charge
These line items are zero on Quake AI. Many other providers meter them separately.
Data transfer (inbound and outbound)
Unlimited data transfer on every plan; Quake AI does not meter per-GB egress.
AWS, GCP, and Azure meter outbound transfer per GB. DigitalOcean and Hetzner include an allowance on compute plans, then charge overage.
Learn morePrivate networking
Private networks, subnets, Neutron routers, and security groups are included with the plan.
VPC objects are usually free to create elsewhere, but NAT gateways bill hourly plus per-GB processed. Quake AI uses router SNAT with no separate NAT line item.
Control-plane API requests
OpenStack API calls for provisioning and management are included.
Some managed services on other clouds meter API calls or charge for premium control-plane features.
Pricing data last validated: . For current rates, check quake.ai/pricing.
Template source#
Show source (7 files)Hide source
data "openstack_images_image_v2" "os" {
name = var.image_name
most_recent = true
}
data "openstack_networking_network_v2" "external" {
name = var.external_network
}
resource "openstack_networking_network_v2" "private" {
name = "${var.app_name}-net"
admin_state_up = true
}
resource "openstack_networking_subnet_v2" "private" {
name = "${var.app_name}-subnet"
network_id = openstack_networking_network_v2.private.id
cidr = var.private_cidr
ip_version = 4
dns_nameservers = ["1.1.1.1", "8.8.8.8"]
}
resource "openstack_networking_router_v2" "main" {
name = "${var.app_name}-router"
external_network_id = data.openstack_networking_network_v2.external.id
}
resource "openstack_networking_router_interface_v2" "private" {
router_id = openstack_networking_router_v2.main.id
subnet_id = openstack_networking_subnet_v2.private.id
}
resource "openstack_networking_secgroup_v2" "mlflow" {
name = "${var.app_name}-sg"
description = "SSH and HTTP/HTTPS for a reverse proxy; MLflow UI port 5000 restricted"
}
resource "openstack_networking_secgroup_rule_v2" "ssh" {
direction = "ingress"
ethertype = "IPv4"
protocol = "tcp"
port_range_min = 22
port_range_max = 22
remote_ip_prefix = "0.0.0.0/0"
security_group_id = openstack_networking_secgroup_v2.mlflow.id
}
# 80 and 443 carry the UI when it is served over a domain with automatic TLS
# through a reverse proxy (Caddy or Nginx). They are not used until you put a
# proxy in front of MLflow; see the reference page.
resource "openstack_networking_secgroup_rule_v2" "http" {
direction = "ingress"
ethertype = "IPv4"
protocol = "tcp"
port_range_min = 80
port_range_max = 80
remote_ip_prefix = "0.0.0.0/0"
security_group_id = openstack_networking_secgroup_v2.mlflow.id
}
resource "openstack_networking_secgroup_rule_v2" "https" {
direction = "ingress"
ethertype = "IPv4"
protocol = "tcp"
port_range_min = 443
port_range_max = 443
remote_ip_prefix = "0.0.0.0/0"
security_group_id = openstack_networking_secgroup_v2.mlflow.id
}
# Raw tracking UI HTTP on 5000 is restricted to ui_allowed_cidr (the private
# network by default). Prefer a domain with TLS on 443 for routine access.
resource "openstack_networking_secgroup_rule_v2" "ui" {
direction = "ingress"
ethertype = "IPv4"
protocol = "tcp"
port_range_min = 5000
port_range_max = 5000
remote_ip_prefix = var.ui_allowed_cidr
security_group_id = openstack_networking_secgroup_v2.mlflow.id
}
resource "openstack_networking_port_v2" "mlflow" {
name = "${var.app_name}-port"
network_id = openstack_networking_network_v2.private.id
security_group_ids = [openstack_networking_secgroup_v2.mlflow.id]
fixed_ip {
subnet_id = openstack_networking_subnet_v2.private.id
}
depends_on = [openstack_networking_router_interface_v2.private]
}
resource "openstack_blockstorage_volume_v3" "data" {
name = "${var.app_name}-data"
size = var.volume_size
}
resource "openstack_compute_instance_v2" "mlflow" {
name = var.app_name
flavor_name = var.flavor_name
key_pair = var.key_name
user_data = templatefile("${path.module}/cloud-init/mlflow.yaml.tftpl", {
app_name = var.app_name
postgres_host = var.postgres_host
postgres_db = var.postgres_db
postgres_user = var.postgres_user
artifact_bucket = var.artifact_bucket
artifact_prefix = var.artifact_prefix
s3_endpoint = var.s3_endpoint
})
block_device {
uuid = data.openstack_images_image_v2.os.id
source_type = "image"
destination_type = "volume"
volume_size = 30
boot_index = 0
delete_on_termination = true
}
network {
port = openstack_networking_port_v2.mlflow.id
}
}
resource "openstack_compute_volume_attach_v2" "data" {
instance_id = openstack_compute_instance_v2.mlflow.id
volume_id = openstack_blockstorage_volume_v3.data.id
}
resource "openstack_networking_floatingip_v2" "mlflow" {
pool = var.external_network
}
resource "openstack_networking_floatingip_associate_v2" "mlflow" {
floating_ip = openstack_networking_floatingip_v2.mlflow.address
port_id = openstack_networking_port_v2.mlflow.id
}
variable "key_name" {
description = "SSH keypair name (must already exist in your project)"
type = string
}
variable "flavor_name" {
description = "Instance size. The MLflow tracking server runs comfortably on 2 vCPU and 2 GiB RAM. Size up when many concurrent clients log runs."
type = string
default = "s1a.small"
}
variable "image_name" {
description = "Operating system image. Ubuntu 24.04 is the recommended base."
type = string
default = "Ubuntu-24.04"
}
variable "app_name" {
description = "Display name prefix for compute and network resources"
type = string
default = "mlflow"
}
variable "volume_size" {
description = "Block volume size in GiB, mounted at /var/lib/docker so Docker state lives on a volume you can grow rather than on the boot disk."
type = number
default = 20
}
variable "external_network" {
description = "Shared external network for router gateway and floating IPs; defaults to PublicStatic (persisted FIP / production pattern). Override with PublicEphemeral for ephemeral demos."
type = string
default = "PublicStatic"
}
variable "private_cidr" {
description = "CIDR for the private tenant network the instance lives in"
type = string
default = "10.40.0.0/24"
}
variable "ui_allowed_cidr" {
description = "CIDR allowed to reach the MLflow UI on port 5000. Defaults to the private network only, so the raw UI is not exposed to the public internet. Reach it over an SSH tunnel, or (recommended) serve it over a domain with HTTPS on 443 behind a reverse proxy. To allow direct access from your workstation, set this to YOUR_IP/32."
type = string
default = "10.40.0.0/24"
}
variable "postgres_host" {
description = "PostgreSQL host for experiment metadata (for example the private IP of a self-managed-postgres instance). The password is never set here: add POSTGRES_PASSWORD to /opt/mlflow/.env on the instance and restart."
type = string
}
variable "postgres_db" {
description = "PostgreSQL database name for MLflow metadata"
type = string
default = "mlflow"
}
variable "postgres_user" {
description = "PostgreSQL user for MLflow metadata. The password is never set here: add POSTGRES_PASSWORD to /opt/mlflow/.env on the instance and restart."
type = string
default = "mlflow"
}
variable "artifact_bucket" {
description = "Object Storage bucket name for MLflow artifacts (models, plots, run files). Provision the bucket with the s3-storage-acl template or an existing container."
type = string
}
variable "artifact_prefix" {
description = "Key prefix inside the artifact bucket where MLflow stores run artifacts"
type = string
default = "mlflow"
}
variable "s3_endpoint" {
description = "S3-compatible endpoint URL for Object Storage (for example https://us-east-1.rumble.cloud). Credentials are never set here: add AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY to /opt/mlflow/.env on the instance."
type = string
}
output "instance_id" {
description = "ID of the compute instance running MLflow"
value = openstack_compute_instance_v2.mlflow.id
}
output "floating_ip" {
description = "Public floating IP address of the MLflow host"
value = openstack_networking_floatingip_v2.mlflow.address
}
output "private_ip" {
description = "Private IP address of the instance"
value = openstack_compute_instance_v2.mlflow.access_ip_v4
}
output "tracking_url" {
description = "MLflow tracking UI URL on port 5000. Reachable from ui_allowed_cidr (the private network by default; tunnel over SSH, or put a reverse proxy in front and use HTTPS on 443)."
value = "http://${openstack_networking_floatingip_v2.mlflow.address}:5000"
}
terraform {
required_version = ">= 1.6.0"
required_providers {
openstack = {
source = "terraform-provider-openstack/openstack"
version = "~> 2.0"
}
}
}
provider "openstack" {}
# Required: SSH keypair must already exist in your project
key_name = "YOUR_KEY_NAME"
# Required: external PostgreSQL for experiment metadata and Object Storage for artifacts
postgres_host = "10.50.0.12"
postgres_db = "mlflow"
postgres_user = "mlflow"
artifact_bucket = "my-ml-artifacts"
s3_endpoint = "https://us-east-1.rumble.cloud"
# Recommended: restrict the MLflow UI (port 5000) to your workstation IP.
# Leave unset to keep 5000 reachable only from the private network and tunnel
# over SSH, or put a reverse proxy in front and use HTTPS on 443.
# ui_allowed_cidr = "203.0.113.10/32"
# artifact_prefix = "mlflow"
# flavor_name = "s1a.small"
# image_name = "Ubuntu-24.04"
# app_name = "mlflow"
# volume_size = 20
# external_network = "PublicStatic"
# private_cidr = "10.40.0.0/24"
#cloud-config
package_update: true
packages:
- ca-certificates
- curl
write_files:
- path: /opt/mlflow/Dockerfile
permissions: "0644"
content: |
FROM python:3.11-slim
RUN pip install --no-cache-dir mlflow==2.22.0 psycopg2-binary boto3
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
EXPOSE 5000
ENTRYPOINT ["/entrypoint.sh"]
- path: /opt/mlflow/entrypoint.sh
permissions: "0755"
content: |
#!/bin/bash
set -euo pipefail
: "$${POSTGRES_HOST:?Set POSTGRES_HOST in /opt/mlflow/.env}"
: "$${POSTGRES_USER:?Set POSTGRES_USER in /opt/mlflow/.env}"
: "$${POSTGRES_DB:?Set POSTGRES_DB in /opt/mlflow/.env}"
: "$${POSTGRES_PASSWORD:?Set POSTGRES_PASSWORD in /opt/mlflow/.env}"
: "$${ARTIFACT_BUCKET:?Set ARTIFACT_BUCKET in /opt/mlflow/.env}"
: "$${S3_ENDPOINT:?Set S3_ENDPOINT in /opt/mlflow/.env}"
: "$${AWS_ACCESS_KEY_ID:?Set AWS_ACCESS_KEY_ID in /opt/mlflow/.env}"
: "$${AWS_SECRET_ACCESS_KEY:?Set AWS_SECRET_ACCESS_KEY in /opt/mlflow/.env}"
ARTIFACT_PREFIX="$${ARTIFACT_PREFIX:-mlflow}"
export MLFLOW_S3_ENDPOINT_URL="$${S3_ENDPOINT}"
exec mlflow server \
--host 0.0.0.0 \
--port 5000 \
--backend-store-uri "postgresql://$${POSTGRES_USER}:$${POSTGRES_PASSWORD}@$${POSTGRES_HOST}:5432/$${POSTGRES_DB}" \
--default-artifact-root "s3://$${ARTIFACT_BUCKET}/$${ARTIFACT_PREFIX}/"
- path: /opt/mlflow/docker-compose.yml
permissions: "0644"
content: |
services:
mlflow:
build: .
restart: unless-stopped
ports:
- "5000:5000"
env_file:
- /opt/mlflow/.env
- path: /opt/mlflow/.env
permissions: "0600"
content: |
# MLflow tracking server for ${app_name}.
# Metadata lives in PostgreSQL; artifacts live in Object Storage.
# Add POSTGRES_PASSWORD, AWS_ACCESS_KEY_ID, and AWS_SECRET_ACCESS_KEY,
# then run `docker compose up -d --build`.
POSTGRES_HOST=${postgres_host}
POSTGRES_DB=${postgres_db}
POSTGRES_USER=${postgres_user}
# POSTGRES_PASSWORD=
ARTIFACT_BUCKET=${artifact_bucket}
ARTIFACT_PREFIX=${artifact_prefix}
S3_ENDPOINT=${s3_endpoint}
# AWS_ACCESS_KEY_ID=
# AWS_SECRET_ACCESS_KEY=
runcmd:
- |
set -e
# The data volume attaches as /dev/sdb on this platform (not /dev/vdb).
# Mount it at /var/lib/docker before Docker is installed so Docker state
# lives on the resizable volume rather than the boot disk.
DEV=/dev/sdb
for i in $(seq 1 30); do [ -b "$DEV" ] && break; sleep 5; done
if ! blkid "$DEV" >/dev/null 2>&1; then mkfs.ext4 -F -L mlflowdata "$DEV"; fi
mkdir -p /var/lib/docker
mount "$DEV" /var/lib/docker
grep -q "$DEV" /etc/fstab || echo "$DEV /var/lib/docker ext4 defaults,nofail 0 2" >> /etc/fstab
curl -fsSL https://get.docker.com | sh
# MLflow does not start until credentials are added to /opt/mlflow/.env.
# See the deployment walkthrough for the full first-boot sequence.
# MLflow experiment tracking
Single compute instance running [MLflow](https://mlflow.org), an open-source experiment-tracking and model-registry platform (a self-hosted alternative to Weights & Biases or Neptune), on infrastructure you control. After apply, you add the PostgreSQL password and Object Storage credentials on the instance, start the tracking server, and log runs from notebooks or training jobs.
**Network class:** production — `external_network` defaults to `PublicStatic` for persisted floating IPs and multi-tier stacks; override with `PublicEphemeral` for ephemeral demos.
The instance provisions a private network, a floating IP, and a block volume mounted at `/var/lib/docker` so Docker state lives on a resizable volume. cloud-init installs Docker Engine and writes the MLflow compose stack on first boot. Metadata lives in an external PostgreSQL database; artifacts live in Object Storage.
## Where this fits
MLflow is the experiment-tracking layer for ML platform teams: it records parameters, metrics, and artifacts from training and evaluation jobs, and exposes a model registry for promoted models. This template hosts the tracking server only. GPU training runs on an external backend you operate; the tracking server itself is CPU-only and fits Quake AI's CPU-only compute tier cleanly.
## Prerequisites
- OpenTofu >= 1.6.0 or Terraform >= 1.6.0
- Quake AI account with OpenStack credentials
- An existing SSH keypair in your project (the value of `key_name` must match that keypair)
- An external PostgreSQL database (for example [self-managed PostgreSQL](/resources/iac-templates/self-managed-postgres)) with a database and user for MLflow metadata
- An Object Storage bucket and S3 credentials (for example from the [S3 Storage with ACLs](/resources/iac-templates/s3-storage-acl) template)
## Resource baseline
The MLflow tracking server runs on 2 vCPU and 2 GiB RAM. The default `s1a.small` flavor leaves headroom for Docker plus moderate concurrent logging from notebooks or batch jobs.
## Usage
1. Clone or copy this template directory
2. Copy `terraform.tfvars.example` to `terraform.tfvars` and fill in your values
3. Source your OpenStack credentials: `source openrc.sh`
4. Initialize: `tofu init`
5. Preview: `tofu plan`
6. Apply: `tofu apply`
After apply, SSH to the instance, add `POSTGRES_PASSWORD`, `AWS_ACCESS_KEY_ID`, and `AWS_SECRET_ACCESS_KEY` to `/opt/mlflow/.env`, then run `docker compose up -d --build`. No credential ships with this template.
## UI access and security
The tracking UI listens on port 5000 over plain HTTP. The security group restricts 5000 to `ui_allowed_cidr`, which defaults to the private network only. Choose one of:
- **Recommended:** put a reverse proxy (Caddy or Nginx) in front of MLflow and serve the UI over HTTPS on 443. Point the domain's DNS A record at `floating_ip`.
- **SSH tunnel:** `ssh -L 5000:localhost:5000 ubuntu@<floating_ip>`, then open `http://localhost:5000`.
- **Direct, scoped:** set `ui_allowed_cidr` to your workstation IP (`YOUR_IP/32`) to reach 5000 directly from one address.
Ports 80 and 443 stay open for the reverse proxy you put in front; they carry no traffic until you add one.
## Metadata and artifacts
- **PostgreSQL:** experiment metadata (runs, parameters, metrics, registry entries) lives in the external database you point at with `postgres_host`, `postgres_db`, and `postgres_user`. Add `POSTGRES_PASSWORD` to `/opt/mlflow/.env` on the instance.
- **Object Storage:** run artifacts (models, plots, files) land in the bucket named by `artifact_bucket` under the prefix `artifact_prefix`. Add S3 credentials to `/opt/mlflow/.env`. Set `s3_endpoint` to your region's Object Storage endpoint.
## Variables
| Name | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `key_name` | string | yes | n/a | SSH keypair name (must already exist in your project) |
| `postgres_host` | string | yes | n/a | PostgreSQL host for metadata |
| `artifact_bucket` | string | yes | n/a | Object Storage bucket for artifacts |
| `s3_endpoint` | string | yes | n/a | S3-compatible endpoint URL |
| `flavor_name` | string | no | `s1a.small` | Instance size (tracking server on 2 vCPU / 2 GiB) |
| `image_name` | string | no | `Ubuntu-24.04` | Operating system image |
| `app_name` | string | no | `mlflow` | Display name prefix for resources |
| `volume_size` | number | no | `20` | Block volume size in GiB, mounted at `/var/lib/docker` |
| `external_network` | string | no | `PublicStatic` | Persisted FIP / production default; override with `PublicEphemeral` for demos |
| `private_cidr` | string | no | `10.40.0.0/24` | CIDR for the private subnet |
| `ui_allowed_cidr` | string | no | `10.40.0.0/24` | CIDR allowed to reach the UI on port 5000 |
| `postgres_db` | string | no | `mlflow` | PostgreSQL database name |
| `postgres_user` | string | no | `mlflow` | PostgreSQL user |
| `artifact_prefix` | string | no | `mlflow` | Key prefix inside the artifact bucket |
## Outputs
| Name | Description |
| --- | --- |
| `floating_ip` | Public floating IP assigned to the instance |
| `private_ip` | Private IP address of the instance |
| `tracking_url` | MLflow tracking UI URL on port 5000 |
| `instance_id` | Compute instance ID |
## Scope
This is a single-VM MLflow tracking host that you operate, not a managed experiment-tracking cloud. It is CPU-only and runs in one region. It records experiments and hosts the model registry; it does not run GPU training. Point training jobs at an external GPU backend and set `MLFLOW_TRACKING_URI` to this server.
## Documentation
See also: [self-managed PostgreSQL](/resources/iac-templates/self-managed-postgres), [S3 Storage with ACLs](/resources/iac-templates/s3-storage-acl), [JupyterHub notebook server](/resources/iac-templates/jupyterhub)
Resources, parameters, and variables
key_namerequiredflavor_name="s1a.small"image_name="Ubuntu-24.04"app_name="mlflow"volume_size=20external_network="PublicStatic"private_cidr="10.40.0.0/24"ui_allowed_cidr="10.40.0.0/24"postgres_hostrequiredpostgres_db="mlflow"postgres_user="mlflow"artifact_bucketrequiredartifact_prefix="mlflow"s3_endpointrequired
Customize this pattern#
- Customize a template's image and flavor
- Add a block volume to a template
- Parameterize a template with a tfvars file
See also#
Usage Guidelines
The sample code, software libraries, command line tools, proofs of concept, templates, and other related technology on this page (including any of the foregoing that is provided by Quake AI personnel) is provided to you as Quake AI Content under the Quake AI Customer Agreement, or the relevant written agreement between you and Quake AI (whichever applies). Do not use this Quake AI Content in your production accounts, or on production or other critical data. You are responsible for testing, securing, and optimizing the Quake AI Content (such as sample code) as appropriate for production grade use based on your specific quality control practices and standards. Deploying Quake AI Content may incur Quake AI charges for creating or using Quake AI chargeable resources, such as running Compute instances or storing data in Object Storage. Your use is also subject to the Acceptable Use Policy.
For the full policy, see Usage Guidelines.
Quick answers
- Why does `openstack image save` write a 0-byte file for my boot-from-volume instance?CLI
- Why does `openstack server create` fail with "Only volume-backed servers are allowed for flavors with zero disk"?CLIAPITerraform
- Why does my project still have a 10 GiB Cinder volume after I deleted my instance?CLIAPI