Ansible provisions the k3d cluster and Flux controllers; Terraform modules deploy the simulated fleet and ground warehouse. Compose and k3d share var/t1 (live lake) and var/t3 (warehouse). The prototype gains a live mode fed by the explorer read-only SQL API.
274 lines
7.0 KiB
Terraform
274 lines
7.0 KiB
Terraform
# Ground warehouse segment (T3, docs/03 + docs/06) — the stationary,
|
|
# long-lifecycle half of the system and therefore the most natural Terraform
|
|
# territory. Runs in the same k3d cluster as the fleet, in its own namespace
|
|
# and with its own state.
|
|
|
|
locals {
|
|
labels = { "app.kubernetes.io/part-of" = "swarm-ground" }
|
|
}
|
|
|
|
resource "kubernetes_namespace" "ground" {
|
|
metadata {
|
|
name = var.namespace
|
|
labels = local.labels
|
|
}
|
|
}
|
|
|
|
# --- MinIO object store -------------------------------------------------------
|
|
|
|
resource "kubernetes_secret" "minio" {
|
|
metadata {
|
|
name = "minio-credentials"
|
|
namespace = kubernetes_namespace.ground.metadata[0].name
|
|
}
|
|
data = {
|
|
MINIO_ROOT_USER = var.minio_root_user
|
|
MINIO_ROOT_PASSWORD = var.minio_root_password
|
|
}
|
|
}
|
|
|
|
resource "kubernetes_persistent_volume_claim" "minio" {
|
|
metadata {
|
|
name = "minio-data"
|
|
namespace = kubernetes_namespace.ground.metadata[0].name
|
|
}
|
|
spec {
|
|
access_modes = ["ReadWriteOnce"]
|
|
resources {
|
|
requests = { storage = var.minio_storage }
|
|
}
|
|
}
|
|
}
|
|
|
|
resource "kubernetes_deployment" "minio" {
|
|
metadata {
|
|
name = "minio"
|
|
namespace = kubernetes_namespace.ground.metadata[0].name
|
|
labels = local.labels
|
|
}
|
|
|
|
spec {
|
|
replicas = 1
|
|
strategy {
|
|
type = "Recreate" # RWO volume
|
|
}
|
|
selector {
|
|
match_labels = { app = "minio" }
|
|
}
|
|
template {
|
|
metadata {
|
|
labels = merge(local.labels, { app = "minio" })
|
|
}
|
|
spec {
|
|
container {
|
|
name = "minio"
|
|
image = "minio/minio:RELEASE.2024-06-13T22-53-53Z"
|
|
args = ["server", "/data", "--console-address", ":9001"]
|
|
|
|
env_from {
|
|
secret_ref {
|
|
name = kubernetes_secret.minio.metadata[0].name
|
|
}
|
|
}
|
|
# Air-gap hygiene: no update checks
|
|
env {
|
|
name = "MINIO_UPDATE"
|
|
value = "off"
|
|
}
|
|
|
|
port {
|
|
container_port = 9000
|
|
}
|
|
port {
|
|
container_port = 9001
|
|
}
|
|
|
|
volume_mount {
|
|
name = "store"
|
|
mount_path = "/data"
|
|
}
|
|
}
|
|
volume {
|
|
name = "store"
|
|
persistent_volume_claim {
|
|
claim_name = kubernetes_persistent_volume_claim.minio.metadata[0].name
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
resource "kubernetes_service" "minio" {
|
|
metadata {
|
|
name = "minio"
|
|
namespace = kubernetes_namespace.ground.metadata[0].name
|
|
}
|
|
spec {
|
|
type = "NodePort"
|
|
selector = { app = "minio" }
|
|
port {
|
|
name = "api"
|
|
port = 9000
|
|
target_port = 9000
|
|
}
|
|
port {
|
|
name = "console"
|
|
port = 9001
|
|
target_port = 9001
|
|
node_port = var.node_ports.minio_console
|
|
}
|
|
}
|
|
}
|
|
|
|
# --- Post-flight offload: T1 lake -> T3 warehouse ------------------------------
|
|
# In production this runs on the docking station after a drone lands: only
|
|
# sealed partitions move, checksums are verified, then the on-board lake is
|
|
# pruned. The simulation compresses that into a periodic rsync-style copy
|
|
# plus an object-store mirror.
|
|
|
|
resource "kubernetes_cron_job_v1" "offload" {
|
|
metadata {
|
|
name = "offload"
|
|
namespace = kubernetes_namespace.ground.metadata[0].name
|
|
labels = local.labels
|
|
}
|
|
|
|
spec {
|
|
schedule = var.offload_schedule
|
|
concurrency_policy = "Forbid"
|
|
successful_jobs_history_limit = 3
|
|
failed_jobs_history_limit = 3
|
|
|
|
job_template {
|
|
metadata {
|
|
labels = local.labels
|
|
}
|
|
spec {
|
|
backoff_limit = 1
|
|
template {
|
|
metadata {
|
|
labels = local.labels
|
|
}
|
|
spec {
|
|
restart_policy = "Never"
|
|
|
|
# Step 1: copy Hive partitions verbatim (T1 layout == T3 layout)
|
|
init_container {
|
|
name = "copy"
|
|
image = "busybox:1.36"
|
|
command = ["sh", "-c", "cp -ru /lake/flight_id=* /warehouse/ 2>/dev/null; ls /warehouse | wc -l"]
|
|
volume_mount {
|
|
name = "lake"
|
|
mount_path = "/lake"
|
|
read_only = true
|
|
}
|
|
volume_mount {
|
|
name = "warehouse"
|
|
mount_path = "/warehouse"
|
|
}
|
|
}
|
|
|
|
# Step 2: mirror the warehouse into the object store for
|
|
# downstream consumers (training pipelines, replay tooling)
|
|
container {
|
|
name = "mirror"
|
|
image = "minio/mc:RELEASE.2024-06-12T14-34-03Z"
|
|
command = ["sh", "-c", "mc alias set store http://minio:9000 \"$MINIO_ROOT_USER\" \"$MINIO_ROOT_PASSWORD\" && mc mb -p store/warehouse && mc mirror --overwrite /warehouse store/warehouse"]
|
|
env_from {
|
|
secret_ref {
|
|
name = kubernetes_secret.minio.metadata[0].name
|
|
}
|
|
}
|
|
volume_mount {
|
|
name = "warehouse"
|
|
mount_path = "/warehouse"
|
|
read_only = true
|
|
}
|
|
}
|
|
|
|
volume {
|
|
name = "lake"
|
|
host_path {
|
|
path = var.lake_host_path
|
|
}
|
|
}
|
|
volume {
|
|
name = "warehouse"
|
|
host_path {
|
|
path = var.warehouse_host_path
|
|
type = "DirectoryOrCreate"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# --- Warehouse explorer: historical read-only SQL over all flights -------------
|
|
|
|
resource "kubernetes_deployment" "warehouse_explorer" {
|
|
metadata {
|
|
name = "warehouse-explorer"
|
|
namespace = kubernetes_namespace.ground.metadata[0].name
|
|
labels = local.labels
|
|
}
|
|
|
|
spec {
|
|
replicas = 1
|
|
selector {
|
|
match_labels = { app = "warehouse-explorer" }
|
|
}
|
|
template {
|
|
metadata {
|
|
labels = merge(local.labels, { app = "warehouse-explorer" })
|
|
}
|
|
spec {
|
|
container {
|
|
name = "explorer"
|
|
image = var.simulator_image
|
|
image_pull_policy = "Never"
|
|
command = ["python", "explorer/server.py"]
|
|
env {
|
|
name = "DATA_DIR"
|
|
value = "/warehouse"
|
|
}
|
|
port {
|
|
container_port = 8088
|
|
}
|
|
volume_mount {
|
|
name = "warehouse"
|
|
mount_path = "/warehouse"
|
|
read_only = true
|
|
}
|
|
}
|
|
volume {
|
|
name = "warehouse"
|
|
host_path {
|
|
path = var.warehouse_host_path
|
|
type = "DirectoryOrCreate"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
resource "kubernetes_service" "warehouse_explorer" {
|
|
metadata {
|
|
name = "warehouse-explorer"
|
|
namespace = kubernetes_namespace.ground.metadata[0].name
|
|
}
|
|
spec {
|
|
type = "NodePort"
|
|
selector = { app = "warehouse-explorer" }
|
|
port {
|
|
port = 8088
|
|
target_port = 8088
|
|
node_port = var.node_ports.warehouse_explorer
|
|
}
|
|
}
|
|
}
|