chore: initial commit

This commit is contained in:
technofab 2025-11-13 21:47:52 +01:00
commit 8cf73a70ef
No known key found for this signature in database
19 changed files with 1004 additions and 0 deletions

121
nix-kubernetes/coder.nix Normal file
View file

@ -0,0 +1,121 @@
{
ref,
utils,
...
}: {
locals."git_repo_folder" = with utils; let
split_repo = split (quot "") ref.data.coder_parameter.git_repo.value;
in
try [
(element split_repo "${rb (length split_repo)} - 1")
(quot "")
];
data = {
coder_external_auth."gitlab" = {
id = "gitlab";
optional = false;
};
coder_workspace."me" = {};
coder_workspace_owner."me" = {};
};
resource = {
coder_agent."coder" = {
arch = ref.var.arch;
os = "linux";
metadata = [
{
display_name = "Container CPU Usage";
key = "0_cpu_usage";
script = "coder stat cpu --host=false";
interval = 10;
timeout = 1;
}
{
display_name = "Container RAM Usage";
key = "1_ram_usage";
script = "coder stat mem --host=false";
interval = 10;
timeout = 1;
}
{
display_name = "Home Disk";
key = "2_home_disk";
script = "coder stat disk --path $HOME";
interval = 60;
timeout = 1;
}
{
display_name = "Nix Store Disk";
key = "3_nix_store_disk";
script = "coder stat disk --path /nix";
interval = 60;
timeout = 1;
}
];
};
coder_script."git_clone" = {
agent_id = ref.coder_agent.coder.id;
display_name = "Git Clone";
icon = "/icon/git.svg";
script = let
repo = ref.data.coder_parameter.git_repo.value;
repo_folder = ref.local.git_repo_folder;
in
# sh
''
mkdir -p ~/repos
if [ ! -z "${repo}" ]; then
echo "Cloning repo \"${repo}\" if it does not exist"
pushd ~/repos >/dev/null
if [[ ! -d "${repo_folder}" ]] then
git clone ${repo} ${repo_folder}
fi
popd >/dev/null
else
echo "No git repo specified, skipping..."
fi
'';
run_on_start = true;
start_blocks_login = true;
};
coder_script."home-manager" = {
agent_id = ref.coder_agent.coder.id;
display_name = "Home Manager";
icon = "/emojis/1f3e0.png";
script =
# sh
''
if [ ! -z "$DOTFILES_REPO" ]; then
echo "Dotfiles present, reloading home-manager profile"
reload-dotfiles
# the homeConfiguration can specify a program "coder_startup", run it
# here if it exists
if command -v coder_startup &> /dev/null; then
echo "Running startup tasks..."
coder_startup
fi
else
echo "No dotfiles repo specified, skipping..."
fi
'';
run_on_start = true;
start_blocks_login = true;
};
coder_script."home-manager-shutdown" = {
agent_id = ref.coder_agent.coder.id;
display_name = "Home Manager Shutdown";
icon = "/emojis/1f3e0.png";
script =
# sh
''
if command -v coder_shutdown &> /dev/null; then
echo "Running shutdown tasks..."
coder_shutdown
fi
'';
run_on_stop = true;
};
};
}

View file

@ -0,0 +1,8 @@
{
imports = [
./parameters.nix
./variables.nix
./coder.nix
./kubernetes.nix
];
}

View file

@ -0,0 +1,216 @@
{
ref,
utils,
...
}: let
identifier = with utils; "${lower ref.data.coder_workspace_owner.me.name}-${lower ref.data.coder_workspace.me.name}";
in {
resource = {
kubernetes_pod."workspace" = {
count = ref.data.coder_workspace.me.start_count;
metadata = [
{
name = "coder-${identifier}";
namespace = ref.var.namespace;
annotations."com.coder.user.email" = ref.data.coder_workspace_owner.me.email;
labels = {
"app.kubernetes.io/instance" = "coder-workspace-${identifier}";
"app.kubernetes.io/name" = "coder-workspace";
"app.kubernetes.io/part-of" = "coder";
"com.coder.resource" = "true";
"com.coder.user.id" = ref.data.coder_workspace_owner.me.id;
"com.coder.user.name" = ref.data.coder_workspace_owner.me.name;
"com.coder.workspace.id" = ref.data.coder_workspace.me.id;
"com.coder.workspace.name" = ref.data.coder_workspace.me.name;
};
}
];
# give the shutdown tasks enough time to run
timeouts.delete = "31m";
spec = [
{
termination_grace_period_seconds = 1800;
affinity.pod_anti_affinity.preferred_during_scheduling_ignored_during_execution = {
weight = 1;
pod_affinity_term = {
topology_key = "kubernetes.io/hostname";
label_selector.match_expressions = {
key = "app.kubernetes.io/name";
operator = "In";
values = ["coder-workspace"];
};
};
};
init_container = [
{
name = "chown";
image = "alpine:3";
command = ["chown" "1000:1000" "/mnt/nix" "/mnt/tmp" "/mnt/home"];
security_context.run_as_user = "0";
volume_mount = [
{
mount_path = "/mnt/home";
name = "home";
read_only = false;
}
{
mount_path = "/mnt/nix";
name = "nix-store";
read_only = false;
}
{
mount_path = "/mnt/tmp";
name = "tmp";
read_only = false;
}
];
}
{
name = "copy-nix-store";
image = "registry.gitlab.com/technofab/coder-templates/nix-coder-image:${ref.data.coder_parameter.image_tag.value}";
command = ["cp" "-nR" "/nix/." "/pv_nix"];
security_context.run_as_user = "1000";
volume_mount = [
{
mount_path = "/pv_nix";
name = "nix-store";
read_only = false;
}
];
}
];
container = [
{
name = "workspace";
image = "registry.gitlab.com/technofab/coder-templates/nix-coder-image:${ref.data.coder_parameter.image_tag.value}";
command = ["/bin/sh" "-c" "${ref.coder_agent.coder.init_script}"];
env = [
{
name = "CODER_AGENT_TOKEN";
value = ref.coder_agent.coder.token;
}
{
name = "DOTFILES_REPO";
value = ref.data.coder_parameter.dotfiles_repo.value;
}
{
name = "TZ";
value = ref.data.coder_parameter.timezone.value;
}
{
name = "NIX_CONFIG";
value = ref.data.coder_parameter.nix_config.value;
}
];
resources = {
requests = {
cpu = ref.var.cpu_request;
memory = ref.var.memory_request;
};
limits = {
cpu = ref.data.coder_parameter.cpu.value;
memory = ref.data.coder_parameter.memory.value;
};
};
security_context = {
run_as_user = "1000";
run_as_group = "1000";
};
volume_mount = [
{
mount_path = "/home";
name = "home";
read_only = false;
}
{
mount_path = "/nix";
name = "nix-store";
read_only = false;
}
{
mount_path = "/tmp";
name = "tmp";
read_only = false;
}
];
}
];
security_context = {
run_as_user = "1000";
run_as_group = "1000";
};
volume = [
{
name = "home";
persistent_volume_claim.claim_name = ref.kubernetes_persistent_volume_claim.home.metadata ".0.name";
}
{
name = "nix-store";
persistent_volume_claim.claim_name = ref.kubernetes_persistent_volume_claim.nix-store.metadata ".0.name";
}
{
name = "tmp";
empty_dir = {
medium = "Memory";
# not used for now
# sizeLimit = "200Mi";
};
}
];
}
];
};
kubernetes_persistent_volume_claim."home" = {
metadata = [
{
name = "coder-home-${identifier}";
namespace = ref.var.namespace;
annotations."com.coder.user.email" = ref.data.coder_workspace_owner.me.email;
labels = {
"app.kubernetes.io/instance" = "coder-pvc-home-${identifier}";
"app.kubernetes.io/name" = "coder-pvc";
"app.kubernetes.io/part-of" = "coder";
"com.coder.resource" = "true";
"com.coder.user.id" = ref.data.coder_workspace_owner.me.id;
"com.coder.user.name" = ref.data.coder_workspace_owner.me.name;
"com.coder.workspace.id" = ref.data.coder_workspace.me.id;
"com.coder.workspace.name" = ref.data.coder_workspace.me.name;
};
}
];
spec = [
{
access_modes = ["ReadWriteOnce"];
resources.requests.storage = "${ref.data.coder_parameter.home_disk_size.value}Gi";
}
];
wait_until_bound = false;
};
kubernetes_persistent_volume_claim."nix-store" = {
metadata = [
{
name = "coder-nix-store-${identifier}";
namespace = ref.var.namespace;
annotations."com.coder.user.email" = ref.data.coder_workspace_owner.me.email;
labels = {
"app.kubernetes.io/instance" = "coder-pvc-nix-store-${identifier}";
"app.kubernetes.io/name" = "coder-pvc";
"app.kubernetes.io/part-of" = "coder";
"com.coder.resource" = "true";
"com.coder.user.id" = ref.data.coder_workspace_owner.me.id;
"com.coder.user.name" = ref.data.coder_workspace_owner.me.name;
"com.coder.workspace.id" = ref.data.coder_workspace.me.id;
"com.coder.workspace.name" = ref.data.coder_workspace.me.name;
};
}
];
spec = [
{
access_modes = ["ReadWriteOnce"];
resources.requests.storage = "${ref.data.coder_parameter.nix_store_disk_size.value}Gi";
}
];
wait_until_bound = false;
};
};
}

View file

@ -0,0 +1,112 @@
{
data.coder_parameter = {
"dotfiles_repo" = {
name = "Dotfiles Repository (passed to home-manager)";
description = ''
Nix flake URI to your dotfiles repository, eg.
github:example/dotfiles#coder
Your flake.nix has to expose a homeManagerConfiguration.coder in this case.
'';
default = "";
order = 1;
type = "string";
mutable = true;
};
"git_repo" = {
name = "Git Repository";
description = ''
URI for a git repository which should automatically be cloned to ~/repos/<name>
'';
default = "";
order = 2;
type = "string";
mutable = true;
};
"image_tag" = {
name = "Image Tag";
description = ''
Which container image tag should be used.
'';
default = "latest";
order = 3;
type = "string";
mutable = true;
};
"cpu" = {
name = "CPU";
description = ''
CPU Limit for Kubernetes Pod. Kubernetes Notation (eg. 500m)
'';
default = "500m";
order = 4;
type = "string";
mutable = true;
};
"memory" = {
name = "Memory";
description = ''
Memory Limit for Kubernetes Pod. Kubernetes Notation (eg. 1Gi)
'';
default = "1Gi";
order = 5;
type = "string";
mutable = true;
};
"home_disk_size" = {
name = "Home Disk Size";
description = ''
Size for the /home PV in GB
'';
default = "5";
order = 6;
type = "number";
mutable = true;
validation = [
{
min = 1;
max = 100;
monotonic = "increasing";
}
];
};
"nix_store_disk_size" = {
name = "Nix Store Disk Size";
description = ''
Size for the /nix PV in GB. This might grow pretty big.
'';
default = "5";
order = 7;
type = "number";
mutable = true;
validation = [
{
min = 1;
max = 100;
monotonic = "increasing";
}
];
};
"timezone" = {
name = "Timezone";
description = ''
Content of the TZ environment variable.
'';
default = "";
order = 8;
type = "string";
mutable = true;
};
"nix_config" = {
name = "Nix Config";
description = ''
Nix config, will be put into $NIX_CONFIG
'';
default = "";
order = 9;
type = "string";
form_type = "textarea";
mutable = true;
};
};
}

View file

@ -0,0 +1,26 @@
{
variable = {
"namespace" = {
type = "string";
description = "Kubernetes namespace (must exist prior to creating workspaces)";
};
"arch" = {
type = "string";
description = "Architecture of the host";
validation = {
condition = ''''${contains(["amd64", "arm64"], var.arch)}'';
error_message = "Invalid architecture selected";
};
};
"cpu_request" = {
type = "string";
description = "CPU request to apply to workspaces. Kubernetes Notation (eg. 500m)";
default = "0";
};
"memory_request" = {
type = "string";
description = "Memory request to apply to workspaces. Kubernetes Notation (eg. 1Gi)";
default = "0";
};
};
}