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.Flexconfigured 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
}
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
}
}
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"]
}
}
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
}
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
}
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}"
}
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
}
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
}
}
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"]
}
}
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
}
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
}
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}"
}
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
3.2 Deploying the ARM Ampere Workload
cd ~/oci-infra/vm-arm/
terraform init
terraform plan
terraform apply -auto-approve
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>
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.Flexwith 1 OCPU and 6 GB RAM) compute instances attached to the shared subnet and state backends.
Top comments (0)