Time Machine из Raspberry Pi

Одна из сильнейших сторон операционных систем от Apple — это инкрементные бэкапы, но чтобы их делать, не подключая каждый раз внешний диск, нужно купить AirPort Time Capsule за 350$ или связку AirPort Extreme + внешний жесткий диск. Вещь нужная и полезная, но дорогая.

В своей статье я опишу как из Raspberry Pi 3 Model B+ сделать дешевую замену Time Capsule.

Необходимые комплектующие

Raspberry Pi 3 Model B+: 2200р

Зарядка на 2.5A/5V: ~600р

Переходник USB/SATA: 700 рублей

Внешний жесткий диск на 2.5 дюйма: 3600 рублей

Спойлер

Узким местом системы будет сеть/диск. Скорость записи на диск по USB 2.0 будет порядка 10МB/s, скорость обмена данными по 5Ghz сети в метре от роутера будет порядка 7–8MB/s.

Предыстория

Буквально через неделю после заказа переходник пришел с Алиэкспресс. Переходник был с активным питанием и к нему можно было подключить диски с любым форм-фактором — 2.5 и 3.5, главное, чтобы был разъем SATA. Я обрадовался и пошел в ближайший магазин электроники COXO, купил самый дешевый жесткий диск на 3.5 на 1 терабайт за 5 минут до закрытия магазина.

Жесткий диск можно обнаружить, выполнив следующую команду:

pi@parrot:~ $ sudo fdisk -l
Disk /dev/sda: 931.5 GiB, 1000204886016 bytes, 1953525168 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes

Прошло буквально 10 минут, я начал ставить git и, диск заглох, унеся плату в цикл перезагрузок. Плате не хватило питания от внешнего источника. Внешним источником оказалось USB питание на 5V/1A, при рекомендованных 5V/2.5A. Время было уже позднее, подходящего источника питания под рукой не было. Позже оказалось, что проблема была в бракованном жестком диске, который пришлось заменить на новый.

В итоге приобрел 2.5 диск, так как он меньше, тише, и ему не нужен дополнительный источник питания.


План

  1. Подготовка внешнего жесткого диска
  2. Настройка Raspberry Pi
  3. Настройка резервного копирования по сети
  4. Восстановление резервной копии

Подготовка диска

Форматируем жесткий диск, предназначающийся для бэкапов.

Выведем список доступных дисков.

➜ ~ sudo diskutil list
/dev/disk0 (internal, physical):
#: TYPE NAME SIZE IDENTIFIER
0: GUID_partition_scheme *251.0 GB disk0
1: EFI EFI 209.7 MB disk0s1
2: Apple_APFS Container disk1 250.8 GB disk0s2
/dev/disk3 (external, physical):
#: TYPE NAME SIZE IDENTIFIER
0: GUID_partition_scheme *1.0 TB disk3
1: EFI EFI 209.7 MB disk3s1
2: Apple_HFS WD Backup 1Tb 999.9 GB disk3s2

Нас интересует /dev/disk3s2, отключаем журналируемость раздела.

➜ ~ sudo diskutil disableJournal /dev/disk3s2
Journaling has been disabled for volume WD Backup 1Tb on disk3s2

В свойствах диска необходимо предоставить права на чтения и запись для всех, для того, чтобы RPi мог записывать на диск.


Настройка Raspberry Pi

  1. Скачиваем Etcher — утилиту для записи образов на SD карты/USB флешки
  2. Скачиваем образ Raspbian Stretch Lite
  3. Записываем на карту образ при помощи Etcher

В некоторых моделях макбуков карта может не сразу читаться, для этого ее нужно немного вытащить из кардридера.

После окончания записи карта будет автоматически извлечена, ее нужно будет вытащить из кардридера и заново вставить.

4. Подготовка образа к первой загрузке

Подразумевается, что флешка смонтирована как boot. С ноутбука необходимо выполнить следующие команды:

➜ ~ touch /Volumes/boot/ssh
➜ ~ sudo umount /Volumes/boot
➜ ~ sudo sudo umount /Volumes/boot
Password:

Выполнив эти команды мы создадим пустой файл ssh в загрузочном разделе карточки и безопасно извлечем карту. Этим мы скажем загрузчику, что при старте операционной системы необходимо запустить ssh демон.

5. Предварительная настройка платы

Вытаскиваем SD карточку из ноутбука, вставляем в RPi, подключаем плату патч-кордом к роутеру, через SATA/USB кабель подключаем внешний жесткий диск. Все вместе будет выглядеть следующим образом:

Для того, чтобы найти адрес платы (в данном примере речь идет только о линейке Raspberry Pi) в сети, необходимо выполнить c ноутбука поиск по MAC-адресу:

➜ ~ arp -na | grep -i b8:27:eb
? (10.0.1.9) at b8:27:eb:df:5c:3f on en0 ifscope [ethernet]

Отлично, теперь у нас есть IP платы: 10.0.1.9. Подключаемся, вводим пароль “raspberry”, а затем меняем его по соображениям безопасности:

➜ ~ ssh pi@10.0.1.9
The authenticity of host ‘10.0.1.9 (10.0.1.9)’ can’t be established.
ECDSA key fingerprint is SHA256: xxxx.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added ‘10.0.1.9’ (ECDSA) to the list of known hosts.
pi@10.0.1.9’s password:
Linux raspberrypi 4.14.34-v7+ #1110 SMP Mon Apr 16 15:18:51 BST 2018 armv7l
...
pi@raspberrypi:~ $ passwd
Changing password for pi.
(current) UNIX password:
Enter new UNIX password:
Retype new UNIX password:
passwd: password updated successfully

Меняем хостнейм:

pi@raspberrypi:~ $ sudo raspi-config
Я назвал девайс Попугаем.

Добавляем подключение по WiFi:

Чтобы девайс увидел 5Ghz сеть, необходимо указать страну UK, хотя многие утверждают что это необязательно.
Вводим название вашей WiFi сети.
Вводим пароль.

Чтобы проверить подключение к беспроводной сети выполним:

pi@raspberrypi:~ $ ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 10.0.1.9 netmask 255.255.255.0 broadcast 10.0.1.255
inet6 fe80::6d85:5595:fa12:7bf3 prefixlen 64 scopeid 0x20<link>
ether b8:27:eb:df:5c:3f txqueuelen 1000 (Ethernet)
RX packets 1376 bytes 146361 (142.9 KiB)
RX errors 0 dropped 12 overruns 0 frame 0
TX packets 713 bytes 468437 (457.4 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
...
wlan0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 10.0.1.2 netmask 255.255.255.0 broadcast 10.0.1.255
inet6 fe80::c8fc:b9de:e365:d187 prefixlen 64 scopeid 0x20<link>
ether b8:27:eb:8a:09:6a txqueuelen 1000 (Ethernet)
RX packets 80 bytes 9175 (8.9 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 34 bytes 5797 (5.6 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

Это означает что сетевая карточка успешно подключилась по интерфейсу wlan0 и получила сетевой адрес 10.0.1.2.

Настоятельно рекомендую задать в настройках роутера адрес статическим. Если роутер — Mikrotik, то можете посмотреть как это делается на видео.

Выходим из программы raspi-config и перезагружаемся:

После перезагрузки Ethernet кабель можно отключить, он нам больше не понадобится.

Чтобы в будущем каждый раз не приходилось вбивать пароль, сделаем авторизацию ключами при помощи утилиты ssh-copy-id. Перед этим замените Parrot.local на ваш хостнейм и добавьте в конце .local. С ноутбука:

➜ ~ ssh-copy-id pi@Parrot.local
...
Now try logging into the machine, with: “ssh ‘pi@Parrot.local’”
and check to make sure that only the key(s) you wanted were added.

Перед тем как перейти к настройке netatalk, настоятельно рекомендую сделать бэкап SD карты. Для этого выключаем RPi:

➜ ~ ssh pi@Parrot.local
...
[pi@parrot] sudo poweroff

Вставляем карту в ноутбук и выполняем следующие команды:

➜  dd if=/dev/disk2 of=/Users/voldemar/rpi3bplus-strench-image.dmg
15235072+0 records in
15235072+0 records out
7800356864 bytes transferred in 905.185329 secs (8617414 bytes/sec)
➜ etc sudo umount /Volumes/boot
Password:

Вместо /Users/voldemar/ стоит подставить адрес своей домашней директории. Этот процесс может занять некоторое время.

Достаем карту и вставляем обратно в RPi.

6. Настройка Netatalk

Netatalk — это демон, который будет запущен на RPi и непосредственно он будет эмулировать Apple Time Capsule.

Статья, где хорошо описана установка, находится здесь. Остальные статьи лучше проигнорировать.

Все рецепты из этой статьи я решил объединить в ansible playbook, которым предлагаю воспользоваться. Перед тем как перейти к установке, выполните на ноутбуке следующие команды:

➜  ~ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
➜ ~ brew install ansible
➜ ~ brew install git

Команды выше ставят brew, ansible, git. Дальше копируем скрипт настройки raspberry из моего репозитория и запускаем настройку:

➜  ~ git clone https://github.com/r00takaspin/raspi-timemachine-playbook.git
➜ ~ RPI_ADDR="$(arp -na | grep -i b8:27:eb | awk '{print $2}' | cut -c 2- | rev | cut -c 2- | rev)"
➜ ~ echo "[raspberry]\n$RPI_ADDR" >> hosts
➜ ~ ansible-playbook timemachine.yml -i hosts --become

Придется немного подождать и в течение примерно 10 минут произойдет установка Netatalk со всеми зависимостями и RPi перезагрузится.


Настройка резервного копирования

Остался последний шаг зайти в настройки резервного копирования и выбрать новый сетевой диск:

В моем случае пришлось подождать несколько дней до завершения первого бэкапа. Я пытался делать первый бэкап прямиком через USB на жесткий диск, чтобы ускорить процедуру, но после подключения жесткого диска по сети бэкап не был виден. Последующие бэкапы должны пройти быстрее.


Восстановление

Чтобы восстановить бэкап — необходимо отключить жесткий диск от RPi и подключить к макбуку. После этого мак нужно перезапустить и при загрузке удерживать Command-R. Дальше при восстановлении копии с внешнего диска вы увидите список резервных копий:

Стоит быть готовым к тому, что после восстановления из резервной копии Time Machine потеряет ссылку на последнюю резервную копию. Почему это происходит, мне так и не удалось разобраться. Но если это произошло — не стоит беспокоиться, нужно просто сделать резервную копию и она затронет изменения только за последний день.


Итог

  • За ~100$ сделали систему бэкапов сравнимую с Time Capsule
  • Первый бэкап прошел за 3 дня
  • Шифрование резервных копий не поддерживается
  • Если работаете с фото/видео или другими большими объемами данных, то, наверное, лучше использовать плату с USB 3.0/SATA интерфейсом, например Odroid-HC2, Orange Pi Plus 2 или Rock64. В этом случае не стоит забывать о покупке производительного роутера (рекомендую Mikrotik hAP ac) и пределе передачи данных по WiFi в 40–50MB/s.