chore: add initial nix-kubernetes template

This commit is contained in:
technofab 2024-04-24 19:01:04 +02:00
parent 6bd319fbe9
commit 7cd71e7537
8 changed files with 425 additions and 2 deletions

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

@ -0,0 +1,42 @@
{...}: {
locals."git_repo_folder" = let
split_repo = ''split("/", data.coder_parameter.git_repo.value)'';
in ''try(element(${split_repo}, length(${split_repo}) - 1), "")'';
data = {
coder_external_auth."gitlab" = {
id = "gitlab";
optional = false;
};
coder_workspace."me" = {};
};
resource = {
coder_agent."coder" = {
arch = "\${var.arch}";
os = "linux";
};
coder_script."git_clone" = {
agent_id = "\${coder_agent.coder.id}";
display_name = "Git Clone";
icon = "/icon/git.svg";
script = let
repo = ''''${data.coder_parameter.git_repo.value}'';
repo_folder = ''''${local.git_repo_folder}'';
in ''
#!/usr/bin/env bash
set -eux
echo "Cloning repo \"${repo}\" if it does not exist"
mkdir -p ~/repos
pushd ~/repos
if [[ ! -z "${repo}" && ! -d "${repo_folder}" ]] then
git clone ${repo} ${repo_folder}
fi
popd
'';
run_on_start = true;
start_blocks_login = true;
};
};
}

View file

@ -0,0 +1,24 @@
{...}: {
imports = [
./parameters.nix
./variables.nix
./coder.nix
./kubernetes.nix
];
terraform.required_providers = {
coder = {
source = "coder/coder";
version = "0.21.0";
};
kubernetes = {
source = "hashicorp/kubernetes";
version = "2.29.0";
};
};
provider = {
coder = {};
kubernetes = {};
};
}

View file

@ -0,0 +1,130 @@
{...}: {
resource = {
kubernetes_pod."workspace" = {
count = "\${data.coder_workspace.me.start_count}";
metadata = {
name = "coder-\${lower(data.coder_workspace.me.owner)}-\${lower(data.coder_workspace.me.name)}";
namespace = "\${var.namespace}";
annotations."com.coder.user.email" = "\${data.coder_workspace.me.owner_email}";
labels = {
"app.kubernetes.io/instance" = "coder-workspace-\${lower(data.coder_workspace.me.owner)}-\${lower(data.coder_workspace.me.name)}";
"app.kubernetes.io/name" = "coder-workspace";
"app.kubernetes.io/part-of" = "coder";
"com.coder.resource" = "true";
"com.coder.user.id" = "\${data.coder_workspace.me.owner_id}";
"com.coder.user.name" = "\${data.coder_workspace.me.owner}";
"com.coder.workspace.id" = "\${data.coder_workspace.me.id}";
"com.coder.workspace.name" = "\${data.coder_workspace.me.name}";
};
};
spec = {
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"];
};
};
};
container = [
{
name = "workspace";
image = "registry.gitlab.com/technofab/coder-templates/coder-workspace:\${data.coder_parameter.image_tag.value}";
command = ["/bin/sh" "-c" "\${resource.coder_agent.coder.init_script}"];
env = [
{
name = "CODER_AGENT_TOKEN";
value = "\${resource.coder_agent.coder.token}";
}
];
resources = {
requests = {
# TODO: allow configuring this via variables (template wide)
cpu = "250m";
memory = "512Mi";
};
limits = {
cpu = "\${data.coder_parameter.cpu.value}";
memory = "\${data.coder_parameter.memory.value}";
};
};
security_context.run_as_user = "1000";
volume_mount = [
{
mount_path = "/home";
name = "home";
read_only = false;
}
{
mount_path = "/nix";
name = "nix-store";
read_only = false;
}
];
}
];
security_context = {
fs_group = "1000";
run_as_user = "1000";
};
volume = [
{
name = "home";
persistent_volume_claim.claim_name = "\${resource.kubernetes_persistent_volume_claim.home.metadata.0.name}";
}
{
name = "nix-store";
persistent_volume_claim.claim_name = "\${resource.kubernetes_persistent_volume_claim.nix-store.metadata.0.name}";
}
];
};
};
kubernetes_persistent_volume_claim."home" = {
metadata = {
name = "coder-home-\${lower(data.coder_workspace.me.owner)}-\${lower(data.coder_workspace.me.name)}";
namespace = "\${var.namespace}";
annotations."com.coder.user.email" = "\${data.coder_workspace.me.owner_email}";
labels = {
"app.kubernetes.io/instance" = "coder-pvc-home-\${lower(data.coder_workspace.me.owner)}-\${lower(data.coder_workspace.me.name)}";
"app.kubernetes.io/name" = "coder-pvc";
"app.kubernetes.io/part-of" = "coder";
"com.coder.resource" = "true";
"com.coder.user.id" = "\${data.coder_workspace.me.owner_id}";
"com.coder.user.name" = "\${data.coder_workspace.me.owner}";
"com.coder.workspace.id" = "\${data.coder_workspace.me.id}";
"com.coder.workspace.name" = "\${data.coder_workspace.me.name}";
};
};
spec = {
access_modes = ["ReadWriteOnce"];
resources.requests.storage = "\${data.coder_parameter.home_disk_size.value}Gi";
};
wait_until_bound = false;
};
kubernetes_persistent_volume_claim."nix-store" = {
metadata = {
name = "coder-nix-store-\${lower(data.coder_workspace.me.owner)}-\${lower(data.coder_workspace.me.name)}";
namespace = "\${var.namespace}";
annotations."com.coder.user.email" = "\${data.coder_workspace.me.owner_email}";
labels = {
"app.kubernetes.io/instance" = "coder-pvc-nix-store-\${lower(data.coder_workspace.me.owner)}-\${lower(data.coder_workspace.me.name)}";
"app.kubernetes.io/name" = "coder-pvc";
"app.kubernetes.io/part-of" = "coder";
"com.coder.resource" = "true";
"com.coder.user.id" = "\${data.coder_workspace.me.owner_id}";
"com.coder.user.name" = "\${data.coder_workspace.me.owner}";
"com.coder.workspace.id" = "\${data.coder_workspace.me.id}";
"com.coder.workspace.name" = "\${data.coder_workspace.me.name}";
};
};
spec = {
access_modes = ["ReadWriteOnce"];
resources.requests.storage = "\${data.coder_parameter.nix_store_disk_size.value}Gi";
};
wait_until_bound = false;
};
};
}

View file

@ -0,0 +1,78 @@
{...}: {
data.coder_parameter = {
git_repo = {
name = "Git Repository";
description = ''
URI for a git repository which should automatically be cloned to ~/repos/<name>
'';
default = "";
order = 1;
type = "string";
mutable = true;
};
image_tag = {
name = "Image Tag";
description = ''
Which container image tag should be used.
'';
default = "latest";
order = 2;
type = "string";
mutable = true;
};
cpu = {
name = "CPU";
description = ''
CPU Limit for Kubernetes Pod. Kubernetes Notation (eg. 500m)
'';
default = "500m";
order = 3;
type = "string";
mutable = true;
};
memory = {
name = "Memory";
description = ''
Memory Limit for Kubernetes Pod. Kubernetes Notation (eg. 1Gi)
'';
default = "1Gi";
order = 4;
type = "string";
mutable = true;
};
home_disk_size = {
name = "Home Disk Size";
description = ''
Size for the /home PV in GB
'';
default = 5;
order = 5;
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 = 6;
type = "number";
mutable = true;
validation = [
{
min = 1;
max = 100;
monotonic = "increasing";
}
];
};
};
}

View file

@ -0,0 +1,16 @@
{...}: {
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";
};
};
};
}