Aunque tar
tiene un modo incremental, hay un par de herramientas más completas para hacer el trabajo:
- Duplicidad
- Duplicados
No solo admiten copias de seguridad incrementales, sino que es fácil configurar un programa en el que se debe realizar una copia de seguridad completa. Por ejemplo en duplicity
:duplicity --full-if-older-than 1M
se asegurará de que se haya ejecutado una copia de seguridad completa. También admiten retroceder en el tiempo a un archivo específico, con tar simple tendrá que revisar todos los archivos incrementales hasta que encuentre uno que contenga el archivo correcto.
Además, admiten el cifrado y la carga en una variedad de backends (como sftp, almacenamiento de blobs, etc.). Obviamente, si cifra, ¡no olvide hacer una buena copia de seguridad de sus claves en una copia de seguridad secundaria!
Otro aspecto importante es que puede verificar la integridad de sus copias de seguridad, asegurándose de que puede restaurar, por ejemplo, usando duplicity verify
.
Aconsejaría negativamente una estrategia de copia de seguridad basada en git. Las restauraciones grandes toman mucho tiempo.
Probé rsync, pero parece que no puede hacer lo que quiero, o más probablemente, no sé cómo hacer que lo haga.
Sé que probablemente podría crear un script que ejecute una diferencia y luego seleccione los archivos para hacer una copia de seguridad en función del resultado (o, de manera más eficiente, simplemente obtener una suma de verificación y comparar), pero quiero saber si hay alguna utilidad que pueda hacer esto. un poco más fácil :)
rsync
es precisamente ese programa el que copia en base a un diff. De forma predeterminada, solo copia cuando hay una diferencia en el tiempo o el tamaño de la última modificación, pero incluso puede comparar mediante suma de comprobación con -c
.
El problema aquí es que tienes tar
haciendo las copias de seguridad. Esto se vuelve más fácil si no haces eso. Ni siquiera sé por qué lo estás haciendo. Puede tener sentido si los está comprimiendo, pero ni siquiera está haciendo eso.
El artículo de Wikipedia sobre copias de seguridad incrementales tiene un ejemplo rsync
comando que dice más o menos:
rsync -va \
--link-dest="$dst/2020-02-16--05-10-45--testdir/" \
"$src/testdir/" \
"$dst/2020-02-17--03-24-16--testdir/"
Lo que hace es vincular archivos de la copia de seguridad anterior cuando no han cambiado desde la fuente. También hay --copy-dest
si desea que se copie en su lugar (aún es más rápido cuando $dst
es un control remoto o en una unidad más rápida).
Si usa un sistema de archivos con subvolúmenes como btrfs, también puede tomar una instantánea de la copia de seguridad anterior antes de rsync. Las instantáneas son instantáneas y no ocupan espacio adicional[1].
btrfs subvolume snapshot \
"$dst/2020-02-16--05-10-45--testdir" \
"$dst/2020-02-17--03-24-16--testdir"
O si está utilizando un sistema de archivos que admite enlaces ref, como ext4, también puede hacerlo. Los enlaces de referencia se realizan creando un nuevo inodo pero haciendo referencia a los mismos bloques que el archivo de origen, implementando la compatibilidad con COW. Todavía es más rápido que la copia normal porque no lee ni escribe los datos, y tampoco ocupa espacio adicional[1].
cp --reflink -av \
"$dst/2020-02-16--05-10-45--testdir" \
"$dst/2020-02-17--03-24-16--testdir"
De todos modos, una vez que hayas hecho algo así, puedes hacer un rsync
normal. para copiar las diferencias:
rsync -va \
"$src/testdir/" \
"$dst/2020-02-17--03-24-16--testdir/"
Sin embargo, es posible que desee agregar --delete
, lo que haría que rsync eliminara archivos del destino que ya no están presentes en el origen.
Otra opción útil es -i
o --itemize-changes
. Produce una salida sucinta y legible por máquina que describe los cambios que está haciendo rsync. Normalmente agrego esa opción y canalizo como:
rsync -Pai --delete \
"$src/testdir/" \
"$dst/2020-02-17--03-24-16--testdir/" \
|& tee -a "$dst/2020-02-17--03-24-16--testdir.log"
para mantener un registro de los cambios fácilmente grep
archivos capaces. El |&
es canalizar tanto stdout como stderr.
El -P
es la abreviatura de --partial
y --progress
. --partial
mantiene los archivos parcialmente transferidos, pero lo más importante --progress
informes de progreso por archivo.
Cómo se compara esto con archivar cambios con tar
Las soluciones anteriores dan como resultado directorios que parecen contener todo. Aunque ese es el caso, en total para cualquier cantidad/frecuencia de copias de seguridad, ocuparían aproximadamente la misma cantidad de espacio que tener archivos de tar simples con solo cambios. Eso se debe a cómo funcionan los enlaces duros, los enlaces de referencia y las instantáneas. El uso del ancho de banda al crear las copias de seguridad también sería el mismo.
Las ventajas son:
- las copias de seguridad son fáciles de restaurar con rsync y más rápidas, ya que rsync solo transferiría las diferencias de la copia de seguridad.
- son más fáciles de navegar y modificar si es necesario.
- las eliminaciones de archivos se pueden codificar naturalmente como la ausencia del archivo en nuevas copias de seguridad. Al usar archivos tar, uno tendría que recurrir a trucos, como eliminar un archivo
foo
, márcalofoo.DELETED
o hacer algo complicado. Por ejemplo, nunca he usado la duplicidad, pero mirando su documentación, parece que codifica las eliminaciones agregando un archivo vacío del mismo nombre en el nuevo tar y manteniendo la firma original del archivo en un archivo .sigtar separado. Me imagino que compara la firma original con la de un archivo vacío para diferenciar entre la eliminación de un archivo y un cambio a un archivo vacío real.
Si aún desea configurar cada copia de seguridad para que solo contenga los archivos que son diferentes (agregados o modificados), entonces puede usar el --link-dest
solución descrita anteriormente y luego elimine los enlaces duros usando algo como lo siguiente:
find $new_backup -type f ! -links 1 -delete
[1] Estrictamente hablando, utilizan espacio adicional en forma de metadatos duplicados, como el nombre del archivo y demás. Sin embargo, creo que cualquiera lo consideraría insignificante.
¿Y por qué no estás considerando git
? ¿sí mismo?
La estrategia que describe, después de una copia de seguridad completa y dos incrementales, tiene sus complicaciones cuando continúa. Es fácil cometer errores y puede volverse muy ineficiente, dependiendo de los cambios. Tendría que haber una especie de rotación, es decir, de vez en cuando haces una nueva copia de seguridad completa, y luego ¿quieres conservar la anterior o no?
Dado un trabajo dir "testdir" que contiene algún proyecto (archivos y subdirectorios), git
hace por defecto un .git
oculto subdirectorio para los datos. Eso sería para el control de versión adicional local caracteristicas. Para la copia de seguridad, puede archivarlo/copiarlo en un medio o clonarlo a través de la red.
El control de revisión obtienes (sin pedir) es un efecto secundario del almacenamiento diferencial de git.
Puede omitir todas las bifurcaciones/ramificaciones, etc. Esto significa que tiene una rama llamada "maestro".
Antes de que pueda confirmar (en realidad, escribir en el archivo/repositorio de git), debe configurar un usuario mínimo para el archivo de configuración. Entonces primero debe aprender y probar en un subdirectorio (tal vez tmpfs). A veces, Git es tan complicado como tar.
De todos modos, como dice un comentario:la copia de seguridad es fácil, la parte difícil es la restauración.
Las desventajas de git serían solo la pequeña sobrecarga/exceso.
Las ventajas son:git pistas contenido y nombres de archivo. Solo guarda lo necesario, basado en una diferencia (al menos para archivos de texto).
Ejemplo
Tengo 3 archivos en un directorio. Después de git init
, git add .
y git commit
Tengo un 260K .git
dir.
Entonces yo cp -r .git /tmp/abpic.git
(un buen lugar para guardar una copia de seguridad :). Yo rm
el jpg de 154K, y también cambiar un archivo de texto. Yo también rm -r .git
.
]# ls
atext btext
]# git --git-dir=/tmp/abpic.git/ ls-files
atext
btext
pic154k.jpg
Antes de restaurar los archivos, puedo obtener las diferencias precisas:
]# git --git-dir=/tmp/abpic.git/ status
On branch master
Changes not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: atext
deleted: pic154k.jpg
no changes added to commit (use "git add" and/or "git commit -a")
Aquí quiero seguir el git restore
pista.
Después de git --git-dir=/tmp/abpic.git/ restore \*
:
]# ls -st
total 164
4 atext 156 pic154k.jpg 4 btext
El jpeg está de vuelta y el archivo de texto btext
tiene no sido actualizado (mantiene la marca de tiempo). Las modificaciones en atext
se sobrescriben.
Para reunir el repositorio y el directorio (de trabajo), simplemente puede volver a copiarlo.
]# cp -r /tmp/abpic.git/ .git
]# git status
On branch master
nothing to commit, working tree clean
Los archivos en el directorio actual son idénticos al .git
archivo (después del restore
). Se mostrarán nuevos cambios y se pueden agregar y confirmar, sin ningún tipo de planificación. Solo tiene que almacenarlo en otro medio, con fines de copia de seguridad.
Después de modificar un archivo, puede usar status
o diff
:
]# echo more >>btext
]# git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: btext
no changes added to commit (use "git add" and/or "git commit -a")
]# git diff
diff --git a/btext b/btext
index 96b5d76..a4a6c5b 100644
--- a/btext
+++ b/btext
@@ -1,2 +1,3 @@
This is file b
second line
+more
#]
Y al igual que git
sabe acerca de "+más" en el archivo 'btext', también solo almacenará esa línea de forma incremental.
Después de git add .
(o git add btext
) el status
el comando cambia de rojo a verde y el commit
te da la información.
]# git add .
]# git status
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: btext
]# git commit -m 'btext: more'
[master fad0453] btext: more
1 file changed, 1 insertion(+)
Y realmente puedes llegar a los contenidos, de alguna manera:
]# git ls-tree @
100644 blob 321e55a5dc61e25fe34e7c79f388101bd1ae4bbf atext
100644 blob a4a6c5bd3359d84705e5fd01884caa8abd1736d0 btext
100644 blob 2d550ffe96aa4347e465109831ac52b7897b9f0d pic154k.jpg
Y luego los primeros 4 dígitos hash hexadecimales
]# git cat-file blob a4a6
This is file b
second line
more
Para viajar en el tiempo con una confirmación es:
]# git ls-tree @^
100644 blob 321e55a5dc61e25fe34e7c79f388101bd1ae4bbf atext
100644 blob 96b5d76c5ee3ccb7e02be421e21c4fb8b96ca2f0 btext
100644 blob 2d550ffe96aa4347e465109831ac52b7897b9f0d pic154k.jpg
]# git cat-file blob 96b5
This is file b
second line
El blob de btext tiene un hash diferente antes de la última confirmación, los demás tienen el mismo.
Un resumen sería:
]# git log
commit fad04538f7f8ddae1f630b648d1fe85c1fafa1b4 (HEAD -> master)
Author: Your Name <[email protected]>
Date: Sun Feb 16 10:51:51 2020 +0000
btext: more
commit 0bfc1837e20988f1b80f8b7070c5cdd2de346dc7
Author: Your Name <[email protected]>
Date: Sun Feb 16 08:45:16 2020 +0000
added 3 files with 'add .'
En lugar de archivos tar con marca de tiempo manual, tiene confirmaciones con un mensaje y una fecha (y un autor). Lógicamente adjuntos a estos compromisos están las listas de archivos y el contenido.
Sencillo git
es un 20 % más complicado que tar
, pero obtienes un 50% más de funcionalidad decisiva.
Quería hacer el tercer cambio de OP:cambiar un archivo más dos nuevos archivos de 'imagen'. Lo hice, pero ahora tengo:
]# git log
commit deca7be7de8571a222d9fb9c0d1287e1d4d3160c (HEAD -> master)
Author: Your Name <[email protected]>
Date: Sun Feb 16 17:56:18 2020 +0000
didn't add the pics before :(
commit b0355a07476c8d8103ce937ddc372575f0fb8ebf
Author: Your Name <[email protected]>
Date: Sun Feb 16 17:54:03 2020 +0000
Two new picture files
Had to change btext...
commit fad04538f7f8ddae1f630b648d1fe85c1fafa1b4
Author: Your Name <[email protected]>
Date: Sun Feb 16 10:51:51 2020 +0000
btext: more
commit 0bfc1837e20988f1b80f8b7070c5cdd2de346dc7
Author: Your Name <[email protected]>
Date: Sun Feb 16 08:45:16 2020 +0000
added 3 files with 'add .'
]#
Entonces, ¿qué hizo exactamente ese Your Name Guy, en sus dos confirmaciones, poco antes de las 6 p. m.?
Los detalles de la última confirmación son:
]# git show
commit deca7be7de8571a222d9fb9c0d1287e1d4d3160c (HEAD -> master)
Author: Your Name <[email protected]>
Date: Sun Feb 16 17:56:18 2020 +0000
didn't add the pics before :(
diff --git a/picture2 b/picture2
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/picture2
@@ -0,0 +1 @@
+1
diff --git a/picture3 b/picture3
new file mode 100644
index 0000000..0cfbf08
--- /dev/null
+++ b/picture3
@@ -0,0 +1 @@
+2
]#
Y para comprobar el penúltimo compromiso, cuyo mensaje anuncia dos imágenes:
]# git show @^
commit b0355a07476c8d8103ce937ddc372575f0fb8ebf
Author: Your Name <[email protected]>
Date: Sun Feb 16 17:54:03 2020 +0000
Two new picture files
Had to change btext...
diff --git a/btext b/btext
index a4a6c5b..de7291e 100644
--- a/btext
+++ b/btext
@@ -1,3 +1 @@
-This is file b
-second line
-more
+Completely changed file b
]#
Esto sucedió porque probé git commit -a
para atajar git add .
, y los dos archivos eran nuevos (sin seguimiento). Se mostraba en rojo con git status
, pero como digo, git no es menos complicado que tar o unix.
"Tu debutante sabe lo que necesitas, pero yo sé lo que quieres" (o al revés. El punto es que no siempre es lo mismo)