From 4d8af5e30e2eaaa3c19f71996831fdedb522e557 Mon Sep 17 00:00:00 2001 From: Simon Emms Date: Sun, 23 Jun 2024 16:44:55 +0000 Subject: [PATCH] feat(kubernetes): deploy the hcloud-csi to the cluster A container storage interface (CSI) is used to kubernetes clusters to use volumes to store data. This uses the official Hetzner CSI to enable it in out cluster. --- modules/kubernetes/.terraform.lock.hcl | 43 +++++++++++++ modules/kubernetes/README.md | 23 ++++++- modules/kubernetes/csi.tf | 77 +++++++++++++++++++++++ modules/kubernetes/terraform.tf | 10 ++- modules/kubernetes/variables.tf | 24 +++++++ stacks/dev/kubernetes/.terraform.lock.hcl | 43 +++++++++++++ 6 files changed, 216 insertions(+), 4 deletions(-) create mode 100644 modules/kubernetes/csi.tf diff --git a/modules/kubernetes/.terraform.lock.hcl b/modules/kubernetes/.terraform.lock.hcl index 568b4d9..41e3a68 100644 --- a/modules/kubernetes/.terraform.lock.hcl +++ b/modules/kubernetes/.terraform.lock.hcl @@ -20,3 +20,46 @@ provider "registry.terraform.io/hashicorp/kubernetes" { "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c", ] } + +provider "registry.terraform.io/hashicorp/time" { + version = "0.11.2" + constraints = ">= 0.11.2, < 1.0.0" + hashes = [ + "h1:bC4b7n4g30ciIn5w6b66mXSTIo2CH6XQbp+gBdDvlYs=", + "zh:02588b5b8ba5d31e86d93edc93b306bcbf47c789f576769245968cc157a9e8c5", + "zh:088a30c23796133678d1d6614da5cf5544430570408a17062288b58c0bd67ac8", + "zh:0df5faa072d67616154d38021934d8a8a316533429a3f582df3b4b48c836cf89", + "zh:12edeeaef96c47f694bd1ba7ead6ccdb96028b25df352eea4bc5e40de7a59177", + "zh:1e859504a656a6e988f07b908e6ffe946b28bfb56889417c0a07ea9605a3b7b0", + "zh:64a6ae0320d4956c4fdb05629cfcebd03bcbd2206e2d733f2f18e4a97f4d5c7c", + "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", + "zh:924d137959193bf7aee6ebf241fbb9aec46d6eef828c5cf8d3c588770acae7b2", + "zh:b3cc76281a4faa9c2293a2460fc6962f6539e900994053f85185304887dddab8", + "zh:cbb40c791d4a1cdba56cffa43a9c0ed8e69930d49aa6bd931546b18c36e3b720", + "zh:d227d43594f8cb3d24f1fdd71382f14502cbe2a6deaddbc74242656bb5b38daf", + "zh:d4840641c46176bb9d70ba3aff09de749282136c779996b546c81e5ff701bbf6", + ] +} + +provider "registry.terraform.io/integrations/github" { + version = "6.2.2" + constraints = ">= 6.2.2, < 7.0.0" + hashes = [ + "h1:3gbrNGsK0dQ5zpN0qeHm3uNdWJl+f760+VtV2GJZ8Vg=", + "zh:43d7e5f1e11d67e38ca717016d209d6d9a6fa03321b489f91984351bfb143b69", + "zh:46e788395034b410bf59dfa43eb748a3d81ecfd23fc442349990fd7d92bd856a", + "zh:5234b7d5c5817ff7ebec29756050708372a071a701e2c8236e714a0bd29ef160", + "zh:74c485a241cc8e8cb99f988d38116fb14e51de896761fc9ca35a34ca5c999a7e", + "zh:7606789521c50937913ea13f851150828b5f9b8804ba80c5b2538c0b019339d8", + "zh:760fb0e74590459689c7159456b6e76f165634f7d0f89f5572d56b57d387f645", + "zh:7979d9085d809bb7d0db2c67e6c3443d1c18d12e51b72220dcb4cc5e883cd64a", + "zh:8bed25d8199bf8b2e7ccf67edc1a4a2fc041bd490b2c11565c669b80be43896c", + "zh:9ff82a6279fb7ae0cd9e44f1e73b64dd2aeca43d4d3096f3f2866b1ebbcb9431", + "zh:a886055ecd63ccb9b880e3c3301c0eca9acb108580d12519617554ae2be9a393", + "zh:c1f20386704919c7964a95daffcb29f494efb061abc28469840df4532833cecf", + "zh:cb6e9c4e33d6a57770073867e174c09c0eed401ee70473a688d20cb1cf0394f7", + "zh:f89ca130cc90b87dc25d036fe8f8cadb6fb53dc33368a032c5cee6275f3bcddc", + "zh:f94a2d1174091f04ed361192cdda9503baa3d161849d4f218c55a96bfb1ea33d", + "zh:fbd1fee2c9df3aa19cf8851ce134dea6e45ea01cb85695c1726670c285797e25", + ] +} diff --git a/modules/kubernetes/README.md b/modules/kubernetes/README.md index 1826400..292f8f4 100644 --- a/modules/kubernetes/README.md +++ b/modules/kubernetes/README.md @@ -5,12 +5,18 @@ | Name | Version | |------|---------| -| [terraform](#requirement\_terraform) | >= 1.0.0 | +| [terraform](#requirement\_terraform) | >= 1.8.0 | +| [github](#requirement\_github) | >= 6.2.2, < 7.0.0 | | [kubernetes](#requirement\_kubernetes) | >= 2.31.0, < 3.0.0 | +| [time](#requirement\_time) | >= 0.11.2, < 1.0.0 | ## Providers -No providers. +| Name | Version | +|------|---------| +| [github](#provider\_github) | 6.2.2 | +| [kubernetes](#provider\_kubernetes) | 2.31.0 | +| [time](#provider\_time) | 0.11.2 | ## Modules @@ -18,12 +24,23 @@ No modules. ## Resources -No resources. +| Name | Type | +|------|------| +| [kubernetes_annotations.restarts](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/annotations) | resource | +| [kubernetes_manifest.csi_driver](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/manifest) | resource | +| [kubernetes_secret_v1.hcloud_token](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs/resources/secret_v1) | resource | +| [time_static.restarted_at](https://registry.terraform.io/providers/hashicorp/time/latest/docs/resources/static) | resource | +| [github_release.csi_driver](https://registry.terraform.io/providers/integrations/github/latest/docs/data-sources/release) | data source | +| [github_repository_file.csi_driver](https://registry.terraform.io/providers/integrations/github/latest/docs/data-sources/repository_file) | data source | ## Inputs | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| +| [hcloud\_token](#input\_hcloud\_token) | Hetzner API token | `string` | n/a | yes | +| [hetzner\_csi\_driver\_owner](#input\_hetzner\_csi\_driver\_owner) | GitHub owner to get the CSI driver from | `string` | `"hetznercloud"` | no | +| [hetzner\_csi\_driver\_repo](#input\_hetzner\_csi\_driver\_repo) | GitHub repo to get the CSI driver from | `string` | `"csi-driver"` | no | +| [hetzner\_csi\_driver\_version](#input\_hetzner\_csi\_driver\_version) | Tag of the CSI driver to use - provide the tag name or latest | `string` | `"latest"` | no | | [kube\_context](#input\_kube\_context) | Kubernetes context to use | `string` | `"default"` | no | | [kubeconfig](#input\_kubeconfig) | Kubeconfig for the cluster | `string` | n/a | yes | diff --git a/modules/kubernetes/csi.tf b/modules/kubernetes/csi.tf new file mode 100644 index 0000000..6a365e7 --- /dev/null +++ b/modules/kubernetes/csi.tf @@ -0,0 +1,77 @@ +# 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. + +data "github_release" "csi_driver" { + repository = var.hetzner_csi_driver_repo + owner = var.hetzner_csi_driver_owner + + retrieve_by = var.hetzner_csi_driver_version == "latest" ? var.hetzner_csi_driver_version : "tag" + release_tag = var.hetzner_csi_driver_version != "latest" ? var.hetzner_csi_driver_version : null +} + +data "github_repository_file" "csi_driver" { + repository = "${var.hetzner_csi_driver_owner}/${var.hetzner_csi_driver_repo}" + branch = data.github_release.csi_driver.release_tag + file = "deploy/kubernetes/hcloud-csi.yml" +} + +// This secret is required by the Hetzner CSI to create cloud resources +resource "kubernetes_secret_v1" "hcloud_token" { + metadata { + name = "hcloud" + namespace = "kube-system" + } + + data = { + token = var.hcloud_token + } +} + +resource "kubernetes_manifest" "csi_driver" { + for_each = { + for m in provider::kubernetes::manifest_decode_multi(data.github_repository_file.csi_driver.content) : + "${m.apiVersion}.${m.kind}.${m.metadata.name}" => m + } + manifest = each.value + + // The hcloud-csi-controller deployment has 5 containers + computed_fields = [ + "spec.template.spec.containers[0].resources", + "spec.template.spec.containers[1].resources", + "spec.template.spec.containers[2].resources", + "spec.template.spec.containers[3].resources", + "spec.template.spec.containers[4].resources", + ] + + depends_on = [kubernetes_secret_v1.hcloud_token, kubernetes_annotations.restarts] +} + +// Restart the core-dns pods as the CSI controller may be in a failed state +// @link https://github.com/hetznercloud/csi-driver/issues/465#issuecomment-1649216197 +resource "time_static" "restarted_at" {} + +resource "kubernetes_annotations" "restarts" { + // The order is important + for_each = toset(["coredns"]) + + api_version = "apps/v1" + kind = "Deployment" + metadata { + name = each.key + namespace = "kube-system" + } + template_annotations = { + "kubectl.kubernetes.io/restartedAt" = time_static.restarted_at.rfc3339 + } +} diff --git a/modules/kubernetes/terraform.tf b/modules/kubernetes/terraform.tf index 3e68222..2fc777d 100644 --- a/modules/kubernetes/terraform.tf +++ b/modules/kubernetes/terraform.tf @@ -13,12 +13,20 @@ # limitations under the License. terraform { - required_version = ">= 1.0.0" + required_version = ">= 1.8.0" required_providers { + github = { + source = "integrations/github" + version = ">= 6.2.2, < 7.0.0" + } kubernetes = { source = "hashicorp/kubernetes" version = ">= 2.31.0, < 3.0.0" } + time = { + source = "hashicorp/time" + version = ">= 0.11.2, < 1.0.0" + } } } diff --git a/modules/kubernetes/variables.tf b/modules/kubernetes/variables.tf index c8dcbe5..65d3315 100644 --- a/modules/kubernetes/variables.tf +++ b/modules/kubernetes/variables.tf @@ -12,6 +12,30 @@ # See the License for the specific language governing permissions and # limitations under the License. +variable "hcloud_token" { + type = string + description = "Hetzner API token" + sensitive = true +} + +variable "hetzner_csi_driver_owner" { + type = string + description = "GitHub owner to get the CSI driver from" + default = "hetznercloud" +} + +variable "hetzner_csi_driver_repo" { + type = string + description = "GitHub repo to get the CSI driver from" + default = "csi-driver" +} + +variable "hetzner_csi_driver_version" { + type = string + description = "Tag of the CSI driver to use - provide the tag name or latest" + default = "latest" +} + variable "kubeconfig" { type = string description = "Kubeconfig for the cluster" diff --git a/stacks/dev/kubernetes/.terraform.lock.hcl b/stacks/dev/kubernetes/.terraform.lock.hcl index 568b4d9..41e3a68 100644 --- a/stacks/dev/kubernetes/.terraform.lock.hcl +++ b/stacks/dev/kubernetes/.terraform.lock.hcl @@ -20,3 +20,46 @@ provider "registry.terraform.io/hashicorp/kubernetes" { "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c", ] } + +provider "registry.terraform.io/hashicorp/time" { + version = "0.11.2" + constraints = ">= 0.11.2, < 1.0.0" + hashes = [ + "h1:bC4b7n4g30ciIn5w6b66mXSTIo2CH6XQbp+gBdDvlYs=", + "zh:02588b5b8ba5d31e86d93edc93b306bcbf47c789f576769245968cc157a9e8c5", + "zh:088a30c23796133678d1d6614da5cf5544430570408a17062288b58c0bd67ac8", + "zh:0df5faa072d67616154d38021934d8a8a316533429a3f582df3b4b48c836cf89", + "zh:12edeeaef96c47f694bd1ba7ead6ccdb96028b25df352eea4bc5e40de7a59177", + "zh:1e859504a656a6e988f07b908e6ffe946b28bfb56889417c0a07ea9605a3b7b0", + "zh:64a6ae0320d4956c4fdb05629cfcebd03bcbd2206e2d733f2f18e4a97f4d5c7c", + "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", + "zh:924d137959193bf7aee6ebf241fbb9aec46d6eef828c5cf8d3c588770acae7b2", + "zh:b3cc76281a4faa9c2293a2460fc6962f6539e900994053f85185304887dddab8", + "zh:cbb40c791d4a1cdba56cffa43a9c0ed8e69930d49aa6bd931546b18c36e3b720", + "zh:d227d43594f8cb3d24f1fdd71382f14502cbe2a6deaddbc74242656bb5b38daf", + "zh:d4840641c46176bb9d70ba3aff09de749282136c779996b546c81e5ff701bbf6", + ] +} + +provider "registry.terraform.io/integrations/github" { + version = "6.2.2" + constraints = ">= 6.2.2, < 7.0.0" + hashes = [ + "h1:3gbrNGsK0dQ5zpN0qeHm3uNdWJl+f760+VtV2GJZ8Vg=", + "zh:43d7e5f1e11d67e38ca717016d209d6d9a6fa03321b489f91984351bfb143b69", + "zh:46e788395034b410bf59dfa43eb748a3d81ecfd23fc442349990fd7d92bd856a", + "zh:5234b7d5c5817ff7ebec29756050708372a071a701e2c8236e714a0bd29ef160", + "zh:74c485a241cc8e8cb99f988d38116fb14e51de896761fc9ca35a34ca5c999a7e", + "zh:7606789521c50937913ea13f851150828b5f9b8804ba80c5b2538c0b019339d8", + "zh:760fb0e74590459689c7159456b6e76f165634f7d0f89f5572d56b57d387f645", + "zh:7979d9085d809bb7d0db2c67e6c3443d1c18d12e51b72220dcb4cc5e883cd64a", + "zh:8bed25d8199bf8b2e7ccf67edc1a4a2fc041bd490b2c11565c669b80be43896c", + "zh:9ff82a6279fb7ae0cd9e44f1e73b64dd2aeca43d4d3096f3f2866b1ebbcb9431", + "zh:a886055ecd63ccb9b880e3c3301c0eca9acb108580d12519617554ae2be9a393", + "zh:c1f20386704919c7964a95daffcb29f494efb061abc28469840df4532833cecf", + "zh:cb6e9c4e33d6a57770073867e174c09c0eed401ee70473a688d20cb1cf0394f7", + "zh:f89ca130cc90b87dc25d036fe8f8cadb6fb53dc33368a032c5cee6275f3bcddc", + "zh:f94a2d1174091f04ed361192cdda9503baa3d161849d4f218c55a96bfb1ea33d", + "zh:fbd1fee2c9df3aa19cf8851ce134dea6e45ea01cb85695c1726670c285797e25", + ] +}