From 9e1beb6895884aef66d8747bbdabf3b5bc752393 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20J=C3=B6rg?= Date: Thu, 12 Dec 2024 22:36:56 +0100 Subject: [PATCH] Add more Nix Apps Rewrite of some of the Apps to Nix. Tried to convert ApplicationSets to simple Applications with an ${env} modifier. --- apps/dapr.nix | 46 ++++++ apps/default.nix | 9 ++ apps/dex.nix | 39 +++++ apps/keycloak.nix | 34 +++++ apps/loki.nix | 249 +++++++++++++++++++++++++++++++ apps/openfga.nix | 4 +- apps/opentelemetry-collector.nix | 117 +++++++++++++++ apps/rabbitmq.nix | 39 +++++ apps/redis.nix | 34 +++++ apps/tempo.nix | 124 +++++++++++++++ apps/wordpress.nix | 39 +++++ 11 files changed, 732 insertions(+), 2 deletions(-) create mode 100644 apps/dapr.nix create mode 100644 apps/dex.nix create mode 100644 apps/keycloak.nix create mode 100644 apps/loki.nix create mode 100644 apps/opentelemetry-collector.nix create mode 100644 apps/rabbitmq.nix create mode 100644 apps/redis.nix create mode 100644 apps/tempo.nix create mode 100644 apps/wordpress.nix diff --git a/apps/dapr.nix b/apps/dapr.nix new file mode 100644 index 00000000..d6f6dea7 --- /dev/null +++ b/apps/dapr.nix @@ -0,0 +1,46 @@ +{ lib, config, ... }: +let + cfg = config.apps.dapr; + env = config.apps.env; + + values = lib.apps.appValues { + inherit env; + extraValues = { + global.ha.enabled = true; + }; + }; + +in +{ + options.apps.dapr = lib.apps.appOptions { + revision = lib.mkOption { + type = lib.types.str; + default = "1.14.4"; + description = "Dapr chart version"; + }; + }; + + config = lib.apps.appConfig cfg "dapr" { + namespace = "argocd"; + helm.releases.dapr = { + inherit values; + chart = lib.helm.downloadHelmChart { + repo = "https://dapr.github.io/helm-charts/"; + chart = "dapr"; + version = cfg.revision; + }; + }; + annotations = { + "argocd.argoproj.io/sync-options" = "SkipDryRunOnMissingResource=true"; + }; + resources = { + "argoproj.io".v1alpha1.Application.dapr.spec = { + destination = { + namespace = "dapr-system"; + server = "https://kubernetes.default.svc"; + }; + project = "default"; + }; + }; + }; +} \ No newline at end of file diff --git a/apps/default.nix b/apps/default.nix index 6277483d..bb381916 100644 --- a/apps/default.nix +++ b/apps/default.nix @@ -2,6 +2,15 @@ { imports = [ ./atlantis.nix + ./dapr.nix + ./dex.nix + ./keycloak.nix + ./loki.nix ./openfga.nix + ./opentelemetry-collector.nix + ./rabbitmq.nix + ./redis.nix + ./tempo.nix + ./wordpress.nix ]; } diff --git a/apps/dex.nix b/apps/dex.nix new file mode 100644 index 00000000..2604c01a --- /dev/null +++ b/apps/dex.nix @@ -0,0 +1,39 @@ +{ lib, config, ... }: +let + cfg = config.apps.dex; + env = config.apps.env; + + values = lib.apps.appValues { + inherit env; + base = ../values/dex; + extraValues = {}; + }; +in +{ + options.apps.dex = lib.apps.appOptions { + enable = lib.mkEnableOption "Dex"; + revision = lib.mkOption { + type = lib.types.str; + default = "0.16.0"; + description = "Dex chart version"; + }; + hostname = lib.mkOption { + type = lib.types.str; + description = "Dex hostname"; + default = "idp.${env}.oceanbox.io"; + }; + }; + config = lib.apps.appConfig cfg "${env}-dex" { + namespace = "idp"; + helm.releases.dex = { + inherit values; + chart = lib.helm.downloadHelmChart { + repo = "https://charts.dexidp.io"; + chart = "dex"; + version = cfg.revision; + chartHash = ""; + }; + transformer = rs: builtins.map (x: kustomize x) rs; + }; + }; +} diff --git a/apps/keycloak.nix b/apps/keycloak.nix new file mode 100644 index 00000000..40ac990a --- /dev/null +++ b/apps/keycloak.nix @@ -0,0 +1,34 @@ +{ lib, config, ... }: +let + cfg = config.apps.keycloak; + env = config.apps.env; + + values = lib.apps.appValues { + inherit env; + base = ../values/keycloak; + extraValues = {}; + }; +in +{ + options.apps.keycloak = lib.apps.appOptions { + enable = lib.mkEnableOption "Keycloak"; + revision = lib.mkOption { + type = lib.types.str; + default = "24.0.2"; + description = "Keycloak chart version"; + }; + }; + config = lib.apps.appConfig cfg "keycloak" { + namespace = "idp"; + helm.releases.keycloak = { + inherit values; + chart = lib.helm.downloadHelmChart { + repo = "https://charts.bitnami.com/bitnami"; + chart = "keycloak"; + version = cfg.revision; + chartHash = ""; + }; + transformer = rs: builtins.map (x: kustomize x) rs; + }; + }; +} \ No newline at end of file diff --git a/apps/loki.nix b/apps/loki.nix new file mode 100644 index 00000000..4952c609 --- /dev/null +++ b/apps/loki.nix @@ -0,0 +1,249 @@ +{ lib, config, ... }: +let + cfg = config.apps.loki; + env = config.apps.env; + + values = lib.apps.appValues { + inherit env; + extraValues = { + loki = { + auth_enabled = false; + storage = { + bucketNames = { + chunks = cfg.buckets.chunks; + ruler = cfg.buckets.ruler; + admin = cfg.buckets.admin; + }; + s3 = + { + endpoint = cfg.s3.endpoint; + region = cfg.s3.region; + secretAccessKey = "\${S3SECRET}"; + accessKeyId = "\${S3KEY}"; + s3ForcePathStyle = true; + } + // lib.optionalAttrs cfg.s3.insecureSkipVerify { + http_config.insecure_skip_verify = true; + }; + }; + schemaConfig.configs = [ + { + from = "2024-04-01"; + index.period = "24h"; + index.prefix = "loki_index_"; + object_store = "s3"; + schema = "v13"; + store = "tsdb"; + } + ]; + compactor = { + compaction_interval = "10m"; + working_directory = "/tmp/loki/compactor"; + retention_enabled = true; + retention_delete_delay = "2h"; + retention_delete_worker_count = 150; + delete_request_store = "s3"; + }; + limits_config.retention_period = "744h"; + }; + + write = { + extraArgs = [ "-config.expand-env=true" ]; + extraEnv = [ + { + name = "S3KEY"; + valueFrom.secretKeyRef = { + name = cfg.secret.name; + key = cfg.secret.accessKey; + }; + } + { + name = "S3SECRET"; + valueFrom.secretKeyRef = { + name = cfg.secret.name; + key = cfg.secret.secretKey; + }; + } + ]; + tolerations = [ + { + effect = "NoSchedule"; + operator = "Equal"; + key = "unschedulable"; + value = "true"; + } + ]; + }; + + read = { + extraArgs = [ "-config.expand-env=true" ]; + extraEnv = [ + { + name = "S3KEY"; + valueFrom.secretKeyRef = { + name = cfg.secret.name; + key = cfg.secret.accessKey; + }; + } + { + name = "S3SECRET"; + valueFrom.secretKeyRef = { + name = cfg.secret.name; + key = cfg.secret.secretKey; + }; + } + ]; + tolerations = [ + { + effect = "NoSchedule"; + operator = "Equal"; + key = "unschedulable"; + value = "true"; + } + ]; + }; + + ingress = { + enabled = true; + ingressClassName = "nginx"; + annotations = { + "cert-manager.io/cluster-issuer" = "letsencrypt-staging"; + "nginx.ingress.kubernetes.io/ssl-redirect" = "true"; + "atlantis.oceanbox.io/expose" = "internal"; + }; + hosts = [ "loki.adm.oceanbox.io" ]; + tls = [{ + hosts = [ "loki.adm.oceanbox.io" ]; + secretName = "loki-distributed-tls"; + }]; + }; + + compactor = { + extraArgs = [ "-config.expand-env=true" ]; + extraEnv = [ + { + name = "S3KEY"; + valueFrom.secretKeyRef = { + name = cfg.secret.name; + key = cfg.secret.accessKey; + }; + } + { + name = "S3SECRET"; + valueFrom.secretKeyRef = { + name = cfg.secret.name; + key = cfg.secret.secretKey; + }; + } + ]; + }; + + backend = { + extraArgs = [ "-config.expand-env=true" ]; + extraEnv = [ + { + name = "S3KEY"; + valueFrom.secretKeyRef = { + name = cfg.secret.name; + key = cfg.secret.accessKey; + }; + } + { + name = "S3SECRET"; + valueFrom.secretKeyRef = { + name = cfg.secret.name; + key = cfg.secret.secretKey; + }; + } + ]; + }; + }; + }; + +in +{ + options.apps.loki = lib.apps.appOptions { + revision = lib.mkOption { + type = lib.types.str; + default = "6.12.0"; + description = "Loki chart version"; + }; + buckets = { + chunks = lib.mkOption { + type = lib.types.str; + default = "loki-chunks"; + description = "S3 bucket for chunks"; + }; + ruler = lib.mkOption { + type = lib.types.str; + default = "loki-chunks"; + description = "S3 bucket for ruler"; + }; + admin = lib.mkOption { + type = lib.types.str; + default = "loki-chunks"; + description = "S3 bucket for admin"; + }; + }; + s3 = { + endpoint = lib.mkOption { + type = lib.types.str; + default = "http://10.255.241.30:30080"; + description = "S3 endpoint"; + }; + region = lib.mkOption { + type = lib.types.str; + default = "tos"; + description = "S3 region"; + }; + insecureSkipVerify = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Skip TLS verification"; + }; + }; + secret = { + name = lib.mkOption { + type = lib.types.str; + default = "loki-s3"; + description = "Name of the S3 credentials secret"; + }; + accessKey = lib.mkOption { + type = lib.types.str; + default = "AWS_ACCESS_KEY_ID"; + description = "Access key field in secret"; + }; + secretKey = lib.mkOption { + type = lib.types.str; + default = "AWS_ACCESS_KEY_SECRET"; + description = "Secret key field in secret"; + }; + }; + }; + + config = lib.apps.appConfig cfg "loki" { + namespace = "argocd"; + helm.releases.loki = { + inherit values; + chart = lib.helm.downloadHelmChart { + repo = "https://grafana.github.io/helm-charts"; + chart = "loki"; + version = cfg.revision; + chartHash = "sha256-YUtEIUiQWRzlttfOOgDk1xfTaiAZ12tIgpGr1QcMpro="; + }; + }; + annotations = { + "argocd.argoproj.io/sync-options" = "SkipDryRunOnMissingResource=true"; + }; + # TODO: Add network policies as a second source or integrate them into `resources`. + resources = { + "argoproj.io".v1alpha1.Application.loki.spec.ignoreDifferences = [ + { + group = "apps"; + kind = "StatefulSet"; + jsonPointers = [ "/spec/persistentVolumeClaimRetentionPolicy" ]; + } + ]; + }; + }; +} \ No newline at end of file diff --git a/apps/openfga.nix b/apps/openfga.nix index d6592ae9..235ecdc6 100644 --- a/apps/openfga.nix +++ b/apps/openfga.nix @@ -24,8 +24,8 @@ in chart = lib.helm.downloadHelmChart { repo = "https://openfga.github.io/helm-charts"; chart = "openfga"; - version = "0.2.12"; - chartHash = "sha256-7yLcw9/oNPvCePrtTJwKAG88t0Ym5Dl/S83Gz+gQdDU="; + version = "0.2.12"; + chartHash = "sha256-7yLcw9/oNPvCePrtTJwKAG88t0Ym5Dl/S83Gz+gQdDU="; }; transformer = rs: builtins.map (x: kustomize x) rs; }; diff --git a/apps/opentelemetry-collector.nix b/apps/opentelemetry-collector.nix new file mode 100644 index 00000000..36a37a68 --- /dev/null +++ b/apps/opentelemetry-collector.nix @@ -0,0 +1,117 @@ +{ lib, config, ... }: +let + cfg = config.apps.opentelemetry-collector; + env = config.apps.env; + + values = lib.apps.appValues { + inherit env; + extraValues = { + mode = "deployment"; + image = { + repository = "otel/opentelemetry-collector-k8s"; + }; + service = { + type = "LoadBalancer"; + loadBalancerIP = "10.255.241.12"; + }; + config = { + receivers = { + "prometheus/collector" = { + config.scrape_configs = [{ + job_name = "opentelemetry-collector"; + static_configs = [{ + targets = [ "\${env:MY_POD_IP}:8888" ]; + }]; + }]; + }; + zipkin.endpoint = "\${env:MY_POD_IP}:9411"; + }; + exporters = { + otlp = { + endpoint = "tempo.tempo.svc:4317"; + tls.insecure = true; + }; + "otlphttp/metrics" = { + endpoint = "http://prom-prometheus.prometheus:9090/api/v1/otlp"; + tls.insecure = true; + }; + "otlphttp/logs" = { + endpoint = "http://loki-write-headless.loki:3100/otlp"; + tls.insecure = true; + }; + "debug/metrics".verbosity = "detailed"; + "debug/traces".verbosity = "detailed"; + "debug/logs".verbosity = "detailed"; + }; + service = { + telemetry.logs.level = "info"; + pipelines = { + traces = { + receivers = [ "otlp" "zipkin" ]; + processors = [ "batch" ]; + exporters = [ "otlp" ]; + }; + metrics = { + receivers = [ "otlp" "prometheus/collector" ]; + processors = [ "batch" ]; + exporters = [ "otlphttp/metrics" ]; + }; + logs = { + receivers = [ "otlp" ]; + processors = [ "batch" ]; + exporters = [ "otlphttp/logs" ]; + }; + }; + }; + }; + ports.metrics.enabled = true; + ingress = { + enabled = false; + annotations = { + "cert-manager.io/cluster-issuer" = "letsencrypt-production"; + "nginx.ingress.kubernetes.io/ssl-redirect" = "true"; + "atlantis.oceanbox.io/expose" = "internal"; + }; + ingressClassName = "nginx"; + hosts = [{ + host = "opentelemetry-collector.adm.oceanbox.io"; + paths = [{ + path = "/"; + pathType = "Prefix"; + port = 4318; + }]; + }]; + tls = [{ + secretName = "collector-tls"; + hosts = [ "opentelemetry-collector.adm.oceanbox.io" ]; + }]; + }; + }; + }; + +in +{ + options.apps.opentelemetry-collector = lib.apps.appOptions { + revision = lib.mkOption { + type = lib.types.str; + default = "0.107.0"; + description = "OpenTelemetry Collector chart version"; + }; + }; + + config = lib.apps.appConfig cfg "opentelemetry-collector" { + namespace = "argocd"; + helm.releases.opentelemetry-collector = { + inherit values; + chart = lib.helm.downloadHelmChart { + repo = "https://open-telemetry.github.io/opentelemetry-helm-charts"; + chart = "opentelemetry-collector"; + version = cfg.revision; + chartHash = "sha256-0000000000000000000000000000000000000000000000"; # TODO: Add correct hash + }; + }; + annotations = { + "argocd.argoproj.io/sync-options" = "SkipDryRunOnMissingResource=true"; + }; + }; +} diff --git a/apps/rabbitmq.nix b/apps/rabbitmq.nix new file mode 100644 index 00000000..da95bcf0 --- /dev/null +++ b/apps/rabbitmq.nix @@ -0,0 +1,39 @@ +{ lib, config, ... }: +let + cfg = config.apps.rabbitmq; + env = config.apps.env; + + values = lib.apps.appValues { + inherit env; + base = ../values/rabbitmq; + extraValues = {}; + }; +in +{ + options.apps.rabbitmq = lib.apps.appOptions { + enable = lib.mkEnableOption "RabbitMQ"; + revision = lib.mkOption { + type = lib.types.str; + default = "12.9.0"; + description = "RabbitMQ chart version"; + }; + hostname = lib.mkOption { + type = lib.types.str; + description = "RabbitMQ hostname"; + default = "rabbitmq.${env}.oceanbox.io"; + }; + }; + config = lib.apps.appConfig cfg "${env}-rabbitmq" { + namespace = "rabbitmq"; + helm.releases.rabbitmq = { + inherit values; + chart = lib.helm.downloadHelmChart { + repo = "https://charts.bitnami.com/bitnami"; + chart = "rabbitmq"; + version = cfg.revision; + chartHash = ""; + }; + transformer = rs: builtins.map (x: kustomize x) rs; + }; + }; +} \ No newline at end of file diff --git a/apps/redis.nix b/apps/redis.nix new file mode 100644 index 00000000..04f1ef0b --- /dev/null +++ b/apps/redis.nix @@ -0,0 +1,34 @@ +{ lib, config, ... }: +let + cfg = config.apps.redis; + env = config.apps.env; + + values = lib.apps.appValues { + inherit env; + base = ../values/redis; + extraValues = {}; + }; +in +{ + options.apps.redis = lib.apps.appOptions { + enable = lib.mkEnableOption "Redis"; + revision = lib.mkOption { + type = lib.types.str; + default = "19.5.2"; + description = "Redis chart version"; + }; + }; + config = lib.apps.appConfig cfg "${env}-redis" { + namespace = "redis"; + helm.releases.redis = { + inherit values; + chart = lib.helm.downloadHelmChart { + repo = "https://charts.bitnami.com/bitnami"; + chart = "redis"; + version = cfg.revision; + chartHash = ""; + }; + transformer = rs: builtins.map (x: kustomize x) rs; + }; + }; +} \ No newline at end of file diff --git a/apps/tempo.nix b/apps/tempo.nix new file mode 100644 index 00000000..7d215df7 --- /dev/null +++ b/apps/tempo.nix @@ -0,0 +1,124 @@ +{ lib, config, ... }: +let + cfg = config.apps.tempo; + env = config.apps.env; + + values = lib.apps.appValues { + inherit env; + extraValues = { + tempo = { + storage = { + trace = { + backend = "s3"; + s3 = { + bucket = cfg.s3.bucket; + endpoint = cfg.s3.endpoint; + access_key = "\${S3SECRET}"; + secret_key = "\${S3KEY}"; + insecure = true; + }; + local = { + path = "/var/tempo/traces"; + }; + wal = { + path = "/var/tempo/wal"; + }; + }; + }; + metricsGenerator = { + enabled = true; + remoteWriteUrl = "http://prom-prometheus.prometheus:9090/api/v1/write"; + }; + extraEnv = [ + { + name = "S3KEY"; + valueFrom.secretKeyRef = { + name = cfg.secret.name; + key = cfg.secret.accessKey; + }; + } + { + name = "S3SECRET"; + valueFrom.secretKeyRef = { + name = cfg.secret.name; + key = cfg.secret.secretKey; + }; + } + ]; + }; + + tempoQuery = { + ingress = { + enabled = true; + ingressClassName = "nginx"; + annotations = { + "cert-manager.io/cluster-issuer" = "letsencrypt-staging"; + "nginx.ingress.kubernetes.io/ssl-redirect" = "true"; + "atlantis.oceanbox.io/expose" = "internal"; + }; + path = "/"; + pathType = "Prefix"; + hosts = [ "query.tempo.adm.oceanbox.io" ]; + tls = [{ + secretName = "tempo-query-tls"; + hosts = [ "query.tempo.adm.oceanbox.io" ]; + }]; + }; + }; + }; + }; + +in +{ + options.apps.tempo = lib.apps.appOptions { + revision = lib.mkOption { + type = lib.types.str; + default = "1.10.3"; + description = "Tempo chart version"; + }; + s3 = { + bucket = lib.mkOption { + type = lib.types.str; + default = "tempo-traces"; + description = "S3 bucket for traces"; + }; + endpoint = lib.mkOption { + type = lib.types.str; + default = "http://10.255.241.30:30080"; + description = "S3 endpoint"; + }; + }; + secret = { + name = lib.mkOption { + type = lib.types.str; + default = "tempo-s3"; + description = "Name of the S3 credentials secret"; + }; + accessKey = lib.mkOption { + type = lib.types.str; + default = "AWS_ACCESS_KEY_ID"; + description = "Access key field in secret"; + }; + secretKey = lib.mkOption { + type = lib.types.str; + default = "AWS_ACCESS_KEY_SECRET"; + description = "Secret key field in secret"; + }; + }; + }; + + config = lib.apps.appConfig cfg "tempo" { + namespace = "argocd"; + helm.releases.tempo = { + inherit values; + chart = lib.helm.downloadHelmChart { + repo = "https://grafana.github.io/helm-charts"; + chart = "tempo"; + version = cfg.revision; + }; + }; + annotations = { + "argocd.argoproj.io/sync-options" = "SkipDryRunOnMissingResource=true"; + }; + }; +} diff --git a/apps/wordpress.nix b/apps/wordpress.nix new file mode 100644 index 00000000..8c963da2 --- /dev/null +++ b/apps/wordpress.nix @@ -0,0 +1,39 @@ +{ lib, config, ... }: +let + cfg = config.apps.wordpress; + env = config.apps.env; + + values = lib.apps.appValues { + inherit env; + base = ../values/wordpress; + extraValues = {}; + }; +in +{ + options.apps.wordpress = lib.apps.appOptions { + enable = lib.mkEnableOption "WordPress"; + revision = lib.mkOption { + type = lib.types.str; + default = "19.2.2"; + description = "WordPress chart version"; + }; + hostname = lib.mkOption { + type = lib.types.str; + description = "WordPress hostname"; + default = "www.${env}.oceanbox.io"; + }; + }; + config = lib.apps.appConfig cfg "www-oceanbox" { + namespace = "www-oceanbox"; + helm.releases.wordpress = { + inherit values; + chart = lib.helm.downloadHelmChart { + repo = "https://charts.bitnami.com/bitnami"; + chart = "wordpress"; + version = cfg.revision; + chartHash = ""; + }; + transformer = rs: builtins.map (x: kustomize x) rs; + }; + }; +} \ No newline at end of file