Overview
In the dynamic landscape of cloud computing, applications often experience fluctuating demand. Imagine an e-commerce platform during a flash sale, or a news portal reacting to a breaking story – traffic can surge dramatically, requiring immediate scaling of resources to maintain performance and user experience. Conversely, during off-peak hours, over-provisioned resources lead to unnecessary costs. This is where the power of automated scaling becomes indispensable.
Oracle Cloud Infrastructure (OCI) offers a robust solution for this challenge through its Compute autoscaling capabilities, seamlessly integrated with Instance Pools and Load Balancer services. This triumvirate forms the backbone of highly available, resilient, and cost-efficient cloud-native architectures.
At its core, OCI Compute autoscaling intelligently adjusts the number of compute instances in response to predefined metrics, such as CPU utilization or network activity. When demand rises, new instances are automatically provisioned and added to the pool; when demand recedes, instances are gracefully terminated, optimizing resource consumption and costs.
An Instance Pool is a collection of identical compute instances, all created from a single Instance Configuration. It acts as a logical grouping, allowing you to manage multiple instances as a single unit. This simplifies operations like patching, updating, or even terminating a group of instances. When autoscaling is applied to an instance pool, OCI ensures that new instances conform to the specified configuration, maintaining consistency across your fleet.
The Load Balancer integration is the final, critical piece of this puzzle. As instances scale in and out, the Load Balancer automatically registers and deregisters them from its backend sets. This ensures that incoming traffic is always distributed efficiently among the available, healthy instances, providing a single point of access for users and maintaining high availability even during scaling events. Without a load balancer, traffic distribution to a dynamically changing set of instances would be a manual, error-prone nightmare.
Key Benefits of this Integration:
- Elasticity and Responsiveness: Automatically adapts to changes in demand, ensuring consistent performance.
- Cost Efficiency: Pay only for the resources you need, when you need them, by scaling down during low demand.
- High Availability and Resilience: Distributes traffic across multiple instances and can replace unhealthy instances, preventing single points of failure.
- Simplified Management: Manage a fleet of instances as a single entity, reducing operational overhead.
- Improved User Experience: Prevents application slowdowns or outages during peak loads.
Common Use Cases:
- Web Servers and API Gateways: Handling fluctuating web traffic for websites, e-commerce, and microservices.
- Batch Processing: Scaling out for large data processing jobs and scaling in once complete.
- Dev/Test Environments: Provisioning resources on demand for testing cycles.
- Streaming Services: Adapting to varying numbers of concurrent users.
By combining these services, OCI empowers organizations to build highly scalable, fault-tolerant, and cost-effective applications that can effortlessly handle unpredictable workloads.
Prerequisites
Before diving into the implementation, ensure you have the following in place. These foundational elements are crucial for a successful setup.
- OCI Account and Permissions:
- An active OCI tenancy.
- IAM policies that grant the necessary permissions to manage Compute instances, Instance Configurations, Instance Pools, Autoscaling Configurations, Networking resources (VCNs, Subnets, Security Lists/NSGs), and Load Balancers. An `Administrator` policy for your compartment will suffice for this exercise, but in production, adhere to the principle of least privilege.
- Example IAM Policy for a specific group:
Allow group <your-group-name> to manage instance-family in compartment <your-compartment> Allow group <your-group-name> to manage instance-pool-family in compartment <your-compartment> Allow group <your-group-name> to manage volume-family in compartment <your-compartment> Allow group <your-group-name> to manage virtual-network-family in compartment <your-compartment> Allow group <your-group-name> to manage load-balancer-family in compartment <your-compartment> Allow group <your-group-name> to manage ons-topics in compartment <your-compartment> # For alarms Allow group <your-group-name> to manage metrics in compartment <your-compartment> # For alarms
- Oracle Cloud Infrastructure CLI (OCI CLI):
- Installed and configured on your local machine. This article will heavily rely on CLI commands.
- Ensure your `~/.oci/config` file is correctly set up with your user OCID, tenancy OCID, region, and API key fingerprint.
- Networking Resources:
- Virtual Cloud Network (VCN): An existing VCN in your compartment.
- Subnets: At least two subnets within your VCN:
- A public or private subnet for your compute instances (the instance pool).
- A public subnet for your Load Balancer. It's best practice for the Load Balancer to be in a public subnet to receive internet traffic, while compute instances can reside in a private subnet for enhanced security.
- Security Lists or Network Security Groups (NSGs): Configured to allow necessary ingress and egress traffic. For this setup, you'll need rules to:
- Allow SSH (port 22) ingress to compute instances (from your IP or bastion).
- Allow HTTP/HTTPS (ports 80/443) ingress to the Load Balancer from the internet.
- Allow HTTP/HTTPS (ports 80/443) ingress from the Load Balancer's subnet to the compute instance subnet.
- Allow all egress from compute instances (or specific ports if locked down).
- SSH Key Pair:
- A public and private SSH key pair. The public key will be used when creating instances, allowing you to connect to them for management or debugging.
- You can generate one using `ssh-keygen -t rsa -b 2048 -f ~/.ssh/oci_key`.
- Compute Image:
- A suitable custom image or a Marketplace image from which your instances will be launched. For this article, we'll use a standard Oracle Linux image and leverage cloud-init to install a basic web server.
Let's assume you have a compartment named `TechNewsVenture` and you've already created a VCN named `TechNewsVenture-VCN` with subnets `Web-Subnet-AD1` (for instances) and `LB-Subnet-AD1` (for the Load Balancer). We'll fetch their OCIDs as we go.
Step-by-step Implementation
This section will walk you through the entire process of setting up OCI Compute autoscaling with instance pools and load balancer integration using the OCI CLI.
1. Gather Required OCIDs
First, let's get the OCIDs of our compartment, VCN, and subnets. Replace the display names with your actual resource names.
# Get Compartment OCID
COMPARTMENT_ID=$(oci iam compartment list --name 'TechNewsVenture' --query 'data[0].id' --raw-output)
echo "Compartment OCID: $COMPARTMENT_ID"
# Get VCN OCID
VCN_ID=$(oci network vcn list --compartment-id $COMPARTMENT_ID --display-name 'TechNewsVenture-VCN' --query 'data[0].id' --raw-output)
echo "VCN OCID: $VCN_ID"
# Get Subnet OCID for instances (e.g., in AD1)
INSTANCE_SUBNET_ID=$(oci network subnet list --compartment-id $COMPARTMENT_ID --vcn-id $VCN_ID --display-name 'Web-Subnet-AD1' --query 'data[0].id' --raw-output)
echo "Instance Subnet OCID: $INSTANCE_SUBNET_ID"
# Get Subnet OCID for Load Balancer (e.g., in AD1, public)
LB_SUBNET_ID=$(oci network subnet list --compartment-id $COMPARTMENT_ID --vcn-id $VCN_ID --display-name 'LB-Subnet-AD1' --query 'data[0].id' --raw-output)
echo "Load Balancer Subnet OCID: $LB_SUBNET_ID"
# Get Oracle Linux 8 image OCID for your region (example for us-ashburn-1)
# You might need to adjust the display-name or query for your specific region and desired OS.
IMAGE_ID=$(oci compute image list --compartment-id $COMPARTMENT_ID --operating-system "Oracle Linux" --operating-system-version "8" --shape-filter "VM.Standard.E4.Flex" --query 'data[?contains("display-name", `Oracle-Linux-8`)].id | [0]' --raw-output)
echo "Image OCID: $IMAGE_ID"
# SSH Public Key Path
SSH_PUBLIC_KEY_PATH="~/.ssh/oci_key.pub"
SSH_PUBLIC_KEY=$(cat $SSH_PUBLIC_KEY_PATH)
echo "SSH Public Key loaded from: $SSH_PUBLIC_KEY_PATH"
# Define a base name for our resources
RESOURCE_NAME_PREFIX="TNVSujay"
2. Configure Security Lists/Network Security Groups (NSGs)
Ensure your subnets have appropriate security rules. For compute instances, you'll need to allow HTTP (port 80) from the Load Balancer's subnet. For the Load Balancer's subnet, you'll need to allow HTTP (port 80) from the internet.
If using NSGs, create them and associate them with your instances and Load Balancer. This is generally preferred over Security Lists for fine-grained control.
# Example: Create an NSG for instances if you don't have one
# NSG_ID_INSTANCES=$(oci network nsg create --compartment-id $COMPARTMENT_ID --vcn-id $VCN_ID --display-name "${RESOURCE_NAME_PREFIX}-Instance-NSG" --query 'data.id' --raw-output)
# echo "Instance NSG OCID: $NSG_ID_INSTANCES"
# Example: Add ingress rule to NSG for HTTP from LB subnet
# oci network nsg rule add --nsg-id $NSG_ID_INSTANCES --direction INGRESS --protocol 6 --source-type CIDR_BLOCK --source $LB_SUBNET_CIDR --tcp-options '{"destinationPortRange":{"max":80,"min":80}}' --description "Allow HTTP from LB"
# Example: Add ingress rule for SSH from your IP
# oci network nsg rule add --nsg-id $NSG_ID_INSTANCES --direction INGRESS --protocol 6 --source-type CIDR_BLOCK --source <YOUR_PUBLIC_IP>/32 --tcp-options '{"destinationPortRange":{"max":22,"min":22}}' --description "Allow SSH"
# For this guide, we assume existing security lists or NSGs are configured correctly.
# Essential rules:
# 1. Instance Subnet Security List/NSG: Ingress on Port 80 from LB Subnet CIDR. Ingress on Port 22 from your trusted IP.
# 2. LB Subnet Security List/NSG: Ingress on Port 80 from 0.0.0.0/0 (internet).
3. Create an Instance Configuration
The instance configuration defines the template for all instances in your pool. This includes the image, shape, network details, and any cloud-init scripts for initial setup. We'll use a cloud-init script to install Nginx and create a simple index page.
# Cloud-init script to install Nginx and create a simple index.html
CLOUD_INIT_SCRIPT='#!/bin/bash
sudo yum update -y
sudo yum install -y nginx
echo "<!DOCTYPE html><html><head><title>Sujay Singh TechNews Venture</title></head><body><h1>Welcome to TechNews Venture - Instance $(hostname)</h1><p>This instance is part of an OCI autoscaling group.</p></body></html>" | sudo tee /usr/share/nginx/html/index.html
sudo systemctl enable nginx
sudo systemctl start nginx
'
# Create the Instance Configuration
INSTANCE_CONFIG_ID=$(oci compute instance-configuration create \
--compartment-id $COMPARTMENT_ID \
--display-name "${RESOURCE_NAME_PREFIX}-WebConfig" \
--instance-details '{
"instanceType": "compute",
"launchDetails": {
"compartmentId": "'"$COMPARTMENT_ID"'",
"shape": "VM.Standard.E4.Flex",
"imageDetails": {
"imageId": "'"$IMAGE_ID"'",
"instanceSourceFromImageDetails": {
"bootVolumeSizeInGBs": "50",
"sourceType": "image"
}
},
"createVnicDetails": {
"subnetId": "'"$INSTANCE_SUBNET_ID"'",
"assignPublicIp": false,
"displayName": "primaryvnic"
},
"metadata": {
"ssh_authorized_keys": "'"$SSH_PUBLIC_KEY"'",
"user_data": "'$(echo "$CLOUD_INIT_SCRIPT" | base64 -w 0)'"
},
"availabilityDomain": "Uocm:US-ASHBURN-AD-1",
"shapeConfig": {
"ocpus": 1,
"memoryInGBs": 16
}
}
}' \
--query 'data.id' --raw-output)
echo "Instance Configuration OCID: $INSTANCE_CONFIG_ID"
echo "Waiting for Instance Configuration to be available..."
oci compute instance-configuration get --instance-configuration-id $INSTANCE_CONFIG_ID --query 'data."lifecycle-state"' --wait-for-state AVAILABLE --max-wait-seconds 600
echo "Instance Configuration ${RESOURCE_NAME_PREFIX}-WebConfig created successfully."
Note: The `availabilityDomain` parameter is hardcoded here (e.g., `Uocm:US-ASHBURN-AD-1`). You should fetch your ADs dynamically or ensure it matches your environment. For a multi-AD setup, you would typically create multiple instance pools, one for each AD, and have the load balancer distribute across them.
4. Create an Instance Pool
Now, we'll create the instance pool using the configuration we just defined. We'll start with a desired size of 1 instance.
INSTANCE_POOL_ID=$(oci compute instance-pool create \
--compartment-id $COMPARTMENT_ID \
--display-name "${RESOURCE_NAME_PREFIX}-WebPool" \
--instance-configuration-id $INSTANCE_CONFIG_ID \
--placement-configurations '[
{
"availabilityDomain": "Uocm:US-ASHBURN-AD-1",
"primaryVnicSubnets": [
{
"subnetId": "'"$INSTANCE_SUBNET_ID"'"
}
]
}
]' \
--size 1 \
--query 'data.id' --raw-output)
echo "Instance Pool OCID: $INSTANCE_POOL_ID"
echo "Waiting for Instance Pool to be active..."
oci compute instance-pool get --instance-pool-id $INSTANCE_POOL_ID --query 'data."lifecycle-state"' --wait-for-state RUNNING --max-wait-seconds 1200
echo "Instance Pool ${RESOURCE_NAME_PREFIX}-WebPool created and running with 1 instance."
5. Create an Autoscaling Configuration
This is where we define the rules for scaling. We'll set up a policy to scale out when CPU utilization exceeds 60% for a sustained period, and scale in when it drops below 20%.
AUTOSCALING_CONFIG_ID=$(oci autoscaling autoscaling-configuration create \
--compartment-id $COMPARTMENT_ID \
--display-name "${RESOURCE_NAME_PREFIX}-WebAutoscaleConfig" \
--is-enabled true \
--resource '{
"id": "'"$INSTANCE_POOL_ID"'",
"type": "instancePool"
}' \
--auto-scaling-resources '[
{
"id": "'"$INSTANCE_POOL_ID"'",
"type": "instancePool"
}
]' \
--policies '[
{
"capacity": {
"initial": 1,
"max": 4,
"min": 1
},
"display-name": "ScaleOutPolicy",
"is-enabled": true,
"policy-type": "metric",
"rules": [
{
"action": {
"type": "CHANGE_COUNT",
"value": 1
},
"display-name": "ScaleOutRule",
"metric": {
"metric-type": "CPU_UTILIZATION",
"threshold": 60,
"period-in-minutes": 1,
"evaluation-duration-in-minutes": 3,
"statistic": "MEAN"
}
}
],
"cool-down-in-seconds": 300
},
{
"capacity": {
"initial": 1,
"max": 4,
"min": 1
},
"display-name": "ScaleInPolicy",
"is-enabled": true,
"policy-type": "metric",
"rules": [
{
"action": {
"type": "CHANGE_COUNT",
"value": -1
},
"display-name": "ScaleInRule",
"metric": {
"metric-type": "CPU_UTILIZATION",
"threshold": 20,
"period-in-minutes": 1,
"evaluation-duration-in-minutes": 3,
"statistic": "MEAN"
}
}
],
"cool-down-in-seconds": 300
}
]' \
--query 'data.id' --raw-output)
echo "Autoscaling Configuration OCID: $AUTOSCALING_CONFIG_ID"
echo "Waiting for Autoscaling Configuration to be active..."
oci autoscaling autoscaling-configuration get --autoscaling-configuration-id $AUTOSCALING_CONFIG_ID --query 'data."lifecycle-state"' --wait-for-state ACTIVE --max-wait-seconds 600
echo "Autoscaling Configuration ${RESOURCE_NAME_PREFIX}-WebAutoscaleConfig created successfully."
This configuration sets a minimum of 1 and a maximum of 4 instances. It scales out by 1 instance if average CPU utilization exceeds 60% for 3 minutes and scales in by 1 instance if it drops below 20% for 3 minutes. A 5-minute cool-down period prevents rapid, unstable scaling.
6. Create a Load Balancer
Now, let's set up the Load Balancer to distribute traffic to our instance pool. We'll create a public load balancer with an HTTP listener.
# Create the Load Balancer
LB_ID=$(oci lb load-balancer create \
--compartment-id $COMPARTMENT_ID \
--display-name "${RESOURCE_NAME_PREFIX}-WebLB" \
--shape "10Mbps" \
--subnet-ids '["'"$LB_SUBNET_ID"'"]' \
--is-private false \
--query 'data.id' --raw-output)
echo "Load Balancer OCID: $LB_ID"
echo "Waiting for Load Balancer to be active..."
oci lb load-balancer get --load-balancer-id $LB_ID --query 'data."lifecycle-state"' --wait-for-state ACTIVE --max-wait-seconds 900
echo "Load Balancer ${RESOURCE_NAME_PREFIX}-WebLB created successfully."
# Get the Public IP of the Load Balancer
LB_IP=$(oci lb load-balancer get --load-balancer-id $LB_ID --query 'data."ip-addresses"[0].ip-address' --raw-output)
echo "Load Balancer Public IP: $LB_IP"
7. Integrate Load Balancer with Instance Pool
This is the critical step to connect our dynamic instance pool to the Load Balancer. We'll create a backend set, define health checks, create a listener, and then attach the instance pool to the backend set.
# Create a Backend Set
BACKEND_SET_NAME="${RESOURCE_NAME_PREFIX}-WebBackendSet"
oci lb backend-set create \
--load-balancer-id $LB_ID \
--name $BACKEND_SET_NAME \
--policy "ROUND_ROBIN" \
--health-checker '{
"port": 80,
"protocol": "HTTP",
"url-path": "/index.html",
"response-body-regex": "Welcome to TechNews Venture",
"retries": 3,
"timeout-in-millis": 3000,
"interval-in-millis": 10000
}'
echo "Backend Set ${BACKEND_SET_NAME} created."
# Create a Listener
LISTENER_NAME="${RESOURCE_NAME_PREFIX}-WebListener"
oci lb listener create \
--load-balancer-id $LB_ID \
--name $LISTENER_NAME \
--default-backend-set-name $BACKEND_SET_NAME \
--port 80 \
--protocol HTTP
echo "Listener ${LISTENER_NAME} created."
# Attach the Instance Pool to the Backend Set
oci compute instance-pool attach-load-balancer \
--instance-pool-id $INSTANCE_POOL_ID \
--backend-set-name $BACKEND_SET_NAME \
--listener-name $LISTENER_NAME \
--port 80 \
--load-balancer-id $LB_ID
echo "Instance Pool ${RESOURCE_NAME_PREFIX}-WebPool attached to Load Balancer."
echo "Waiting for Load Balancer to update..."
# This command doesn't have a direct wait-for-state, so we'll add a short sleep.
sleep 60
The health check is crucial. It verifies that Nginx is running and serving our `index.html` page. The `response-body-regex` ensures the content is as expected, not just a generic HTTP 200.
8. Test the Setup
Now that everything is configured, you can test it.
- Access the Load Balancer: Open your web browser and navigate to the Load Balancer's public IP address (`http://$LB_IP`). You should see the "Welcome to TechNews Venture - Instance (hostname)" page. Refreshing might show different hostnames if multiple instances are up.
- Monitor Instances: Go to the OCI Console -> Compute -> Instance Pools. You'll see the current number of instances.
- Simulate Load: Use a tool like `ab` (ApacheBench) or `hey` to generate traffic to your Load Balancer's IP.
This will send 100,000 requests with 100 concurrent connections.# Example using ApacheBench (install with `sudo yum install httpd-tools -y` on Linux) # ab -n 100000 -c 100 http://$LB_IP/ - Observe Autoscaling:
- Monitor the CPU utilization metric for your instance pool in OCI Monitoring.
- After a few minutes of sustained high load (above 60% CPU), you should see the instance count in your instance pool increase (e.g., from 1 to 2, then to 3, up to the max of 4).
- Once the load is removed, and CPU utilization drops below 20% for 3 minutes, observe the instance count decreasing.
Important Note: Autoscaling events are not instantaneous. There's a delay due to metric collection, evaluation period, and instance provisioning time. Expect scaling out to take several minutes (e.g., 5-10 minutes) and scaling in similarly.
Security Considerations
Implementing autoscaling and load balancing introduces several security considerations that must be addressed to protect your applications and data.
IAM Policies: Principle of Least Privilege
- Granular Permissions: Do not grant `Administrator` access in production environments. Create specific IAM policies that