diff --git a/apps/gitea/kustomization.yaml b/apps/gitea/kustomization.yaml index ab46666..23069ed 100755 --- a/apps/gitea/kustomization.yaml +++ b/apps/gitea/kustomization.yaml @@ -7,6 +7,7 @@ resources: - gitea-ingress.yaml - runner-pvc.yaml - runner-deployment.yaml +- ./restic generators: - secret-generator.yaml diff --git a/apps/gitea/restic/backup.sh b/apps/gitea/restic/backup.sh new file mode 100644 index 0000000..e6e5bc0 --- /dev/null +++ b/apps/gitea/restic/backup.sh @@ -0,0 +1,22 @@ +#!/bin/sh + +# Set up colors +GREEN='\033[0;32m' +NC='\033[0m' + +echo -e "\n${GREEN}`date` - Starting backup...${NC}\n" + +restic unlock + +# Gitea +echo -e "\n${GREEN}`date` - Backing up Gitea...${NC}\n" +gitea=$(kubectl get deploy -n gitea -l app=gitea -o name --no-headers=true) +kubectl scale -n gitea --replicas=0 $gitea +restic backup /gitea +restic backup /backup/postgres_backup.dump +kubectl scale -n gitea --replicas=1 $gitea + +# Forget and prune +echo -e "\n${GREEN}`date` - Running forget and prune...${NC}\n" +restic forget --prune --keep-daily 7 --keep-weekly 2 +echo -e "\n${GREEN}`date` - Backup finished.${NC}\n" diff --git a/apps/gitea/restic/cronjob.yaml b/apps/gitea/restic/cronjob.yaml new file mode 100644 index 0000000..eb7a21e --- /dev/null +++ b/apps/gitea/restic/cronjob.yaml @@ -0,0 +1,58 @@ +apiVersion: batch/v1 +kind: CronJob +metadata: + name: restic-backup-cronjob + namespace: gitea +spec: + schedule: "0 2 * * *" # Cron expression for running daily at 2 AM + jobTemplate: + spec: + template: + spec: + + serviceAccountName: restic-sa + + volumes: + - name: gitea-data + persistentVolumeClaim: + claimName: gitea-shared-storage + - name: restic-backup-vol + persistentVolumeClaim: + claimName: restic-backup-vol + - name: backup-script-vol + configMap: + name: restic-backup-script + + initContainers: + - name: postgres-dump-init + image: bitnami/postgresql:15.3.0-debian-11-r24 + command: ["/bin/sh", "-c"] + args: ["pg_dump -h gitea-postgresql -p 5432 -U gitea gitea -Fc > /backup/postgres_backup.dump"] + env: + - name: PGPASSWORD + valueFrom: + secretKeyRef: + name: gitea-postgresql + key: postgres-password + volumeMounts: + - name: restic-backup-vol + mountPath: /backup + + containers: + - name: restic-container + hostname: restic-cronjob + image: git.namesny.com/cluster/restic:latest + imagePullPolicy: Always + command: ["/bin/sh", "/app/backup.sh"] + envFrom: + - secretRef: + name: restic-secret + volumeMounts: + - name: restic-backup-vol + mountPath: /backup + - name: gitea-data + mountPath: /gitea + - name: backup-script-vol + mountPath: /app + + restartPolicy: OnFailure diff --git a/apps/gitea/restic/debug-pod.yaml b/apps/gitea/restic/debug-pod.yaml new file mode 100644 index 0000000..9b68498 --- /dev/null +++ b/apps/gitea/restic/debug-pod.yaml @@ -0,0 +1,28 @@ +apiVersion: v1 +kind: Pod +metadata: + name: restic-debug-pod + namespace: gitea +spec: + serviceAccountName: restic-sa + volumes: + - name: restic-backup-vol + persistentVolumeClaim: + claimName: restic-backup-vol + - name: gitea-data + persistentVolumeClaim: + claimName: gitea-shared-storage + containers: + - name: restic-debug + image: git.namesny.com/cluster/restic:latest + command: ["/bin/sh", "-c"] + args: ["sleep infinity"] + envFrom: + - secretRef: + name: restic-secret + volumeMounts: + - name: restic-backup-vol + mountPath: /backup + - name: gitea-data + mountPath: /gitea + diff --git a/apps/gitea/restic/kustomization.yaml b/apps/gitea/restic/kustomization.yaml new file mode 100755 index 0000000..2a8b5b5 --- /dev/null +++ b/apps/gitea/restic/kustomization.yaml @@ -0,0 +1,21 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +namespace: gitea + +resources: +- service-account.yaml +- role.yaml +- role-binding.yaml +- pvc.yaml +- debug-pod.yaml +- cronjob.yaml + +generators: +- secret-generator.yaml + +configMapGenerator: +- name: restic-backup-script + namespace: gitea + files: + - ./backup.sh + diff --git a/apps/gitea/restic/pvc.yaml b/apps/gitea/restic/pvc.yaml new file mode 100755 index 0000000..67d7aaf --- /dev/null +++ b/apps/gitea/restic/pvc.yaml @@ -0,0 +1,12 @@ +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: restic-backup-vol + namespace: gitea +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 5Gi + storageClassName: retain-local-path diff --git a/apps/gitea/restic/role-binding.yaml b/apps/gitea/restic/role-binding.yaml new file mode 100644 index 0000000..f1a0a5d --- /dev/null +++ b/apps/gitea/restic/role-binding.yaml @@ -0,0 +1,13 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: restic-role-binding + namespace: gitea +subjects: +- kind: ServiceAccount + name: restic-sa + namespace: gitea +roleRef: + kind: Role + name: restic-role + apiGroup: rbac.authorization.k8s.io diff --git a/apps/gitea/restic/role.yaml b/apps/gitea/restic/role.yaml new file mode 100644 index 0000000..83e2e4f --- /dev/null +++ b/apps/gitea/restic/role.yaml @@ -0,0 +1,9 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: restic-role + namespace: gitea +rules: +- apiGroups: ["apps"] + resources: ["deployments", "deployments/scale"] + verbs: ["get", "list", "update", "patch"] diff --git a/apps/gitea/restic/secret-generator.yaml b/apps/gitea/restic/secret-generator.yaml new file mode 100644 index 0000000..636967b --- /dev/null +++ b/apps/gitea/restic/secret-generator.yaml @@ -0,0 +1,11 @@ +apiVersion: viaduct.ai/v1 +kind: ksops +metadata: + name: restic-secret-generator + annotations: + config.kubernetes.io/function: | + exec: + path: ksops +files: +- ./secret.enc.yaml + diff --git a/apps/gitea/restic/secret.enc.yaml b/apps/gitea/restic/secret.enc.yaml new file mode 100644 index 0000000..2e9af40 --- /dev/null +++ b/apps/gitea/restic/secret.enc.yaml @@ -0,0 +1,30 @@ +apiVersion: v1 +kind: Secret +metadata: + name: restic-secret + namespace: gitea +stringData: + AWS_ACCESS_KEY_ID: ENC[AES256_GCM,data:IjDw3i+8BIvA816obn5BpQBTkzo=,iv:A/CrhyIm5kljCwvneQziux36O6+SWG5Z9mOlV+mRIXQ=,tag:XVh4X8Xf587nmbDCtgazAg==,type:str] + AWS_SECRET_ACCESS_KEY: ENC[AES256_GCM,data:WdfHxdXnPOLvIOecN+WFONAEDr2Sc/r6bKQ/H9KS1BT2C9cj,iv:GCY6MaSEhu9WEsVA23hWN30Ix7x6dz/umNRsQ0jsb8I=,tag:8Qa0dvU3bq+J2S6trBDFDw==,type:str] + RESTIC_REPOSITORY: ENC[AES256_GCM,data:FZCqro3fpgQ7NJc+4ORVC2yWdqMNCLd4AjCwdolXgu5uJXq0IQ==,iv:nWttNrSvFpcj1HMOFwZNfJqVUy0esR7fVXlvidp3MlY=,tag:T0HzAZ/w83IFrvap8Gx3gg==,type:str] + RESTIC_PASSWORD: ENC[AES256_GCM,data:PjSE4FejVPW8e8e/PDtoSCsuskI=,iv:MTUMYim3obMHaYBEoEJBMEj9GMbaqdbdVV09o3ep/fw=,tag:pQ6vakVWHUdk4F/PwqpgAw==,type:str] +sops: + kms: [] + gcp_kms: [] + azure_kv: [] + hc_vault: [] + age: + - recipient: age14dgmts59tc2gv2xu9305auvu854n3pfl8vkheqzzqyrygyeequ0sjhl92v + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB2RTlocERzUmtUdnhsNHJk + SkNXZFpVdmM5Y1hnQlQzcUg1OUxNYkRiaEFZCi82MW9TbkI2VCtjMDVKYTlWTVBs + QVZMekVoT1JSQWRZV3F3SHgxOGR3a2sKLS0tIGJCd21aY05jS0xva2RmclBlQWdl + UVZSNm9pRUM3YmFFSWl3NGNUdnZOOGsKIuepNrrdgoNoOMZQ77cIrtwPTL8acahG + paE+K2EKa8pqXnAVkxORTkUYRlorKRLjiyalxrDZYsMAbCSrrtfx/A== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2024-01-30T17:21:08Z" + mac: ENC[AES256_GCM,data:mR4vi8WLLiuUY5i7NgIYHfAZcBsQ3u2Cg9TtXcFtwtDAuyy9Xzx07yeR1HC0D+YhiAu+mYAJPmk6jHZsCE2OX26sLTyvEULqDQc71sCgM8dsyl50hoZ2BsbY7o6g8D9Yks+2szuKmlxZ0nN5aHxcf+67+gotzjlBfcmLx+E1TfA=,iv:+9Kv7ZwGoMU0QBTvCgq232nHo+tjoeHTJBdOuOiqpPk=,tag:9VrOFmUFbdiPKSWnt+8z7w==,type:str] + pgp: [] + unencrypted_regex: ^(apiVersion|metadata|kind|type)$ + version: 3.8.1 diff --git a/apps/gitea/restic/service-account.yaml b/apps/gitea/restic/service-account.yaml new file mode 100644 index 0000000..9b0c685 --- /dev/null +++ b/apps/gitea/restic/service-account.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: restic-sa + namespace: gitea diff --git a/apps/gitea/secret-generator.yaml b/apps/gitea/secret-generator.yaml index bf81b2e..124ed06 100644 --- a/apps/gitea/secret-generator.yaml +++ b/apps/gitea/secret-generator.yaml @@ -10,3 +10,4 @@ files: - ./gitea-admin-secret.enc.yaml - ./renovate-bot-secret.enc.yaml - ./runner-secret.enc.yaml +