IaC Bazaar
Oracle CloudPlan-validated

Instance Pool with Autoscaling

Self-healing instance pool from an instance configuration with metric- or schedule-based autoscaling and LB attachment.

terraformOracle Cloud#oci

Compare Virtual Machines across clouds →

oci-instance-pool-autoscalingterraform v1.7

Verification

Plan-validated

Passed: module logic verified on a mocked plan — inputs, validation rules, conditional creation and outputs resolve (no real provider, no cloud).

Conformance

  • Static validation (fmt · validate · tflint)
  • Security scan clean (Checkov)
  • Plan tests (mocked: validation rules · outputs)

Provenance

  • SHA-256 checksum
  • Signature (pending)

Functional

  • Live test pending (no cloud run yet)

Last verified 2026-06-28 · how we verify

Documentation

oci-instance-pool-autoscaling — Instance Pool with Autoscaling

A self-healing OCI instance pool built from an immutable instance configuration, with optional metric-based (CPU/memory threshold) and schedule-based (cron) autoscaling, and automatic load-balancer backend registration. Works with Terraform and OpenTofu (>= 1.6), OCI provider >= 8.0, < 9.0.

Status: static-validated, live-test pending. Ships under live-test quarantine — validated with tofu fmt, tofu validate, and tflint. Real apply → scale → destroy against an OCI tenancy is pending a cloud sandbox. Testable cheaply with micro shapes, so this is a strong early candidate once the live lane exists.

The immutability problem (design note)

An instance configuration is immutable: any change to the launch template (shape, image, boot volume, metadata, …) forces OCI to create a new configuration. This module marks the configuration create_before_destroy and feeds its id into the pool, so a template change stands up the new configuration first, re-points the pool, then retires the old one — the pool is never left pointing at a deleted configuration. The pool's size is ignore_changesd because autoscaling owns the live instance count; a scaling event must not surface as configuration drift on the next plan.

Secure / sane defaults

  • No public IP by default. Pool instances sit in a private subnet behind a load balancer; assign_public_ip = false. Scope ingress to the LB with nsg_ids (deny-by-default).
  • Legacy IMDS (v1) disabled on every launched instance (OCI's IMDSv2 enforcement).
  • Encryption at rest always on — bring your own Vault key via boot_volume_kms_key_id; in-transit encryption on by default.
  • Deterministic template. image_id is required — the pool launches from a pinned image so scale-outs are reproducible (no platform-image drift).
  • Bounded scaling. capacity (min/initial/max) caps how far autoscaling can grow or shrink the pool; cool-down floors at 300s.

Usage

module "web_pool" {
  source = "./oci-instance-pool-autoscaling"

  compartment_id = "ocid1.compartment.oc1..xxxx"
  name           = "web"

  image_id      = "ocid1.image.oc1.iad.xxxx"
  shape         = "VM.Standard.E5.Flex"
  ocpus         = 2
  memory_in_gbs = 16

  subnet_id = "ocid1.subnet.oc1.iad.xxxx" # private
  nsg_ids   = ["ocid1.networksecuritygroup.oc1.iad.xxxx"]

  placements = {
    ad1 = { availability_domain = "Uocm:US-ASHBURN-AD-1" }
    ad2 = { availability_domain = "Uocm:US-ASHBURN-AD-2" }
  }

  pool_size = 2

  load_balancers = {
    web = {
      load_balancer_id = "ocid1.loadbalancer.oc1.iad.xxxx"
      backend_set_name = "web-backends"
      port             = 8080
    }
  }

  autoscaling_enabled = true
  capacity            = { initial = 2, min = 2, max = 6 }
  metric_policy = {
    metric_type         = "CPU_UTILIZATION"
    scale_out_threshold = 75
    scale_in_threshold  = 25
  }

  schedule_policies = {
    nightly_floor = { target_size = 2, expression = "0 0 22 * * ? *", timezone = "UTC" }
  }
}

Inputs (key)

NameTypeDefaultDescription
compartment_idstringCompartment OCID (required)
namestringBase name / resource prefix (required)
image_idstringPinned boot image OCID (required)
shapestringVM.Standard.E5.FlexCompute shape; .Flex honours ocpus/memory
ocpus / memory_in_gbsnumber1 / 16Flex shape sizing
boot_volume_size_in_gbsnumber50Boot volume size (50-32768)
boot_volume_vpus_per_gbnumber10Boot volume performance (10-120)
boot_volume_kms_key_idstringnullCustomer-managed boot-volume key
in_transit_encryption_enabledbooltrueIn-transit encryption for boot volume
disable_legacy_imdsbooltrueDisable IMDS v1 endpoints
assign_public_ipboolfalsePublic IP on instances
nsg_idslist(string)[]NSGs on each instance's VNIC
ssh_authorized_keysstringnullSSH key(s) injected into instances
user_datastringnullRaw cloud-init (module base64-encodes)
subnet_idstringPrimary-VNIC subnet for placements (required)
placementsmap(object)ADs to spread over: { availability_domain, fault_domains? } (required)
pool_sizenumber2Baseline pool size
load_balancersmap(object){}LB backends: { load_balancer_id, backend_set_name, port, vnic_selection? }
autoscaling_enabledbooltrueCreate an autoscaling configuration
cool_down_in_secondsnumber300Min seconds between scaling actions (≥300)
capacityobject{2,2,6}{ initial, min, max } scaling bounds
metric_policyobject{} (CPU)Threshold policy; null = none. { metric_type?, scale_out_threshold?, scale_in_threshold?, scale_out_by?, scale_in_by?, pending_duration? }
schedule_policiesmap(object){}Cron scale-to policies: { target_size, expression, timezone? }
freeform_tags / defined_tagsmap(string){}Tags on all resources

Outputs

instance_configuration_id, instance_pool_id, instance_pool_state, instance_pool_size, autoscaling_configuration_id.

Notes

  • Either metric_policy or at least one schedule_policies entry is required when autoscaling_enabled = true (an autoscaling configuration needs at least one policy) — a precondition enforces this.
  • Schedule policies use Quartz cron (second minute hour day-of-month month day-of-week year) and scale the pool to target_size at the trigger time.
  • The pool registers instances into the named load-balancer backend set automatically as it scales; create the backend set (with health checks) outside this module.
  • Updating the template (shape/image/etc.) replaces the instance configuration and triggers a rolling instance refresh in the pool — expect instance churn.

Requirements

  • Terraform or OpenTofu >= 1.6
  • oracle/oci >= 8.0, < 9.0

Verification

Static-validated (tofu fmt, tofu validate, tflint). Live apply/scale/destroy testing pending cloud sandbox availability — see catalog status.

License

Commercial — LicenseRef-IaCBazaar-Commercial. © IaC Bazaar. Original work (not derived from a third-party module).