# 使用tar方式备份和恢复系统

为了能够编译LFS([Linux From Scratch(LFS)](https://github.com/huataihuang/cloud-atlas-draft/tree/894113fe2256d8fc97ba6b1093141246b6280c91/os/linux/lfs/README/README.md))，我尝试[在U盘上安装Ubuntu](https://github.com/huataihuang/cloud-atlas-draft/tree/894113fe2256d8fc97ba6b1093141246b6280c91/os/linux/ubuntu/install/install_ubuntu_to_usb_stick/README.md)但是尚未成功，所以改成先安装到笔记本的本地磁盘，然后再通过TAR方式备份恢复到U盘运行。

## 备份前准备

在备份系统前，最好先清空“垃圾箱”并删除所有不许要的文件和程序:

* 清理掉浏览器缓存，密码
* 清理掉邮件帐号
* 清理掉密码、私钥和私有文件

## 备份

```
cd /
tar -cvpzf backup.tar.gz --exclude=/backup.tar.gz --exclude=/home/huatai/Dropbox --one-file-system /
```

参数解释：

* `c` - 创建新的备份归档
* `v` - 详细模式，`tar`命令将在屏幕显示所有过程
* `p` - 保留归档文件的权限设置
* `z` - 使用gzip压缩
* `f <filename>` - 指定存储的备份文件名
* `--exclude=/example/path` 备份中不包括指定的文件
* `--one-file-system` - 不包含其他文件系统中文件。如果你需要其他文件系统，例如独立的`/home`分区，或者也想包含`/media`挂载的扩展目录中文件，则要么单独备份这些文件，要么不使用这个参数。如果不使用这个参数，就需要使用`--exclude=`参数一一指定不包含的目录。这些不包含的目录有`/proc`，`/sys`，`/mnt`，`/media`，`/run`和`/dev`目录。

以下时手工设置不备份目录的方法，例如：

```
cd / # THIS CD IS IMPORTANT THE FOLLOWING LONG COMMAND IS RUN FROM /
tar -cvpzf backup.tar.gz \
--exclude=/backup.tar.gz \
--exclude=/proc \
--exclude=/tmp \
--exclude=/mnt \
--exclude=/dev \
--exclude=/sys \
--exclude=/run \ 
--exclude=/media \ 
--exclude=/var/log \
--exclude=/var/cache/apt/archives \
--exclude=/usr/src/linux-headers* \ 
--exclude=/home/*/.gvfs \
--exclude=/home/*/.cache \ 
--exclude=/home/*/.local/share/Trash /
```

如果需要将备份文件分割成小文件：

```
tar -cvpz <put options here> / | split -d -b 3900m - /name/of/backup.tar.gz.
```

## 通过网络备份

### 使用Netcat通过网络备份

netcat提供了非常方便的网络备份：

* 在接收服务器上：

```
nc -l 1024 > backup.tar.gz
```

* 发送服务器上：

```
tar -cvpz <all those other options like above> / | nc -q 0 <receiving host> 1024
```

### 使用SSH通过网络备份

```
tar -cvpz <all those other options like above> / | ssh <backuphost> "( cat > ssh_backup.tar.gz )"
```

## 恢复

假设需要恢复的目录挂载在`/media`目录：

```
sudo tar -xvpzf /path/to/backup.tar.gz -C /media/whatever --numeric-owner
```

* `x` 告诉tar解压缩
* `-C <directory>` 告知tar在解压缩文件之前先进入指定`<directory>`目录，这样就会恢复在这目录下。这里的案例是将文件恢复到`/media/whatever`目录，也就是挂载分区的目录
* `--numeric-owner` 告诉tar恢复文件的owner帐号数字，而不是匹配用于恢复系统的用户名帐号。

### 恢复步骤

* 如果你能够通过live-cd启动主机，建议采用chroot方式进入恢复后的操作系统目录（这里假设`/media/sda5`）

```
mount -t proc proc /media/sda5/proc
mount --rbind /sys /media/sda5/sys
mount --make-rslave /media/sda5/sys
mount --rbind /dev /media/sda5/dev
mount --make-rslave /media/sda5/dev
```

> `--make-rslave`参数在后面安装的systemd支持所需

进入Ubuntu系统

```
chroot /media/sda5 /bin/bash
source /etc/profile
export PS1="(chroot) $PS1"
```

> （实际可忽略）恢复之后可能还需要恢复没有包含在`--one-file-system`中的一些系统目录

```
cd /media/sda5
mkdir proc sys mnt media
```

* 如果是在不同的主机上恢复系统，需要修改`/etc/fstab`以及`/boot/grub`

例如`/boot/grub/grub.cfg`中所有原 `root=UUID=3db306b6-2d5e-4e4c-8d22-4fe70ce0d0a4` 需要修改成新的分区UUID `root=`

### 恢复GRUB

```
sudo -s
for f in dev dev/pts proc ; do mount --bind /$f /media/whatever/$f ; done
chroot /media/whatever
dpkg-reconfigure grub-pc
```

遇到无法启动的问题则需要确保：

* UEFI启动的分区必须是FAT32，独立分区（`/dev/sda1`），并且挂载到`/boot`，这样才能够启动
* 如果是多Linux操作系统启动，需要把多个操作系统到启动内核都复制到同一个`/boot`分区
* 设置内核启动参数中`root=PARTUUID=5e878358-02`，应该使用的是分区UUID，这个分区UUID是`parted`划分分区时候创建的标记

> 详细参考我的实践
>
> [How to Repair, Restore, or Reinstall Grub 2 with a Ubuntu Live CD or USB](http://howtoubuntu.org/how-to-repair-restore-reinstall-grub-2-with-a-ubuntu-live-cd)提供了一个修复方法：

```
grub-install /dev/sdX

grub-install --recheck /dev/sdX

update-grub
```

此外，在CentOS论坛有一篇[multi boot with Ubuntu](https://www.centos.org/forums/viewtopic.php?t=15774)可以参考，方法是先安装CentOS，然后再安装Ubntu。最后在Ubuntu的`/etc/grub.d/40_custom`中添加CentOS内容

```bash
#!/bin/sh
exec tail -n +3 $0
# This file provides an easy way to add custom menu entries.  Simply type the
# menu entries you want to add after this comment.  Be careful not to change
# the 'exec tail' line above.
###
menuentry "Centos-5.4" {
set root=(hd0,[b]1[/b])
chainloader +1
}
```

然后执行`sudo update-grub`或者`sudo update-grub2`就可以双启动。

## 从网络恢复

* 接收服务器

> 以下案例假设恢复到分区`/dev/sda5`

确保接收服务器已经挂载磁盘`/dev/sda5`目录`/media/sda5`

```
mkdir /media/sda5
mount /dev/sda5 /media/sda5
```

```
nc -l 1024 | sudo tar -xvpzf - -C /media/sda5
```

> 这个命令中`-`字符表示`tar`接收从标准输入而不是一个文件，这里的标准输入是从pipe管道

这里如果出现报错`Ncat: socket: Address family not supported by protocol QUITTING.`请检查一下服务器是否禁止了`IPv6`，默认情况下`nc`会尝试同时使用`IPv4`和`IPv6`。

* 发送服务器

```
cat backup.tar.gz | nc -q 0 <receiving host> 1024
```

> 备份文件解压缩通过管道经`nc`发送给远程服务器的1024端口

## dd命令结合ssh

对于服务器磁盘完全一致(磁盘规格和分区都一致)，则还可以通过 `dd` 命令来完成clone，并且通过SSH通道可以实现远程复制:

```bash
dd if=/dev/sda | ssh user@<receiving host> dd of=/dev/sda
```

> 注意：上述 `/dev/sda` 非系统磁盘

备份可以采用压缩方式

```bash
dd if=/dev/sda | gzip -1 - | ssh user@<receiving host> dd of=image.gz
```

或者反向执行（从远程备份到本地）

```bash
ssh user@remote "dd if=/dev/sda | gzip -1 -" | dd of=image.gz
```

## 参考

* [BackupYourSystem/TAR](https://help.ubuntu.com/community/BackupYourSystem/TAR)
* [ssh user@remote "dd if=/dev/sda | gzip -1 -" | dd of=image.gz](https://unix.stackexchange.com/questions/132797/how-to-dd-a-remote-disk-using-ssh-on-local-machine-and-save-to-a-local-disk)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://huataihuang.gitbook.io/cloud-atlas-draft/os/linux/ubuntu/install/backup_and_restore_system_by_tar.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
