diff --git a/templates/cronjob.yaml b/templates/cronjob.yaml new file mode 100644 index 0000000..4a3f5a2 --- /dev/null +++ b/templates/cronjob.yaml @@ -0,0 +1,203 @@ +{{- if .Values.backup.enabled }} +apiVersion: batch/v1 +kind: CronJob +metadata: + name: {{ include "phpmyadmin-nginx.fullname" . }}-backup + labels: + {{- include "phpmyadmin-nginx.labels" . | nindent 4 }} + app.kubernetes.io/component: backup +spec: + schedule: {{ .Values.backup.schedule | quote }} + successfulJobsHistoryLimit: {{ .Values.backup.successfulJobsHistoryLimit }} + failedJobsHistoryLimit: {{ .Values.backup.failedJobsHistoryLimit }} + concurrencyPolicy: {{ .Values.backup.concurrencyPolicy }} + suspend: {{ .Values.backup.suspend }} + jobTemplate: + spec: + backoffLimit: {{ .Values.backup.backoffLimit }} + template: + metadata: + labels: + {{- include "phpmyadmin-nginx.selectorLabels" . | nindent 12 }} + app.kubernetes.io/component: backup + {{- with .Values.backup.podAnnotations }} + annotations: + {{- toYaml . | nindent 12 }} + {{- end }} + spec: + restartPolicy: OnFailure + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 12 }} + {{- end }} + serviceAccountName: {{ include "phpmyadmin-nginx.serviceAccountName" . }} + securityContext: + fsGroup: 999 + runAsNonRoot: true + seccompProfile: + type: RuntimeDefault + containers: + - name: mysql-backup + image: "{{ .Values.backup.image.registry }}/{{ .Values.backup.image.repository }}:{{ .Values.backup.image.tag }}" + imagePullPolicy: {{ .Values.backup.image.pullPolicy }} + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + runAsNonRoot: true + runAsUser: 999 + env: + - name: MYSQL_HOST + value: {{ .Values.backup.mysql.host | quote }} + - name: MYSQL_PORT + value: {{ .Values.backup.mysql.port | quote }} + - name: MYSQL_USER + valueFrom: + secretKeyRef: + name: {{ .Values.backup.mysql.existingSecret | default (printf "%s-backup" (include "phpmyadmin-nginx.fullname" .)) }} + key: {{ .Values.backup.mysql.userKey | default "mysql-user" }} + - name: MYSQL_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.backup.mysql.existingSecret | default (printf "%s-backup" (include "phpmyadmin-nginx.fullname" .)) }} + key: {{ .Values.backup.mysql.passwordKey | default "mysql-password" }} + - name: BACKUP_TIMESTAMP + value: $(date +%Y%m%d_%H%M%S) + {{- if .Values.backup.databases }} + - name: DATABASES + value: {{ join " " .Values.backup.databases | quote }} + {{- end }} + {{- if .Values.backup.compression.enabled }} + - name: COMPRESSION_ENABLED + value: "true" + - name: COMPRESSION_LEVEL + value: {{ .Values.backup.compression.level | quote }} + {{- end }} + {{- if .Values.backup.retention.enabled }} + - name: RETENTION_DAYS + value: {{ .Values.backup.retention.days | quote }} + {{- end }} + command: + - /bin/bash + - -c + - | + set -euo pipefail + + BACKUP_DIR="{{ .Values.backup.destinationPath }}" + TIMESTAMP=$(date +%Y%m%d_%H%M%S) + DATE_DIR=$(date +%Y%m%d) + + echo "=== MySQL Backup Started at $(date) ===" + echo "Backup destination: ${BACKUP_DIR}/${DATE_DIR}" + + # Create backup directory + mkdir -p "${BACKUP_DIR}/${DATE_DIR}" + + # Function to backup a database + backup_database() { + local db=$1 + local backup_file="${BACKUP_DIR}/${DATE_DIR}/${db}_${TIMESTAMP}.sql" + + echo "Backing up database: ${db}" + + mysqldump \ + -h "${MYSQL_HOST}" \ + -P "${MYSQL_PORT}" \ + -u "${MYSQL_USER}" \ + -p"${MYSQL_PASSWORD}" \ + --single-transaction \ + --quick \ + --lock-tables=false \ + --routines \ + --triggers \ + --events \ + "${db}" > "${backup_file}" + + {{- if .Values.backup.compression.enabled }} + echo "Compressing backup: ${db}" + gzip -{{ .Values.backup.compression.level }} "${backup_file}" + backup_file="${backup_file}.gz" + {{- end }} + + # Verify backup file + if [ -f "${backup_file}" ]; then + size=$(du -h "${backup_file}" | cut -f1) + echo "✓ Backup completed: ${backup_file} (${size})" + else + echo "✗ Backup failed: ${backup_file}" + return 1 + fi + } + + # Backup specified databases or all databases + {{- if .Values.backup.databases }} + for db in ${DATABASES}; do + backup_database "${db}" || echo "Warning: Failed to backup ${db}" + done + {{- else }} + # Get all databases except system databases + DATABASES=$(mysql \ + -h "${MYSQL_HOST}" \ + -P "${MYSQL_PORT}" \ + -u "${MYSQL_USER}" \ + -p"${MYSQL_PASSWORD}" \ + -N -B -e "SHOW DATABASES" | \ + grep -Ev '^(information_schema|performance_schema|mysql|sys)$') + + for db in ${DATABASES}; do + backup_database "${db}" || echo "Warning: Failed to backup ${db}" + done + {{- end }} + + {{- if .Values.backup.retention.enabled }} + # Cleanup old backups + echo "Cleaning up backups older than {{ .Values.backup.retention.days }} days" + find "${BACKUP_DIR}" -type f -name "*.sql*" -mtime +{{ .Values.backup.retention.days }} -delete + find "${BACKUP_DIR}" -type d -empty -delete + {{- end }} + + # Summary + echo "=== Backup Summary ===" + echo "Total backup size:" + du -sh "${BACKUP_DIR}/${DATE_DIR}" + echo "Backup files:" + ls -lh "${BACKUP_DIR}/${DATE_DIR}" + + echo "=== MySQL Backup Completed at $(date) ===" + resources: + {{- toYaml .Values.backup.resources | nindent 14 }} + volumeMounts: + - name: backup-storage + mountPath: {{ .Values.backup.destinationPath }} + - name: tmp + mountPath: /tmp + volumes: + - name: backup-storage + {{- if .Values.backup.nfs.enabled }} + nfs: + server: {{ .Values.backup.nfs.server }} + path: {{ .Values.backup.nfs.path }} + {{- if .Values.backup.nfs.readOnly }} + readOnly: false + {{- end }} + {{- else }} + persistentVolumeClaim: + claimName: {{ .Values.backup.existingClaim | default (printf "%s-backup" (include "phpmyadmin-nginx.fullname" .)) }} + {{- end }} + - name: tmp + emptyDir: {} + {{- with .Values.backup.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.backup.affinity }} + affinity: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.backup.tolerations }} + tolerations: + {{- toYaml . | nindent 12 }} + {{- end }} +{{- end }} \ No newline at end of file