upgrade_to_cluster
ActiveTool of cloud.redu/mcp
Turns a single running instance into a horizontally-autoscaling cluster: snapshots the instance and puts your SOURCE VM behind an Octavia load balancer as its ALWAYS-ON BASELINE MEMBER, then an autoscaling group adds EXTRA members (booted from that snapshot) on CPU load and scales them back down to zero. At rest ONLY your source VM serves — there is NO idle extra VM to pay for (the source VM is the cluster's minimum, so the floor is 0 extra members). Use it to LOAD-SCALE a stateless app tier while managed services hold state: it becomes highly-available UNDER LOAD (multiple members behind the LB), but at rest a SINGLE source VM serves — and that source VM is a plain Nova server, not an autoscaled member, so it is NOT auto-replaced if it fails while idle (only the autoscaled extra members are ASG-managed and self-healed). If you need always-on redundancy, keep the app under enough load to hold >=1 extra member, or use a separate always-on setup. BILLED — at rest it costs just your source VM (which you already run) plus the load balancer; under load it adds up to max_size EXTRA members at the member flavor (flavor_id), billed only while they run. In guided mode show the cost that way (now: source VM already running + the LB; under load: up to max_size x the member flavor) and get the user's explicit go first. redu automatically repoints the extra members from the old single-VM URL to the load-balancer URL across app config. It REFUSES a STATEFUL VM with 409 cluster_needs_stateless unless confirm_stateless:true. To have redu FIX a stateful VM for you instead of refusing, pass auto_restructure:true — for a single_vm Postgres it fully-automatically provisions a managed DB + migrates the data + repoints the members; for a compose-stack DB it provisions the matching managed DB (set restructure_engine, e.g. 'mysql'/'mariadb' for WordPress) and returns migration commands to run from the app VM. WordPress/WooCommerce is not generic autoscaling: managed DB alone is not enough because wp-content/uploads is file state. Use app_profile:'wordpress'/'woocommerce', cluster_media_mode:'media_space', and either media_space_id or create_media_space:true so all members mount the same uploads filesystem; otherwise the backend refuses with 409 cluster_needs_media_space. PUT THE CLUSTER ON THE SAME private network as the managed DB and media space. If the app does not auto-start on a fresh boot, pass startup_command. The snapshot upload can take several minutes; poll list_clusters until CREATE_COMPLETE.
Parameters schema
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"required": [
"instance_id",
"name",
"flavor_id",
"network_id",
"keypair_name"
],
"properties": {
"name": {
"type": "string",
"maxLength": 63,
"minLength": 1,
"description": "Name for the cluster (lowercase letters, numbers, hyphens)."
},
"port": {
"type": "integer",
"maximum": 65535,
"minimum": 1,
"description": "Port the app listens on / the load balancer forwards to (default 80). Your source VM must actually serve on this port — the load balancer health-checks it."
},
"dname": {
"type": "string",
"description": "Optional public DNS name for the cluster's load-balancer access point (a .redu.cloud name is auto-generated if omitted)."
},
"max_size": {
"type": "integer",
"maximum": 10,
"minimum": 1,
"description": "Maximum number of EXTRA members the group adds ON TOP OF your always-on source VM under load (default 5). At rest only your source VM serves (no idle extra VM); this is the peak burst size, not a permanent member count. There is no min_size — the source VM IS the baseline member, so the floor is 0 extra members."
},
"flavor_id": {
"type": "string",
"minLength": 1,
"description": "Member VM size — from list_flavors. Every autoscaling member uses this flavor."
},
"network_id": {
"type": "string",
"minLength": 1,
"description": "Private network id — from list_private_networks. Use the SAME network the app's managed DB / other services are on, so members can reach them by private IP."
},
"app_profile": {
"enum": [
"generic",
"wordpress",
"woocommerce"
],
"type": "string",
"description": "Set wordpress/woocommerce when upgrading an older deployment or raw VM that the backend has not profiled. WordPress/WooCommerce clusters require managed MySQL/MariaDB plus a media_space or explicitly configured central_media_origin."
},
"instance_id": {
"type": "string",
"minLength": 1,
"description": "The instance to turn into a cluster (from list_instances, or the VM of a deploy_app/deploy_compose deployment). It is snapshotted, and the autoscaling members are booted from that snapshot."
},
"keypair_name": {
"type": "string",
"minLength": 1,
"description": "SSH keypair name — from list_keypairs."
},
"media_space_id": {
"type": "integer",
"description": "Existing Redu media space id to mount on every WordPress/WooCommerce cluster member.",
"exclusiveMinimum": 0
},
"idempotency_key": {
"type": "string",
"minLength": 8
},
"startup_command": {
"type": "string",
"pattern": "^[^\\n\\r]*$",
"maxLength": 2000,
"description": "Single-line shell command to (re)start the app on each fresh member if the snapshot's own services do not auto-start it. For a podman-compose app: 'cd /opt/app && podman-compose up -d'. Omit to rely on the image's own auto-starting services."
},
"auto_restructure": {
"type": "boolean",
"description": "Instead of just refusing a stateful VM, have redu get its co-located database OFF the VM first, then cluster. FULLY AUTO for a single_vm Postgres (redu deployed it): redu provisions a managed Postgres on the cluster's private network and the members migrate the data + repoint the app on boot — no manual steps (response restructure.mode='auto'). For a compose/unknown DB, ASSISTED: redu provisions the matching managed DB (see restructure_engine) and returns the exact dump/restore/repoint commands to run FROM THE APP VM (response restructure.mode='assisted') — redu will not run an unattended dump against a database it does not own. Only addresses the co-located-DB refusal (cluster_needs_stateless); it does NOT bypass the WordPress media guard. Writes to the OLD VM during the (several-minute) upgrade are not migrated; cut traffic over to the cluster URL once it is up."
},
"media_mount_path": {
"type": "string",
"description": "Host mount path on cluster members. Redu mounts this into /var/www/html/wp-content/uploads for WordPress/WooCommerce."
},
"media_origin_url": {
"type": "string",
"format": "uri",
"description": "Public base URL where WordPress wp-content/uploads is served from the central media origin. This should be a separate media origin, not the DB VM."
},
"media_space_name": {
"type": "string",
"maxLength": 63,
"minLength": 1,
"description": "Optional name for the media space when create_media_space:true. Defaults to <cluster-name>-media."
},
"confirm_stateless": {
"type": "boolean",
"description": "Override the stateful-VM safety refusal. redu REFUSES to cluster a VM that holds its own data (deployed with database:'single_vm' or a compose 'db' service) - a cluster clones the VM into members, so on-VM data diverges and is lost on scale-in; it returns 409 cluster_needs_stateless + a restructure_plan (move the DB to managed, repoint, redeploy, then cluster). Set true ONLY when the VM is genuinely stateless (state in a managed DB / external store, e.g. database:'managed'), or a raw VM you have made stateless."
},
"cluster_media_mode": {
"enum": [
"local_uploads",
"central_media_origin",
"media_space"
],
"type": "string",
"description": "For WordPress/WooCommerce, use media_space as the default real cluster fix. local_uploads is refused because wp-content/uploads would diverge across members."
},
"create_media_space": {
"type": "boolean",
"description": "Set TRUE when upgrading a WordPress/WooCommerce deployment that has no media_space_id yet. Redu creates a small NFS media VM + volume, records it, and mounts it on all members."
},
"restructure_engine": {
"enum": [
"postgres",
"mysql",
"mariadb"
],
"type": "string",
"description": "For the ASSISTED path (a compose-stack database), which managed engine to provision. WordPress/WooCommerce = 'mysql' (or 'mariadb'). Required when auto_restructure is set and the DB runs inside the compose stack; ignored for a single_vm Postgres (always Postgres)."
},
"scale_in_threshold": {
"type": "number",
"maximum": 1,
"minimum": 0,
"description": "Average CPU fraction (0-1) below which a member is removed (default 0.2)."
},
"media_space_size_gb": {
"type": "integer",
"maximum": 2048,
"minimum": 1,
"description": "Media space data volume size in GB when create_media_space:true (default 20)."
},
"scale_out_threshold": {
"type": "number",
"maximum": 1,
"minimum": 0,
"description": "Average CPU fraction (0-1) above which a member is added (default 0.7)."
},
"media_space_flavor_id": {
"type": "string",
"minLength": 1,
"description": "Flavor id for the media VM when create_media_space:true. Defaults to the cluster member flavor."
},
"restructure_db_flavor_id": {
"type": "string",
"description": "Optional VM size for the provisioned managed database (from list_flavors). Defaults to the member flavor; pick a smaller one (e.g. m1.small) if the DB is light."
}
},
"additionalProperties": false
}Parent server
cloud.redu/mcp
1/7 registries