In questo articolo vedremo come sviluppare ulteriormente una soluzione minimale per l'importazione di un dump MySQL in modo da approdare ad una soluzione più avanzata ed affidabile.
La soluzione originale
La one-liner di partenza funziona, ma è rigida e poco sicura:
docker exec -i mysql-container mysql -uuser -ppassword name_db < data.sql
Problemi della one-liner originale
- Credenziali in chiaro sulla riga di comando (visibili con
ps
). - Nomi hardcoded (container, utente, database, file).
- Nessun supporto a dump compressi o controllo errori della pipeline.
- Poca portabilità tra
docker
edocker compose
.
One-liner parametrica e più sicura
Useremo variabili e l’env
MYSQL_PWD
per non esporre la password tra gli argomenti del processo:
CONTAINER="mysql-container"
MYSQL_USER="user"
MYSQL_PASSWORD="supersecret"
MYSQL_DB="name_db"
FILE="data.sql"
docker exec -i -e MYSQL_PWD="$MYSQL_PASSWORD" "$CONTAINER"
mysql -u"$MYSQL_USER" --database="$MYSQL_DB" < "$FILE"
Import di dump compressi
Rileveremo automaticamente il tipo di compressione e decomprimeremo con stream:
# .sql.gz
gzip -dc data.sql.gz | docker exec -i -e MYSQL_PWD="$MYSQL_PASSWORD" "$CONTAINER"
mysql -u"$MYSQL_USER" --database="$MYSQL_DB"
# .sql.xz
xz -dc data.sql.xz | docker exec -i -e MYSQL_PWD="$MYSQL_PASSWORD" "$CONTAINER"
mysql -u"$MYSQL_USER" --database="$MYSQL_DB"
Variante con Docker Compose
Con servizi gestiti da Compose, evitiamo il TTY interattivo usando -T
:
docker compose exec -T -e MYSQL_PWD="$MYSQL_PASSWORD" db
mysql -u"$MYSQL_USER" "$MYSQL_DB" < data.sql
Script riusabile: import-mysql-dump.sh
Questo script punta a essere un “drop-in” per docker exec
o docker compose exec
, con supporto a file compressi e errori nella pipeline.
#!/usr/bin/env bash
set -euo pipefail
usage() {
cat << EOF
Uso:
./import-mysql-dump.sh -f dump.sql[.gz|.xz] -d DB -u USER [-p PASS] (-c CONTAINER | -s SERVICE)
Esempi:
./import-mysql-dump.sh -f data.sql -d app -u app -p secret -c mysql-container
./import-mysql-dump.sh -f dump.sql.gz -d app -u app -p secret -s db
Note:
* Usa -c per docker exec (container), -s per docker compose exec (service).
* Se -p non è passato, lo script non imposta la password (usa credenziali preconfigurate).
EOF
}
FILE=""; DB=""; USERNAME=""; PASS="${PASS-}"; CONTAINER=""; SERVICE=""
while getopts ":f:d:u:p:c:s:h" opt; do
case "$opt" in
f) FILE="$OPTARG" ;;
d) DB="$OPTARG" ;;
u) USERNAME="$OPTARG" ;;
p) PASS="$OPTARG" ;;
c) CONTAINER="$OPTARG" ;;
s) SERVICE="$OPTARG" ;;
h) usage; exit 0 ;;
?) echo "Opzione non valida: -$OPTARG" >&2; usage; exit 1 ;;
:) echo "L'opzione -$OPTARG richiede un argomento." >&2; usage; exit 1 ;;
esac
done
if [[ -z "$FILE" || -z "$DB" || -z "$USERNAME" || ( -z "$CONTAINER" && -z "$SERVICE" ) ]]; then
echo "Parametri mancanti." >&2
usage
exit 1
fi
if [[ ! -f "$FILE" ]]; then
echo "File non trovato: $FILE" >&2
exit 1
fi
# Selettore decompressore
reader_cmd=()
case "$FILE" in
*.sql) reader_cmd=(cat "$FILE") ;;
*.sql.gz|*.gz) reader_cmd=(gzip -dc "$FILE") ;;
*.sql.xz|*.xz) reader_cmd=(xz -dc "$FILE") ;;
*) echo "Formato non supportato (usa .sql, .sql.gz o .sql.xz)" >&2; exit 1 ;;
esac
# Comando di esecuzione dentro al container
exec_cmd_base=(mysql -u"$USERNAME" "$DB")
# Aggiungo env MYSQL_PWD se fornita
env_args=()
if [[ -n "${PASS:-}" ]]; then
env_args=(-e "MYSQL_PWD=$PASS")
fi
if [[ -n "$SERVICE" ]]; then
# Docker Compose
exec_cmd=(docker compose exec -T "${env_args[@]}" "$SERVICE" "${exec_cmd_base[@]}")
else
# Docker
exec_cmd=(docker exec -i "${env_args[@]}" "$CONTAINER" "${exec_cmd_base[@]}")
fi
# Esecuzione pipeline con status propagation
"${reader_cmd[@]}" | "${exec_cmd[@]}"
Come usarlo
chmod +x import-mysql-dump.sh
# Docker "puro"
./import-mysql-dump.sh -f ./data.sql -d name_db -u user -p supersecret -c mysql-container
# Docker Compose (service "db")
./import-mysql-dump.sh -f ./dump.sql.gz -d app_db -u app -p secret -s db
Integrazione comoda con Makefile
Un target per standardizzare l’import in locale e CI:
# Makefile
import:
./import-mysql-dump.sh -f $$(FILE) -d $$(DB) -u $$(USER) -p $$(PASS) -s db
# Esempio:
# make import FILE=dump.sql.gz DB=app USER=app PASS=secret
Ottimizzazioni utili
- Charset coerente: esporta e importa in
utf8mb4
per evitare problemi di encoding. - Dump grandi: aumenta
max_allowed_packet
sul server se necessario. - Performance: quando possibile, disabilita controlli temporaneamente nel dump con righe tipo:
SET FOREIGN_KEY_CHECKS=0; SET UNIQUE_CHECKS=0; SET AUTOCOMMIT=0;
e riattivali alla fine. - Ripetibilità: aggiungi l’import a uno script di bootstrap del progetto o a una pipeline CI.
Verifica rapida post-import
# Conta le tabelle
docker exec -i -e MYSQL_PWD="$MYSQL_PASSWORD" "$CONTAINER"
mysql -u"$MYSQL_USER" -N -e "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='${MYSQL_DB}';"
# Controlla righe in una tabella chiave
docker exec -i -e MYSQL_PWD="$MYSQL_PASSWORD" "$CONTAINER"
mysql -u"$MYSQL_USER" -N -e "SELECT COUNT(*) FROM ${MYSQL_DB}.users;"
Conclusione
Partendo dalla one-liner iniziale, hai ora un flusso robusto: parametrico, compatibile con Docker e Compose, sicuro sulle credenziali e capace di gestire dump compressi. Incapsula tutto nello script proposto e rendi l’import del database un’operazione standard, affidabile e ripetibile.