1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
|
---
title: Getting started with Oracle Cloud Infrastructure
description: Oracle Cloud Infrastructure's always free tier is very generous
date: 2021-09-05
tags:
- terraform
---
## Introduction
Oracle Cloud Infrastructure provides quite a generous always free tier for you to use and test their cloud... or host some light services. But getting started was a little difficult with many pieces missing or incomplete in the examples, especially how to configure ipv6 on your instances.
The documentation is very good and exhaustive but information was scattered : the following should help you get started right after you create your oracle cloud infrastructure's account.
## Create your API access
In order to terraform your infrastructure, you are going to need to generate an api access which is composed of a key and several other things :
- Open the web console, click the top left menu and select `Identity & Security` then `Users`.
- Click your account
- Scroll to bottom left and select `API Keys`
- click `Add an api key`
- Select `Generic API Key Pair`, download the private key file then click `Add`
- Copy the information displayed for the next phase
## Terraform
### Provider configuration
Here is the relevant snippet from my `providers.tf` file :
```hcl
variable "oracle_tenancy_ocid" {}
variable "oracle_user_ocid" {}
variable "oracle_fingerprint" {}
provider "oci" {
tenancy_ocid = var.oracle_tenancy_ocid
user_ocid = var.oracle_user_ocid
fingerprint = var.oracle_fingerprint
private_key_path = "../tf-common/oracle_key.pem"
region = "eu-amsterdam-1"
}
variable "oracle_amd64_instances_names" {}
```
This goes along with a `terraform.tfvars` file that you should fill with the api access information you saved up earlier :
```hcl
oracle_tenancy_ocid = "XXXXX"
oracle_user_ocid = "YYYYY"
oracle_fingerprint = "ZZZZZ"
oracle_amd64_instances_names = ["dalinar", "kaladin"]
```
The last bit is how I name the two free instances I want to create, pick anything you like.
### Networking
Here is how to bootstrap a vcn and the associated objects for direct internet access. For simplicity I will leave the access lists opened, firewall rules really are a pain to write with terraform... I plan to keep on using iptables or shorewall on the hosts for now.
```hcl
resource "oci_core_vcn" "adyxax" {
compartment_id = var.oracle_tenancy_ocid
cidr_blocks = ["10.0.0.0/16"]
display_name = "adyxax"
dns_label = "adyxax"
is_ipv6enabled = true
}
resource "oci_core_internet_gateway" "gw" {
compartment_id = var.oracle_tenancy_ocid
vcn_id = oci_core_vcn.adyxax.id
enabled = true
display_name = "gw"
}
resource "oci_core_route_table" "default-via-gw" {
compartment_id = var.oracle_tenancy_ocid
vcn_id = oci_core_vcn.adyxax.id
display_name = "default-via-gw"
route_rules {
destination = "0.0.0.0/0"
destination_type = "CIDR_BLOCK"
network_entity_id = oci_core_internet_gateway.gw.id
}
route_rules {
destination = "::/0"
destination_type = "CIDR_BLOCK"
network_entity_id = oci_core_internet_gateway.gw.id
}
}
# protocol - Specify either all or an IPv4 protocol number : ICMP ("1"), TCP ("6"), UDP ("17"), and ICMPv6 ("58").·
resource "oci_core_security_list" "allow-all" {
compartment_id = var.oracle_tenancy_ocid
vcn_id = oci_core_vcn.adyxax.id
display_name = "allow-all"
egress_security_rules {
protocol = "all"
destination = "0.0.0.0/0"
}
ingress_security_rules {
protocol = "all"
source = "0.0.0.0/0"
}
egress_security_rules {
protocol = "all"
destination = "::/0"
}
ingress_security_rules {
protocol = "all"
source = "::/0"
}
}
resource "oci_core_subnet" "adyxax-production" {
cidr_block = cidrsubnet(oci_core_vcn.adyxax.cidr_blocks[0], 8, 0)
compartment_id = var.oracle_tenancy_ocid
vcn_id = oci_core_vcn.adyxax.id
display_name = "production"
dns_label = "production"
ipv6cidr_block = cidrsubnet(oci_core_vcn.adyxax.ipv6cidr_blocks[0], 8, 0)
security_list_ids = [oci_core_security_list.allow-all.id]
route_table_id = oci_core_route_table.default-via-gw.id
}
```
### Instances
Here is how to create the two always free tier instances, each in a different fault domain. The tricky part was to understand how ipv6 addresses are like second class citizens on oracle cloud :
```hcl
data "oci_identity_availability_domains" "ads" {
compartment_id = var.oracle_tenancy_ocid
}
data "oci_identity_fault_domains" "fd" {
compartment_id = var.oracle_tenancy_ocid
availability_domain = data.oci_identity_availability_domains.ads.availability_domains[0].name
}
# taken from https://docs.oracle.com/en-us/iaas/images/all/?search=Oracle-Linux-8.4
data "oci_core_image" "ol8" {
image_id = "ocid1.image.oc1.eu-amsterdam-1.aaaaaaaaj46eslsa6ivgneyneypomtvzb6dmg22gtewy6opwiniuwgsdv7uq"
}
resource "oci_core_instance" "amd64-vms" {
count = length(var.oracle_amd64_instances_names)
compartment_id = var.oracle_tenancy_ocid
availability_domain = data.oci_identity_availability_domains.ads.availability_domains[0].name
fault_domain = data.oci_identity_fault_domains.fd.fault_domains[count.index % length(data.oci_identity_fault_domains.fd.fault_domains)].name
display_name = var.oracle_amd64_instances_names[count.index % length(var.oracle_amd64_instances_names)]
shape = "VM.Standard.E2.1.Micro"
preserve_boot_volume = true
create_vnic_details {
subnet_id = oci_core_subnet.adyxax-production.id
hostname_label = var.oracle_amd64_instances_names[count.index]
display_name = var.oracle_amd64_instances_names[count.index]
}
source_details {
boot_volume_size_in_gbs = 50
source_type = "image"
source_id = data.oci_core_image.ol8.id
}
metadata = {
"ssh_authorized_keys" : "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILOJV391WFRYgCVA2plFB8W8sF9LfbzXZOrxqaOrrwco"
}
}
data "oci_core_vnic_attachments" "amd64-vms-vnics" {
count = length(var.oracle_amd64_instances_names)
compartment_id = var.oracle_tenancy_ocid
instance_id = oci_core_instance.amd64-vms[count.index].id
}
resource "oci_core_ipv6" "amd64-vms-ipv6s" {
count = length(var.oracle_amd64_instances_names)
vnic_id = data.oci_core_vnic_attachments.amd64-vms-vnics[count.index].vnic_attachments[0].vnic_id
display_name = var.oracle_amd64_instances_names[count.index]
}
```
### Bonus : Provisionning cloudflare's dns
If like me you are managing your dns with cloudflare, here is how to provision the relevant records :
```hcl
resource "cloudflare_record" "adyxax-org-oracle-amd64-vms-ipv4" {
count = length(var.oracle_amd64_instances_names)
zone_id = lookup(data.cloudflare_zones.adyxax-org.zones[0], "id")
name = var.oracle_amd64_instances_names[count.index]
value = oci_core_instance.amd64-vms[count.index].public_ip
type = "A"
proxied = false
}
resource "cloudflare_record" "adyxax-org-oracle-amd64-vms-ipv6" {
count = length(var.oracle_amd64_instances_names)
zone_id = lookup(data.cloudflare_zones.adyxax-org.zones[0], "id")
name = var.oracle_amd64_instances_names[count.index]
value = oci_core_ipv6.amd64-vms-ipv6s[count.index].ip_address
type = "AAAA"
proxied = false
}
```
## Conclusion
Putting all of this together was an interesting experience, and I am satisfied that it works well. In the future I plan to add my own oci image based on alpine linux which is not available natively. I tried oracle linux and it is fine, but consumes way too much ram for my taste. For now I installed alpine linux using the instance's cloud console and [my procedure for that]({{< ref "docs/alpine/remote_install_iso" >}}).
|