# Описание процесса создания резервной копии Raspberry Pi 4

Существует множество способов создания резервных копий системы, среди которых - использование специализированного ПО, самописные скрипты, которые выполняют копирование/архивирование выбранных директорий, ручное копирование, создание образов дисков и разделов и т.д.

Создать резервную копию мало, необходимо также быть уверенным в том, что в случае необходимости, с ранее созданной резервной копии можно восстановиться. Ведь в процессе создания резервной копии, исходные данные могут изменяться - происходит чтение/запись, таким образом, есть вероятность, что в резервную копию попадут не консистентные данные и восстановиться с такой резервной копии будет невозможно. Чтобы избежать подобных проблем, необходимо исключить возможность изменения исходных данных в процессе создания резервных копий. Например, при создании образа системы, необходимо, чтобы раздел, резервную копию которого будем выполнять, не был смонтирован. Этого легко добиться, если это не загрузочный раздел.

Но как быть, если нужно создать резервную копию (образ) загрузочного раздела или всего диска? - Необходимо выполнить загрузку с какого-нибудь live-cd и средствами этого самого live-cd создать образ системы. С Raspberry Pi 4 ситуация немного проще, достаточно извлечь SD-карту, создать её образ и сохранить этот образ в надёжном месте. Всё это ручная работа, которая требует времени.

## Один из способов автоматизации создания образа системы Raspberry Pi 4 описан ниже

Raspberry Pi 4, 400 и Compute Module 4 используют EEPROM для загрузки системы. Все остальные модели Raspberry Pi используют bootcode.bin файл, расположенный в загрузочной файловой системе.

Если не углубляться в детали ([BOOT ORDER](https://www.raspberrypi.com/documentation/computers/raspberry-pi.html#BOOT_ORDER)), EEPROM позволяет выполнять загрузку c SD карты, USB, сети. Такую возможность добавили в одном из обновлений, необходимо убедиться, что используется последняя версия EEPROM.

Таким образом, выполнить создание образа SD-карты RPI можно если:

- записать образ системы на USB накопитель, подойдёт Raspberry Pi OS lite (<https://www.raspberrypi.com/software/operating-systems/>);
- подключить USB накопитель к RPI;
- переключить EEPROM в режим загрузки с USB;
- выполнить загрузку с USB;
- создать образ SD-карты и передать его в надёжное сетевое хранилище;
- вернуть EEPROM в режим загрузки с SD-карты;
- перезагрузить RPI.

Ничего сложного, осталось найти способ автоматического переключения способов загрузки в EEPROM. И такой способ существует - утилита `rpi-eeprom-config`

Нам достаточно двух ключей:

-a, --apply  
-o, --out

сохранить текущие настройки EEPROM во внешний файл

```bash
pi@host:~ $ sudo rpi-eeprom-config -o ~/eeprom.conf
```

применить конфигурацию EEPROM из файла

```bash
pi@host:~ $ sudo rpi-eeprom-config -a ~/eeprom.conf
```

### Осталось окончательно сформировать архитектуру нашего решения по созданию образа.

**На системе загруженной с SD**

1. Необходимо создать конфигурационный файл EEPROM, который установит загрузку на USB

```bash
pi@host:~ $ sudo mkdir /opt/backup_from_usb && sudo vim /opt/backup_from_usb/usb_eeprom.conf
```

```bash
pi@host:~ $ cat /opt/backup_from_usb/usb_eeprom.conf 
[all]
BOOT_UART=0
WAKE_ON_GPIO=1
POWER_OFF_ON_HALT=0
BOOT_ORDER=0xf4
```

2. Создать скрипт, который будет выполнять обновление конфигурации EEPROM

```bash
pi@host:~ $ sudo vim /opt/backup_from_usb/rpi_usb_boot.sh
```

```bash
#!/bin/bash

###################################################################################################

# Скрипт выполняет обновление конфигурации EEPROM Raspberry PI для загрузки с USB.
# В директории с этим скриптом должен находится конфигурационный файл EEPROM - $eeprom_conf

# Для корректной работы скрипта, EEPROM RPI должен поддерживать режим переключения загрузки SD<=>USB.

###################################################################################################

# Убедиться, что запуск происходит от root
if [ "$EUID" -ne 0 ]
  then echo "Скрипт необходимо запускать от администратора"
  exit
fi

# Директория, в которой хранится конфигурационный файл EEPROM
eeprom_conf_path=/opt/backup_from_usb

# Перенаправить весь вывод и ошибки в файл
exec > $eeprom_conf_path/run_log 2>&1

# Необходимо убедиться, что в папке присутствует конфиг EEPROM для изменения порядка загрузки
eeprom_conf="usb_eeprom.conf"

if [ ! -e "$eeprom_conf_path/$eeprom_conf" ]; then
    echo Файл настроек EEPROM $eeprom_conf не найден в директории $eeprom_conf_path > log 2>&1
    exit
fi

# Необходимо переключить EEPROM на загрузку с USB
rpi-eeprom-config -a $eeprom_conf_path/$eeprom_conf

# Перезагрузка
/usr/sbin/reboot
```

Добавить права на выполнение

```bash
pi@host:~ $ sudo chmod +x /opt/backup_from_usb/rpi_usb_boot.sh
```

3. Выполнить настройку запуска скрипта по расписанию.

*т.к. обновление конфигурации EEPROM необходимо выполнять с привилегиями root, настраивать расписание нужно также пользователя root, чтобы скрипт запускался с повышенными привилегиями.*

```bash
pi@host:~ $ sudo crontab -e
```

например, для запуска скрипта каждую среду в 2 часа ночи, необходимо добавить строку

```bash
0 2 * * 3 /opt/backup_from_usb/rpi_usb_boot.sh
```

**На системе загруженной с USB**

*для этого нужно запустить скрипт `/opt/backup_from_usb/rpi_usb_boot.sh` от рута или вручную переопределить загрузочный носитель с помощью `sudo rpi-eeprom-config -a /opt/backup_from_usb/usb_eeprom.conf` и перезагрузиться*

4. Обеспечить подключение к хранилищу по SSH на основе ключа пользователю root, т.к. скрипт будет выполняться от его имени

```bash
root@host-usb:~ $ ssh-keygen
root@host-usb:~ $ ssh-copy-id da2001@nas.dav.lan
```

5. Создать конфигурационный файл EEPROM, который вернёт загрузку на SD

```bash
pi@host-usb:~ $ sudo mkdir /opt/backup_rpi && sudo vim /opt/backup_rpi/sd_eeprom.conf
```

```bash
pi@host-usb:~ $ cat /opt/backup_rpi/sd_eeprom.conf 
[all]
BOOT_UART=0
WAKE_ON_GPIO=1
POWER_OFF_ON_HALT=0
BOOT_ORDER=0xf1
```

6. Подготовить основной скрипт, который выполнит создание образа SD-карты и передаст его по SSH в сетевое хранилище

```bash
pi@host-usb:~ $ sudo vim /opt/backup_rpi/rpi_backup.sh
```

```bash
#!/bin/bash

###################################################################################################

# Скрипт создаёт образ SD-карты Raspberry PI и отправляет его на удалённый сервер по SSH,
# при этом на удалённом сервере происходит сжатие образа для экономии места.
# Сжатие происходит на удалённом сервере, чтобы минимизировать операции записи на Flash память,
# с которой произведена загрузка RPI.
# После создания образа, происходит обновление конфигурации EEPROM Raspberry PI для загрузки с SD карты.
# В директории с этим скриптом должен находится конфигурационный файл EEPROM - $eeprom_conf

# Для корректной работы скрипта, EEPROM RPI должен поддерживать режим переключения загрузки SD<=>USB.

###################################################################################################

# Убедиться, что запуск происходит от root
if [ "$EUID" -ne 0 ]
  then echo "Скрипт необходимо запускать от администратора"
  exit
fi

# Удалённый сервер. Необходимо предварительно обеспечить доступ по ключам - ssh-keygen && ssh-sopy-id user@server
server=da2001@nas.dav.lan

# Путь сохранения на удалённом сервре
remote_path=/mnt/main/data/Backup/bastion_rpi

# Директория, в которой хранится конфигурационный файл EEPROM
eeprom_conf_path=/opt/backup_rpi

# Необходимо убедиться, что в папке присутствует конфиг EEPROM для изменения порядка загрузки
eeprom_conf="sd_eeprom.conf"

if [ ! -e "$eeprom_conf_path/$eeprom_conf" ]; then
    ssh $server "echo Файл настроек EEPROM $eeprom_conf не найден" > $remote_path/lastlog 2>&1
    exit
fi

# Необходимо синхронизировать время, т.к. сейчас оно отстаёт на неделю.
# Для этого используем утилиту ntpdate, Её необходимо заранее установить sudo apt install ntpdate.
ntpdate ntp1.vniiftri.ru

# Имя образа
name=$(echo $(date +%Y-%m-%d)_${HOSTNAME}_image.img.gz | sed 's/-usb//')

# Имя диска, над которым будем работать. SD в RPI называется mmcblk0
disk=/dev/mmcblk0

# запишем в переменную последний сектор последнего раздела диска
last_sector=$(fdisk -l -o end $disk | tail -1)

# Считаем, что размер сектора составляет 512 Байт, тогда необходимо сохранить ($last_sector+1)*512 Байт.
# Или ($last_sector+1)*512/1024/1024 Мб.
count=$(($(($last_sector+1))*512/1024/1024))

# Команда создания образа
dd if=$disk bs=1M count=$count conv=noerror,sync | ssh $server "gzip -c  > $remote_path/$name 2>> $remote_path/lastlog" && \
ssh $server "echo `date +"%A, %d %B %Y"` - Образ создан успешно >> $remote_path/log" || \
ssh $server "echo `date +"%A, %d %B %Y"` - При создании образа произошла ошибка >> $remote_path/log"

# Необходимо хранить только последние 20 строк в файле log
ssh $server 'echo "$(tail -5 $remote_path/log)" > $remote_path/log'

# Необходимо хранить только последние 3 резервные копии
count_copies=3
ssh $server "find $remote_path -type f -name '*_image.img.gz' -printf '%T@ %p\n' | sort -nr | cut -d' ' -f 2- | tail -n +$(($count_copies+1)) | xargs rm -f --"

# Необходимо переключить EEPROM на загрузку с SD карты
rpi-eeprom-config -a $eeprom_conf_path/$eeprom_conf

# Перезагрузка
/usr/sbin/reboot

```

Добавить права на выполнение

```bash
pi@host-usb:~ $ sudo chmod +x /opt/backup_rpi/rpi_backup.sh
```

7. Обеспечить выполнение скрипта при загрузке с USB. Сервис systemd

Для этого вам нужно создать скрипт запуска systemd и поместить его в каталог `/etc/systemd/system/`.

```bash
pi@host-usb:~ $ sudo vim /etc/systemd/system/rpi_backup.service
```

```bash
pi@host-usb:~ $ cat /etc/systemd/system/rpi_backup.service
[Unit]
Description=Run a Backup Script at Startup
After=default.target

[Service]
ExecStart=/opt/backup_rpi/rpi_backup.sh

[Install]
WantedBy=default.target
```

Перечитать скрипты и активировать созданный сервис

```bash
pi@host-usb:~ $ sudo systemctl daemon-reload
pi@host-usb:~ $ sudo systemctl enable rpi_backup.service
```

***

<https://www.raspberrypi.com/documentation/computers/raspberry-pi.html#raspberry-pi-4-bootloader-configuration>  
<https://www.raspberrypi.com/documentation/computers/raspberry-pi.html#raspberry-pi-4-boot-eeprom>  
<https://www.raspberrypi.com/documentation/computers/raspberry-pi.html#BOOT_ORDER>  
