How to build microservice which is based on OCI Function and ATP with Terraform

A lot of people around the world believe the serverless approach is the ultimate future of cloud computing. I am also such a believer, but it will be a gradual move, sort of evolution within the next couple of years. Some time ago I have published a blog about private endpoints for ATP. I have used the code related to this blog post and I have refactored it a bit. The idea behind was to eliminate VM-based web server with Flask microservice. This old school technology could be replaced by OCI Function and API Gateway (btw. check Kranthi blog post). I guess this refactoring has been pretty successful. Below in this 15 minutes video, you will see my hard work on this topic. Hope it will be tasty πŸ™‚

Bon Appetit,

Martin, The Cook.

USE OCI OBJECT STORAGE TO STORE TERRAFORM STATE FILES

download.png

Introduction

Terraform allows you to deploy infrastructure very quickly, and you can find thousands of script/modules/snippets on the web to get you started in a snap.

Once you move from the “Let’s try this at home” phase to a more “Let’s do this for a real environment” oriented phase you will have to make a lot of decisions about how you are going to maintain your infrastructure and how you are going to manage change, possibly in a non destructive way.

Nothing like dropping a production environment on a Friday evening while you are testing a small change in your dev environment will make you realise how badly you need this when moving past the Terraform learning phase.

One important decision during this transition to real world use of terraform is the location where you are going to store a Terraform project state file.

In this tutorial you will learn how to configure OCI Object storage as a remote backend for a sample terraform project, this will allow you to replicate the setup for your projects.

What is a terraform state file?

Terraform must store state information about your managed infrastructure and configuration. This state is used by Terraform to map real world resources to your configuration, keep track of metadata, and to improve performance for large infrastructures.

This state is stored by default in a local file named “terraform.tfstate”, but it can also be stored remotely, which is essential when more than one person is working on the same project. WithΒ remote state, Terraform writes the state data to a remote data store, which can then be shared between all members of a team, encrypted, versioned and secured. Terraform supports storing state in Terraform Cloud,Β HashiCorp Consul, Amazon S3, Alibaba Cloud OSS, and other providers.

If you want to dig deeper into why Terraform needs a state file to work you can have a look here: https://www.terraform.io/docs/state/purpose.html

Terraform remote state file and OCI support

OCI object storage is not supported natively for storing state files, but since it has an AWS S3 compatibility layer we can use it all the same

Requirements

An Active Oracle Cloud Tenancy

If you do not have one, you can enroll here for a trial subscription that includes $300 of free credits

An Oracle Cloud Shell Instance

The OCI Cloud Shell is a web browser-based terminal accessible from the Oracle Cloud Console. Cloud Shell is free to use (within monthly tenancy limits), and provides access to a Linux shell, with a pre-authenticated Oracle Cloud Infrastructure CLI and other useful tools for following Oracle Cloud Infrastructure service tutorials and labs. Cloud Shell is a feature available to all OCI users, accessible from the Console. Your Cloud Shell will appear in the Oracle Cloud Console as a persistent frame of the Console and will stay active as you navigate to different pages of the Console. You can find detailed instructions on how to get started with the OCI Cloud Shell here

cloudshell-1.png

Create an initial working dir:

mkdir fk-terraform-objectstorage
cd fk-terraform-objectstorage/

A test terraform project

git clone https://github.com/mattiarossi/terraform-oci-default-vcn/


Cloning into 'terraform-oci-default-vcn'...
remote: Enumerating objects: 61, done.
remote: Counting objects: 100% (61/61), done.
remote: Compressing objects: 100% (36/36), done.
remote: Total 75 (delta 27), reused 44 (delta 14), pack-reused 14
Unpacking objects: 100% (75/75), done.


cd terraform-oci-default-vcn/examples/vcn_default/

The test project will deploy a simple VCN in a compartment of your choice, configurable in the project variables, and will store the state file in an OCI Object storage Bucket that needs to be created in advance

An OCI Object Storage Bucket

The bucket needs to be created in the Compartment that is designated on OCI to be the target for the AWS S3 compatibility layer. You can check the active S3 compartment by using the following command:

oci os ns  get-metadata --output=table
+-------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------+-----------+
| default-s3-compartment-id                                                           | default-swift-compartment-id                                                        | namespace |
+-------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------+-----------+
| ocid1.compartment.oc1..aaaaaaa...4nxhlvbbbbbbb3kpmffof6vba                          | ocid1.compartment.oc1..aaaaaaa...hlvbbbbbbbbpmffof6vba                              | mytenancy |
+-------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------+-----------+

We will be using a bucket named tf-fk-test-01

This command will create a bucket named tf-fk-test-01 in the AWS s3 compatibility layer compartment:

oci os bucket create --compartment-id ocid1.compartment.oc1..aaaaaaa...4nxhlvb3luoh3kpmffof6vba --name tf-fk-test-01

A properly configured AWS S3 compatibility environment

In order to be able to access the Object Storage bucket using the S3 compatibility layer, you need to generate a set of access credentials, and the oci cli command needed for creating these needs to know the current user ocid:

export ME=mattia.rossi@myemail.com (my tenancy username)
oci iam user list --query "data[?\"name\"=='$ME']".{"name:\"name\",id:\"id\""} --output table

+------------------------------------------------------------------------------+--------------------------+
| id                                                                           | name                     |
+------------------------------------------------------------------------------+--------------------------+
| ocid1.user.oc1..aaaaaaa..................................tojgy2qybdkcayvnxsq | mattia.rossi@myemail.com |
+------------------------------------------------------------------------------+--------------------------+

export OCIUID=ocid1.user.oc1..aaaaaaa..................................tojgy2qybdkcayvnxsq

The following command will reuse the ocid variable to create the credentials needed to setup the AWS compatibility layer (please note that these are examples only and you will need to insert the proper secrets generated by the oci cli in the export command

oci iam customer-secret-key create --user-id $OCIUID --display-name 'key-tf-test' --query "data".{"AWS_ACCESS_KEY_ID:\"id\",AWS_SECRET_ACCESS_KEY:\"key\""} --output=table

+------------------------------------------+----------------------------------------------+
| AWS_ACCESS_KEY_ID                        | AWS_SECRET_ACCESS_KEY                        |
+------------------------------------------+----------------------------------------------+
| fd9bcbb0.........................93e7139 | kS/...............................PRDoGX1NY= |
+------------------------------------------+----------------------------------------------+

export AWS_ACCESS_KEY_ID=fd9bcbb0.........................93e7139
export AWS_SECRET_ACCESS_KEY=kS/...............................PRDoGX1NY=

Environment variables

The only other environment variable needed by the project for authenticating is the tenancy ocid, that can be set up using this command:

export TF_VAR_tenancy_ocid=`cat /etc/oci/config  | grep tenancy | uniq | cut -d '=' -f 2`

Terraform project config

Prepare one variable file named “terraform.tfvars” with the configuration information. The content of “terraform.tfvars” should look something like the following:

$ cat terraform.tfvars
# Region
region = "eu-frankfurt-1"

# Compartment
compartment_ocid = ""

# VCN Configurations
vcn_display_name = "testVCN"
vcn_cidr = "10.0.0.0/16"

Use the following script to retrieve the ocid of the compartment where you want to deploy the test VCN:

export COMPARTMENT=my-compartment
oci iam compartment list --query "data[?\"name\"=='$COMPARTMENT']".{"name:\"name\",id:\"id\""} --output=table
+-------------------------------------------------------------------------------------+-----------------------+
| id                                                                                  | name                  |
+-------------------------------------------------------------------------------------+-----------------------+
| ocid1.compartment.oc1..aaaaaaaabmc54lgslm..........................3hygseg6qeh5pvwq | my-compartment        |
+-------------------------------------------------------------------------------------+-----------------------+

Edit the file vcn_default.tf, and update the terraform backend section to match your OCI setup:

terraform {
  backend "s3" {
    endpoint                    = "https://__mytenancy__.compat.objectstorage.__region__.oraclecloud.com"
    skip_metadata_api_check     = true
    skip_region_validation      = true
    force_path_style            = true
    skip_credentials_validation = true
    bucket                      = "__mybucket__"
    key                         = "__key__"
    region                      = "__region__"
  }
}

where:

  • __mytenancy__ is your tenancy name
  • __region__ is the region where you created the Object Storage bucket
  • __mybucket__ is the name of the bucket you created
  • key is the name of the bucket entry that will hold your terraform state file (for example: terraform/state/oci/vcn/testVCN/terraform.tfstate)

Then apply the example using the following commands:

terraform init
terraform plan
terraform apply

Init:

mattia_ros@cloudshell:vcn_default (eu-frankfurt-1)$ terraform init
Initializing modules...
- vcn in ../..

Initializing the backend...

Successfully configured the backend "s3"! Terraform will automatically
use this backend unless the backend configuration changes.

Initializing provider plugins...
- Checking for available provider plugins...
- Downloading plugin for provider "oci" (hashicorp/oci) 3.74.0...

The following providers do not have any version constraints in configuration,
so the latest version was installed.

To prevent automatic upgrades to new major versions that may contain breaking
changes, it is recommended to add version = "..." constraints to the
corresponding provider blocks in configuration, with the constraint strings
suggested below.

* provider.oci: version = "~> 3.74"

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

Plan:

mattia_ros@cloudshell:vcn_default (eu-frankfurt-1)$ terraform plan
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.

module.vcn.data.oci_identity_availability_domains.this: Refreshing state...

------------------------------------------------------------------------

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
+ create

Terraform will perform the following actions:

# module.vcn.oci_core_default_route_table.this will be created
+ resource "oci_core_default_route_table" "this" {
+ defined_tags = (known after apply)
+ display_name = (known after apply)
+ freeform_tags = (known after apply)
+ id = (known after apply)
+ manage_default_resource_id = (known after apply)
+ state = (known after apply)
+ time_created = (known after apply)

+ route_rules {
+ cidr_block = (known after apply)
+ description = (known after apply)
+ destination = "0.0.0.0/0"
+ destination_type = (known after apply)
+ network_entity_id = (known after apply)
}
}

# module.vcn.oci_core_internet_gateway.this will be created
+ resource "oci_core_internet_gateway" "this" {
+ compartment_id = "ocid1.compartment.oc1..aaaaaaaan2lhk5eqy2hvum45ahjsvgs2sz7x72ur5kw4euwe6my2226mk5ia"
+ defined_tags = (known after apply)
+ display_name = (known after apply)
+ enabled = true
+ freeform_tags = (known after apply)
+ id = (known after apply)
+ state = (known after apply)
+ time_created = (known after apply)
+ vcn_id = (known after apply)
}

# module.vcn.oci_core_subnet.this[0] will be created
+ resource "oci_core_subnet" "this" {
+ availability_domain = "okVf:EU-FRANKFURT-1-AD-1"
+ cidr_block = "192.168.0.0/28"
+ compartment_id = "ocid1.compartment.oc1..aaaaaaaan2lhk5eqy2hvum45ahjsvgs2sz7x72ur5kw4euwe6my2226mk5ia"
+ defined_tags = (known after apply)
+ dhcp_options_id = (known after apply)
+ display_name = "Default Subnet okVf:EU-FRANKFURT-1-AD-1"
+ dns_label = "subnet1"
+ freeform_tags = (known after apply)
+ id = (known after apply)
+ ipv6cidr_block = (known after apply)
+ ipv6public_cidr_block = (known after apply)
+ ipv6virtual_router_ip = (known after apply)
+ prohibit_public_ip_on_vnic = (known after apply)
+ route_table_id = (known after apply)
+ security_list_ids = (known after apply)
+ state = (known after apply)
+ subnet_domain_name = (known after apply)
+ time_created = (known after apply)
+ vcn_id = (known after apply)
+ virtual_router_ip = (known after apply)
+ virtual_router_mac = (known after apply)
}

# module.vcn.oci_core_subnet.this[1] will be created
+ resource "oci_core_subnet" "this" {
+ availability_domain = "okVf:EU-FRANKFURT-1-AD-2"
+ cidr_block = "192.168.0.16/28"
+ compartment_id = "ocid1.compartment.oc1..aaaaaaaan2lhk5eqy2hvum45ahjsvgs2sz7x72ur5kw4euwe6my2226mk5ia"
+ defined_tags = (known after apply)
+ dhcp_options_id = (known after apply)
+ display_name = "Default Subnet okVf:EU-FRANKFURT-1-AD-2"
+ dns_label = "subnet2"
+ freeform_tags = (known after apply)
+ id = (known after apply)
+ ipv6cidr_block = (known after apply)
+ ipv6public_cidr_block = (known after apply)
+ ipv6virtual_router_ip = (known after apply)
+ prohibit_public_ip_on_vnic = (known after apply)
+ route_table_id = (known after apply)
+ security_list_ids = (known after apply)
+ state = (known after apply)
+ subnet_domain_name = (known after apply)
+ time_created = (known after apply)
+ vcn_id = (known after apply)
+ virtual_router_ip = (known after apply)
+ virtual_router_mac = (known after apply)
}

# module.vcn.oci_core_subnet.this[2] will be created
+ resource "oci_core_subnet" "this" {
+ availability_domain = "okVf:EU-FRANKFURT-1-AD-3"
+ cidr_block = "192.168.0.32/28"
+ compartment_id = "ocid1.compartment.oc1..aaaaaaaan2lhk5eqy2hvum45ahjsvgs2sz7x72ur5kw4euwe6my2226mk5ia"
+ defined_tags = (known after apply)
+ dhcp_options_id = (known after apply)
+ display_name = "Default Subnet okVf:EU-FRANKFURT-1-AD-3"
+ dns_label = "subnet3"
+ freeform_tags = (known after apply)
+ id = (known after apply)
+ ipv6cidr_block = (known after apply)
+ ipv6public_cidr_block = (known after apply)
+ ipv6virtual_router_ip = (known after apply)
+ prohibit_public_ip_on_vnic = (known after apply)
+ route_table_id = (known after apply)
+ security_list_ids = (known after apply)
+ state = (known after apply)
+ subnet_domain_name = (known after apply)
+ time_created = (known after apply)
+ vcn_id = (known after apply)
+ virtual_router_ip = (known after apply)
+ virtual_router_mac = (known after apply)
}

# module.vcn.oci_core_vcn.this will be created
+ resource "oci_core_vcn" "this" {
+ cidr_block = "192.168.0.0/25"
+ compartment_id = "ocid1.compartment.oc1..aaaaaaaan2lhk5eqy2hvum45ahjsvgs2sz7x72ur5kw4euwe6my2226mk5ia"
+ default_dhcp_options_id = (known after apply)
+ default_route_table_id = (known after apply)
+ default_security_list_id = (known after apply)
+ defined_tags = (known after apply)
+ display_name = "TEST-FK-VCN"
+ dns_label = "vcn"
+ freeform_tags = (known after apply)
+ id = (known after apply)
+ ipv6cidr_block = (known after apply)
+ ipv6public_cidr_block = (known after apply)
+ is_ipv6enabled = (known after apply)
+ state = (known after apply)
+ time_created = (known after apply)
+ vcn_domain_name = (known after apply)
}

Plan: 6 to add, 0 to change, 0 to destroy.

------------------------------------------------------------------------

Note: You didn't specify an "-out" parameter to save this plan, so Terraform
can't guarantee that exactly these actions will be performed if
"terraform apply" is subsequently run.

Apply:

mattia_ros@cloudshell:vcn_default (eu-frankfurt-1)$ terraform apply
module.vcn.data.oci_identity_availability_domains.this: Refreshing state...

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
+ create

Terraform will perform the following actions:

# module.vcn.oci_core_default_route_table.this will be created
+ resource "oci_core_default_route_table" "this" {
+ defined_tags = (known after apply)
+ display_name = (known after apply)
+ freeform_tags = (known after apply)
+ id = (known after apply)
+ manage_default_resource_id = (known after apply)
+ state = (known after apply)
+ time_created = (known after apply)

+ route_rules {
+ cidr_block = (known after apply)
+ description = (known after apply)
+ destination = "0.0.0.0/0"
+ destination_type = (known after apply)
+ network_entity_id = (known after apply)
}
}

# module.vcn.oci_core_internet_gateway.this will be created
+ resource "oci_core_internet_gateway" "this" {
+ compartment_id = "ocid1.compartment.oc1..aaaaaaaan2lhk5eqy2hvum45ahjsvgs2sz7x72ur5kw4euwe6my2226mk5ia"
+ defined_tags = (known after apply)
+ display_name = (known after apply)
+ enabled = true
+ freeform_tags = (known after apply)
+ id = (known after apply)
+ state = (known after apply)
+ time_created = (known after apply)
+ vcn_id = (known after apply)
}

# module.vcn.oci_core_subnet.this[0] will be created
+ resource "oci_core_subnet" "this" {
+ availability_domain = "okVf:EU-FRANKFURT-1-AD-1"
+ cidr_block = "192.168.0.0/28"
+ compartment_id = "ocid1.compartment.oc1..aaaaaaaan2lhk5eqy2hvum45ahjsvgs2sz7x72ur5kw4euwe6my2226mk5ia"
+ defined_tags = (known after apply)
+ dhcp_options_id = (known after apply)
+ display_name = "Default Subnet okVf:EU-FRANKFURT-1-AD-1"
+ dns_label = "subnet1"
+ freeform_tags = (known after apply)
+ id = (known after apply)
+ ipv6cidr_block = (known after apply)
+ ipv6public_cidr_block = (known after apply)
+ ipv6virtual_router_ip = (known after apply)
+ prohibit_public_ip_on_vnic = (known after apply)
+ route_table_id = (known after apply)
+ security_list_ids = (known after apply)
+ state = (known after apply)
+ subnet_domain_name = (known after apply)
+ time_created = (known after apply)
+ vcn_id = (known after apply)
+ virtual_router_ip = (known after apply)
+ virtual_router_mac = (known after apply)
}

# module.vcn.oci_core_subnet.this[1] will be created
+ resource "oci_core_subnet" "this" {
+ availability_domain = "okVf:EU-FRANKFURT-1-AD-2"
+ cidr_block = "192.168.0.16/28"
+ compartment_id = "ocid1.compartment.oc1..aaaaaaaan2lhk5eqy2hvum45ahjsvgs2sz7x72ur5kw4euwe6my2226mk5ia"
+ defined_tags = (known after apply)
+ dhcp_options_id = (known after apply)
+ display_name = "Default Subnet okVf:EU-FRANKFURT-1-AD-2"
+ dns_label = "subnet2"
+ freeform_tags = (known after apply)
+ id = (known after apply)
+ ipv6cidr_block = (known after apply)
+ ipv6public_cidr_block = (known after apply)
+ ipv6virtual_router_ip = (known after apply)
+ prohibit_public_ip_on_vnic = (known after apply)
+ route_table_id = (known after apply)
+ security_list_ids = (known after apply)
+ state = (known after apply)
+ subnet_domain_name = (known after apply)
+ time_created = (known after apply)
+ vcn_id = (known after apply)
+ virtual_router_ip = (known after apply)
+ virtual_router_mac = (known after apply)
}

# module.vcn.oci_core_subnet.this[2] will be created
+ resource "oci_core_subnet" "this" {
+ availability_domain = "okVf:EU-FRANKFURT-1-AD-3"
+ cidr_block = "192.168.0.32/28"
+ compartment_id = "ocid1.compartment.oc1..aaaaaaaan2lhk5eqy2hvum45ahjsvgs2sz7x72ur5kw4euwe6my2226mk5ia"
+ defined_tags = (known after apply)
+ dhcp_options_id = (known after apply)
+ display_name = "Default Subnet okVf:EU-FRANKFURT-1-AD-3"
+ dns_label = "subnet3"
+ freeform_tags = (known after apply)
+ id = (known after apply)
+ ipv6cidr_block = (known after apply)
+ ipv6public_cidr_block = (known after apply)
+ ipv6virtual_router_ip = (known after apply)
+ prohibit_public_ip_on_vnic = (known after apply)
+ route_table_id = (known after apply)
+ security_list_ids = (known after apply)
+ state = (known after apply)
+ subnet_domain_name = (known after apply)
+ time_created = (known after apply)
+ vcn_id = (known after apply)
+ virtual_router_ip = (known after apply)
+ virtual_router_mac = (known after apply)
}

# module.vcn.oci_core_vcn.this will be created
+ resource "oci_core_vcn" "this" {
+ cidr_block = "192.168.0.0/25"
+ compartment_id = "ocid1.compartment.oc1..aaaaaaaan2lhk5eqy2hvum45ahjsvgs2sz7x72ur5kw4euwe6my2226mk5ia"
+ default_dhcp_options_id = (known after apply)
+ default_route_table_id = (known after apply)
+ default_security_list_id = (known after apply)
+ defined_tags = (known after apply)
+ display_name = "TEST-FK-VCN"
+ dns_label = "vcn"
+ freeform_tags = (known after apply)
+ id = (known after apply)
+ ipv6cidr_block = (known after apply)
+ ipv6public_cidr_block = (known after apply)
+ is_ipv6enabled = (known after apply)
+ state = (known after apply)
+ time_created = (known after apply)
+ vcn_domain_name = (known after apply)
}

Plan: 6 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.

Enter a value: yes

module.vcn.oci_core_vcn.this: Creating...
module.vcn.oci_core_vcn.this: Creation complete after 0s [id=ocid1.vcn.oc1.eu-frankfurt-1.amaaaaaavyxeuaqaavuidjkp2un5v7fgodw63pytlkaxvrfs5coucgfqmgfa]
module.vcn.oci_core_internet_gateway.this: Creating...
module.vcn.oci_core_subnet.this[2]: Creating...
module.vcn.oci_core_subnet.this[1]: Creating...
module.vcn.oci_core_subnet.this[0]: Creating...
module.vcn.oci_core_subnet.this[0]: Creation complete after 0s [id=ocid1.subnet.oc1.eu-frankfurt-1.aaaaaaaa2feksp66yxjrj2twxypjbuk5blefju2ghkk34z4hvex57obkxzqa]
module.vcn.oci_core_subnet.this[2]: Creation complete after 1s [id=ocid1.subnet.oc1.eu-frankfurt-1.aaaaaaaadqbslze7krqigudqg6ajhxhxddpmhvaottievimyk6jdxz754pta]
module.vcn.oci_core_subnet.this[1]: Creation complete after 1s [id=ocid1.subnet.oc1.eu-frankfurt-1.aaaaaaaaoqrhcrv743sdt6norse7wql7rmin3ca6amoigqonvsejuoavnjtq]
module.vcn.oci_core_internet_gateway.this: Creation complete after 2s [id=ocid1.internetgateway.oc1.eu-frankfurt-1.aaaaaaaau4sdjijm4b3miu2hwf5lcbkyb7eaea62qg7dpaar2udn4u4zhfnq]
module.vcn.oci_core_default_route_table.this: Creating...
module.vcn.oci_core_default_route_table.this: Creation complete after 0s [id=ocid1.routetable.oc1.eu-frankfurt-1.aaaaaaaa5ag3j4kbkb763c3qorcowy5r3swyileytlyhagkv7mqragxysgma]

Apply complete! Resources: 6 added, 0 changed, 0 destroyed.

Outputs:

default_dhcp_options_id = ocid1.dhcpoptions.oc1.eu-frankfurt-1.aaaaaaaabzs2tgdpnq6jrd2p67lks44qovk272uxuoi3kgciib62fyflgyja
default_route_table_id = ocid1.routetable.oc1.eu-frankfurt-1.aaaaaaaa5ag3j4kbkb763c3qorcowy5r3swyileytlyhagkv7mqragxysgma
default_security_list_id = ocid1.securitylist.oc1.eu-frankfurt-1.aaaaaaaadm7oi73fwjx2kiiqbc7ucsuvqcmxfjis27at4p3tyhuopod5tqoq
internet_gateway_id = ocid1.internetgateway.oc1.eu-frankfurt-1.aaaaaaaau4sdjijm4b3miu2hwf5lcbkyb7eaea62qg7dpaar2udn4u4zhfnq
subnet_ids = [
"ocid1.subnet.oc1.eu-frankfurt-1.aaaaaaaa2feksp66yxjrj2twxypjbuk5blefju2ghkk34z4hvex57obkxzqa",
"ocid1.subnet.oc1.eu-frankfurt-1.aaaaaaaaoqrhcrv743sdt6norse7wql7rmin3ca6amoigqonvsejuoavnjtq",
"ocid1.subnet.oc1.eu-frankfurt-1.aaaaaaaadqbslze7krqigudqg6ajhxhxddpmhvaottievimyk6jdxz754pta",
]
vcn_id = ocid1.vcn.oc1.eu-frankfurt-1.amaaaaaavyxeuaqaavuidjkp2un5v7fgodw63pytlkaxvrfs5coucgfqmgfa

Now let’s check the local terraform state file:

mattia_ros@cloudshell:vcn_default (eu-frankfurt-1)$ cat .terraform/terraform.tfstate 
{
"version": 3,
"serial": 1,
"lineage": "1250a1d2-3e20-124b-7c25-524f67566052",
"backend": {
"type": "s3",
"config": {
"access_key": null,
"acl": null,
"assume_role_policy": null,
"bucket": "tf-fk-test-01",
"dynamodb_endpoint": null,
"dynamodb_table": null,
"encrypt": null,
"endpoint": "https://mytenancy.compat.objectstorage.eu-frankfurt-1.oraclecloud.com",
"external_id": null,
"force_path_style": true,
"iam_endpoint": null,
"key": "terraform/state/oci/vcn/testVCN/terraform.tfstate",
"kms_key_id": null,
"lock_table": null,
"max_retries": null,
"profile": null,
"region": "eu-frankfurt-1",
"role_arn": null,
"secret_key": null,
"session_name": null,
"shared_credentials_file": null,
"skip_credentials_validation": true,
"skip_get_ec2_platforms": null,
"skip_metadata_api_check": true,
"skip_region_validation": true,
"skip_requesting_account_id": null,
"sse_customer_key": null,
"sts_endpoint": null,
"token": null,
"workspace_key_prefix": null
},
"hash": 1758364997
},
"modules": [
{
"path": [
"root"
],
"outputs": {},
"resources": {},
"depends_on": []
}
]
}

And let’s check the Object storage bucket:

oci os object list -bn tf-fk-test-01 --output=table
+------+--------------------------+---------------------------------------------------+-------+----------------------------------+---------------+
| etag | md5 | name | size | time-created | time-modified |
+------+--------------------------+---------------------------------------------------+-------+----------------------------------+---------------+
| None | PRXsobIN......efUorHfg== | terraform/state/oci/vcn/testVCN/terraform.tfstate | 14161 | 2020-05-08T18:43:19.428000+00:00 | None |
+------+--------------------------+---------------------------------------------------+-------+----------------------------------+---------------+
prefixes: []

.. and we’re done, you have configured terraform to store state files remotely on OCI.

If you want to use the same pattern outside the OCI cloud shell you will need to configure the oci provider to use the usual API key/fingerprint combo

Have Fun!

Mattia

My thoughts after successful Oracle Cloud Infrastructure 2019 Certified Architect Professional exam

mattia_rossi_oci_certified_solution_architect_professional_2019Right, last 2 weeks I was silent. I am so sorry about that, but believe me… I had to focus on 1Z0-997 final preparation. It was a really hard exam. Mostly because of the wide range of topics to be explored in detail. On one hand, I was sure about my knowledge after building my Terraform+OCI tutorial plus some howtos for OCI compute autoscaling or OKE deployment. But frankly speaking still there was a lot of things where I was not fully familiar or let’s say I have forgotten details after a few months with no practicing. So if you ask me how to pass this exam the answer is rather simple. You need to put yourself in front of your computer and watch all videos which are available at Oracle University (OU).Β  Although I guess it is also good to practice with Terraform for most of the OCI services and not count only on theoretical knowledge from learning paths in OU. I have been also asked many times about brain dumps usage… well… honestly speaking I am not a big fan of that approach. Mostly because it is just a shortcut approach. Learning answers for the particular set of questions will not make you capable of architecting OCI cloud topologies for the real customers. You need to know all of the topics well. This is the only way to be really professional. I know it is hard, especially when there is no time, but this is only way πŸ™‚ Good luck on your exams! I know from Rohit’s message that OCI certs are now extremely popular! It is another sign that our OCI community is growing! :)))

Bon Appetit,

Martin, The Cook.

TF_VAR variables – how to collect it from the OCI Cloud Console…

Recently one of my subscribers has asked me about this topic. How to collect all TF_VAR variables values for Terraform OCI Provider before starting into the first lesson? A small thing, but very important, right? In this short video, I am explaining how to do it step by step πŸ™‚ BTW. I have added this video to my Terraform OCI course.

Bon Appetit,

Martin, The Cook.

 

 

Every story should have the beginning…

Every story should have the beginning, right? Recently I have had two zoom sessions with great mates, followers of my blog and YT channel. Such talk is an excellent thing, especially now, in this COVID-19 self-isolation period. Both discussions have made me realize that my tutorial has a significant gap… there is no introduction to this training. I guess it is a common and stupid mistake of experienced people who are focused on the essence and sophisticated details, forgetting that for newbies it’s really hard to start. Shame on me! πŸ˜‰ Let me fix it immediately! Below you can find the introduction. Hope it will be tasty for newbies in Terraform+OCI field πŸ™‚

Bon Appetit,

Martin, The Cook.

OCI Subcompartments support in Terraform

Nested subcompartments in OCI has been introduced more than one year ago. So frankly speaking feedback about my course was valid. Yes, it should have proper code for nesting all of the examples somewhere in a subcompartment structure instead of the root compartment. Recently I have fixed the code for each and every lesson. Here is a video on how to use it in practice (lesson1). A pinch of spices for our dish! πŸ™‚

Bon Appetit!

Martin, The Cook.

 

How to use Terraform and OCI – lesson 2a

Recently someone has told me, that my course is great but … it will not work in OCI’s single AD regions. Well… yeah… unfortunately that is true, but I believe we can fix it, right?… so I have introduced additional lesson2a, which is an extension to the original lesson2 where web servers have been deployed in two different ADs. In this short and additional lesson, I am deploying everything in one AD and I am using the fault domain concept, just to achieve hardware failure protection to some extent. In the video below, I am trying to show how to make all of that with Terraform. Please taste it πŸ™‚ I hope you will like it. πŸ™‚

Bon Appetit,

Martin, The Cook.