My first soup in OCI infra with Terraform
After my last post, one of my mates has asked me for something more basic, let’s say fundamental. He has argued that he cannot use NAT Gateway or Bastion Host when some basic stuff such as VCN is not well explained. This is true when we talk with OCI newbies. There is nothing to be wrong with being OCI newbie. Some time ago I was myself that kind of a newbie. Unfortunately, as an expert, I use to forget that every aspect of knowledge should be taught incrementally. From basic and simple up to advanced and complex. In this context, IT knowledge is not an exception. So let’s do something more basic, for my friend and other newbies in Infrastructure as Code (IaC) and Oracle Cloud Infrastructure (OCI). When I say IaC, I expect you will not think only about Terraform. You have to be aware there is the real choice, now. Terraform is great and I cannot imagine working without terraform plan capabilities. But the truth is you can use Ansible as well, with OCI Ansible modules available here in GitHub repo. But as my friend has said – keep it simple. So let me write about OCI Ansible modules next time, ok? Let’s focus on Terraform and OCI, ok? 🙂
As previously, let’s start with a simple topology diagram as follows:
Someone could say it is not simple at all, but let me explain it step by step. You will understand it soon, it is complex only at first glance. 🙂 Ok, so this is the first topology diagram, right? As you can see, I will build everything in one region called eu-frankfurt-1. Within that region, I can utilize 2 availability domains (AD1, AD2 …). ADs could be treated as separated DataCenter with independent cooling, power, and network. Failure of AD1 means AD2 (plus further ADs) will still function and can provide the resources. And now I will build VCN with address CIDR 10.0.0.0/16::
resource "oci_core_virtual_network" "FoggyKitchenVCN" { cidr_block = "${var.VCN-CIDR}" dns_label = "FoggyKitchenVCN" compartment_id = "${oci_identity_compartment.FoggyKitchenCompartment.id}" display_name = "FoggyKitchenVCN" }
BTW: You have probably noticed I am not coding CIDR address directly. Instead of I am using ${var.VCN-CIDR} variable which can be found in variables.tf file:
(...) variable "VCN-CIDR" { default = "10.0.0.0/16" } (...)
Ok, but let’s return to VCN itself and further infra resources. VCN will be connected to the Internet with InternetGateway:
resource "oci_core_internet_gateway" "FoggyKitchenInternetGateway" { compartment_id = "${oci_identity_compartment.FoggyKitchenCompartment.id}" display_name = "FoggyKitchenInternetGateway" vcn_id = "${oci_core_virtual_network.FoggyKitchenVCN.id}" }
Is it clear so far? I hope so 🙂
Next, within that VCN, I will create my first public subnet located in AD1:
resource "oci_core_subnet" "FoggyKitchenSubnet1" { availability_domain = "${var.ADs[0]}" cidr_block = "10.0.1.0/24" display_name = "FoggyKitchen Subnet1" dns_label = "FoggyKitchenN1" compartment_id = "${oci_identity_compartment.FoggyKitchenCompartment.id}" vcn_id = "${oci_core_virtual_network.FoggyKitchenVCN.id}" route_table_id = "${oci_core_route_table.FoggyKitchenRouteTable1.id}" dhcp_options_id = "${oci_core_dhcp_options.FoggyKitchenDhcpOptions1.id}" security_list_ids = ["${oci_core_security_list.FoggyKitchenSSHSecurityList.id}","${oci_core_security_list.FoggyKitchenHTTPSecurityList.id}","${oci_core_security_list.FoggyKitchenHTTPSSecurityList.id}"] }
Like previously with CIDR for VCN, here availability domain will be derived from 3 element array which has been defined in variables.tf. In that case, AD1 is an element number 0 in the array:
variable "ADs" { default = ["pnkC:EU-FRANKFURT-1-AD-1", "pnkC:EU-FRANKFURT-1-AD-2", "pnkC:EU-FRANKFURT-1-AD-3"] }
Let’s move forward. Now I will define my first VM:
resource "oci_core_instance" "FoggyKitchenWebserver1" { availability_domain = "${var.ADs[0]}" compartment_id = "${oci_identity_compartment.FoggyKitchenCompartment.id}" display_name = "FoggyKitchenWebServer1" shape = "${var.Shapes[0]}" subnet_id = "${oci_core_subnet.FoggyKitchenSubnet1.id}" source_details { source_type = "image" source_id = "${var.Images[0]}" } metadata { ssh_authorized_keys = "${file("${var.public_key_oci}")}" } create_vnic_details { subnet_id = "${oci_core_subnet.FoggyKitchenSubnet1.id}" assign_public_ip = true } }
Ok, but what about the second box below the topology diagram? I have here FoggyKitchenRouteTable1 which defines the route from inside to outside of the subnet via InternetGateway entity:
resource "oci_core_route_table" "FoggyKitchenRouteTable1" { compartment_id = "${oci_identity_compartment.FoggyKitchenCompartment.id}" vcn_id = "${oci_core_virtual_network.FoggyKitchenVCN.id}" display_name = "FoggyKitchenRouteTable1" route_rules { destination = "0.0.0.0/0" destination_type = "CIDR_BLOCK" network_entity_id = "${oci_core_internet_gateway.FoggyKitchenInternetGateway.id}" } }
For security reasons I have also created some Security Lists which will enable traffic for SSH, HTTP and HTTPS protocols and your web server could be accessed from the Internet on ports 22, 80 and 443. It is a firewall with stateful inspection which can be applied on top of VCN. Here is the example of HTTP protocol:
resource "oci_core_security_list" "FoggyKitchenHTTPSecurityList" { compartment_id = "${oci_identity_compartment.FoggyKitchenCompartment.id}" display_name = "FoggyKitchenHTTPSecurity List" vcn_id = "${oci_core_virtual_network.FoggyKitchenVCN.id}" egress_security_rules = [{ protocol = "6" destination = "0.0.0.0/0" }] ingress_security_rules = [{ tcp_options { "max" = 80 "min" = 80 } protocol = "6" source = "0.0.0.0/0" }, { protocol = "6" source = "${var.VCN-CIDR}" }] }
In FoggyKitchenDHCPOptions I will define how DHCP/DNS will be resolved. I will not spend too much time over that topic now, but hope to explain it in the future posts if needed:
resource "oci_core_dhcp_options" "FoggyKitchenDhcpOptions1" { compartment_id = "${oci_identity_compartment.FoggyKitchenCompartment.id}" vcn_id = "${oci_core_virtual_network.FoggyKitchenVCN.id}" display_name = "FoggyKitchenDHCPOptions1" // required options { type = "DomainNameServer" server_type = "VcnLocalPlusInternet" } // optional options { type = "SearchDomain" search_domain_names = [ "foggykitchen.com" ] } }
Looks like we are ready for execution. Let’s cook this soup! Terraform plan & Terraform apply commands to be executed 🙂 Hope it will be tasty 🙂
MasterChef Martin.
PS. My code is here in small GitHub repo.
Leave A Reply
You must be logged in to post a comment.
1 Comment