diff --git a/kubernetes/app/media/cronjob-backup.yaml b/kubernetes/app/media/cronjob-backup.yaml index 31212f3..9d6ba2f 100644 --- a/kubernetes/app/media/cronjob-backup.yaml +++ b/kubernetes/app/media/cronjob-backup.yaml @@ -1,10 +1,10 @@ apiVersion: batch/v1 kind: CronJob metadata: - name: sonarr-db-backup + name: media-db-backup namespace: media labels: - app: sonarr-db-backup + app: media-backup spec: schedule: "0 3 * * *" concurrencyPolicy: Forbid @@ -15,11 +15,11 @@ spec: template: metadata: labels: - app: sonarr-db-backup + app: media-backup spec: restartPolicy: OnFailure initContainers: - - name: pg-dump + - name: pg-dump-sonarr image: postgres:14.21 env: - name: PGHOST @@ -42,52 +42,11 @@ spec: command: - sh - -c - - pg_dump --clean --if-exists -v > /backup/dump.sql + - pg_dump --clean --if-exists > /backup/sonarr.sql volumeMounts: - - name: backup + - name: backup-tmp mountPath: /backup - containers: - - name: rclone-upload - image: rclone/rclone:1.69 - command: - - sh - - -c - - rclone copy /backup/dump.sql b2crypt:sonarr/ --config /config/rclone/rclone.conf -v 2>&1 - volumeMounts: - - name: backup - mountPath: /backup - - name: rclone-config - mountPath: /config/rclone - readOnly: true - volumes: - - name: backup - emptyDir: {} - - name: rclone-config - secret: - secretName: rclone-config ---- -apiVersion: batch/v1 -kind: CronJob -metadata: - name: radarr-db-backup - namespace: media - labels: - app: radarr-db-backup -spec: - schedule: "0 3 * * *" - concurrencyPolicy: Forbid - successfulJobsHistoryLimit: 3 - failedJobsHistoryLimit: 3 - jobTemplate: - spec: - template: - metadata: - labels: - app: radarr-db-backup - spec: - restartPolicy: OnFailure - initContainers: - - name: pg-dump + - name: pg-dump-radarr image: postgres:14.21 env: - name: PGHOST @@ -110,26 +69,70 @@ spec: command: - sh - -c - - pg_dump --clean --if-exists -v > /backup/dump.sql + - pg_dump --clean --if-exists > /backup/radarr.sql volumeMounts: - - name: backup + - name: backup-tmp mountPath: /backup - containers: - - name: rclone-upload - image: rclone/rclone:1.69 + - name: pg-dump-seerr + image: postgres:14.21 + env: + - name: PGHOST + value: seerr-db + - name: PGUSER + valueFrom: + secretKeyRef: + name: seerr-credentials + key: SEERR_DB_USER + - name: PGPASSWORD + valueFrom: + secretKeyRef: + name: seerr-credentials + key: SEERR_DB_PASSWORD + - name: PGDATABASE + valueFrom: + secretKeyRef: + name: seerr-credentials + key: SEERR_DB_NAME command: - sh - -c - - rclone copy /backup/dump.sql b2crypt:radarr/ --config /config/rclone/rclone.conf -v 2>&1 + - pg_dump --clean --if-exists > /backup/seerr.sql volumeMounts: - - name: backup + - name: backup-tmp mountPath: /backup - - name: rclone-config - mountPath: /config/rclone + containers: + - name: resticprofile + image: creativeprojects/resticprofile:0.32.0 + command: + - sh + - -c + - | + resticprofile -c /secrets/profiles.yaml -n sonarr-db backup + resticprofile -c /secrets/profiles.yaml -n sonarr-db copy + resticprofile -c /secrets/profiles.yaml -n radarr-db backup + resticprofile -c /secrets/profiles.yaml -n radarr-db copy + resticprofile -c /secrets/profiles.yaml -n seerr-db backup + resticprofile -c /secrets/profiles.yaml -n seerr-db copy + env: + - name: B2_ACCOUNT_ID + valueFrom: + secretKeyRef: + name: media-backup-config + key: B2_ACCOUNT_ID + - name: B2_ACCOUNT_KEY + valueFrom: + secretKeyRef: + name: media-backup-config + key: B2_ACCOUNT_KEY + volumeMounts: + - name: secrets + mountPath: /secrets readOnly: true + - name: backup-tmp + mountPath: /backup volumes: - - name: backup - emptyDir: {} - - name: rclone-config + - name: secrets secret: - secretName: rclone-config + secretName: media-backup-config + - name: backup-tmp + emptyDir: {} diff --git a/kubernetes/app/media/networkpolicy.yaml b/kubernetes/app/media/networkpolicy.yaml index 06cccef..f19dc0a 100644 --- a/kubernetes/app/media/networkpolicy.yaml +++ b/kubernetes/app/media/networkpolicy.yaml @@ -52,7 +52,7 @@ spec: app: sonarr - podSelector: matchLabels: - app: sonarr-db-backup + app: media-backup --- # radarr-db: only reachable from radarr and backup jobs apiVersion: networking.k8s.io/v1 @@ -73,7 +73,7 @@ spec: app: radarr - podSelector: matchLabels: - app: radarr-db-backup + app: media-backup --- # Allow prowlarr to receive connections from sonarr and radarr apiVersion: networking.k8s.io/v1 @@ -169,7 +169,7 @@ spec: matchLabels: app: jellyfin --- -# seerr-db: only reachable from seerr +# seerr-db: only reachable from seerr and backup jobs apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: @@ -186,3 +186,34 @@ spec: - podSelector: matchLabels: app: seerr + - podSelector: + matchLabels: + app: media-backup +--- +# Allow backup pods egress to Synology (rest-server), B2, DNS, and DB +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: allow-backup-egress + namespace: media +spec: + podSelector: + matchLabels: + app: media-backup + policyTypes: + - Egress + egress: + - ports: + - port: 53 + protocol: UDP + - port: 53 + protocol: TCP + - ports: + - port: 8888 + protocol: TCP + - ports: + - port: 443 + protocol: TCP + - ports: + - port: 5432 + protocol: TCP diff --git a/kubernetes/app/media/secret-backup.sops.yaml b/kubernetes/app/media/secret-backup.sops.yaml new file mode 100644 index 0000000..a9e2166 --- /dev/null +++ b/kubernetes/app/media/secret-backup.sops.yaml @@ -0,0 +1,26 @@ +apiVersion: v1 +kind: Secret +metadata: + name: media-backup-config + namespace: media +stringData: + profiles.yaml: ENC[AES256_GCM,data:FvqC4eyDKTqy+rCcuq5XiAcOF6oVFGVrsPKY0ElwMVqhsxTxdbGmfoeB6tjvOaz4IS0MyM7hekU4ydGCQN+O9O97eazNj2QIrmjw354Ckt+k/5R+i61jua96ErVnJef9RzrhfW1L+4gV3nYTx4oy6YVGoGk0FDpCuD98SR0TGWxbk+HOJ7BN7QZ91GPNre8G4SrizAoTIkYUmfQK/h8XvKhgScLdAZf4f9UDfW2bra9oekQc1EzzA33XeeOxuWr7lTeTG7/EIJCijtFmu+XdAvxWHgQ6S7breHGcAbyRtXF/ZSdPxtU/4y9RCxDmcd4tNhmP9b0QOaBeo6AAqq7epu7SC/dXHriOROJJ0orF88OVX+ptrP+3OwFE3WyuDCTcoOFoznXdGii+CHX7DJRnnsY3Q4HAL3jxOSGmtqauvoB6hMVO3l45gMG/DRJofHTJbIXZY08fw27cukeJlh0cWKyA+/KTPYI/V18OdMNfKrTuQ6rrpD29j6xbmI0m4Ho9FbeInatDtix21JJ2EpFEtBi3RrCeDXk0uqPU1eC7buUHdVQ3VO+01KLGrMIaVx5taP+4tclzdzbatEZ3hjI8u0g84jMJUryG0yjFpqAuZLqwFRuYzCALyWXtfj8aQt3+7ljEXaf8Ho2Pq3xDJAz1u7NArci7CYOXHHtJXINhgVEyFI+LTtkphdMP39k6rZ63KG7HISjzH1Fchqqzl8FJj6wyTIGLK2PoSizjBNoKO1bc3mMtbM+/x4MV5tYGOVzbQ9z9xqutEXoUZaBat7fWdKIMK4TsdOcrQt0x65Sa5/AewyGcHJh2yq2QgvaCPKzT6pY+88NGoWGUeqB62GO/nDybWFUPk1rdv2hdCwKIuLjbxxP5P123VOeOdfodKRqIjGZq97lZLiccCObrW9WvOuAKnDTL3s0fWa5zmYM19xJaq/Iwg9GyjUJMRhRaTdrttaOMYle2Yt+E0VW4ETGEG/3PwH7M/FzjEyGn4FTjYxbxcmkJha75JX3L3Q6bb5x9bIV6s0uDvptX3pKlw2431TUaWDkuJ+ZzpcLJwFZvNJ40maF3bI+LC9abHYQHtIxtPDF6EI70G3paO0UVItpd33+J92X/qiCFCTasdjzAr+HqGQ1SepkV74Puj/sIKs+6f1Sot+i22USXASGdaD0F/IqpwbgJXufbiYSrRdVw/EgZ7WuzGme0gL1AW7lchw0jBcNA7T2dKbVeuhmN3hUHe6rCCAS+mmBg+KxybXH9UJabfe9N7XYzjCeZ5afmSn663UxCq5V3wC0qh8edLih41XYTAMOw2ytlBWxZsVQE8mwTJRQrXDZrj3aB3Xc10vmj+mlma38lfz4ghGb3AqAFtdALJyqYeBxx1Wan6KA2tpWR39hCj1Jj3dPlAZc/ZXcs/zQJTsf3ohVqjBJD7s/42jp5wTO9lEvPESyekYsvaS82gSSuAJ57K0Yvbx278jciHyjX6vhi1uzdXFep0TPjQ3/rBf8PgngOyEjWV216C7dBLry0ou8B3HJElqItFuchtBVOHXvFY4B55OzzEaDJJ2eWFW7LZKS2UO12j/xFzfSdx2UdGkGUuJ9DjpvRdLB58HtbSDjclECvmyLQ7iRN7Q0W+7ei/aSWj/3t3ZC01IoCrj4arg4JlrjtC4VYxpKI4hyhX1M5ibdw8J3rOX/KqBtFBwoEiQgvSP5YxD1sfjwPRelaMgUHO8n6eXrfNTA0X2LJB++5B6nDaxTmNEq9eVu9L/kUo/WuE59UulRtkYs/ClP5zTclqUKdTVkPnNRQV9dcZOCjuiSpyDTIOlxwUR3I/7xRVP7B33CCgkXOWUISZb98RmQOJFkBPsXqiyRYVgHfn/SbarrvqvWF3XXNcQ+at2taYGF/WJB1Y2B+oFTppC+mNHfxmklJKwcIcwk39Q==,iv:hP5emno4sxU0g+hcCpfXtf8lhxhk7NDCjwcq5lSjmQ8=,tag:K3bNiO9BnGnMRqvM7E9TfQ==,type:str] + restic-password-nas: ENC[AES256_GCM,data:OfCOmmU85bnWWFAAir90+Vj3d0Vh0bUqNICQg+2aCksd5aiVl3M+OUXZaVhQQtukVd2Mw22y4Die3zO7wlzXAQ==,iv:M7SuVZfm541Rvm7m3Gh8EkDgQ3kU2gKIMJZ+u1s+xf8=,tag:5EwXbugyG+idxt12sJXNhQ==,type:str] + restic-password-b2: ENC[AES256_GCM,data:dSt6fWJknKPslHKrjfaCLRI+r4K2lhz9hYYE4CKcEaTutxFNBfAoj70abwtIj1hoLv0SzyZUWtxrIrZCILR/yw==,iv:5tRzv0KQMqbw5zAx9eBGGxngiowOxLYSMf3vsvoRcVA=,tag:2utz3OFpup4/NK/sWKzKVg==,type:str] + B2_ACCOUNT_ID: ENC[AES256_GCM,data:os8HLCWv9ujoZWLFEuhondgCVvRwMNBlHQ==,iv:bQNshEL7pFF/+1hjStaRo8Aa2uzVmai3L+5wFLoC8BE=,tag:7JGG/ocByA83E1ncNoZEXw==,type:str] + B2_ACCOUNT_KEY: ENC[AES256_GCM,data:+CNHqdPcTqHONYOY4DYJZ9G+mi3RHfX8hxzLXuSemw==,iv:Ojx0XDGUdvt+9UvEopQLpqQhoCmAzlz4kZTdYtq+Qcs=,tag:lYq7T2Q+wvycnU1JcNpvZQ==,type:str] +sops: + age: + - recipient: age1zffnskvuezntkk703a0pyxsd5m8vx2hm33dr47wdfy8mn4fdw4sqgw0jgc + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBlQnBxVFhqY3l4U1hLZlhC + RWE5RHlIQXo3U2FqZVg3d2ZpRDhmbk1XSkI4CmxFcEt5VjBPZTNGQlRDYmIxMU91 + VVphNE5TcUdnK29mcXVIc0VYaFkwWVEKLS0tIExOWTdjUGd5eHlBOVJTcXJHNFFQ + cER0MEpOb1J2Y1ZYQWlwT3A3dkdkZ1kK0PhrZsURFuA8c4rMVRE/jLiHBkxQ65ds + iVqJJHjuiOuOed5Wcr4FbAaghKIsc5AiZO06Zsj+pfpt5aQGdcettw== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2026-03-22T09:08:31Z" + mac: ENC[AES256_GCM,data:veSRpp9RZatCrGkS5w/OPrPz1Av2SZQ+M5d/MlNYFraoMFluhejAQIt3vh+mO3Bd1hxPm3PPZzxHvLwpVH10lczxD9Uvc+LhA7FWrhr0BWrjbN5WKwhP3T3v/VFfkJctPi9ITOd/aGkusWfZ9ghVWnW4oe7RXxtCZhsh141QBHs=,iv:JPvqfB6T9DGFFsNrSGbrlaHv0UhQJB005Uj5tJgBVJQ=,tag:ih/gh7+FORz+CfP/nKahmA==,type:str] + encrypted_regex: ^(data|stringData|email)$ + version: 3.12.2 diff --git a/kubernetes/app/media/secret-rclone.sops.yaml b/kubernetes/app/media/secret-rclone.sops.yaml deleted file mode 100644 index 2bc2e37..0000000 --- a/kubernetes/app/media/secret-rclone.sops.yaml +++ /dev/null @@ -1,22 +0,0 @@ -apiVersion: v1 -kind: Secret -metadata: - name: rclone-config - namespace: media -stringData: - rclone.conf: ENC[AES256_GCM,data:aTthn7P4ESDNtqRDW+R7RI1e0B2ftgHg6406vqHtsUPW25SEaNUiGuWlSY/BoiCuagBBM6TM+Gow2XrtTQauPND1irb5D5xyhcphFM5uF+8dE4qNJV4J09NjBd7Lzdp1udej2BJoRAeCwgAEwq8857log4TRwrbGzNrfRKOPrz7D3okBQP2hyxfZ85dlQH0ojUEodPi4U3mpwgXc8Kb0JhziZc1KjHbIzZ1/GkaKcYLI8Rl8q7esdqxnrA51sssWVkmSC4zoiPjwPwUWifSNMb7KC8L8bXRIVdpP8/f4rDyYJoa9uC7GW44nYIBVfLJrM015ZtpSzh05/IS9ev6N2REkjudLmOwwvOw52s8dKh1IRXixcV1JPk3knam2jnezYcnvmLYgyReryZFRFFP0xgaVOmZa5is=,iv:zrFW+ssUTt8T14TZz5n30rVr792FiDYxr89BdIIxn1c=,tag:XVtMvVbuo1vQU3hp8VTnHQ==,type:str] -sops: - age: - - recipient: age1zffnskvuezntkk703a0pyxsd5m8vx2hm33dr47wdfy8mn4fdw4sqgw0jgc - enc: | - -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBlR1BZak5zZWdmZ2g3YktL - Q1lqZzVTWEtpVGhqSk9WamxmRm1WSFNnNkN3CjNzMEtyMnh6bEtjbW9BY0NGZm1G - dnMyOW5DVFpZT3JMVGNxVW9raWZkSzAKLS0tIHNHMXdZTlhXYWFRYmYvS21tQUps - MXB5QVkyZDZlQWlMd1NqdEl1V0g0d00KMSyMsWeN5oEx3s5Zh3x9MHiRywFvRuZm - lZEdl0ho90lJ8m+rPHIT+pI7vBMHLB3mJiBfIVR4KJQRUkhPjGSMRQ== - -----END AGE ENCRYPTED FILE----- - lastmodified: "2026-02-22T16:12:51Z" - mac: ENC[AES256_GCM,data:gUyVh53pNCUHfW9+pww9sQ10kL/U92N0AV1Ys+fKt3W/wq4msyXLErQVVJBrHoPQo/ncKUMbCUGvMNHsUnJT7H8g8LuqMUxLbZhFju6rLHrgg+1hIKeA1cStOlTgBTQLbXA2gfsclQQ+nAf9zeAsgz3MfuK8PEHs3U2O8cSrtP4=,iv:fQd6lggTw3OI+8lZ1BOZvD+lLt7p5wlelf59sFsQHZE=,tag:4V8do9D3IiNPDDR5GRLXOg==,type:str] - encrypted_regex: ^(data|stringData|email)$ - version: 3.11.0