Cloud cost surprises follow a predictable pattern. Something gets deployed, nobody sets a budget, utilization grows quietly, and the first signal is the invoice. By then, the workload has been running at unexpected scale for weeks. OCI Cost Management gives you the tools to catch this early: budgets that alert before the threshold is hit, cost allocation through defined tags, and rightsizing recommendations from actual utilization data.
Step 1: Monthly Budget with Forecast Alert
resource "oci_budget_budget" "production_monthly" {
compartment_id = var.tenancy_ocid
display_name = "production-monthly-budget"
amount = 10000
budget_processing_period_start_offset = 1
processing_period_type = "MONTH"
reset_period = "MONTHLY"
target_type = "COMPARTMENT"
targets = [var.compartment_id]
}
resource "oci_budget_alert_rule" "warning" {
budget_id = oci_budget_budget.production_monthly.id
display_name = "75-percent-warning"
type = "ACTUAL"
threshold = 75
threshold_type = "PERCENTAGE"
recipients = var.finance_email
message = "Production has consumed 75 percent of the monthly budget."
}
resource "oci_budget_alert_rule" "critical" {
budget_id = oci_budget_budget.production_monthly.id
display_name = "90-percent-critical"
type = "ACTUAL"
threshold = 90
threshold_type = "PERCENTAGE"
recipients = join(",", [var.finance_email, var.eng_manager_email])
message = "Production has consumed 90 percent of the monthly budget. Immediate review required."
}
resource "oci_budget_alert_rule" "forecast" {
budget_id = oci_budget_budget.production_monthly.id
display_name = "forecast-overrun"
type = "FORECAST"
threshold = 100
threshold_type = "PERCENTAGE"
recipients = var.finance_email
message = "Forecast: production spend will exceed the monthly budget before month end."
}
Step 2: Tag Namespace for Cost Allocation
resource "oci_identity_tag_namespace" "operations" {
compartment_id = var.tenancy_ocid
description = "Operational tags for cost allocation"
name = "Operations"
}
resource "oci_identity_tag" "team" {
description = "Owning team for cost chargeback"
name = "Team"
tag_namespace_id = oci_identity_tag_namespace.operations.id
validator {
validator_type = "ENUM"
values = ["platform", "orders", "payments", "notifications", "data"]
}
}
resource "oci_identity_tag" "environment" {
description = "Deployment environment"
name = "Environment"
tag_namespace_id = oci_identity_tag_namespace.operations.id
validator {
validator_type = "ENUM"
values = ["production", "staging", "development", "sandbox"]
}
}
# Tag default automatically applies the Environment tag to every resource created in this compartment
resource "oci_identity_tag_default" "production_env" {
compartment_id = var.compartment_id
tag_definition_id = oci_identity_tag.environment.id
value = "production"
is_required = true
}
Step 3: Query Costs via Usage API
import oci
from datetime import datetime, timezone
from dateutil.relativedelta import relativedelta
def get_cost_by_service(compartment_id: str) -> list:
config = oci.config.from_file()
client = oci.usage_api.UsageapiClient(config)
now = datetime.now(timezone.utc)
start = (now - relativedelta(months=1)).replace(day=1, hour=0, minute=0, second=0)
resp = client.request_summarized_usages(
request_summarized_usages_details=oci.usage_api.models.RequestSummarizedUsagesDetails(
tenant_id=config["tenancy"],
time_usage_started=start,
time_usage_ended=now,
granularity="MONTHLY",
is_aggregate_by_time=False,
group_by=["service", "skuName"],
filter=oci.usage_api.models.Filter(
operator="AND",
dimensions=[oci.usage_api.models.Dimension(key="compartmentId", value=compartment_id)]
)
)
)
items = [{
"service": i.service,
"sku": i.sku_name,
"cost_usd": round(float(i.computed_amount or 0), 2)
} for i in resp.data.items]
return sorted(items, key=lambda x: x["cost_usd"], reverse=True)
for item in get_cost_by_service("ocid1.compartment.oc1..yourcompartmentocid")[:10]:
print(f"${item['cost_usd']:>10.2f} | {item['service']:<30} | {item['sku']}")
Step 4: Rightsizing via OCI Optimizer
import oci
def get_rightsizing_recommendations(compartment_id: str) -> list:
config = oci.config.from_file()
client = oci.optimizer.OptimizerClient(config)
recs = client.list_recommendations(
compartment_id=compartment_id,
compartment_id_in_subtree=True,
status="PENDING_IMPLEMENTATION"
).data.items
results = [
{"name": r.name, "savings": r.estimated_cost_saving, "priority": r.importance}
for r in recs
if "right" in r.name.lower() or "underutilized" in r.name.lower()
]
return sorted(results, key=lambda x: x["savings"], reverse=True)
for rec in get_rightsizing_recommendations("ocid1.compartment.oc1..yourcompartmentocid"):
print(f"Save ${rec['savings']:.2f}/month | {rec['priority']:<10} | {rec['name']}")
Step 5: OCI CLI Cost Queries
# Get current month spend by service
oci usage-api usage-summary request-summarized-usages \
--tenant-id ${TENANCY_OCID} \
--time-usage-started "$(date -u +%Y-%m-01T00:00:00Z)" \
--time-usage-ended "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
--granularity MONTHLY \
--group-by '["service"]' \
--query 'data.items[*].{service:service, cost:"computedAmount"}' \
--output table
# Get current budget status
oci budgets budget list \
--compartment-id ${TENANCY_OCID} \
--query 'data[*].{name:"display-name", amount:amount, actual:"actual-spend", forecast:"forecast-spend"}' \
--output table
# List pending Optimizer recommendations sorted by savings
oci optimizer recommendation list \
--compartment-id ${COMPARTMENT_OCID} \
--compartment-id-in-subtree true \
--status PENDING_IMPLEMENTATION \
--query 'data.items[*].{name:name, savings:"estimatedCostSaving", importance:importance}' \
--output table | sort -t"$" -k2 -rn
Operational Notes
Tag defaults on compartments automatically apply tags to every resource created there, including resources created by automated pipelines. Without tag defaults, tag compliance depends on every engineer and automation script remembering to set tags. With tag defaults, the baseline tags are always present and only team-specific tags need to be set explicitly per resource.
FORECAST budget alerts fire before month end when projected spend is on track to exceed the budget. Set forecast alerts at 100 percent of the budget. The forecast model uses current run-rate, so if 60 percent of the budget is consumed in the first half of the month, the forecast alert fires immediately rather than waiting for actual spend to reach 90 percent.
OCI Optimizer rightsizing recommendations are based on 30 days of utilization data. A recommendation to downsize a compute instance only appears after 30 days of consistently low CPU and memory utilization. Check recommendations monthly, not daily, and validate that the utilization data covers your peak usage periods before acting on a downsize recommendation.
Regards,
Osama
#OCI #OracleCloud #CostManagement #FinOps #Terraform #IaC #OracleCloudInfrastructure #CloudCost #TechBlog #Oracle #Budgets #CloudGovernance #CostAllocation #Rightsizing #CloudOptimization #TagManagement #PlatformEngineering #DevOps #UsageAPI #CloudFinance
Leave a comment