Skip to content

Commit

Permalink
feat: add an example for Talos on OCI
Browse files Browse the repository at this point in the history
adds example Terraform code and documentation to deploy Talos on Oracle Cloud

Signed-off-by: Andrey Smirnov <[email protected]>
Signed-off-by: Caleb Woodbine <[email protected]>
  • Loading branch information
BobyMCbobs authored and smira committed Sep 27, 2024
1 parent 1be5874 commit 2346f82
Show file tree
Hide file tree
Showing 12 changed files with 1,046 additions and 0 deletions.
147 changes: 147 additions & 0 deletions examples/terraform/oci/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
# Oracle Cloud Terraform Example

Example of a highly available Kubernetes cluster with Talos on Oracle Cloud.

## Prequisites

**general**

- a top-level tenancy

**install things**

``` bash
brew install oci-cli hashicorp/tap/terraform siderolabs/tap/talosctl qemu
```

## Notes

- although not officially supported by Oracle Cloud, network LoadBalancers are provided through the Oracle Cloud Controller (only officially supported on OKE)
- this guide will target arm64, though you can replace with amd64 if it doesn't suit your needs
- instances will only launch with firmware set to UEFI_64 and lauch mode set to PARAVIRTUALIZED

## Uploading an image

Unfortunately due to upload constraints, this portion of the deployment is unable to be run using Terraform. This may change in the future.

Prepare and upload a Talos disk image for Oracle Cloud, with

1. create a storage bucket: https://cloud.oracle.com/object-storage/buckets
2. using Talos Linux Image Factory, create a plan and generate an image to use. See this example: https://factory.talos.dev/?arch=arm64&cmdline=console%3DttyAMA0&cmdline-set=true&extensions=-&platform=oracle&target=cloud&version=1.8.0
3. download the disk image (ending in raw.xz)
4. define the image metadata, with the steps under the section "**defining metadata**"
5. repack the image, with steps under the section "**repacking the image**"
6. upload the image to the storage bucket under objects
7. under object and view object details, copy the dedicated endpoint url. Example: https://axe608t7iscj.objectstorage.us-phoenix-1.oci.customer-oci.com/n/axe608t7iscj/b/talos/o/talos-v1.8.0-oracle-arm64.oci

### defining metadata

create a file called `image_metadata.json` with contents such as

``` json
{
"version": 2,
"externalLaunchOptions": {
"firmware": "UEFI_64",
"networkType": "PARAVIRTUALIZED",
"bootVolumeType": "PARAVIRTUALIZED",
"remoteDataVolumeType": "PARAVIRTUALIZED",
"localDataVolumeType": "PARAVIRTUALIZED",
"launchOptionsSource": "PARAVIRTUALIZED",
"pvAttachmentVersion": 2,
"pvEncryptionInTransitEnabled": true,
"consistentVolumeNamingEnabled": true
},
"imageCapabilityData": null,
"imageCapsFormatVersion": null,
"operatingSystem": "Talos",
"operatingSystemVersion": "1.8.0",
"additionalMetadata": {
"shapeCompatibilities": [
{
"internalShapeName": "VM.Standard.A1.Flex",
"ocpuConstraints": null,
"memoryConstraints": null
}
]
}
}
```

### repacking the image

decompress the downloaded disk image artifact from factory

``` bash
xz --decompress DISK_IMAGE.raw.xz
```

use `qemu-img` to convert the image to qcow2

``` bash
qemu-img convert -f raw -O qcow2 oracle-arm64.raw oracle-arm64.qcow2
```

repack the image as a tar file with the metadata

``` bash
tar zcf oracle-arm64.oci oracle-arm64.qcow2 image_metadata.json
```

## Create a .tfvars file

to configure authentication and namespacing, create a `.tfvars` file with values from the links placeholding in the example below

``` hcl
tenancy_ocid = "TENANCY OCID : https://cloud.oracle.com/tenancy"
user_ocid = "YOUR USER OCID : https://cloud.oracle.com/identity/domains/my-profile"
private_key_path = "YOUR PRIVATE KEY PATH : https://cloud.oracle.com/identity/domains/my-profile/api-keys"
fingerprint = "THE FINGERPRINT FOR YOUR PRIVATE KEY : ^^"
region = "YOUR PREFERRED REGION : https://cloud.oracle.com/regions"
compartment_ocid = "YOUR COMPARTMENT OCID : https://cloud.oracle.com/identity/compartments"
talos_image_oci_bucket_url = "YOUR DEDICATED BUCKET OBJECT URL : https://cloud.oracle.com/object-storage/buckets"
```

## Bringing it up

prepare the local direction for using Terraform

``` bash
terraform init
```

verify the changes to provision

``` bash
terraform plan -var-file=.tfvars
```

apply the changes

``` bash
terraform apply -var-file=.tfvars
```

get the talosconfig

``` bash
terraform output -raw talosconfig > ./talosconfig
```

get the kubeconfig

``` bash
terraform output -raw kubeconfig > ./kubeconfig
```

destroy the worker nodes

``` bash
terraform destroy -var-file=.tfvars -target=random_pet.worker
```

destroy

``` bash
terraform destroy -var-file=.tfvars
```
145 changes: 145 additions & 0 deletions examples/terraform/oci/data.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
data "oci_identity_compartment" "this" {
id = var.compartment_ocid
}

data "oci_identity_availability_domains" "availability_domains" {
#Required
compartment_id = var.tenancy_ocid
}

data "oci_core_image_shapes" "image_shapes" {
depends_on = [oci_core_shape_management.image_shape]
#Required
image_id = oci_core_image.talos_image.id
}

data "talos_image_factory_extensions_versions" "this" {
# get the latest talos version
talos_version = var.talos_version
filters = {
names = var.talos_extensions
}
}

data "talos_image_factory_urls" "this" {
talos_version = var.talos_version
schematic_id = talos_image_factory_schematic.this.id
platform = "oracle"
architecture = var.architecture
}

data "talos_client_configuration" "talosconfig" {
cluster_name = var.cluster_name
client_configuration = talos_machine_secrets.machine_secrets.client_configuration
endpoints = [for k, v in oci_core_instance.controlplane : v.public_ip]
nodes = concat(
[for k, v in oci_core_instance.controlplane : v.public_ip],
[for k, v in oci_core_instance.worker : v.private_ip]
)
}

data "talos_machine_configuration" "controlplane" {
cluster_name = var.cluster_name
# cluster_endpoint = "https://${var.kube_apiserver_domain}:6443"
cluster_endpoint = "https://${oci_network_load_balancer_network_load_balancer.controlplane_load_balancer.ip_addresses[0].ip_address}:6443"

machine_type = "controlplane"
machine_secrets = talos_machine_secrets.machine_secrets.machine_secrets

talos_version = var.talos_version
kubernetes_version = var.kubernetes_version

docs = false
examples = false

config_patches = [
local.talos_base_configuration,
<<-EOT
machine:
features:
kubernetesTalosAPIAccess:
enabled: true
allowedRoles:
- os:reader
allowedKubernetesNamespaces:
- kube-system
EOT
,
yamlencode({
machine = {
certSANs = concat([
var.kube_apiserver_domain,
oci_network_load_balancer_network_load_balancer.controlplane_load_balancer.ip_addresses[0].ip_address,
],
[for k, v in oci_core_instance.controlplane : v.public_ip]
)
}
cluster = {
apiServer = {
certSANs = concat([
var.kube_apiserver_domain,
oci_network_load_balancer_network_load_balancer.controlplane_load_balancer.ip_addresses[0].ip_address,
],
[for k, v in oci_core_instance.controlplane : v.public_ip]
)
}
}
}),
]
}

data "talos_machine_configuration" "worker" {
cluster_name = var.cluster_name
# cluster_endpoint = "https://${var.kube_apiserver_domain}:6443"
cluster_endpoint = "https://${oci_network_load_balancer_network_load_balancer.controlplane_load_balancer.ip_addresses[0].ip_address}:6443"

machine_type = "worker"
machine_secrets = talos_machine_secrets.machine_secrets.machine_secrets

talos_version = var.talos_version
kubernetes_version = var.kubernetes_version

docs = false
examples = false

config_patches = [
local.talos_base_configuration,
<<EOF
machine:
disks:
- device: /dev/sdb
partitions:
- mountpoint: /var/lib/longhorn
kubelet:
extraMounts:
- destination: /var/lib/longhorn
type: bind
source: /var/lib/longhorn
options:
- bind
- rshared
- rw
EOF
,
yamlencode({
machine = {
certSANs = concat([
var.kube_apiserver_domain,
oci_network_load_balancer_network_load_balancer.controlplane_load_balancer.ip_addresses[0].ip_address,
],
[for k, v in oci_core_instance.controlplane : v.public_ip]
)
}
cluster = {
apiServer = {
certSANs = concat([
var.kube_apiserver_domain,
oci_network_load_balancer_network_load_balancer.controlplane_load_balancer.ip_addresses[0].ip_address,
],
[for k, v in oci_core_instance.controlplane : v.public_ip]
)
}
}
}),
]
}
31 changes: 31 additions & 0 deletions examples/terraform/oci/iam.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
resource "oci_identity_dynamic_group" "oci-ccm" {
#Required
name = "${var.cluster_name}-oci-ccm"
compartment_id = var.tenancy_ocid # tenancy_ocid, compartment_ocid and domain_ocid doesn't work
description = "Instance access"
matching_rule = "ALL {instance.compartment.id = '${var.compartment_ocid}'}"

#Optional
freeform_tags = local.common_labels
}

locals {
ns_type_name = strcontains(var.compartment_ocid, ".tenancy.") ? "tenancy" : "compartment"
ns_select_name = strcontains(var.compartment_ocid, ".compartment.") ? data.oci_identity_compartment.this.name : ""
}

resource "oci_identity_policy" "oci-ccm" {
#Required
name = "${var.cluster_name}-oci-ccm"
compartment_id = var.tenancy_ocid
description = "Instance access"
statements = [
// LoadBalancer Services
"Allow dynamic-group ${oci_identity_dynamic_group.oci-ccm.name} to read instance-family in ${local.ns_type_name} ${local.ns_select_name}",
"Allow dynamic-group ${oci_identity_dynamic_group.oci-ccm.name} to use virtual-network-family in ${local.ns_type_name} ${local.ns_select_name}",
"Allow dynamic-group ${oci_identity_dynamic_group.oci-ccm.name} to manage load-balancers in ${local.ns_type_name} ${local.ns_select_name}",
]

#Optional
freeform_tags = local.common_labels
}
26 changes: 26 additions & 0 deletions examples/terraform/oci/image.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
resource "oci_core_image" "talos_image" {
#Required
compartment_id = var.compartment_ocid

#Optional
display_name = "Talos ${var.talos_version}"
freeform_tags = local.common_labels
launch_mode = local.instance_mode

image_source_details {
source_type = "objectStorageUri"
source_uri = var.talos_image_oci_bucket_url

#Optional
operating_system = "Talos Linux"
operating_system_version = var.talos_version
source_image_type = "QCOW2"
}
}

resource "oci_core_shape_management" "image_shape" {
#Required
compartment_id = var.compartment_ocid
image_id = oci_core_image.talos_image.id
shape_name = var.instance_shape
}
Loading

0 comments on commit 2346f82

Please sign in to comment.