{ pkgs, myLib, ... }: { kubernetes.resources = let atticSettings = { # The '+" is to explicitly denote the end of the Vals expression. # This is done because we quote the template for the INI file. # See: https://github.com/helmfile/vals?tab=readme-ov-file#expression-syntax database.url = "ref+sops://secrets/kubernetes.yaml#attic/databaseURL+"; storage = { type = "local"; path = "/var/lib/atticd/storage"; }; listen = "[::]:8080"; # Data chunking # # Warning: If you change any of the values here, it will be # difficult to reuse existing chunks for newly-uploaded NARs # since the cutpoints will be different. As a result, the # deduplication ratio will suffer for a while after the change. chunking = { # The minimum NAR size to trigger chunking # # If 0, chunking is disabled entirely for newly-uploaded NARs. # If 1, all NARs are chunked. nar-size-threshold = 64 * 1024; # 64 KiB # The preferred minimum size of a chunk, in bytes min-size = 16 * 1024; # 16 KiB # The preferred average size of a chunk, in bytes avg-size = 64 * 1024; # 64 KiB # The preferred maximum size of a chunk, in bytes max-size = 256 * 1024; # 256 KiB }; }; generatedConfig = (pkgs.formats.toml { }).generate "attic.toml" atticSettings; in { secrets = { server.stringData = { token = "ref+sops://secrets/kubernetes.yaml#attic/jwtToken"; config = builtins.readFile generatedConfig; }; database.stringData.password = "ref+sops://secrets/kubernetes.yaml#/attic/databasePassword"; }; deployments = { attic.spec = { selector.matchLabels = { app = "attic"; component = "website"; }; strategy = { type = "RollingUpdate"; rollingUpdate = { maxSurge = 0; maxUnavailable = 1; }; }; template = { metadata.labels = { app = "attic"; component = "website"; }; spec = { containers.attic = { image = myLib.globals.images.attic; ports.web.containerPort = 8080; args = [ "-f" "/etc/atticd/config.toml" ]; env.ATTIC_SERVER_TOKEN_HS256_SECRET_BASE64.valueFrom.secretKeyRef = { name = "server"; key = "token"; }; volumeMounts = [ { name = "data"; mountPath = "/var/lib/atticd/storage"; } { name = "config"; mountPath = "/etc/atticd/config.toml"; subPath = "config"; } ]; }; volumes = { data.persistentVolumeClaim.claimName = "data"; config.secret.secretName = "server"; }; securityContext = { fsGroup = 0; fsGroupChangePolicy = "OnRootMismatch"; }; }; }; }; attic-db.spec = { selector.matchLabels = { app = "attic"; component = "database"; }; template = { metadata.labels = { app = "attic"; component = "database"; }; spec = { containers.postgres = { image = myLib.globals.images.atticPostgres; imagePullPolicy = "IfNotPresent"; ports.postgres.containerPort = 5432; env = { POSTGRES_DB.value = "attic"; POSTGRES_USER.value = "attic"; PGDATA.value = "/pgdata/data"; POSTGRES_PASSWORD.valueFrom.secretKeyRef = { name = "database"; key = "password"; }; }; volumeMounts = [{ name = "data"; mountPath = "/pgdata"; }]; }; volumes.data.persistentVolumeClaim.claimName = "database"; }; }; }; }; services = { attic.spec = { selector = { app = "attic"; component = "website"; }; ports.web = { port = 80; targetPort = "web"; }; }; database.spec = { selector = { app = "attic"; component = "database"; }; ports.postgres = { port = 5432; targetPort = "postgres"; }; }; }; }; lab = { ingresses.attic = { host = "attic.kun.is"; service = { name = "attic"; portName = "web"; }; }; longhorn.persistentVolumeClaim = { data = { volumeName = "attic"; storage = "15Gi"; }; database = { volumeName = "attic-db"; storage = "150Mi"; }; }; }; }