diff --git a/kubernetes/media/booklore/backup/backblaze.secret.sops.yaml b/kubernetes/media/booklore/backup/backblaze.secret.sops.yaml new file mode 100644 index 00000000..04577679 --- /dev/null +++ b/kubernetes/media/booklore/backup/backblaze.secret.sops.yaml @@ -0,0 +1,55 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/master/secret.json +apiVersion: v1 +kind: Secret +type: Opaque +metadata: + name: restic-media-booklore + namespace: media +stringData: + RESTIC_REPOSITORY: ENC[AES256_GCM,data:74X7h4M5EzC59xFHIeoydBBOsk0oyfoR5d0FGVPZ6sp8aoQ8xtwQTOI0aTHdN89bIhOJlWKj3ZM9NgqTNQ==,iv:FXyU95+NmTxVyzE153yRVp2WyAbhY3FWKShmYAij1LI=,tag:xYdzGKmbVd2hXkwi5+gOyQ==,type:str] + RESTIC_PASSWORD: ENC[AES256_GCM,data:CmvDlNq5A6NX3cQE6T3j55RTfJN8NtKrL2Qlm/Et9rg=,iv:J0QL3N7sGkAO8TA5dyIfwaM2D6oyaJdKzuAYxFbKjl0=,tag:t6fBOeQ5OVWVtTrpJ4Dluw==,type:str] + AWS_ACCESS_KEY_ID: ENC[AES256_GCM,data:s19IGgMw/U6dd48ghzyBl7GI2eRfs1KqhQ==,iv:7CsRHsk3BLyXbqKz7IBvVOV5ZS+M02dSBdJB/Xj49w8=,tag:NdmVFxzf8grfoHqTs/LfRg==,type:str] + AWS_SECRET_ACCESS_KEY: ENC[AES256_GCM,data:uLML8phnRNZPziJBx8qR/fBclfiPxfkJBy6SYWu3Fw==,iv:l90SIw2g4e0z6F+DALvOLD7FYCEdwNAsr32drQVxLGc=,tag:ZVqsnaEECa6Yf03nT/WtYg==,type:str] +sops: + age: + - recipient: age1ht2mpnqakafawr4akvukz2ketzdlwuwkhdzwsy8hl7rwfkhkh90qp36und + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBudXBqTGFlRm9rbFNCWnhI + UkI4L1cyYjRtOXBRdjZabkMrTXFxOWQ0ZlhNCnlZMnA0d0Y2ZHhtWFU4SDA2TWtK + elVUY3dwREtmVVRIU3FMVkRhSTNhdm8KLS0tIDZPZDVaRGtPbDlNdEdGZnp4ZGlS + K2w3U2RyS09ybVU2RVdvMW12Y3BDM3cKC0Wu/gJu0rNjRu/KaqZ6wtkRouw7Cduz + dhpNw1fMPOYVZbNE2DzxvJakp403IXdfxoLAmMOHaX10IBYZDqyhJA== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2026-01-07T18:25:49Z" + mac: ENC[AES256_GCM,data:auZAsYy/TNy18OqLLrgxqoZmZk6WGDMc2A7MgPpadsM34/V4HyPHmcc10H7P/9/uiq44J1djr0gWdrIeJuwSZObTbpwgDqM8vD/BCaLdhvSg/Zklv/I1OTml5C0nSYISeQV8gv9j26oL3jcxU6Qa2La0Gpv+uF4DiAS8N0dgT4o=,iv:/WlwJpeblCH6n6zIr0/kt9NPVsptIy9RxVw+E9iad/E=,tag:anIzj8Mn7jwxNb399eJ8qw==,type:str] + encrypted_regex: ^(data|stringData|email|host|apiKey)$ + version: 3.11.0 +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/master/secret.json +apiVersion: v1 +kind: Secret +type: Opaque +metadata: + name: restic-media-booklore-mariadb + namespace: media +stringData: + RESTIC_REPOSITORY: ENC[AES256_GCM,data:WQ1ith3s72WvrxnGuWaTTqW87gfUotVQ/k1/2K9JvhOgXCPUW7Er9xwankE62oR0w7JIVL95PONvwIjejZLS4BJozNWZ,iv:Uo3l0rn4et1Uq540VVnaBhlYtWZfv+byFIY5jFvAJk4=,tag:7WWJTsGfSH54Kxtq3EtPiA==,type:str] + RESTIC_PASSWORD: ENC[AES256_GCM,data:QwQzptjbOv9TJLOtJxJjzu2n27dMYyw/hrCl1OCyBIs=,iv:4qJzu9wD7Fen9okKQSuePmX6GhlU3WOUfP17CQ46nzc=,tag:h9yr50ptwCJalWkdU1sxcA==,type:str] + AWS_ACCESS_KEY_ID: ENC[AES256_GCM,data:f6msBWFGvwlnJSfor+V0oSHoFpH7IQrDCQ==,iv:BwmSlo3DeXr7x6mcwNGZMQllegL039SpMZjYvas3Mdk=,tag:gYSnheVsGbHTBdnThz+wFw==,type:str] + AWS_SECRET_ACCESS_KEY: ENC[AES256_GCM,data:M6GM+tJRSjqvGfv3hgqil9jzvjGr50vb2UicIjXJxg==,iv:t32fIif8Eat0Iv5NOi2Hf95iCJTJzwj6Mmo9YyLscHM=,tag:tfrSlagwOmLB5GtazW//ng==,type:str] +sops: + age: + - recipient: age1ht2mpnqakafawr4akvukz2ketzdlwuwkhdzwsy8hl7rwfkhkh90qp36und + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBudXBqTGFlRm9rbFNCWnhI + UkI4L1cyYjRtOXBRdjZabkMrTXFxOWQ0ZlhNCnlZMnA0d0Y2ZHhtWFU4SDA2TWtK + elVUY3dwREtmVVRIU3FMVkRhSTNhdm8KLS0tIDZPZDVaRGtPbDlNdEdGZnp4ZGlS + K2w3U2RyS09ybVU2RVdvMW12Y3BDM3cKC0Wu/gJu0rNjRu/KaqZ6wtkRouw7Cduz + dhpNw1fMPOYVZbNE2DzxvJakp403IXdfxoLAmMOHaX10IBYZDqyhJA== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2026-01-07T18:25:49Z" + mac: ENC[AES256_GCM,data:auZAsYy/TNy18OqLLrgxqoZmZk6WGDMc2A7MgPpadsM34/V4HyPHmcc10H7P/9/uiq44J1djr0gWdrIeJuwSZObTbpwgDqM8vD/BCaLdhvSg/Zklv/I1OTml5C0nSYISeQV8gv9j26oL3jcxU6Qa2La0Gpv+uF4DiAS8N0dgT4o=,iv:/WlwJpeblCH6n6zIr0/kt9NPVsptIy9RxVw+E9iad/E=,tag:anIzj8Mn7jwxNb399eJ8qw==,type:str] + encrypted_regex: ^(data|stringData|email|host|apiKey)$ + version: 3.11.0 diff --git a/kubernetes/media/booklore/backup/backup.yaml b/kubernetes/media/booklore/backup/backup.yaml new file mode 100644 index 00000000..62a5dfcc --- /dev/null +++ b/kubernetes/media/booklore/backup/backup.yaml @@ -0,0 +1,50 @@ +--- +# yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/volsync.backube/replicationsource_v1alpha1.json +apiVersion: volsync.backube/v1alpha1 +kind: ReplicationSource +metadata: + name: media-booklore + namespace: media +spec: + sourcePVC: booklore + trigger: + schedule: "0 13 * * *" + restic: + moverSecurityContext: + runAsNonRoot: true + runAsUser: 1000 + runAsGroup: 1000 + fsGroup: 1000 + fsGroupChangePolicy: OnRootMismatch + pruneIntervalDays: 14 + repository: restic-media-booklore + retain: + daily: 7 + weekly: 4 + monthly: 2 + copyMethod: Direct +--- +# yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/volsync.backube/replicationsource_v1alpha1.json +apiVersion: volsync.backube/v1alpha1 +kind: ReplicationSource +metadata: + name: media-booklore-mariadb + namespace: media +spec: + sourcePVC: booklore-mariadb + trigger: + schedule: "0 13 * * *" + restic: + moverSecurityContext: + runAsNonRoot: true + runAsUser: 1000 + runAsGroup: 1000 + fsGroup: 1000 + fsGroupChangePolicy: OnRootMismatch + pruneIntervalDays: 14 + repository: restic-media-booklore-mariadb + retain: + daily: 7 + weekly: 4 + monthly: 2 + copyMethod: Direct diff --git a/kubernetes/media/booklore/backup/kustomization.yaml b/kubernetes/media/booklore/backup/kustomization.yaml new file mode 100644 index 00000000..745e06fd --- /dev/null +++ b/kubernetes/media/booklore/backup/kustomization.yaml @@ -0,0 +1,7 @@ +--- +# yaml-language-server: $schema=https://json.schemastore.org/kustomization.json +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - backup.yaml + - backblaze.secret.sops.yaml diff --git a/kubernetes/media/booklore/booklore.secret.sops.yaml b/kubernetes/media/booklore/booklore.secret.sops.yaml new file mode 100644 index 00000000..0f4e9853 --- /dev/null +++ b/kubernetes/media/booklore/booklore.secret.sops.yaml @@ -0,0 +1,25 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/master/secret.json +apiVersion: v1 +kind: Secret +metadata: + name: booklore-secret + namespace: media +type: Opaque +stringData: + DATABASE_PASSWORD: ENC[AES256_GCM,data:KBG5HsEZ8WBcDbYCTf2P6aawwUEiKZJVmXjKR6s=,iv:eEsXNWaq7DjhDvBDUeAygx+jR+mgAQ/2FCm2Wwlad68=,tag:2odCuWNtvphi6MXn3DULhw==,type:str] + DATABASE_ROOT_PASSWORD: ENC[AES256_GCM,data:nyDrGileJveO9S6KG23gYEEdJKGNNoURck7q+xxiyDc=,iv:Z6nWEHedD3fCTKCbXiNX5mLBwraYPLeNgh+BOPJqlWU=,tag:OR+3GsjwIc7lTIxizDcaeg==,type:str] +sops: + age: + - recipient: age1ht2mpnqakafawr4akvukz2ketzdlwuwkhdzwsy8hl7rwfkhkh90qp36und + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBwb2I1L2wzYkcxaWFrMXBp + ck8wYzlkdE1vTENkbGJCQUJoVitqUjc0NkRnCm9GMjdqaWxlbDdYZjQyL3ZoRGVC + eTVKZkZGcUlUSzBxYUFVTVFiY3dqdTgKLS0tIG1odnRuazd4ZEhQdFdCcjd4bmdt + N096YzMwcmlYSHRYQ2l1ZTBSTTNuT2sKN6t/4JR3eq4AfAEs1eQhz8tU0Kl4xWki + Tt+b5WfG6pUn9dSwPvt7YNsxkUHblzkFcmAU1Pz81pH5E+FxHRMdTQ== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2026-01-07T18:26:16Z" + mac: ENC[AES256_GCM,data:ONKuO4ovcKjBWPFkwXaymnmSzMWayiNQP6b6rYSxSHyG3bNk+coXrxV+U0Fs4IV8/HSavY9kTXS08NCJPK0LvMDm/fl0/BaKqyXOhPGq2UUStSku6ICIj1MaihdcGRXUcpSarR+GVqfsUIR16NYaeTxG236talIHbZ9H4n9jo9M=,iv:g7Pe+HKOR5Lau4DpFY5rrIkiet0Wq1tJftK87AXRVns=,tag:q26E6nk+4n6p176cLD/enw==,type:str] + encrypted_regex: ^(data|stringData|email|host|apiKey)$ + version: 3.11.0 diff --git a/kubernetes/media/booklore/ingress.yaml b/kubernetes/media/booklore/ingress.yaml new file mode 100644 index 00000000..8106b9f1 --- /dev/null +++ b/kubernetes/media/booklore/ingress.yaml @@ -0,0 +1,22 @@ +--- +# yaml-language-server: $schema=https://json.schemastore.org/traefik-v3.json +apiVersion: traefik.io/v1alpha1 +kind: IngressRoute +metadata: + name: booklore + namespace: traefik +spec: + routes: + - match: Host(`booklore.axis.scottmckendry.tech`) + kind: Rule + middlewares: + - name: ipallowlist + namespace: traefik + - name: forwardauth + namespace: traefik + services: + - name: booklore-app + namespace: media + port: 6060 + tls: + secretName: axis-tls diff --git a/kubernetes/media/booklore/kustomization.yaml b/kubernetes/media/booklore/kustomization.yaml new file mode 100644 index 00000000..6f13d32c --- /dev/null +++ b/kubernetes/media/booklore/kustomization.yaml @@ -0,0 +1,10 @@ +--- +# yaml-language-server: $schema=https://json.schemastore.org/kustomization.json +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - release.yaml + - ingress.yaml + - pvc.yaml + - booklore.secret.sops.yaml + - backup diff --git a/kubernetes/media/booklore/pvc.yaml b/kubernetes/media/booklore/pvc.yaml new file mode 100644 index 00000000..56122cb5 --- /dev/null +++ b/kubernetes/media/booklore/pvc.yaml @@ -0,0 +1,26 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/master/persistentvolumeclaim.json +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: booklore + namespace: media +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/master/persistentvolumeclaim.json +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: booklore-mariadb + namespace: media +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi diff --git a/kubernetes/media/booklore/release.yaml b/kubernetes/media/booklore/release.yaml new file mode 100644 index 00000000..c0ff4e32 --- /dev/null +++ b/kubernetes/media/booklore/release.yaml @@ -0,0 +1,126 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/bjw-s/helm-charts/main/charts/other/app-template/schemas/helmrelease-helm-v2.schema.json +apiVersion: helm.toolkit.fluxcd.io/v2 +kind: HelmRelease +metadata: + name: booklore + namespace: media +spec: + interval: 1h + chartRef: + kind: OCIRepository + name: app-template + namespace: flux-system + values: + controllers: + booklore: + containers: + app: + image: + repository: ghcr.io/booklore-app/booklore + tag: v1.16.2 + env: + TZ: Pacific/Auckland + DATABASE_URL: jdbc:mariadb://booklore-mariadb:3306/booklore + DATABASE_USERNAME: booklore + DATABASE_PASSWORD: + valueFrom: + secretKeyRef: + name: booklore-secret + key: DATABASE_PASSWORD + probes: + liveness: &probes + enabled: true + custom: true + spec: + tcpSocket: + port: &port 6060 + initialDelaySeconds: 30 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 3 + readiness: *probes + mariadb: + pod: + securityContext: + fsGroup: 999 + fsGroupChangePolicy: OnRootMismatch + containers: + app: + image: + repository: mariadb + tag: 12.1.2@sha256:a78483ea9488eefdc32af4d4dcf116748df0bc0cdea583815e51438d8fa4d9f5 + env: + MYSQL_USER: booklore + MYSQL_DATABASE: booklore + MYSQL_PASSWORD: + valueFrom: + secretKeyRef: + name: booklore-secret + key: DATABASE_PASSWORD + MYSQL_ROOT_PASSWORD: + valueFrom: + secretKeyRef: + name: booklore-secret + key: DATABASE_ROOT_PASSWORD + probes: + liveness: &mariadb-probes + enabled: true + custom: true + spec: + exec: + command: + - sh + - -c + - mariadb-admin ping -u root -p${MYSQL_ROOT_PASSWORD} + initialDelaySeconds: 30 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 5 + readiness: *mariadb-probes + securityContext: + allowPrivilegeEscalation: false + readOnlyRootFilesystem: false + runAsNonRoot: true + runAsUser: 999 + capabilities: { drop: ["ALL"] } + service: + app: + controller: booklore + ports: + http: + port: *port + mariadb: + controller: mariadb + ports: + mysql: + port: 3306 + persistence: + config: + existingClaim: booklore + advancedMounts: + booklore: + app: + - path: /app/data + mariadb-data: + existingClaim: booklore-mariadb + advancedMounts: + mariadb: + app: + - path: /var/lib/mysql + books: + type: nfs + server: 10.0.6.1 + path: /mnt/TrueBlue/media/books + advancedMounts: + booklore: + app: + - path: /books + ingest: + type: nfs + server: 10.0.6.1 + path: /mnt/TrueBlue/media/books/ingest + advancedMounts: + booklore: + app: + - path: /bookdrop diff --git a/kubernetes/media/kustomization.yaml b/kubernetes/media/kustomization.yaml index 29d1f9b2..5b47f7d6 100644 --- a/kubernetes/media/kustomization.yaml +++ b/kubernetes/media/kustomization.yaml @@ -4,6 +4,7 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - ns.yaml + - booklore - prowlarr - qbittorrent - radarr diff --git a/kubernetes/storage/local-path-provisioner/repo.yaml b/kubernetes/storage/local-path-provisioner/repo.yaml index da6cf36e..692131ee 100644 --- a/kubernetes/storage/local-path-provisioner/repo.yaml +++ b/kubernetes/storage/local-path-provisioner/repo.yaml @@ -9,7 +9,7 @@ spec: interval: 24h url: https://github.com/rancher/local-path-provisioner ref: - tag: v0.0.33 + tag: v0.0.34 ignore: | # exclude all /*