Files
phpmyadmin/templates/cronjob.yaml
T
claude be7671b55b
Helm Chart Release / release-chart (push) Successful in 4s
fix: fix backup CronJob template bugs
- Fix MYSQL_HOST/PORT: were referencing non-existent .Values.backup.mysql.host/port;
  now correctly read from .Values.phpmyadmin.hosts[0] as documented in README
- Remove broken BACKUP_TIMESTAMP env var (shell command substitution does not
  execute in k8s env vars; timestamp is already defined inside the script)
- Fix NFS readOnly: was always outputting "readOnly: false" even when
  .Values.backup.nfs.readOnly was true; now renders the actual value
- Add MYSQL_HISTFILE=/dev/null to prevent mysql client from writing history
  file when readOnlyRootFilesystem: true
- Fix variable name collision: renamed shell var DATABASES -> DB_LIST in the
  all-databases branch to avoid conflict with the DATABASES env var
- Use /bin/bash (available in mysql:8.0 Debian image) for set -euo pipefail
  and local keyword support
- Split retention find into separate *.sql and *.sql.gz patterns
- Add -mindepth 1 to empty dir cleanup to avoid removing the root backup dir

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 08:04:30 +09:00

204 lines
8.0 KiB
YAML

{{- 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:
# MySQL接続情報は phpmyadmin.hosts[0] から取得
- name: MYSQL_HOST
value: {{ (index .Values.phpmyadmin.hosts 0).host | quote }}
- name: MYSQL_PORT
value: {{ (index .Values.phpmyadmin.hosts 0).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" }}
# readOnlyRootFilesystem: true のためmysqlコマンドの履歴ファイルを無効化
- name: MYSQL_HISTFILE
value: /dev/null
{{- 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 "Host: ${MYSQL_HOST}:${MYSQL_PORT}"
echo "Backup destination: ${BACKUP_DIR}/${DATE_DIR}"
# Create backup directory
mkdir -p "${BACKUP_DIR}/${DATE_DIR}"
# Function to backup a single 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 }}
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
}
{{- if .Values.backup.databases }}
# Backup specified databases
for db in ${DATABASES}; do
backup_database "${db}" || echo "Warning: Failed to backup ${db}"
done
{{- else }}
# Get all databases except system databases
DB_LIST=$(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 ${DB_LIST}; 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 f -name "*.sql.gz" -mtime +{{ .Values.backup.retention.days }} -delete
find "${BACKUP_DIR}" -mindepth 1 -type d -empty -delete
{{- end }}
# Summary
echo "=== Backup Summary ==="
echo "Total backup size:"
du -sh "${BACKUP_DIR}/${DATE_DIR}" 2>/dev/null || echo "(no files)"
echo "Backup files:"
ls -lh "${BACKUP_DIR}/${DATE_DIR}" 2>/dev/null || echo "(none)"
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 }}
readOnly: {{ .Values.backup.nfs.readOnly }}
{{- 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 }}