1+ {{- if .Values.backupJunoDataJob.enabled -}}
2+ # Service Account for the Backup Job
3+ apiVersion : v1
4+ kind : ServiceAccount
5+ metadata :
6+ name : {{ .Values.deployment.namespace }}-backup-junodata-sa
7+ namespace : {{ .Values.deployment.namespace }}
8+ ---
9+
10+ # Role for Backup Job with necessary permissions
11+ apiVersion : rbac.authorization.k8s.io/v1
12+ kind : Role
13+ metadata :
14+ name : {{ .Values.deployment.namespace }}-backup-junodata-role
15+ namespace : {{ .Values.deployment.namespace }}
16+ rules :
17+ - apiGroups : [ "", "apps","batch"]
18+ resources : ["pods", "jobs", "persistentvolumeclaims"]
19+ verbs : ["get", "list","create", "update", "patch", "delete"]
20+ ---
21+ # RoleBinding to bind Role with ServiceAccount
22+ apiVersion : rbac.authorization.k8s.io/v1
23+ kind : RoleBinding
24+ metadata :
25+ name : {{ .Values.deployment.namespace }}-backup-junodata-rolebinding
26+ namespace : {{ .Values.deployment.namespace }}
27+ subjects :
28+ - kind : ServiceAccount
29+ name : {{ .Values.deployment.namespace }}-backup-junodata-sa
30+ namespace : {{ .Values.deployment.namespace }}
31+ roleRef :
32+ apiGroup : rbac.authorization.k8s.io
33+ kind : Role
34+ name : {{ .Values.deployment.namespace }}-backup-junodata-role
35+ ---
36+
37+ # Secret to store R2 Cloud credentials
38+ apiVersion : v1
39+ kind : Secret
40+ metadata :
41+ name : {{ .Values.deployment.namespace }}-rclone-config
42+ namespace : {{ .Values.deployment.namespace }}
43+ stringData :
44+ rclone.conf : |
45+ [R2]
46+ type = s3
47+ provider = Cloudflare
48+ env_auth = true
49+ endpoint = https://d1cc7d59ae8f8dc2b1aa530c41b5c6ec.r2.cloudflarestorage.com
50+ ---
51+ # ConfigMap for cloning disk manifest
52+ apiVersion : v1
53+ kind : ConfigMap
54+ metadata :
55+ name : {{ .Values.deployment.namespace }}-cloning-disk-manifest
56+ namespace : {{ .Values.deployment.namespace }}
57+ data :
58+ cloning-disk-manifest.yaml : |
59+ apiVersion: v1
60+ kind: PersistentVolumeClaim
61+ metadata:
62+ name: {{ .Values.deployment.namespace }}-pv-ssd-snapshot
63+ namespace: {{ .Values.deployment.namespace }}
64+ spec:
65+ dataSource:
66+ name: {{ .Values.backupJunoDataJob.dataSource }}
67+ kind: PersistentVolumeClaim
68+ accessModes:
69+ - ReadWriteOnce
70+ storageClassName: premium-rwo
71+ resources:
72+ requests:
73+ storage: {{ .Values.backupJunoDataJob.storageSize }}
74+ ---
75+ apiVersion: v1
76+ kind: PersistentVolumeClaim
77+ metadata:
78+ name: {{ .Values.deployment.namespace }}-juno-data-backup-pvc
79+ namespace: {{ .Values.deployment.namespace }}
80+ spec:
81+ accessModes:
82+ - ReadWriteOnce
83+ storageClassName: premium-rwo
84+ resources:
85+ requests:
86+ storage: {{ .Values.backupJunoDataJob.storageSize }}
87+ ---
88+ # ConfigMap for cloning juno manifest
89+ apiVersion : v1
90+ kind : ConfigMap
91+ metadata :
92+ name : {{ .Values.deployment.namespace }}-cloning-juno-manifest
93+ namespace : {{ .Values.deployment.namespace }}
94+ data :
95+ cloning-juno-manifest.yaml : |
96+ apiVersion: batch/v1
97+ kind: Job
98+ metadata:
99+ name: {{ .Values.deployment.namespace }}-juno-data-archival-job
100+ namespace: {{ .Values.deployment.namespace }}
101+ spec:
102+ ttlSecondsAfterFinished: 60
103+ template:
104+ spec:
105+ serviceAccountName: {{ .Values.deployment.namespace }}-backup-junodata-sa
106+ volumes:
107+ - name: juno-data-volume
108+ persistentVolumeClaim:
109+ claimName: {{ .Values.deployment.namespace }}-pv-ssd-snapshot
110+ - name: {{ .Values.deployment.namespace }}-rclone-config
111+ secret:
112+ secretName: {{ .Values.deployment.namespace }}-rclone-config
113+ - name: tar-backup-volume
114+ persistentVolumeClaim:
115+ claimName: {{ .Values.deployment.namespace }}-juno-data-backup-pvc
116+ initContainers:
117+ - name: juno-archival-tar
118+ image: busybox
119+ command: ["/bin/sh", "-c"]
120+ args:
121+ - |
122+ rm -rf /mnt/juno-tar-backup/*.tar &&
123+ rm -rf /mnt/data/*.tar &&
124+ tar -cf /mnt/juno-tar-backup/juno_{{ .Values.backupJunoDataJob.network }}_{{ .Values.deployment.imagetag }}_$(date +\%Y\%m\%d).tar --exclude=./lost+found -C /mnt/data . && sleep 10
125+ volumeMounts:
126+ - name: juno-data-volume
127+ mountPath: /mnt/data
128+ - name: tar-backup-volume
129+ mountPath: /mnt/juno-tar-backup
130+ containers:
131+ - name: rclone-upload-container
132+ image: rclone/rclone:latest
133+ env:
134+ - name: AWS_ACCESS_KEY_ID
135+ valueFrom:
136+ secretKeyRef:
137+ name: {{ .Values.secret.data.targetName }}
138+ key: r2_access_key_id
139+ - name: AWS_SECRET_ACCESS_KEY
140+ valueFrom:
141+ secretKeyRef:
142+ name: {{ .Values.secret.data.targetName }}
143+ key: r2_secret_access_key
144+ command: ["/bin/sh", "-c"]
145+ args:
146+ - |
147+ apk add --no-cache curl &&
148+ apk add --no-cache jq &&
149+ latestBlockNumber=$(curl --location '{{ .Values.backupJunoDataJob.junoFreeEndpoint }}/{{ .Values.backupJunoDataJob.network }}-juno' --header 'Content-Type: application/json' --data '{ "jsonrpc": "2.0","method": "starknet_blockNumber", "id": 1}' | jq '.result') &&
150+ echo "latestBlockNumber is $latestBlockNumber" &&
151+ mv /mnt/juno-tar-backup/juno_{{ .Values.backupJunoDataJob.network }}_{{ .Values.deployment.imagetag }}*.tar /mnt/juno-tar-backup/juno_{{ .Values.backupJunoDataJob.network }}_{{ .Values.deployment.imagetag }}_$latestBlockNumber.tar &&
152+ echo "/mnt/juno-tar-backup/juno_{{ .Values.backupJunoDataJob.network }}_{{ .Values.deployment.imagetag }}_$latestBlockNumber.tar" &&
153+ rclone copy /mnt/juno-tar-backup/*.tar R2:/{{ .Values.backupJunoDataJob.bucketName }}/{{ .Values.backupJunoDataJob.network }}
154+ volumeMounts:
155+ - name: {{ .Values.deployment.namespace }}-rclone-config
156+ mountPath: /config/rclone
157+ - name: tar-backup-volume
158+ mountPath: /mnt/juno-tar-backup
159+ restartPolicy: OnFailure
160+ ---
161+ # CronJob for Backup Task
162+ apiVersion : batch/v1
163+ kind : CronJob
164+ metadata :
165+ name : {{ .Values.deployment.namespace }}-backup-junodata-cronjob
166+ namespace : {{ .Values.deployment.namespace }}
167+ spec :
168+ schedule : " {{ .Values.backupJunoDataJob.backupSchedule }}"
169+ concurrencyPolicy : Forbid
170+ successfulJobsHistoryLimit : 1
171+ failedJobsHistoryLimit : 1
172+ jobTemplate :
173+ spec :
174+ completions : 1
175+ ttlSecondsAfterFinished : 30
176+ template :
177+ spec :
178+ serviceAccountName : {{ .Values.deployment.namespace }}-backup-junodata-sa
179+ restartPolicy : Never
180+ initContainers :
181+ - name : copy-disk-kubectl-container
182+ image : bitnami/kubectl:latest
183+ command : ["/bin/sh"]
184+ args : ["-c", "kubectl apply -f /cloning-disk-manifest/cloning-disk-manifest.yaml"]
185+ volumeMounts :
186+ - name : cloning-disk-manifest-volume
187+ mountPath : /cloning-disk-manifest
188+ containers :
189+ - name : clone-juno-kubectl-container
190+ image : bitnami/kubectl:latest
191+ command : ["/bin/sh"]
192+ args : ["-c", "kubectl apply -f /cloning-juno-manifest/cloning-juno-manifest.yaml"]
193+ volumeMounts :
194+ - name : cloning-juno-manifest-volume
195+ mountPath : /cloning-juno-manifest
196+ volumes :
197+ - name : cloning-disk-manifest-volume
198+ configMap :
199+ name : {{ .Values.deployment.namespace }}-cloning-disk-manifest
200+ - name : cloning-juno-manifest-volume
201+ configMap :
202+ name : {{ .Values.deployment.namespace }}-cloning-juno-manifest
203+ ---
204+ # CronJob for Cleaning up Completed Pods and PVCs
205+ apiVersion : batch/v1
206+ kind : CronJob
207+ metadata :
208+ name : {{ .Values.deployment.namespace }}-delete-used-pvc
209+ namespace : {{ .Values.deployment.namespace }}
210+ spec :
211+ schedule : " {{ .Values.backupJunoDataJob.cleanupSchedule }}"
212+ concurrencyPolicy : Forbid
213+ successfulJobsHistoryLimit : 1
214+ failedJobsHistoryLimit : 1
215+ jobTemplate :
216+ spec :
217+ completions : 1
218+ ttlSecondsAfterFinished : 30
219+ template :
220+ spec :
221+ serviceAccountName : {{ .Values.deployment.namespace }}-backup-junodata-sa
222+ restartPolicy : OnFailure
223+ containers :
224+ - name : kubectl-container
225+ image : bitnami/kubectl:latest
226+ command :
227+ - " /bin/bash"
228+ - " -c"
229+ - |
230+ # Delete PVC if not used
231+ describe_output=$(kubectl describe pvc {{ .Values.deployment.namespace }}-pv-ssd-snapshot)
232+ if echo "$describe_output" | grep -q "Used By:[[:space:]]*<none>"; then
233+ echo "Deleting {{ .Values.deployment.namespace }}-pv-ssd-snapshot..."
234+ kubectl delete pvc {{ .Values.deployment.namespace }}-pv-ssd-snapshot
235+ sleep 30
236+ fi
237+ describe_output=$(kubectl describe pvc {{ .Values.deployment.namespace }}-juno-data-backup-pvc)
238+ if echo "$describe_output" | grep -q "Used By:[[:space:]]*<none>"; then
239+ echo "Deleting {{ .Values.deployment.namespace }}-juno-data-backup-pvc..."
240+ kubectl delete pvc {{ .Values.deployment.namespace }}-juno-data-backup-pvc
241+ sleep 30
242+ fi
243+ ---
244+ # CronJob for Cleaning up Completed Pods and PVCs
245+ apiVersion : batch/v1
246+ kind : CronJob
247+ metadata :
248+ name : {{ .Values.deployment.namespace }}-r2-retention-cronjob
249+ namespace : {{ .Values.deployment.namespace }}
250+ spec :
251+ schedule : " 0 0 * * */2"
252+ jobTemplate :
253+ spec :
254+ completions : 1
255+ ttlSecondsAfterFinished : 30
256+ template :
257+ spec :
258+ restartPolicy : OnFailure
259+ containers :
260+ - name : {{ .Values.deployment.namespace }}-r2-retention
261+ image : ubuntu:latest
262+ env :
263+ - name : RETENTION_LIMIT
264+ value : " {{ .Values.backupJunoDataJob.retentionLimit }}"
265+ - name : API_TOKEN
266+ valueFrom :
267+ secretKeyRef :
268+ name : {{ .Values.secret.data.targetName }}
269+ key : r2_api_token
270+ - name : ACCOUNT_ID
271+ value : " d1cc7d59ae8f8dc2b1aa530c41b5c6ec"
272+ - name : BUCKET_NAME
273+ value : " {{ .Values.backupJunoDataJob.bucketName }}"
274+ command :
275+ - /bin/sh
276+ - -c
277+ - |
278+ #!/bin/sh
279+ mkdir -p /var/lib/apt/lists/partial
280+ apt-get update && apt-get install -y curl jq
281+ # Constants
282+ API_TOKEN="$API_TOKEN"
283+ RETENTION_LIMIT="$RETENTION_LIMIT"
284+ ACCOUNT_ID="$ACCOUNT_ID"
285+ BUCKET_NAME="$BUCKET_NAME"
286+
287+ # Construct the Cloudflare API URL with account ID and bucket name
288+ CLOUDFLARE_API_URL="https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/r2/buckets/$BUCKET_NAME/objects?prefix={{ .Values.backupJunoDataJob.network }}/"
289+ # Get the list of objects with the specified prefix
290+ objects=$(curl -s -X GET "$CLOUDFLARE_API_URL" -H "Authorization: Bearer $API_TOKEN" | jq -r '.result')
291+
292+ # Check if the number of objects exceeds the retention limit
293+ object_count=$(echo "$objects" | jq length)
294+ echo "total backup number is $object_count"
295+
296+ if [ "$object_count" -le "$RETENTION_LIMIT" ]; then
297+ echo "exiting...."
298+ exit 0
299+ fi
300+ delete_number=$((object_count - RETENTION_LIMIT))
301+ # Sort the objects by last_modified date and delete the oldest ones
302+ echo "$objects" | jq -r '.[] | [.key, .last_modified] | @tsv' | sort -k2 | head -n "$delete_number" | while IFS=$'\t' read -r key last_modified; do
303+ delete_url="https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/r2/buckets/$BUCKET_NAME/objects/${key}tar"
304+ echo "Deleting ${key}tar at $delete_url"
305+ delete_response=$(curl -s -X DELETE "$delete_url" -H "Authorization: Bearer $API_TOKEN")
306+ echo "Delete response: $delete_response"
307+ done
308+ ---
309+ {{- end -}}
0 commit comments