Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save Lillecarl/a3b7368964fd3b9f64417395bea03a97 to your computer and use it in GitHub Desktop.

Select an option

Save Lillecarl/a3b7368964fd3b9f64417395bea03a97 to your computer and use it in GitHub Desktop.
From b39df2392ba95b50d6a4864188063ee354313170 Mon Sep 17 00:00:00 2001
From: Carl Andersson <[email protected]>
Date: Mon, 13 Oct 2025 13:08:24 +0200
Subject: [PATCH] Add namespacing to kubernetes.resources
This way we can't collide when rendering manifests and such.
I took too much inspiration from kubenix when putting the original API together!
---
cluster-config/cilium.nix | 2 +-
cluster-config/cnpg.nix | 2 +-
cluster-config/coredns.nix | 5 ++-
cluster-config/hccm.nix | 11 ++-----
cluster-config/hcsi.nix | 10 ++----
cluster-config/nginx.nix | 4 +--
cluster-config/victoriametrics.nix | 4 +--
easykubenix/default.nix | 1 +
easykubenix/demo.nix | 13 +++-----
easykubenix/helm.nix | 2 +-
easykubenix/importyaml.nix | 2 +-
easykubenix/kubernetes.nix | 49 +++++++++++++++++-------------
hetzner-capi.nix | 2 +-
hetzner-init.nix | 4 +--
14 files changed, 48 insertions(+), 63 deletions(-)
diff --git a/cluster-config/cilium.nix b/cluster-config/cilium.nix
index 8357b31..9edfd8b 100644
--- a/cluster-config/cilium.nix
+++ b/cluster-config/cilium.nix
@@ -24,7 +24,7 @@ in
};
};
config = lib.mkIf cfg.enable {
- kubernetes.resources.Namespace.${cfg.namespace} = { };
+ kubernetes.resources.none.Namespace.${cfg.namespace} = { };
helm.releases.${moduleName} = {
namespace = cfg.namespace;
diff --git a/cluster-config/cnpg.nix b/cluster-config/cnpg.nix
index 12a669c..38075e5 100644
--- a/cluster-config/cnpg.nix
+++ b/cluster-config/cnpg.nix
@@ -25,7 +25,7 @@ in
overrideNamespace = cfg.namespace;
};
kubernetes = {
- resources.Cluster.pg0 = {
+ resources.default.Cluster.pg0 = {
spec = {
instances = 1;
storage.size = "1Gi";
diff --git a/cluster-config/coredns.nix b/cluster-config/coredns.nix
index d64984a..6dab0f1 100644
--- a/cluster-config/coredns.nix
+++ b/cluster-config/coredns.nix
@@ -29,9 +29,8 @@ in
};
config = lib.mkIf cfg.enable {
# Create coredns namespace
- kubernetes.resources.Namespace.${cfg.namespace} = { };
- kubernetes.resources.ConfigMap.coredns = {
- metadata.namespace = cfg.namespace;
+ kubernetes.resources.none.Namespace.${cfg.namespace} = { };
+ kubernetes.resources.${cfg.namespace}.ConfigMap.coredns = {
data.Corefile = ''
.:53 {
errors
diff --git a/cluster-config/hccm.nix b/cluster-config/hccm.nix
index 5680f82..6e63111 100644
--- a/cluster-config/hccm.nix
+++ b/cluster-config/hccm.nix
@@ -25,15 +25,8 @@ in
};
};
config = lib.mkIf cfg.enable {
- kubernetes.resources.Namespace.${cfg.namespace} = { };
- kubernetes.resources.Secret.hccm = {
- metadata = {
- name = "hcloud";
- namespace = cfg.namespace;
- };
- type = "Opaque";
- stringData.token = cfg.apiToken;
- };
+ kubernetes.resources.none.Namespace.${cfg.namespace} = { };
+ kubernetes.resources.${cfg.namespace}.Secret.hcloud.stringData.token = cfg.apiToken;
helm.releases.${moduleName} = {
namespace = cfg.namespace;
diff --git a/cluster-config/hcsi.nix b/cluster-config/hcsi.nix
index 674f663..1e924eb 100644
--- a/cluster-config/hcsi.nix
+++ b/cluster-config/hcsi.nix
@@ -27,13 +27,7 @@ in
src = cfg.url;
overrideNamespace = cfg.namespace;
};
- kubernetes.resources.Namespace.${cfg.namespace} = { };
- kubernetes.resources.Secret.hcloud-csi = {
- metadata = {
- name = "hcloud";
- namespace = cfg.namespace;
- };
- stringData.token = cfg.apiToken;
- };
+ kubernetes.resources.none.Namespace.${cfg.namespace} = { };
+ kubernetes.resources.${cfg.namespace}.Secret.hcloud.stringData.token = cfg.apiToken;
};
}
diff --git a/cluster-config/nginx.nix b/cluster-config/nginx.nix
index 07da089..d4fa1b7 100644
--- a/cluster-config/nginx.nix
+++ b/cluster-config/nginx.nix
@@ -9,7 +9,7 @@ let
cfg = config.${moduleName};
in
{
- options.${moduleName}= {
+ options.${moduleName} = {
enable = lib.mkEnableOption moduleName;
namespace = lib.mkOption {
type = lib.types.str;
@@ -21,7 +21,7 @@ in
};
};
config = lib.mkIf cfg.enable {
- kubernetes.resources.Namespace.${cfg.namespace} = { };
+ kubernetes.resources.none.Namespace.${cfg.namespace} = { };
helm.releases.${moduleName} = {
namespace = cfg.namespace;
diff --git a/cluster-config/victoriametrics.nix b/cluster-config/victoriametrics.nix
index 1c5f01b..d56e1a9 100644
--- a/cluster-config/victoriametrics.nix
+++ b/cluster-config/victoriametrics.nix
@@ -24,9 +24,7 @@ in
src = "https://github.com/VictoriaMetrics/operator/releases/download/${cfg.version}/install-no-webhook.yaml";
};
kubernetes = {
- resources = {
- VMSingle.vm0 = { };
- };
+ resources.default.VMSingle.vm0 = { };
apiMappings = {
VLAgent = "operator.victoriametrics.com/v1";
VLCluster = "operator.victoriametrics.com/v1";
diff --git a/easykubenix/default.nix b/easykubenix/default.nix
index 677bc15..b0b6f91 100644
--- a/easykubenix/default.nix
+++ b/easykubenix/default.nix
@@ -36,6 +36,7 @@ let
in
{
inherit (eval.config.internal)
+ manifestAttrs
manifestJSON
manifestJSONFile
manifestYAML
diff --git a/easykubenix/demo.nix b/easykubenix/demo.nix
index cf4294e..c44f70f 100644
--- a/easykubenix/demo.nix
+++ b/easykubenix/demo.nix
@@ -6,11 +6,7 @@
{ helm, ... }:
{
config = {
- kluctl = {
- enable = true;
- discriminator = "easykubenix-demo";
- };
- resources.Secret.hcloud = {
+ kubernetes.resources.kube-system.Secret.hcloud = {
metadata = {
name = "hcloud";
namespace = "kube-system";
@@ -19,7 +15,7 @@
data.token = "OXdZaU9zNHhhZE9JWVFvYTNRY2MzWXFtSmp1ODQzdUg4aDZaNTZ6MmtzNWt4YVNXV1djTzRxc2lLZDdqQWZGcA==";
};
helm.releases.hccm = {
- namespace = "kube-system";
+ namespace = "hccm-system";
chart = helm.fetch {
repo = "https://charts.hetzner.cloud";
@@ -46,12 +42,11 @@
{ ... }:
{
config = {
- resources.ConfigMap."my-app-config" = {
+ kubernetes.resources.default.ConfigMap."my-app-config" = {
metadata = {
- namespace = "default";
labels.app = "my-app";
};
- data = {
+ stringData = {
"config.yaml" = "some-value";
"storePath" = toString pkgs.fishMinimal;
};
diff --git a/easykubenix/helm.nix b/easykubenix/helm.nix
index ba06732..011baab 100644
--- a/easykubenix/helm.nix
+++ b/easykubenix/helm.nix
@@ -137,7 +137,7 @@ in
mapAttrsToList (
_: release:
map (object: {
- ${object.kind}."${object.metadata.name}" = mkMerge (
+ ${object.metadata.namespace or "none"}.${object.kind}."${object.metadata.name}" = mkMerge (
[
object
]
diff --git a/easykubenix/importyaml.nix b/easykubenix/importyaml.nix
index 1dfc6f6..613d946 100644
--- a/easykubenix/importyaml.nix
+++ b/easykubenix/importyaml.nix
@@ -118,7 +118,7 @@ in
mapAttrsToList (
_: yaml:
map (object: {
- ${object.kind}."${object.metadata.name}" = mkMerge (
+ ${object.metadata.namespace or "none"}.${object.kind}."${object.metadata.name}" = mkMerge (
[
object
]
diff --git a/easykubenix/kubernetes.nix b/easykubenix/kubernetes.nix
index 9132761..717c6ef 100644
--- a/easykubenix/kubernetes.nix
+++ b/easykubenix/kubernetes.nix
@@ -49,10 +49,11 @@ let
in
{
options.kubernetes = {
+ # In your options definition
resources = lib.mkOption {
- type = lib.types.attrsOf (lib.types.attrsOf resourceBody);
+ type = lib.types.attrsOf (lib.types.attrsOf (lib.types.attrsOf resourceBody));
default = { };
- description = "Kubernetes resources, grouped by kind.";
+ description = "Kubernetes resources, grouped by namespace, then kind.";
};
apiMappings = lib.mkOption {
@@ -96,28 +97,34 @@ in
generated =
let
- # Update apiVersion and kind if they're unset. This way kind name
- # collisions don't matter, and collisions are rare anyways.
+ cleanedResources = lib.filterAttrsRecursive (n: v: v != null) cfg.resources;
mappedResources = lib.mapAttrs (
- kind: resourcesByName:
+ namespace: resourcesByKind:
lib.mapAttrs (
- name: attrs:
- attrs
- // {
- apiVersion = if attrs.apiVersion != null then attrs.apiVersion else cfg.apiMappings.${kind};
- kind = if attrs.kind != null then attrs.kind else kind;
- }
- ) resourcesByName
- ) cfg.resources;
+ kind: resourcesByName:
+ lib.mapAttrs (
+ name: attrs:
+ # Provide a base set of attributes. `recursiveUpdate` will merge `attrs` on top,
+ # so any user-defined values for these fields will take precedence.
+ lib.recursiveUpdate (
+ {
+ apiVersion = cfg.apiMappings.${kind};
+ kind = kind;
+ metadata.name = name;
+ }
+ // lib.optionalAttrs (namespace != "none") {
+ metadata.namespace = namespace;
+ }
+ ) attrs
+ ) resourcesByName
+ ) resourcesByKind
+ ) cleanedResources;
- resourceList = lib.pipe mappedResources [
- # Remove nulls
- (lib.filterAttrsRecursive (n: v: v != null))
- # Extract resource attributes into a list
- lib.attrValues
- (listOfAttrSets: lib.map (kindResources: lib.attrValues kindResources) listOfAttrSets)
- lib.flatten
- ];
+ resourceList = lib.flatten (
+ lib.mapAttrsToList (
+ nsName: kinds: lib.mapAttrsToList (kindName: names: lib.attrValues names) kinds
+ ) mappedResources
+ );
in
resourceList;
};
diff --git a/hetzner-capi.nix b/hetzner-capi.nix
index c2b0d20..0fd0b4c 100644
--- a/hetzner-capi.nix
+++ b/hetzner-capi.nix
@@ -37,7 +37,7 @@ import ./easykubenix {
(
{ config, ... }:
{
- config.kubernetes.resources =
+ config.kubernetes.resources.none =
let
kubeletExtraArgs = {
"fail-swap-on" = "false";
diff --git a/hetzner-init.nix b/hetzner-init.nix
index 35c119e..b88cb2e 100644
--- a/hetzner-init.nix
+++ b/hetzner-init.nix
@@ -28,9 +28,7 @@ import ./easykubenix {
config = {
clusterName = "hetzner-test";
# Create a ConfigMap indicating the cluster is already initialized
- kubernetes.resources.ConfigMap.initialized = {
- metadata.namespace = "kube-public";
- };
+ kubernetes.resources.kube-public.ConfigMap.initialized = { };
cilium = {
enable = true;
k8sServiceHost = builtins.getEnv "K8S_SERVICE_HOST";
--
2.51.0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment