From 6361b06a5a4dbbbf6c011ce182642e2a6f23e9dc Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Sat, 6 Apr 2024 16:45:10 +0200 Subject: [PATCH] migrate transmission to kubernetes --- docker_swarm/roles/media/docker-stack.yml.j2 | 33 --- .../roles/traefik/docker-stack.yml.j2 | 6 + nix/flake/kubenix/media.nix | 244 ++++++++++++++---- 3 files changed, 198 insertions(+), 85 deletions(-) diff --git a/docker_swarm/roles/media/docker-stack.yml.j2 b/docker_swarm/roles/media/docker-stack.yml.j2 index e49a603..c0b5205 100644 --- a/docker_swarm/roles/media/docker-stack.yml.j2 +++ b/docker_swarm/roles/media/docker-stack.yml.j2 @@ -49,39 +49,6 @@ volumes: jellyfin_cache: services: - transmission: - image: lscr.io/linuxserver/transmission:latest - ports: - - "{{ bittorrent_port }}:{{ bittorrent_port }}" - - "{{ bittorrent_port }}:{{ bittorrent_port }}/udp" - environment: - - PUID=1000 - - PGID=1000 - - TZ=Europe/Amsterdam - volumes: - - type: volume - source: transmission_config - target: /config - volume: - nocopy: true - - type: volume - source: media - target: /media - volume: - nocopy: true - networks: - - traefik - deploy: - labels: - - traefik.enable=true - - traefik.http.routers.transmission.entrypoints=localsecure - - traefik.http.routers.transmission.rule=Host(`transmission.kun.is`) - - traefik.http.routers.transmission.tls=true - - traefik.http.routers.transmission.tls.certresolver=letsencrypt - - traefik.http.routers.transmission.service=transmission - - traefik.http.services.transmission.loadbalancer.server.port=9091 - - traefik.docker.network=traefik - jellyseerr: image: fallenbagel/jellyseerr:1.7.0 environment: diff --git a/docker_swarm/roles/traefik/docker-stack.yml.j2 b/docker_swarm/roles/traefik/docker-stack.yml.j2 index c9f4f1d..ff9c4c3 100644 --- a/docker_swarm/roles/traefik/docker-stack.yml.j2 +++ b/docker_swarm/roles/traefik/docker-stack.yml.j2 @@ -126,6 +126,12 @@ services: - traefik.http.routers.jellyfin.rule=Host(`media.kun.is`) - traefik.http.routers.jellyfin.tls=true - traefik.http.routers.jellyfin.tls.certresolver=letsencrypt + + - traefik.http.routers.transmission.entrypoints=localsecure + - traefik.http.routers.transmission.service=k3s@file + - traefik.http.routers.transmission.rule=Host(`transmission.kun.is`) + - traefik.http.routers.transmission.tls=true + - traefik.http.routers.transmission.tls.certresolver=letsencrypt volumes: - type: bind source: /var/run/docker.sock diff --git a/nix/flake/kubenix/media.nix b/nix/flake/kubenix/media.nix index 84f9f77..13d2e4a 100644 --- a/nix/flake/kubenix/media.nix +++ b/nix/flake/kubenix/media.nix @@ -1,57 +1,129 @@ { kubernetes.resources = { - configMaps.jellyfin-env.data.JELLYFIN_PublishedServerUrl = "https://media.kun.is"; - - deployments.jellyfin = { - metadata.labels = { - app = "media"; - component = "jellyfin"; + configMaps = { + jellyfin-env.data.JELLYFIN_PublishedServerUrl = "https://media.kun.is"; + transmission-env.data = { + PUID = "1000"; + PGID = "1000"; + TZ = "Europe/Amsterdam"; }; + }; - spec = { - selector.matchLabels = { + deployments = { + jellyfin = { + metadata.labels = { app = "media"; component = "jellyfin"; }; - template = { - metadata.labels = { + spec = { + selector.matchLabels = { app = "media"; component = "jellyfin"; }; - spec = { - containers.jellyfin = { - image = "jellyfin/jellyfin:10.8.13-1"; - envFrom = [{ configMapRef.name = "jellyfin-env"; }]; + template = { + metadata.labels = { + app = "media"; + component = "jellyfin"; + }; - ports = [{ - containerPort = 8096; - protocol = "TCP"; - }]; + spec = { + containers.jellyfin = { + image = "jellyfin/jellyfin:10.8.13-1"; + envFrom = [{ configMapRef.name = "jellyfin-env"; }]; - volumeMounts = [ + ports = [{ + containerPort = 8096; + protocol = "TCP"; + }]; + + volumeMounts = [ + { + name = "config"; + mountPath = "/config"; + } + { + name = "media"; + mountPath = "/media"; + } + ]; + }; + + volumes = [ { name = "config"; - mountPath = "/config"; + persistentVolumeClaim.claimName = "jellyfin-config"; } { name = "media"; - mountPath = "/media"; + persistentVolumeClaim.claimName = "media"; } ]; }; + }; + }; + }; - volumes = [ - { - name = "config"; - persistentVolumeClaim.claimName = "jellyfin-config"; - } - { - name = "media"; - persistentVolumeClaim.claimName = "media"; - } - ]; + transmission = { + metadata.labels = { + app = "media"; + component = "transmission"; + }; + + spec = { + selector.matchLabels = { + app = "media"; + component = "transmission"; + }; + + template = { + metadata.labels = { + app = "media"; + component = "transmission"; + }; + + spec = { + containers.transmission = { + image = "lscr.io/linuxserver/transmission:latest"; + envFrom = [{ configMapRef.name = "transmission-env"; }]; + + ports = [ + { + containerPort = 9091; + protocol = "TCP"; + } + # TODO: Only use TCP, as Kubernetes does not support multiple protocols for a port number. + # Should see if this works as correctly though. + { + containerPort = 31780; + protocol = "TCP"; + } + ]; + + volumeMounts = [ + { + name = "config"; + mountPath = "/config"; + } + { + name = "media"; + mountPath = "/media"; + } + ]; + }; + + volumes = [ + { + name = "config"; + persistentVolumeClaim.claimName = "transmission-config"; + } + { + name = "media"; + persistentVolumeClaim.claimName = "media"; + } + ]; + }; }; }; }; @@ -77,6 +149,16 @@ path = "/mnt/data/nfs/media"; }; }; + + transmission-config.spec = { + capacity.storage = "1Mi"; + accessModes = [ "ReadWriteMany" ]; + + nfs = { + server = "lewis.hyp"; + path = "/mnt/data/nfs/transmission/config"; + }; + }; }; persistentVolumeClaims = { @@ -93,37 +175,95 @@ resources.requests.storage = "1Mi"; volumeName = "media"; }; + + transmission-config.spec = { + accessModes = [ "ReadWriteMany" ]; + storageClassName = ""; + resources.requests.storage = "1Mi"; + volumeName = "transmission-config"; + }; }; - services.jellyfin.spec = { - selector = { - app = "media"; - component = "jellyfin"; + services = { + jellyfin.spec = { + selector = { + app = "media"; + component = "jellyfin"; + }; + + ports = [{ + protocol = "TCP"; + port = 80; + targetPort = 8096; + }]; }; - ports = [{ - protocol = "TCP"; - port = 80; - targetPort = 8096; - }]; + transmission-web.spec = { + selector = { + app = "media"; + component = "transmission"; + }; + + ports = [{ + protocol = "TCP"; + port = 80; + targetPort = 9091; + }]; + }; + + transmission-bittorrent.spec = { + type = "LoadBalancer"; + loadBalancerIP = "192.168.30.133"; + + selector = { + app = "media"; + component = "transmission"; + }; + + ports = [{ + protocol = "TCP"; + port = 31780; + targetPort = 31780; + }]; + }; }; - ingresses.jellyfin.spec = { - ingressClassName = "traefik"; + ingresses = { + jellyfin.spec = { + ingressClassName = "traefik"; - rules = [{ - host = "media.kun.is"; + rules = [{ + host = "media.kun.is"; - http.paths = [{ - path = "/"; - pathType = "Prefix"; + http.paths = [{ + path = "/"; + pathType = "Prefix"; - backend.service = { - name = "jellyfin"; - port.number = 80; - }; + backend.service = { + name = "jellyfin"; + port.number = 80; + }; + }]; }]; - }]; + }; + + transmission.spec = { + ingressClassName = "traefik"; + + rules = [{ + host = "transmission.kun.is"; + + http.paths = [{ + path = "/"; + pathType = "Prefix"; + + backend.service = { + name = "transmission-web"; + port.number = 80; + }; + }]; + }]; + }; }; }; }