diff --git a/modules/kubernetes/.terraform.lock.hcl b/modules/kubernetes/.terraform.lock.hcl index 9687444..7301670 100644 --- a/modules/kubernetes/.terraform.lock.hcl +++ b/modules/kubernetes/.terraform.lock.hcl @@ -39,3 +39,23 @@ provider "registry.terraform.io/hashicorp/kubernetes" { "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c", ] } + +provider "registry.terraform.io/hashicorp/random" { + version = "3.6.2" + constraints = ">= 3.6.2, < 4.0.0" + hashes = [ + "h1:wmG0QFjQ2OfyPy6BB7mQ57WtoZZGGV07uAPQeDmIrAE=", + "zh:0ef01a4f81147b32c1bea3429974d4d104bbc4be2ba3cfa667031a8183ef88ec", + "zh:1bcd2d8161e89e39886119965ef0f37fcce2da9c1aca34263dd3002ba05fcb53", + "zh:37c75d15e9514556a5f4ed02e1548aaa95c0ecd6ff9af1119ac905144c70c114", + "zh:4210550a767226976bc7e57d988b9ce48f4411fa8a60cd74a6b246baf7589dad", + "zh:562007382520cd4baa7320f35e1370ffe84e46ed4e2071fdc7e4b1a9b1f8ae9b", + "zh:5efb9da90f665e43f22c2e13e0ce48e86cae2d960aaf1abf721b497f32025916", + "zh:6f71257a6b1218d02a573fc9bff0657410404fb2ef23bc66ae8cd968f98d5ff6", + "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", + "zh:9647e18f221380a85f2f0ab387c68fdafd58af6193a932417299cdcae4710150", + "zh:bb6297ce412c3c2fa9fec726114e5e0508dd2638cad6a0cb433194930c97a544", + "zh:f83e925ed73ff8a5ef6e3608ad9225baa5376446349572c2449c0c0b3cf184b7", + "zh:fbef0781cb64de76b1df1ca11078aecba7800d82fd4a956302734999cfd9a4af", + ] +} diff --git a/modules/kubernetes/README.md b/modules/kubernetes/README.md index 23abc58..b340de0 100644 --- a/modules/kubernetes/README.md +++ b/modules/kubernetes/README.md @@ -8,6 +8,7 @@ | [terraform](#requirement\_terraform) | >= 1.0.0 | | [helm](#requirement\_helm) | >= 2.14.0, < 3.0.0 | | [kubernetes](#requirement\_kubernetes) | >= 2.31.0, < 3.0.0 | +| [random](#requirement\_random) | >= 3.6.2, < 4.0.0 | ## Providers @@ -15,6 +16,7 @@ |------|---------| | [helm](#provider\_helm) | 2.14.0 | | [kubernetes](#provider\_kubernetes) | 2.31.0 | +| [random](#provider\_random) | 3.6.2 | ## Modules @@ -25,25 +27,35 @@ No modules. | Name | Type | |------|------| | [helm_release.cluster_autoscaler](https://registry.terraform.io/providers/hashicorp/helm/latest/docs/resources/release) | resource | +| [helm_release.external_dns](https://registry.terraform.io/providers/hashicorp/helm/latest/docs/resources/release) | resource | | [helm_release.hcloud_ccm](https://registry.terraform.io/providers/hashicorp/helm/latest/docs/resources/release) | resource | | [helm_release.hcloud_csi](https://registry.terraform.io/providers/hashicorp/helm/latest/docs/resources/release) | resource | +| [helm_release.ingress_nginx](https://registry.terraform.io/providers/hashicorp/helm/latest/docs/resources/release) | resource | | [kubernetes_annotations.hcloud_ccm](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/annotations) | resource | | [kubernetes_namespace.cluster_autoscaler](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/namespace) | resource | +| [kubernetes_namespace_v1.external_dns](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/namespace_v1) | resource | | [kubernetes_secret_v1.cluster_autoscaler](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/secret_v1) | resource | +| [kubernetes_secret_v1.external_dns](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/secret_v1) | resource | | [kubernetes_secret_v1.hcloud](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/secret_v1) | resource | +| [random_integer.ingress_load_balancer_id](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/integer) | resource | ## Inputs | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| +| [cloudflare\_api\_token](#input\_cloudflare\_api\_token) | Cloudflare API token | `string` | n/a | yes | | [cluster\_autoscaler\_version](#input\_cluster\_autoscaler\_version) | Version of Cluster Autoscaler to use - defaults to latest | `string` | `null` | no | +| [external\_dns\_version](#input\_external\_dns\_version) | Version of External DNS to install - defaults to latest | `string` | `null` | no | | [hcloud\_network\_name](#input\_hcloud\_network\_name) | Hetzner network name | `string` | n/a | yes | | [hcloud\_token](#input\_hcloud\_token) | Hetzner API token | `string` | n/a | yes | | [hetzner\_cloud\_config\_manager\_version](#input\_hetzner\_cloud\_config\_manager\_version) | Version of the HCloud CCM to use - defaults to latest | `string` | `null` | no | | [hetzner\_csi\_driver\_version](#input\_hetzner\_csi\_driver\_version) | Tag of the CSI driver to use - defaults to latest | `string` | `null` | no | +| [ingress\_nginx\_version](#input\_ingress\_nginx\_version) | Version of Ingress Nginx to install - defaults to latest | `string` | `null` | no | | [k3s\_cluster\_cidr](#input\_k3s\_cluster\_cidr) | CIDR used for the k3s cluster | `string` | `"10.244.0.0/16"` | no | | [kube\_context](#input\_kube\_context) | Kubernetes context to use | `string` | `"default"` | no | | [kubeconfig](#input\_kubeconfig) | Kubeconfig for the cluster | `string` | n/a | yes | +| [load\_balancer\_region](#input\_load\_balancer\_region) | Region to use for the load balancer | `string` | n/a | yes | +| [load\_balancer\_type](#input\_load\_balancer\_type) | Type of load balancer to use | `string` | `"lb11"` | no | | [worker\_pools](#input\_worker\_pools) | Cluster autoscaler configuration |
list(object({
cloud_init = string
firewall_id = string
image = string
labels = list(object({
key = string
value = string
}))
network_id = string
pool = object({
instanceType = string
minSize = number
maxSize = number
name = string
region = string
})
ssh_key_id = string
taints = list(object({
key = string
value = string
effect = string
}))
}))
| `[]` | no | ## Outputs diff --git a/modules/kubernetes/ingress.tf b/modules/kubernetes/ingress.tf new file mode 100644 index 0000000..c160f8b --- /dev/null +++ b/modules/kubernetes/ingress.tf @@ -0,0 +1,102 @@ +# Copyright 2024 Simon Emms +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +resource "kubernetes_namespace_v1" "external_dns" { + metadata { + name = "external-dns" + } + + wait_for_default_service_account = true +} + +resource "kubernetes_secret_v1" "external_dns" { + metadata { + name = "cloudflare" + namespace = kubernetes_namespace_v1.external_dns.metadata[0].name + } + + data = { + cloudflare_api_token = var.cloudflare_api_token + } +} + +resource "helm_release" "external_dns" { + chart = "oci://registry-1.docker.io/bitnamicharts/external-dns" + name = "external-dns" + atomic = true + cleanup_on_fail = true + namespace = kubernetes_namespace_v1.external_dns.metadata[0].name + reset_values = true + version = var.external_dns_version + wait = true + + set { + name = "provider" + value = "cloudflare" + } + + set { + name = "cloudflare.secretName" + value = kubernetes_secret_v1.external_dns.metadata[0].name + } + + set { + name = "podAnnotations.secret" + value = sha512(yamlencode(kubernetes_secret_v1.external_dns.data)) + } +} + +resource "random_integer" "ingress_load_balancer_id" { + min = 1000 + max = 9999 +} + +resource "helm_release" "ingress_nginx" { + chart = "ingress-nginx" + name = "ingress-nginx" + atomic = true + cleanup_on_fail = true + create_namespace = true + namespace = "ingress-nginx" + repository = "https://kubernetes.github.io/ingress-nginx" + reset_values = true + version = var.ingress_nginx_version + wait = true + + dynamic "set" { + for_each = { + "load-balancer.hetzner.cloud/name" = "k3s-${random_integer.ingress_load_balancer_id.result}" + "load-balancer.hetzner.cloud/network-zone" = var.load_balancer_region + "load-balancer.hetzner.cloud/type" = var.load_balancer_type + "load-balancer.hetzner.cloud/disable-private-ingress" = "true" + "load-balancer.hetzner.cloud/use-private-ip" = "true" + "load-balancer.hetzner.cloud/uses-proxyprotocol" = "true" + } + content { + name = "controller.service.annotations.${replace(set.key, ".", "\\.")}" + value = set.value + } + } + + set { + name = "controller.config.use-proxy-protocol" + value = "true" + } + + # Depend upon the HCloud CCM to allow the load balancer to be deleted on destroy + depends_on = [ + helm_release.hcloud_ccm, + helm_release.hcloud_csi, + ] +} diff --git a/modules/kubernetes/terraform.tf b/modules/kubernetes/terraform.tf index 9909e16..f84da4b 100644 --- a/modules/kubernetes/terraform.tf +++ b/modules/kubernetes/terraform.tf @@ -23,6 +23,10 @@ terraform { source = "hashicorp/kubernetes" version = ">= 2.31.0, < 3.0.0" } + random = { + source = "hashicorp/random" + version = ">= 3.6.2, < 4.0.0" + } } } diff --git a/modules/kubernetes/variables.tf b/modules/kubernetes/variables.tf index 8d3b860..4d641be 100644 --- a/modules/kubernetes/variables.tf +++ b/modules/kubernetes/variables.tf @@ -18,6 +18,18 @@ variable "cluster_autoscaler_version" { default = null } +variable "cloudflare_api_token" { + type = string + description = "Cloudflare API token" + sensitive = true +} + +variable "external_dns_version" { + type = string + description = "Version of External DNS to install - defaults to latest" + default = null +} + variable "hcloud_network_name" { type = string description = "Hetzner network name" @@ -41,6 +53,12 @@ variable "hetzner_csi_driver_version" { default = null } +variable "ingress_nginx_version" { + type = string + description = "Version of Ingress Nginx to install - defaults to latest" + default = null +} + variable "k3s_cluster_cidr" { type = string description = "CIDR used for the k3s cluster" @@ -59,6 +77,17 @@ variable "kube_context" { default = "default" } +variable "load_balancer_region" { + type = string + description = "Region to use for the load balancer" +} + +variable "load_balancer_type" { + type = string + description = "Type of load balancer to use" + default = "lb11" +} + variable "worker_pools" { type = list(object({ cloud_init = string diff --git a/stacks/dev/kubernetes/.terraform.lock.hcl b/stacks/dev/kubernetes/.terraform.lock.hcl index 9687444..7301670 100644 --- a/stacks/dev/kubernetes/.terraform.lock.hcl +++ b/stacks/dev/kubernetes/.terraform.lock.hcl @@ -39,3 +39,23 @@ provider "registry.terraform.io/hashicorp/kubernetes" { "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c", ] } + +provider "registry.terraform.io/hashicorp/random" { + version = "3.6.2" + constraints = ">= 3.6.2, < 4.0.0" + hashes = [ + "h1:wmG0QFjQ2OfyPy6BB7mQ57WtoZZGGV07uAPQeDmIrAE=", + "zh:0ef01a4f81147b32c1bea3429974d4d104bbc4be2ba3cfa667031a8183ef88ec", + "zh:1bcd2d8161e89e39886119965ef0f37fcce2da9c1aca34263dd3002ba05fcb53", + "zh:37c75d15e9514556a5f4ed02e1548aaa95c0ecd6ff9af1119ac905144c70c114", + "zh:4210550a767226976bc7e57d988b9ce48f4411fa8a60cd74a6b246baf7589dad", + "zh:562007382520cd4baa7320f35e1370ffe84e46ed4e2071fdc7e4b1a9b1f8ae9b", + "zh:5efb9da90f665e43f22c2e13e0ce48e86cae2d960aaf1abf721b497f32025916", + "zh:6f71257a6b1218d02a573fc9bff0657410404fb2ef23bc66ae8cd968f98d5ff6", + "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", + "zh:9647e18f221380a85f2f0ab387c68fdafd58af6193a932417299cdcae4710150", + "zh:bb6297ce412c3c2fa9fec726114e5e0508dd2638cad6a0cb433194930c97a544", + "zh:f83e925ed73ff8a5ef6e3608ad9225baa5376446349572c2449c0c0b3cf184b7", + "zh:fbef0781cb64de76b1df1ca11078aecba7800d82fd4a956302734999cfd9a4af", + ] +} diff --git a/stacks/dev/kubernetes/terragrunt.hcl b/stacks/dev/kubernetes/terragrunt.hcl index ea3989e..ddb51e6 100644 --- a/stacks/dev/kubernetes/terragrunt.hcl +++ b/stacks/dev/kubernetes/terragrunt.hcl @@ -27,13 +27,15 @@ dependency "hetzner" { hcloud_network_name = "some-network-name" k3s_cluster_cidr = "some-cluster-cidr" kubeconfig = "some-kubeconfig" + region = "some-region" worker_pools = [] } } inputs = { - hcloud_network_name = dependency.hetzner.outputs.hcloud_network_name - k3s_cluster_cidr = dependency.hetzner.outputs.k3s_cluster_cidr - kubeconfig = dependency.hetzner.outputs.kubeconfig - worker_pools = dependency.hetzner.outputs.worker_pools + hcloud_network_name = dependency.hetzner.outputs.hcloud_network_name + k3s_cluster_cidr = dependency.hetzner.outputs.k3s_cluster_cidr + kubeconfig = dependency.hetzner.outputs.kubeconfig + load_balancer_region = dependency.hetzner.outputs.region + worker_pools = dependency.hetzner.outputs.worker_pools }