diff --git a/docker/Dockerfile.minimal b/docker/Dockerfile.minimal new file mode 100644 index 00000000..1e8edb4b --- /dev/null +++ b/docker/Dockerfile.minimal @@ -0,0 +1,13 @@ +FROM python:alpine + +# Install required non-python dependencies. +# Just using the built-in ffmpeg for ease of creation. +RUN apk add --no-cache ffmpeg aria2 + +RUN --mount=type=cache,target=/root/.cache \ + pip install ytdl-sub + +VOLUME /config +VOLUME /media +# Default to a non-root user after build. +USER nobody diff --git a/kubernetes/README.md b/kubernetes/README.md new file mode 100644 index 00000000..2e817f40 --- /dev/null +++ b/kubernetes/README.md @@ -0,0 +1,24 @@ +# Deploying with Kubernetes + +## TL;DR + +```console +$ git clone git@github.com:jmbannon/ytdl-sub.git +$ cd ytdl-sub/kubernetes +$ $EDITOR kustomization.yaml subs.yaml presets.yaml +$ kuzomise build . | kubectl apply -f - +``` + +## Configuration + +Make sure you set the following to the right values for your kubernetes setup: +- `storageClassName` for each of the volumes in `./volumes.yaml` +- `namespace` in `kustomization.yaml` +- `images` overrides in `kustomization.yaml` if you don't want to use the minimal image +- `schedule` in `cronjob.yaml` if you want to run on a different schedule (defaults to + hourly.) + +It should build a valid configuration without changing these kubernetes settings, but +it will probably not be what you're expecting. + +See the normal documentation for configuring the `subs.yaml` and `presets.yaml` files. diff --git a/kubernetes/config.yaml b/kubernetes/config.yaml new file mode 100644 index 00000000..e69de29b diff --git a/kubernetes/cronjob.yaml b/kubernetes/cronjob.yaml new file mode 100644 index 00000000..c33111b5 --- /dev/null +++ b/kubernetes/cronjob.yaml @@ -0,0 +1,64 @@ +apiVersion: batch/v1 +kind: CronJob + +metadata: + name: ytdl +spec: + schedule: '@hourly' + successfulJobsHistoryLimit: 3 + concurrencyPolicy: Forbid + jobTemplate: + metadata: + labels: + app: ytdl + spec: + parallelism: 1 + template: + metadata: + labels: + app: ytdl + spec: + containers: + - name: ytdl + image: kaictl/ytdl-sub:notlatest + command: + - ytdl-sub + - sub + volumeMounts: + # Where to download to + - mountPath: /media + name: media + # Storage for .ytdl-sub-working-directory. + - mountPath: /cache + name: cache + # Configuration and preset files location. + - mountPath: /config + name: config + # Run in the cache directory, just for ease of use. + workingDir: /cache/ + # Run as non-root so we don't have security issues. + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + privileged: false + readOnlyRootFilesystem: false + runAsNonRoot: true + volumes: + - name: media + persistentVolumeClaim: + claimName: yt-media + - name: cache + persistentVolumeClaim: + claimName: yt-cache + - name: config + configMap: + name: ytdl + # More security settings. Runs as `nobody`. + securityContext: + fsGroup: 65534 + fsGroupChangePolicy: OnRootMismatch + runAsGroup: 65534 + runAsNonRoot: false + runAsUser: 65534 diff --git a/kubernetes/kustomization.yaml b/kubernetes/kustomization.yaml new file mode 100644 index 00000000..9faee8d1 --- /dev/null +++ b/kubernetes/kustomization.yaml @@ -0,0 +1,22 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +# Set this to wherever you want your jobs to run. It should exist already. +namespace: ytdl-sub + +images: + # Override this with your own image if you would like. + # This is a smaller image than the default that includes all the editor stuff. + - name: kaictl/ytdl-sub + newName: kaictl/ytdl-sub + newTag: latest + +resources: + - ./volumes.yaml + - ./cronjob.yaml + +configMapGenerator: + - name: ytdl-config + files: + - ./config.yaml + - ./subscriptions.yaml diff --git a/kubernetes/subscriptions.yaml b/kubernetes/subscriptions.yaml new file mode 100644 index 00000000..e69de29b diff --git a/kubernetes/volumes.yaml b/kubernetes/volumes.yaml new file mode 100644 index 00000000..b50ef528 --- /dev/null +++ b/kubernetes/volumes.yaml @@ -0,0 +1,38 @@ +# Final media storage. +# This should have enough space to store all the media you download. If you already have +# a media volume that you're serving stuff from (plex, etc.), then you can mount it +# here, or do the opposite and mount this volume to your running media server pods. +# It's recommended to use a separate volume from your other media downloads for safety. +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: yt-media +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + # Set to the size of the storage volume you need + storage: 100Gi + # Will use the default storage class if not set, otherwise set to your desired + # storageclass name. + #storageClassName: my-video-storage-name +--- + +# For persistence of your cache, it is recommended to use a PVC for your /cache +# directory. Make sure the storage is fast enough, since it will be used as a cache for +# downloading a lot of small files, as well as temporary files while ytdl and ffmpeg do +# their work. +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: yt-cache +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + # You probably don't need much storage, but that depends on the kinds of videos + # you download. I'd recommend at least 10Gi. + storage: 16Gi + #storageClassName: my-fast-storage-name