Skip to content

Commit e12dc3a

Browse files
authored
[juno-node] Feat/upload juno data file (#130)
* feat: add chart to backup juno data and upload to cloudflare r2 * feat: add chart to backup juno data and upload to cloudflare r2 - add new line at the end of file * feat: add chart to backup juno data and upload to cloudflare r2 - change readme and change typo. * feat: add chart to backup juno data and upload to cloudflare r2 - auto generate README.md and helm-docs v1.13.1 changed. * Fix: change dynamic name * Fix: enhance to replace pod with job. * Fix: remove tail space * Fix: add space * Fix: add space to correct syntax error * Fix: change rclone's secret from local file to secret managers * Fix: change schedule * Fix: add blank line and add externalsecret-common.yaml * Fix: add relative path ofdataFromKey * Fix: add relative path ofdataFromKey * Fix: change DB size * Revert "Fix: change DB size" This reverts commit 9e58710. * Fix: change DB size -v * Fix: test purpose to exclude sst files * Fix: test purpose to exclude sst files * Fix: test purpose to exclude sst files * Update externalsecret-common.yaml Signed-off-by: PhilexWong <[email protected]> * Update externalsecret-common.yaml Signed-off-by: PhilexWong <[email protected]> * Update externalsecret-common.yaml Signed-off-by: PhilexWong <[email protected]> * Fix: test purpose to exclude sst files - revert * Fix: rename the jar file * Fix: rename the jar file -exclude sst file for testing * feat: add retention function * feat: add retention function * feat: add retention function - add values * feat: add retention function * feat: add retention function * Remove -z param during tar package * Fix: Remove -z param during tar package * Fix: add values.yaml files * Fix: Remove -z param during tar package * Fix: Remove -z param during tar package * Fix: add values.yaml files * Fix: change format. --------- Signed-off-by: PhilexWong <[email protected]>
1 parent 80f0af7 commit e12dc3a

File tree

5 files changed

+376
-5
lines changed

5 files changed

+376
-5
lines changed

charts/juno-node/Chart.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
apiVersion: v2
22
name: juno-chart
3-
version: 0.1.4
3+
version: 0.1.5
44
appVersion: "1"
55
description: A Helm chart for deploying Juno service
66
maintainers:

charts/juno-node/README.md

+12-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# juno-chart
22

3-
![Version: 0.1.4](https://img.shields.io/badge/Version-0.1.4-informational?style=flat-square) ![AppVersion: 1](https://img.shields.io/badge/AppVersion-1-informational?style=flat-square)
3+
![Version: 0.1.5](https://img.shields.io/badge/Version-0.1.5-informational?style=flat-square) ![AppVersion: 1](https://img.shields.io/badge/AppVersion-1-informational?style=flat-square)
44

55
A Helm chart for deploying Juno service
66

@@ -27,6 +27,15 @@ A Helm chart for deploying Juno service
2727
| args.--ws | string | `"true"` | |
2828
| args.--ws-host | string | `"0.0.0.0"` | |
2929
| args.--ws-port | string | `"6061"` | |
30+
| backupJunoDataJob.backupSchedule | string | `"*/20 * * * *"` | |
31+
| backupJunoDataJob.cleanupSchedule | string | `"*/40 * * * *"` | |
32+
| backupJunoDataJob.dataSource | string | `"juno-sepolia-pv-ssd-juno-sepolia-0"` | |
33+
| backupJunoDataJob.enabled | bool | `true` | |
34+
| backupJunoDataJob.endpoint | string | `"https://12345543.r2.cloudflarestorage.com"` | |
35+
| backupJunoDataJob.key | string | `"key-1234"` | |
36+
| backupJunoDataJob.network | string | `"sepolia"` | |
37+
| backupJunoDataJob.secret | string | `"secret-12345"` | |
38+
| backupJunoDataJob.storageSize | string | `"200Gi"` | |
3039
| batchjob.enabled | bool | `false` | |
3140
| batchjob.schedule | string | `"* */1 * * *"` | |
3241
| deployment.healthCheck.enabled | bool | `false` | |
@@ -84,6 +93,7 @@ A Helm chart for deploying Juno service
8493
| serviceAccount.enabled | bool | `false` | |
8594
| serviceAccount.gcpServiceAccount | string | `"[email protected]"` | |
8695
| serviceAccount.name | string | `"juno-pgo"` | |
96+
| svc.externalTrafficPolicy | string | `""` | |
8797
| svc.globalStaticInternalIpName | string | `""` | |
8898
| svc.globalStaticIpName | string | `""` | |
8999
| svc.ingress.enabled | bool | `true` | |
@@ -155,4 +165,4 @@ A Helm chart for deploying Juno service
155165
| taintsToleration.tolerations.network | string | `"juno"` | |
156166

157167
----------------------------------------------
158-
Autogenerated from chart metadata using [helm-docs v1.12.0](https://github.com/norwoodj/helm-docs/releases/v1.12.0)
168+
Autogenerated from chart metadata using [helm-docs v1.13.1](https://github.com/norwoodj/helm-docs/releases/v1.13.1)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{{- if .Values.secret }}
2+
{{- with .Values.secret.data }}
3+
apiVersion: external-secrets.io/v1beta1
4+
kind: ExternalSecret
5+
metadata:
6+
name: {{ $.Values.deployment.projectName }}-external-secret
7+
namespace: {{ $.Values.deployment.namespace }}
8+
spec:
9+
refreshInterval: {{ $.Values.secret.data.refreshInterval }}
10+
secretStoreRef:
11+
name: {{ $.Values.secret.data.secretStoreName }}
12+
kind: {{ $.Values.secret.data.secretStoreKind }}
13+
target:
14+
name: {{ $.Values.secret.data.targetName }}
15+
creationPolicy: {{ $.Values.secret.data.targetCreationPolicy }}
16+
dataFrom:
17+
- extract:
18+
key: {{ $.Values.secret.data.dataFromKey }} # name of the secret in secret manager (GCP secret manager)
19+
{{- end }}
20+
{{- end }}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,309 @@
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

Comments
 (0)