Instance Pool with Autoscaling
Self-healing instance pool from an instance configuration with metric- or schedule-based autoscaling and LB attachment.
Verification
Plan-validatedPassed: 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, andtflint. 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 withnsg_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_idis 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)
| Name | Type | Default | Description |
|---|---|---|---|
compartment_id | string | — | Compartment OCID (required) |
name | string | — | Base name / resource prefix (required) |
image_id | string | — | Pinned boot image OCID (required) |
shape | string | VM.Standard.E5.Flex | Compute shape; .Flex honours ocpus/memory |
ocpus / memory_in_gbs | number | 1 / 16 | Flex shape sizing |
boot_volume_size_in_gbs | number | 50 | Boot volume size (50-32768) |
boot_volume_vpus_per_gb | number | 10 | Boot volume performance (10-120) |
boot_volume_kms_key_id | string | null | Customer-managed boot-volume key |
in_transit_encryption_enabled | bool | true | In-transit encryption for boot volume |
disable_legacy_imds | bool | true | Disable IMDS v1 endpoints |
assign_public_ip | bool | false | Public IP on instances |
nsg_ids | list(string) | [] | NSGs on each instance's VNIC |
ssh_authorized_keys | string | null | SSH key(s) injected into instances |
user_data | string | null | Raw cloud-init (module base64-encodes) |
subnet_id | string | — | Primary-VNIC subnet for placements (required) |
placements | map(object) | — | ADs to spread over: { availability_domain, fault_domains? } (required) |
pool_size | number | 2 | Baseline pool size |
load_balancers | map(object) | {} | LB backends: { load_balancer_id, backend_set_name, port, vnic_selection? } |
autoscaling_enabled | bool | true | Create an autoscaling configuration |
cool_down_in_seconds | number | 300 | Min seconds between scaling actions (≥300) |
capacity | object | {2,2,6} | { initial, min, max } scaling bounds |
metric_policy | object | {} (CPU) | Threshold policy; null = none. { metric_type?, scale_out_threshold?, scale_in_threshold?, scale_out_by?, scale_in_by?, pending_duration? } |
schedule_policies | map(object) | {} | Cron scale-to policies: { target_size, expression, timezone? } |
freeform_tags / defined_tags | map(string) | {} | Tags on all resources |
Outputs
instance_configuration_id, instance_pool_id, instance_pool_state,
instance_pool_size, autoscaling_configuration_id.
Notes
- Either
metric_policyor at least oneschedule_policiesentry is required whenautoscaling_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 totarget_sizeat 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).