OCI Container Instances sit between OCI Functions and OKE. Functions are best for short-lived event handlers. OKE handles long-running, scalable production services that need full Kubernetes orchestration. Container Instances fills the middle: long-running containers without the overhead of provisioning a Kubernetes cluster, node pools, ingress controllers, or any of the surrounding infrastructure. You define the container spec, choose a shape, and the instance runs until you stop it.
Step 1: IAM Policy
resource "oci_identity_policy" "container_instances_policy" {
compartment_id = var.compartment_id
name = "container-instances-policy"
statements = [
"Allow group DevOpsEngineers to manage compute-containers in compartment id COMPARTMENT_OCID",
"Allow group DevOpsEngineers to read repos in compartment id COMPARTMENT_OCID",
"Allow dynamic-group ContainerInstances to read secret-bundle in compartment id COMPARTMENT_OCID"
]
}
Step 2: Provision a Container Instance
resource "oci_container_instances_container_instance" "orders_worker" {
compartment_id = var.compartment_id
display_name = "orders-background-worker"
availability_domain = data.oci_identity_availability_domains.ads.availability_domains[0].name
shape = "CI.Standard.E4.Flex"
shape_config {
ocpus = 2
memory_in_gbs = 8
}
vnics {
subnet_id = var.private_subnet_id
nsg_ids = [var.worker_nsg_id]
is_public_ip_assigned = false
display_name = "orders-worker-vnic"
}
image_pull_secrets {
secret_type = "VAULT"
secret_id = var.ocir_auth_token_secret_id
registry_endpoint = "me-jeddah-1.ocir.io"
}
containers {
image_url = "me-jeddah-1.ocir.io/NAMESPACE/production/orders-worker:1.4.2"
display_name = "orders-worker"
environment_variables = {
QUEUE_URL = "https://cell1.queue.messaging.me-jeddah-1.oci.oraclecloud.com/20190401/queues/QUEUE_OCID"
LOG_LEVEL = "INFO"
REGION = "me-jeddah-1"
MAX_BATCH = "10"
}
resource_config {
vcpus_limit = 2
memory_limit_in_gbs = 8
}
health_checks {
health_check_type = "HTTP"
port = 8080
path = "/health"
interval_in_seconds = 30
timeout_in_seconds = 5
failure_threshold = 3
success_threshold = 1
}
}
# Inject secrets from OCI Vault as volume mounts
volumes {
volume_type = "SECRET"
name = "db-credentials"
configs {
secret_id = var.db_password_secret_id
file_name = "db_password"
}
}
container_restart_policy = "ON_FAILURE"
defined_tags = {
"Operations.Environment" = "production"
"Operations.ManagedBy" = "terraform"
}
}
output "container_instance_id" {
value = oci_container_instances_container_instance.orders_worker.id
}
Step 3: Multi-Container Sidecar Pattern
resource "oci_container_instances_container_instance" "orders_api_with_sidecar" {
compartment_id = var.compartment_id
display_name = "orders-api-with-log-sidecar"
availability_domain = data.oci_identity_availability_domains.ads.availability_domains[0].name
shape = "CI.Standard.E4.Flex"
shape_config { ocpus = 4; memory_in_gbs = 16 }
vnics {
subnet_id = var.private_subnet_id
is_public_ip_assigned = false
}
image_pull_secrets {
secret_type = "VAULT"
secret_id = var.ocir_auth_token_secret_id
registry_endpoint = "me-jeddah-1.ocir.io"
}
# Main application container
containers {
image_url = "me-jeddah-1.ocir.io/NAMESPACE/production/orders-api:2.1.0"
display_name = "orders-api"
environment_variables = { DB_HOST = var.db_host, LOG_DIR = "/var/log/app" }
resource_config { vcpus_limit = 3; memory_limit_in_gbs = 12 }
}
# Log shipping sidecar
containers {
image_url = "me-jeddah-1.ocir.io/NAMESPACE/tools/log-shipper:1.0.0"
display_name = "log-shipper"
environment_variables = { LOGGING_ENDPOINT = var.oci_logging_endpoint, LOG_DIR = "/var/log/app" }
resource_config { vcpus_limit = 0.5; memory_limit_in_gbs = 1 }
}
# Shared volume for log files between containers
volumes {
volume_type = "EMPTYDIR"
name = "app-logs"
}
container_restart_policy = "ALWAYS"
}
Operational Notes
Container Instances do not auto-scale. If you need scale-out, use OKE. Container Instances are appropriate for: background workers that process from a queue at a fixed concurrency, scheduled jobs that run on a timer and exit, internal tooling that needs to run continuously but does not need multiple replicas, and migration workloads that need a long-running process without building a Kubernetes deployment for a one-time job.
Vault secret injection via volumes means the secret value is written to a file inside the container at the specified path. Your application reads it from the filesystem rather than from an environment variable. This is more secure than environment variables because environment variable values are visible in process listings and debug output, while file contents require filesystem access to read.
Regards,
Osama
#OCI #OracleCloud #ContainerInstances #Serverless #Docker #Terraform #IaC #TechBlog #Oracle #PlatformEngineering #CloudNative #OracleCloudInfrastructure #Kubernetes #OKE #Sidecar #VaultIntegration #OCIR #ContainerRegistry #DevOps #CloudContainers
Leave a comment