Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement terraform modules and infrastructure example #125

Merged
merged 6 commits into from
Feb 26, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions infra-examples/digitalocean/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# DigitalOcean Infrastructure Example

This is an example implementation to create a production grade infrastructure for hosting Open edX instances on DigitalOcean, using the Terraform modules provided by Harmony.

## Requirements

| Name | Version |
|------|---------|
| <a name="requirement_digitalocean"></a> [digitalocean](#requirement\_digitalocean) | >=2.45 |
| <a name="requirement_helm"></a> [helm](#requirement\_helm) | >=2.16 |
| <a name="requirement_kubectl"></a> [kubectl](#requirement\_kubectl) | >=1.17 |
| <a name="requirement_kubernetes"></a> [kubernetes](#requirement\_kubernetes) | >=2.34 |

## Providers

| Name | Version |
|------|---------|
| <a name="provider_digitalocean"></a> [digitalocean](#provider\_digitalocean) | 2.45.0 |

## Modules

| Name | Source | Version |
|------|--------|---------|
| <a name="module_kubernetes_cluster"></a> [kubernetes\_cluster](#module\_kubernetes\_cluster) | ../../terraform/modules/digitalocean/doks | n/a |
| <a name="module_main_vpc"></a> [main\_vpc](#module\_main\_vpc) | ../../terraform/modules/digitalocean/vpc | n/a |
| <a name="module_mongodb_database"></a> [mongodb\_database](#module\_mongodb\_database) | ../../terraform/modules/digitalocean/database | n/a |
| <a name="module_mysql_database"></a> [mysql\_database](#module\_mysql\_database) | ../../terraform/modules/digitalocean/database | n/a |
| <a name="module_spaces"></a> [spaces](#module\_spaces) | ../../terraform/modules/digitalocean/spaces | n/a |

## Resources

| Name | Type |
|------|------|
| [digitalocean_database_db.forum_database](https://registry.terraform.io/providers/digitalocean/digitalocean/latest/docs/resources/database_db) | resource |
| [digitalocean_project.project](https://registry.terraform.io/providers/digitalocean/digitalocean/latest/docs/resources/project) | resource |
| [digitalocean_kubernetes_cluster.cluster](https://registry.terraform.io/providers/digitalocean/digitalocean/latest/docs/data-sources/kubernetes_cluster) | data source |
| [digitalocean_kubernetes_versions.available_versions](https://registry.terraform.io/providers/digitalocean/digitalocean/latest/docs/data-sources/kubernetes_versions) | data source |

## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| <a name="input_do_access_token"></a> [do\_access\_token](#input\_do\_access\_token) | DitialOcean access token. | `string` | n/a | yes |
| <a name="input_environment"></a> [environment](#input\_environment) | The DigitalOcean project environment. (for example: production, staging, development, etc.) | `string` | n/a | yes |
| <a name="input_kubernetes_cluster_name"></a> [kubernetes\_cluster\_name](#input\_kubernetes\_cluster\_name) | Name of the DigitalOcean Kubernetes cluster to create. | `string` | n/a | yes |
| <a name="input_region"></a> [region](#input\_region) | DigitalOcean region to create the resources in. | `string` | n/a | yes |

## Outputs

No outputs.
55 changes: 0 additions & 55 deletions infra-examples/digitalocean/k8s-cluster/main.tf

This file was deleted.

143 changes: 71 additions & 72 deletions infra-examples/digitalocean/main.tf
Original file line number Diff line number Diff line change
@@ -1,94 +1,93 @@
# A cluster to test proof of concept on DigitalOcean
terraform {
required_providers {
digitalocean = {
source = "digitalocean/digitalocean"
version = ">=2.23"
}
kubernetes = {
source = "hashicorp/kubernetes"
version = "2.35.0"
}
kubectl = {
source = "gavinbunney/kubectl"
version = "1.18.0"
}
helm = {
source = "hashicorp/helm"
version = "2.16.1"
}
}
}
data "digitalocean_kubernetes_versions" "available_versions" {}

# Configure the DigitalOcean Provider
provider "digitalocean" {
token = var.do_token
}
module "main_vpc" {
source = "../../terraform/modules/digitalocean/vpc"

variable "cluster_name" { type = string }
variable "do_token" {
type = string
sensitive = true
region = var.region
environment = var.environment
}

module "k8s_cluster" {
source = "./k8s-cluster"
module "kubernetes_cluster" {
source = "../../terraform/modules/digitalocean/doks"

cluster_name = var.cluster_name
# max_worker_node_count = var.max_worker_node_count
# min_worker_node_count = var.min_worker_node_count
# worker_node_size = var.worker_node_size
# region = var.do_region
# vpc_uuid = digitalocean_vpc.main_vpc.id
# vpc_ip_range = var.vpc_ip_range
}
region = var.region
environment = var.environment
vpc_id = module.main_vpc.vpc_id

# Pre-declare data sources that we can use to get the cluster ID and auth info, once it's created
data "digitalocean_kubernetes_cluster" "cluster" {
name = var.cluster_name
# Set the depends_on so that the data source doesn't
# try to read from a cluster that doesn't exist, causing
# failures when trying to run a `tofu plan`.
depends_on = [module.k8s_cluster.cluster_id]
cluster_name = var.kubernetes_cluster_name
kubernetes_version = data.digitalocean_kubernetes_versions.available_versions.latest_version
}

# Configure Kubernetes provider
provider "kubernetes" {
host = data.digitalocean_kubernetes_cluster.cluster.endpoint
token = data.digitalocean_kubernetes_cluster.cluster.kube_config[0].token
cluster_ca_certificate = base64decode(data.digitalocean_kubernetes_cluster.cluster.kube_config[0].cluster_ca_certificate)
}
module "spaces" {
source = "../../terraform/modules/digitalocean/spaces"

region = var.region
environment = var.environment

# Configure Helm provider
provider "helm" {
kubernetes {
host = data.digitalocean_kubernetes_cluster.cluster.endpoint
token = data.digitalocean_kubernetes_cluster.cluster.kube_config[0].token
cluster_ca_certificate = base64decode(data.digitalocean_kubernetes_cluster.cluster.kube_config[0].cluster_ca_certificate)
}
bucket_prefix = "my-institute"
}

provider "kubectl" {
host = data.digitalocean_kubernetes_cluster.cluster.endpoint
token = data.digitalocean_kubernetes_cluster.cluster.kube_config[0].token
cluster_ca_certificate = base64decode(data.digitalocean_kubernetes_cluster.cluster.kube_config[0].cluster_ca_certificate)
load_config_file = false
module "mysql_database" {
source = "../../terraform/modules/digitalocean/database"

region = var.region
environment = var.environment
access_token = var.do_access_token
vpc_id = module.main_vpc.vpc_id
kubernetes_cluster_name = var.kubernetes_cluster_name

database_engine = "mysql"
database_engine_version = 8
database_cluster_instances = 1
database_cluster_instance_size = "db-s-1vcpu-1gb"
database_maintenance_window_day = "sunday"
database_maintenance_window_time = "01:00:00"

# Database cluster firewalls cannot use VPC CIDR, therefore the access is
# limited to the k8s cluster
firewall_rules = [
{
type = "k8s"
value = module.kubernetes_cluster.cluster_id
},
]
}

module "mongodb_database" {
source = "../../terraform/modules/digitalocean/database"

# Declare the kubeconfig as an output - access it anytime with "tofu output -raw kubeconfig"
output "kubeconfig" {
value = module.k8s_cluster.kubeconfig.raw_config
sensitive = true
region = var.region
environment = var.environment
access_token = var.do_access_token
vpc_id = module.main_vpc.vpc_id
kubernetes_cluster_name = var.kubernetes_cluster_name

database_engine = "mongodb"
database_engine_version = 7
database_cluster_instances = 3
database_cluster_instance_size = "db-s-1vcpu-1gb"
database_maintenance_window_day = "sunday"
database_maintenance_window_time = "1:00"

# Database cluster firewalls cannot use VPC CIDR, therefore the access is
# limited to the k8s cluster
firewall_rules = [
{
type = "k8s"
value = module.kubernetes_cluster.cluster_id
},
]
}

resource "digitalocean_project" "project" {
name = var.cluster_name
description = "Testing the use of Helm to provision a cluster for multi-instance tutor deployment"
name = var.kubernetes_cluster_name
description = "Open edX deployment using Harmony"
purpose = "Web Application"
environment = "Production"

resources = [
module.k8s_cluster.cluster_urn,
module.kubernetes_cluster.cluster_urn,
module.spaces.bucket_urn,
module.mysql_database.cluster_urn,
module.mongodb_database.cluster_urn,
]
}
56 changes: 56 additions & 0 deletions infra-examples/digitalocean/providers.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
terraform {
required_providers {
digitalocean = {
source = "digitalocean/digitalocean"
version = ">=2.45"
}
kubernetes = {
source = "hashicorp/kubernetes"
version = ">=2.34"
}
kubectl = {
source = "gavinbunney/kubectl"
version = ">=1.17"
}
helm = {
source = "hashicorp/helm"
version = ">=2.16"
}
}
}

# Pre-declare data sources that we can use to get the cluster ID and auth info,
# once it's created. Set the `depends_on` so that the data source doesn't try
# to read from a cluster that doesn't exist, causing failures when trying to
# run a `terraform plan`.
data "digitalocean_kubernetes_cluster" "cluster" {
name = module.kubernetes_cluster.cluster_name
depends_on = [module.kubernetes_cluster.cluster_id]
}

provider "digitalocean" {
token = var.do_access_token
spaces_access_id = "DO00M682HAUD3KXUQNL3"
spaces_secret_key = "fnoviZN11Y0NAoeAXxUrOU0liJyKcfP4yQboHJkJKY0"
}

provider "kubernetes" {
host = data.digitalocean_kubernetes_cluster.cluster.endpoint
token = data.digitalocean_kubernetes_cluster.cluster.kube_config[0].token
cluster_ca_certificate = base64decode(data.digitalocean_kubernetes_cluster.cluster.kube_config[0].cluster_ca_certificate)
}

provider "helm" {
kubernetes {
host = data.digitalocean_kubernetes_cluster.cluster.endpoint
token = data.digitalocean_kubernetes_cluster.cluster.kube_config[0].token
cluster_ca_certificate = base64decode(data.digitalocean_kubernetes_cluster.cluster.kube_config[0].cluster_ca_certificate)
}
}

provider "kubectl" {
host = data.digitalocean_kubernetes_cluster.cluster.endpoint
token = data.digitalocean_kubernetes_cluster.cluster.kube_config[0].token
cluster_ca_certificate = base64decode(data.digitalocean_kubernetes_cluster.cluster.kube_config[0].cluster_ca_certificate)
load_config_file = false
}
35 changes: 35 additions & 0 deletions infra-examples/digitalocean/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
variable "do_access_token" {
type = string
description = "DitialOcean access token."
sensitive = true
}

variable "kubernetes_cluster_name" {
type = string
description = "Name of the DigitalOcean Kubernetes cluster to create."
}

variable "region" {
type = string
description = "DigitalOcean region to create the resources in."
validation {
condition = contains([
"ams3",
"blr1",
"fra1",
"lon1",
"nyc3",
"sfo2",
"sfo3",
"sgp1",
"syd1",
"tor1",
], var.region)
error_message = "The DigitalOcean region must be in the acceptable region list."
}
}

variable "environment" {
type = string
description = "The DigitalOcean project environment. (for example: production, staging, development, etc.)"
}
Loading