DEV Community

sys-ronin
sys-ronin

Posted on

Complete OCI Free Tier Infrastructure Guide - Part 03: Compute Layer (AMD & ARM)

In Part 01 and Part 02 of this series, we configured local API keys, environment variables, created an offline provider mirror, built our remote state bucket, and provisioned the shared networking layer (VCN, public subnet, route tables, and security lists).

Now in Part 03, we complete the series by building the compute layer across two isolated directories:

  • ~/oci-infra/vm-amd/ — x86 Architecture (VM.Standard.E2.1.Micro)
  • ~/oci-infra/vm-arm/ — ARM Ampere Architecture (VM.Standard.A1.Flex configured with 1 OCPU and 6 GB RAM)

Both instances connect directly to the shared-public-subnet provisioned in Part 02 and persist state to their dedicated S3-compatible backend paths (vm-amd.tfstate and vm-arm.tfstate).


Section 1: AMD x86 Compute Instance (~/oci-infra/vm-amd/)

The AMD instance leverages the Always Free VM.Standard.E2.1.Micro shape (1 OCPU, 1 GB RAM, 50 GB boot volume).

1.1 Provider & Remote State (provider.tf & backend.tf)

provider.tf

terraform {
  required_version = ">= 1.5.0"
  required_providers {
    oci = {
      source  = "oracle/oci"
      version = "6.20.0"
    }
  }
}

provider "oci" {
  tenancy_ocid     = var.tenancy_ocid
  user_ocid        = var.user_ocid
  fingerprint      = var.fingerprint
  private_key_path = var.private_key_path
  region           = var.region
}
Enter fullscreen mode Exit fullscreen mode

backend.tf

terraform {
  backend "s3" {
    bucket = "terraform-states"
    key    = "vm-amd.tfstate"
    region = "ap-hyderabad-1"
    endpoints = {
      s3 = "https://axjetxazylvl.compat.objectstorage.ap-hyderabad-1.oraclecloud.com"
    }

    skip_region_validation      = true
    skip_credentials_validation = true
    skip_metadata_api_check     = true
    skip_requesting_account_id  = true
    skip_s3_checksum            = true
    use_path_style              = true
  }
}
Enter fullscreen mode Exit fullscreen mode

1.2 Data Resources (data.tf)

# Fetch availability domains
data "oci_identity_availability_domains" "ads" {
  compartment_id = var.tenancy_ocid
}

locals {
  first_ad = data.oci_identity_availability_domains.ads.availability_domains[0].name
}

# Image lookup for Oracle Linux 9 on x86_64
data "oci_core_images" "ol9" {
  compartment_id           = var.compartment_id
  operating_system         = "Oracle Linux"
  operating_system_version = "9"
  shape                    = "VM.Standard.E2.1.Micro"
  sort_by                  = "TIMECREATED"
  sort_order               = "DESC"
}

# Network lookup: find the shared subnet by display name
data "oci_core_subnets" "shared" {
  compartment_id = var.compartment_id

  filter {
    name   = "display_name"
    values = ["shared-public-subnet"]
  }
}
Enter fullscreen mode Exit fullscreen mode

1.3 Variables (variables.tf)

variable "tenancy_ocid" {
  description = "OCID of the tenancy"
  type        = string
}

variable "user_ocid" {
  description = "OCID of the user"
  type        = string
}

variable "fingerprint" {
  description = "API key fingerprint"
  type        = string
}

variable "private_key_path" {
  description = "Path to the private API key"
  type        = string
}

variable "region" {
  description = "OCI region"
  type        = string
}

variable "compartment_id" {
  description = "OCID of the compartment"
  type        = string
}

variable "ssh_public_key_path" {
  description = "Path to SSH public key"
  type        = string
}
Enter fullscreen mode Exit fullscreen mode

1.4 Resource Definition (main.tf)

locals {
  ssh_private_key_path = trimsuffix(pathexpand(var.ssh_public_key_path), ".pub")
}

resource "oci_core_instance" "amd" {
  availability_domain = local.first_ad
  compartment_id      = var.compartment_id
  display_name        = "amd-vm"
  shape               = "VM.Standard.E2.1.Micro"

  source_details {
    source_type             = "image"
    source_id               = data.oci_core_images.ol9.images[0].id
    boot_volume_size_in_gbs = 50
  }

  create_vnic_details {
    subnet_id        = data.oci_core_subnets.shared.subnets[0].id
    display_name     = "amd-vm-vnic"
    assign_public_ip = true
  }

  metadata = {
    ssh_authorized_keys = file(pathexpand(var.ssh_public_key_path))
  }

  preserve_boot_volume = false
}
Enter fullscreen mode Exit fullscreen mode

1.5 Outputs (outputs.tf)

output "instance_id" {
  value = oci_core_instance.amd.id
}

output "public_ip" {
  value = oci_core_instance.amd.public_ip
}

output "ssh_command" {
  value = "ssh -i ${local.ssh_private_key_path} opc@${oci_core_instance.amd.public_ip}"
}
Enter fullscreen mode Exit fullscreen mode

Section 2: ARM Ampere Flex Compute Instance (~/oci-infra/vm-arm/)

The ARM Ampere instance utilizes VM.Standard.A1.Flex configured explicitly with 1 OCPU and 6 GB RAM.

2.1 Provider & Remote State (provider.tf & backend.tf)

provider.tf

terraform {
  required_version = ">= 1.5.0"
  required_providers {
    oci = {
      source  = "oracle/oci"
      version = "6.20.0"
    }
  }
}

provider "oci" {
  tenancy_ocid     = var.tenancy_ocid
  user_ocid        = var.user_ocid
  fingerprint      = var.fingerprint
  private_key_path = var.private_key_path
  region           = var.region
}
Enter fullscreen mode Exit fullscreen mode

backend.tf

terraform {
  backend "s3" {
    bucket = "terraform-states"
    key    = "vm-arm.tfstate"
    region = "ap-hyderabad-1"
    endpoints = {
      s3 = "https://axjetxazylvl.compat.objectstorage.ap-hyderabad-1.oraclecloud.com"
    }

    skip_region_validation      = true
    skip_credentials_validation = true
    skip_metadata_api_check     = true
    skip_requesting_account_id  = true
    skip_s3_checksum            = true
    use_path_style              = true
  }
}
Enter fullscreen mode Exit fullscreen mode

2.2 Data Resources (data.tf)

# -----------------------------------------------------------------------------
# Availability Domains
# -----------------------------------------------------------------------------
data "oci_identity_availability_domains" "ads" {
  compartment_id = var.tenancy_ocid
}

locals {
  first_ad = data.oci_identity_availability_domains.ads.availability_domains[0].name
}

# -----------------------------------------------------------------------------
# Image Lookup: Oracle Linux 9 for A1.Flex (ARM)
# -----------------------------------------------------------------------------
data "oci_core_images" "ol9" {
  compartment_id           = var.compartment_id
  operating_system         = "Oracle Linux"
  operating_system_version = "9"
  shape                    = "VM.Standard.A1.Flex"
  sort_by                  = "TIMECREATED"
  sort_order               = "DESC"
}

# -----------------------------------------------------------------------------
# Network Discovery: Find the shared subnet by name
# -----------------------------------------------------------------------------
data "oci_core_subnets" "shared" {
  compartment_id = var.compartment_id

  filter {
    name   = "display_name"
    values = ["shared-public-subnet"]
  }
}
Enter fullscreen mode Exit fullscreen mode

2.3 Variables (variables.tf)

variable "tenancy_ocid" {
  description = "OCID of the tenancy"
  type        = string
}

variable "user_ocid" {
  description = "OCID of the user"
  type        = string
}

variable "fingerprint" {
  description = "API key fingerprint"
  type        = string
}

variable "private_key_path" {
  description = "Path to the private API key"
  type        = string
}

variable "region" {
  description = "OCI region"
  type        = string
}

variable "compartment_id" {
  description = "OCID of the compartment to create resources in"
  type        = string
}

variable "ssh_public_key_path" {
  description = "Path to the SSH public key for instance access"
  type        = string
}
Enter fullscreen mode Exit fullscreen mode

2.4 Resource Definition (main.tf)

locals {
  ssh_private_key_path = trimsuffix(pathexpand(var.ssh_public_key_path), ".pub")
}

resource "oci_core_instance" "arm" {
  availability_domain = local.first_ad
  compartment_id      = var.compartment_id
  display_name        = "arm-vm"
  shape               = "VM.Standard.A1.Flex"

  shape_config {
    ocpus         = 1
    memory_in_gbs = 6
  }

  source_details {
    source_type             = "image"
    source_id               = data.oci_core_images.ol9.images[0].id
    boot_volume_size_in_gbs = 50
  }

  create_vnic_details {
    subnet_id        = data.oci_core_subnets.shared.subnets[0].id
    display_name     = "arm-vm-vnic"
    assign_public_ip = true
  }

  metadata = {
    ssh_authorized_keys = file(pathexpand(var.ssh_public_key_path))
  }

  preserve_boot_volume = false
}
Enter fullscreen mode Exit fullscreen mode

2.5 Outputs (outputs.tf)

output "instance_id" {
  description = "OCID of the ARM instance"
  value       = oci_core_instance.arm.id
}

output "instance_name" {
  description = "Display name of the ARM instance"
  value       = oci_core_instance.arm.display_name
}

output "shape" {
  description = "Shape of the ARM instance"
  value       = oci_core_instance.arm.shape
}

output "ocpus" {
  description = "Configured OCPUs"
  value       = oci_core_instance.arm.shape_config[0].ocpus
}

output "memory_in_gbs" {
  description = "Configured memory in GBs"
  value       = oci_core_instance.arm.shape_config[0].memory_in_gbs
}

output "availability_domain" {
  description = "Availability domain of the ARM instance"
  value       = oci_core_instance.arm.availability_domain
}

output "private_ip" {
  description = "Private IP address of the ARM instance"
  value       = oci_core_instance.arm.private_ip
}

output "public_ip" {
  description = "Public IP address of the ARM instance"
  value       = oci_core_instance.arm.public_ip
}

output "subnet_id" {
  description = "OCID of the attached subnet"
  value       = oci_core_instance.arm.create_vnic_details[0].subnet_id
}

output "image_id" {
  description = "OCID of the boot image used"
  value       = oci_core_instance.arm.source_details[0].source_id
}

output "ssh_username" {
  description = "Default SSH username"
  value       = "opc"
}

output "ssh_command" {
  description = "SSH command to connect to the instance"
  value       = "ssh -i ${local.ssh_private_key_path} opc@${oci_core_instance.arm.public_ip}"
}
Enter fullscreen mode Exit fullscreen mode

Section 3: Deployment & Verification Workflow

3.1 Deploying the AMD x86 Workload

cd ~/oci-infra/vm-amd/
terraform init
terraform plan
terraform apply -auto-approve
Enter fullscreen mode Exit fullscreen mode

3.2 Deploying the ARM Ampere Workload

cd ~/oci-infra/vm-arm/
terraform init
terraform plan
terraform apply -auto-approve
Enter fullscreen mode Exit fullscreen mode

3.3 Accessing the Instances

Upon completion, retrieve the SSH commands from the output variables or run:

# SSH into AMD Instance
ssh -i ~/.ssh/oci_vm_key opc@<AMD_PUBLIC_IP>

# SSH into ARM Instance
ssh -i ~/.ssh/oci_vm_key opc@<ARM_PUBLIC_IP>
Enter fullscreen mode Exit fullscreen mode

Series Conclusion

You have successfully built an automated, production-grade cloud foundation on Oracle Cloud Infrastructure:

  • Part 01: Setup environment authentication, API keys, offline provider mirror, and remote state bucket (terraform-states).
  • Part 02: Provisioned core networking (main-vcn, shared-public-subnet, internet gateway, security list) and application object storage.
  • Part 03: Deployed modular AMD (VM.Standard.E2.1.Micro) and ARM (VM.Standard.A1.Flex with 1 OCPU and 6 GB RAM) compute instances attached to the shared subnet and state backends.

Top comments (0)