Skip to content

Commit

Permalink
Merge pull request #16 from johncosta/johncosta/gh-11a
Browse files Browse the repository at this point in the history
[GH-11] Integrate argo as an addon
  • Loading branch information
johncosta committed Dec 26, 2023
2 parents 421d858 + 2640e33 commit ffcf1e3
Show file tree
Hide file tree
Showing 12 changed files with 510 additions and 21 deletions.
21 changes: 20 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ This module is inspired by [terraform-aws-eks](https://github.com/terraform-aws-
```hcl
module "k8s" {
source = "terraform-digitalocean-kubernetes"
version = "0.0.7"
version = "0.0.10"
cluster_name_prefix = "test-cluster"
cluster_region = "nyc1"
Expand All @@ -38,5 +38,24 @@ module "k8s" {
# writes the kubeconfig to the local filesystem
path_to_kubeconfig = "/full/path/to/.kube"
use_cluster_name_in_config = true
cluster_addons = {
/*
* Add ArgoCD into its own namespace
*/
argo = {
enabled = true
}
/*
* Add ingress-nginx and cert-manager into their own namespaces
*/
ingress = {
enabled = true
config = {
domain_root = "example.com"
domain_certificate_email = "name@example.com"
}
}
}
}
```
22 changes: 22 additions & 0 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ resource "digitalocean_vpc" "vpc" {
name = local.vpc_name
region = var.cluster_region
ip_range = var.cluster_ipv4_cidr

timeouts {
delete = "10m"
}
}

resource "local_sensitive_file" "kubeconfig" {
Expand All @@ -52,3 +56,21 @@ resource "local_sensitive_file" "kubeconfig" {
digitalocean_kubernetes_cluster.this
]
}

module "addons" {
source = "./modules/addons"

/*
* Pass the cluster name and id to the module to ensure that addons depend on the cluster.
*/
cluster_name = digitalocean_kubernetes_cluster.this.name
cluster_id = digitalocean_kubernetes_cluster.this.id
cluster_addons = var.cluster_addons

providers = {
digitalocean = digitalocean
kubernetes = kubernetes
kubectl = kubectl
helm = helm
}
}
61 changes: 61 additions & 0 deletions modules/addons/argo.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
locals {
argo_addon = lookup(var.cluster_addons, "argo", {
enabled = false,
config = {}
})
argo_enabled = lookup(local.argo_addon, "enabled", false)
argo_name = lookup(local.argo_addon, "name", "argo")
argo_namespace = lookup(local.argo_addon, "namespace", "argo")
argo_chart_config = lookup(local.argo_addon, "chart_config", {})
argo_chart_version = lookup(local.argo_addon, "chart_version", "5.51.6")
argo_record_name = lookup(local.argo_addon, "record_name", "argo")
argo_module_config = lookup(local.argo_addon, "config", {
subdomain_create = false
})
argo_subdomain_create = lookup(local.argo_module_config, "subdomain_create", false)

argo_hostname = join(".", [local.argo_record_name, local.dns_domain_root])
}

################################################################################
# Namespace
################################################################################

resource "kubernetes_namespace" "argo" {
count = local.argo_enabled ? 1 : 0

metadata {
name = local.argo_namespace
}

depends_on = [
kubernetes_namespace.cert-manager,
]
}

################################################################################
# Helm
################################################################################

resource "helm_release" "argo" {
count = local.argo_enabled ? 1 : 0

name = local.argo_name
namespace = local.argo_namespace
repository = "https://argoproj.github.io/argo-helm"
chart = "argo-cd"
version = local.argo_chart_version

dynamic "set" {
for_each = local.argo_chart_config

content {
name = set.key
value = set.value
}
}

depends_on = [
kubernetes_namespace.argo,
]
}
117 changes: 117 additions & 0 deletions modules/addons/cert-manager.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
locals {
cert_manager_addon = lookup(local.nginx_addon, "cert-manager", {
enabled = false,
name = "cert-manager",
namespace = "cert-manager",
chart_config = {
installCRDs = true
},
chart_version = "1.5.3",
module_config = {},
})
cert_manager_enabled = lookup(local.cert_manager_addon, "enabled", false) # tflint-ignore: terraform_unused_declarations
cert_manager_name = lookup(local.cert_manager_addon, "name", "cert-manager")
cert_manager_namespace = lookup(local.cert_manager_addon, "namespace", "cert-manager")
cert_manager_chart_config = lookup(local.cert_manager_addon, "chart_config", { installCRDs = true })
cert_manager_chart_version = lookup(local.cert_manager_addon, "chart_version", "1.5.3")
cert_manager_module_config = lookup(local.cert_manager_addon, "module_config", {}) # tflint-ignore: terraform_unused_declarations
}

################################################################################
# Namespace
################################################################################

resource "kubernetes_namespace" "cert-manager" {
count = local.dns_enabled ? 1 : 0

metadata {
name = local.cert_manager_namespace
}
}

################################################################################
# Helm
################################################################################

resource "helm_release" "cert-manager" {
count = local.dns_enabled ? 1 : 0

name = local.cert_manager_name
namespace = local.cert_manager_namespace
repository = "https://charts.jetstack.io"
chart = "cert-manager"
version = local.cert_manager_chart_version

dynamic "set" {
for_each = local.cert_manager_chart_config

content {
name = set.key
value = set.value
}
}

depends_on = [
kubernetes_namespace.cert-manager,
]
}

################################################################################
# Issuers
################################################################################

resource "kubectl_manifest" "letsencrypt-staging" {
count = local.dns_enabled ? 1 : 0
yaml_body = <<YAML
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-staging
namespace: cert-manager
spec:
acme:
# The ACME server URL
server: https://acme-staging-v02.api.letsencrypt.org/directory
# Email address used for ACME registration
email: ${local.domain_certificate_email}
# Name of a secret used to store the ACME account private key
privateKeySecretRef:
name: letsencrypt-staging
# Enable the HTTP-01 challenge provider
solvers:
- http01:
ingress:
class: nginx
YAML
depends_on = [
helm_release.cert-manager,
]
}

resource "kubectl_manifest" "letsencrypt-prod" {
count = local.dns_enabled ? 1 : 0
yaml_body = <<YAML
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
namespace: cert-manager
spec:
acme:
# The ACME server URL
server: https://acme-v02.api.letsencrypt.org/directory
# Email address used for ACME registration
email: ${local.domain_certificate_email}
# Name of a secret used to store the ACME account private key
privateKeySecretRef:
name: letsencrypt-prod
# Enable the HTTP-01 challenge provider
solvers:
- http01:
ingress:
class: nginx
YAML
depends_on = [
helm_release.cert-manager,
]
}
86 changes: 86 additions & 0 deletions modules/addons/ingress.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
locals {
nginx_addon = lookup(var.cluster_addons, "ingress", {
enabled = false,
config = {
domain_root = "example.com",
domain_create = false,
domain_certificate_email = "name@example.com"
}
})
nginx_enabled = lookup(local.nginx_addon, "enabled", false)
nginx_name = lookup(local.nginx_addon, "name", "nginx")
nginx_namespace = lookup(local.nginx_addon, "namespace", "nginx")
nginx_chart_version = lookup(local.nginx_addon, "chart_version", "4.9.0")
nginx_config = lookup(local.nginx_addon, "config", {
domain_root = "example.com",
domain_create = false,
domain_certificate_email = "name@example.com"
})

dns_domain_root = lookup(local.nginx_config, "domain_root", "example.com")
dns_domain_create = lookup(local.nginx_config, "domain_create", false)
domain_certificate_email = lookup(local.nginx_config, "domain_certificate_email", "name@example.com")

ingress_public_ip_file_path = "/tmp"
ingress_public_ip_file = "nginx_public_ips.txt"
full_path_to_public_ip_file = join("/", [local.ingress_public_ip_file_path, local.ingress_public_ip_file])
}

################################################################################
# Namespace
################################################################################

resource "kubernetes_namespace" "nginx" {
count = local.nginx_enabled ? 1 : 0

metadata {
name = local.nginx_namespace
}
depends_on = [
kubernetes_namespace.cert-manager,
kubernetes_namespace.argo
]
}

################################################################################
# Helm
################################################################################

resource "helm_release" "nginx" {
count = local.nginx_enabled ? 1 : 0

name = local.nginx_name
namespace = local.nginx_namespace
repository = "https://kubernetes.github.io/ingress-nginx"
chart = "ingress-nginx"
version = local.nginx_chart_version

depends_on = [
kubernetes_namespace.nginx,
]
}

################################################################################
# External IP
################################################################################

resource "null_resource" "get-nginx-public-ip" {
count = local.nginx_enabled && local.dns_enabled ? 1 : 0

triggers = { always_run = timestamp() }
provisioner "local-exec" {
command = "kubectl get svc nginx-ingress-nginx-controller -n nginx --output jsonpath='{.status.loadBalancer.ingress[0].ip}' > ${local.full_path_to_public_ip_file}"
}
depends_on = [
helm_release.nginx,
]
}

data "local_file" "nginx-public-ip" {
count = local.nginx_enabled && local.dns_enabled ? 1 : 0

filename = local.full_path_to_public_ip_file
depends_on = [
null_resource.get-nginx-public-ip,
]
}

0 comments on commit ffcf1e3

Please sign in to comment.