From 612456241a8563c61d998620a645a0be5992c56d Mon Sep 17 00:00:00 2001 From: RaviAnand Mohabir Date: Tue, 25 Mar 2025 18:21:23 +0100 Subject: [PATCH] ci: :construction_worker: add terraform deploy module and drone deploy pipelines --- .drone.yml | 64 ++++++++++++++ deploy/main.tf | 204 ++++++++++++++++++++++++++++++++++++++++++++ deploy/variables.tf | 43 ++++++++++ 3 files changed, 311 insertions(+) create mode 100644 deploy/main.tf create mode 100644 deploy/variables.tf diff --git a/.drone.yml b/.drone.yml index 3494ee2..3c74635 100644 --- a/.drone.yml +++ b/.drone.yml @@ -19,3 +19,67 @@ trigger: - main event: - push +--- +kind: pipeline +type: kubernetes +name: run terraform plan +steps: + - commands: + - cd deploy + - terraform init + - terraform plan + environment: + AWS_ACCESS_KEY_ID: + from_secret: digitalocean_spaces_access_key_id + AWS_SECRET_ACCESS_KEY: + from_secret: digitalocean_spaces_secret_key + TF_VAR_cluster_issuer_name: letsencrypt + TF_VAR_dikurium_k8s_cluster_name_all: k8s-dik-all + TF_VAR_do_token: + from_secret: digitalocean_token + TF_VAR_image_repository: freund_und_partner/customer-files-organizer-web + TF_VAR_image_tag: latest + TF_VAR_registry: gitea.dikurium.ch + TF_VAR_registry_password: + from_secret: git_pass + TF_VAR_registry_username: + from_secret: git_user + image: hashicorp/terraform:1.6.5 + name: terraform plan +trigger: + branch: + - main + event: + - push +--- +kind: pipeline +type: kubernetes +name: run terraform apply +steps: + - commands: + - cd deploy + - terraform init + - terraform apply -auto-approve + environment: + AWS_ACCESS_KEY_ID: + from_secret: digitalocean_spaces_access_key_id + AWS_SECRET_ACCESS_KEY: + from_secret: digitalocean_spaces_secret_key + TF_VAR_cluster_issuer_name: letsencrypt + TF_VAR_dikurium_k8s_cluster_name_all: k8s-dik-all + TF_VAR_do_token: + from_secret: digitalocean_token + TF_VAR_image_repository: freund_und_partner/customer-files-organizer-web + TF_VAR_image_tag: latest + TF_VAR_registry: gitea.dikurium.ch + TF_VAR_registry_password: + from_secret: git_pass + TF_VAR_registry_username: + from_secret: git_user + image: hashicorp/terraform:1.6.5 + name: terraform apply +trigger: + event: + - promote + target: + - production diff --git a/deploy/main.tf b/deploy/main.tf new file mode 100644 index 0000000..e9bb00d --- /dev/null +++ b/deploy/main.tf @@ -0,0 +1,204 @@ +terraform { + backend "s3" { + bucket = "dik-terraform-state" + key = "apps/customer-files-organizer/terraform.tfstate" + region = "fra1" + endpoints = { + s3 = "https://fra1.digitaloceanspaces.com" + } + + skip_credentials_validation = true + skip_metadata_api_check = true + skip_region_validation = true + skip_requesting_account_id = true + skip_s3_checksum = true + } + required_providers { + random = { + source = "hashicorp/random" + version = "3.3.2" + } + digitalocean = { + source = "digitalocean/digitalocean" + version = "~> 2.0" + } + kubernetes = { + source = "hashicorp/kubernetes" + version = ">= 2.0.0" + } + } +} + +locals { + domain = "dikurium.ch" + subdomain = "customer-files-organizer" + hostname = "${local.subdomain}.${local.domain}" + url = "https://${local.hostname}" + namespace = "customer-files-organizer" + match_labels = { + "app.kubernetes.io/component" = "frontend" + "app.kubernetes.io/name" = "customer-files-organizer" + "app.kubernetes.io/part-of" = "consulting" + } + labels = merge(local.match_labels, { + "app.kubernetes.io/version" = var.image_tag + "app.kubernetes.io/managed-by" = "terraform" + }) +} + +provider "random" { +} + +provider "digitalocean" { + token = var.do_token +} + +data "digitalocean_kubernetes_cluster" "dikurium_kube_cluster" { + name = var.dikurium_k8s_cluster_name_all +} + +provider "kubernetes" { + host = data.digitalocean_kubernetes_cluster.dikurium_kube_cluster.endpoint + token = data.digitalocean_kubernetes_cluster.dikurium_kube_cluster.kube_config[0].token + cluster_ca_certificate = base64decode( + data.digitalocean_kubernetes_cluster.dikurium_kube_cluster.kube_config[0].cluster_ca_certificate + ) +} + +resource "kubernetes_namespace" "customer_files_organizer" { + metadata { + name = local.namespace + } +} + +resource "kubernetes_deployment" "customer_files_organizer" { + metadata { + name = "customer_files_organizer" + namespace = kubernetes_namespace.customer_files_organizer.metadata.0.name + } + spec { + replicas = 1 + selector { + match_labels = local.match_labels + } + template { + metadata { + labels = local.labels + annotations = { + "dikurium.ch/last-updated" = timestamp() + } + } + spec { + image_pull_secrets { + name = kubernetes_secret.registry_auth.metadata.0.name + } + container { + image = "${var.registry}/${var.image_repository}:${var.image_tag}" + name = "customer_files_organizer" + image_pull_policy = "Always" + port { + container_port = 3000 + name = "http" + } + } + } + } + } +} + +resource "kubernetes_service" "customer_files_organizer" { + metadata { + name = "customer_files_organizer" + namespace = kubernetes_namespace.customer_files_organizer.metadata.0.name + } + spec { + selector = local.match_labels + type = "ClusterIP" + port { + port = 80 + target_port = "http" + } + } +} + +resource "kubernetes_ingress_v1" "customer_files_organizer" { + metadata { + name = "customer_files_organizer" + namespace = kubernetes_namespace.customer_files_organizer.metadata.0.name + annotations = { + "cert-manager.io/cluster-issuer" = var.cluster_issuer_name + } + } + spec { + ingress_class_name = "nginx" + + rule { + host = local.hostname + http { + path { + backend { + service { + name = kubernetes_service.customer_files_organizer.metadata.0.name + port { + name = "http" + } + } + } + path = "/" + path_type = "Prefix" + } + } + } + + tls { + secret_name = "customer-files-organizer-tls" + hosts = [local.hostname] + } + } + depends_on = [ + time_sleep.wait_for_dns_record + ] +} + +data "digitalocean_domain" "dikurium" { + name = local.domain +} + +data "digitalocean_loadbalancer" "nginx-ingress-controller" { + name = "nginx-ingress-controller.service.dikurium.ch" +} + +resource "digitalocean_record" "customer_files_organizer" { + domain = data.digitalocean_domain.dikurium.id + type = "A" + name = local.subdomain + value = data.digitalocean_loadbalancer.nginx-ingress-controller.ip +} + +resource "time_sleep" "wait_for_dns_record" { + depends_on = [ + digitalocean_record.customer_files_organizer + ] + create_duration = "30s" +} + +resource "kubernetes_secret" "registry_auth" { + metadata { + name = "registry-auth" + namespace = kubernetes_namespace.customer_files_organizer.metadata.0.name + } + + data = { + ".dockerconfigjson" = jsonencode({ + "auths" = { + "${var.registry}" = { + "auth" = base64encode("${var.registry_username}:${var.registry_password}") + } + }, + "credsStore" = "", + "credHelpers" = {} + }) + } + + type = "kubernetes.io/dockerconfigjson" +} diff --git a/deploy/variables.tf b/deploy/variables.tf new file mode 100644 index 0000000..a33cd28 --- /dev/null +++ b/deploy/variables.tf @@ -0,0 +1,43 @@ +variable "do_token" { + description = "DigitalOcean API Access Token" + type = string + sensitive = true +} + +variable "dikurium_k8s_cluster_name_all" { + description = "The name of the Dikurium main Kubernetes cluster" + default = "k8s-dik-all" + type = string +} + +variable "cluster_issuer_name" { + description = "Name of the ClusterIssuer Kubernetes resource." + type = string + sensitive = true +} + +variable "registry" { + description = "Registry to fetch advisement tool image from" + type = string +} + +variable "image_repository" { + description = "Repository for advisement tool image" + type = string +} + +variable "image_tag" { + description = "Docker image tag for advisement tool" + type = string +} + +variable "registry_username" { + description = "Username to access registry" + type = string +} + +variable "registry_password" { + description = "Password to access registry" + type = string + sensitive = true +}