Back Up Encrypted ZFS Data without Unlocking It

Michael Lynch

잠금 해제 없이 암호화된 ZFS 데이터 백업하기

최근에 첫 홈 TrueNAS 서버를 직접 구축했습니다. 개인 데이터와 업무 데이터 대부분을 이 서버에 보관하고 있어서, TrueNAS와 그 파일 시스템인 ZFS를 최대한 활용하는 방법을 익히는 중입니다.

오늘은 암호화된 데이터를 백업하는 방법에 대해 이야기해보려 합니다.

소매 포장 상태의 NAS 서버 부품 사진완성된 서버 조립 사진

홈랩 TrueNAS 서버

ZFS의 멋진 기능 중 하나는 암호화된 데이터를 암호화된 상태 그대로 백업할 수 있다는 점입니다. 까다로운 부분은 TrueNAS가 오직 다른 TrueNAS 시스템으로만 백업할 것이라고 가정한다는 것입니다. 저처럼 암호화된 데이터를 일반적인 클라우드 스토리지 제공업체에 백업하고 싶다면 조금 더 손을 써야 합니다. 오늘 글에서는 그 방법을 보여드리겠습니다.

왜 암호화된 데이터를 백업해야 할까요?

자주 접근하지는 않지만 암호화된 데이터셋에 보관하고 싶은 파일들이 있습니다.

이전에 쓰던 Synology NAS에서는 암호화된 볼륨을 백업할 방법이 없었습니다. 데이터가 암호화되면 잠금을 해제하기 전까지는 어떤 것도 접근할 수 없었습니다. 대부분의 데이터는 그래도 괜찮지만, 자주 접근하지 않는 볼륨은 어떻게 해야 할까요? 매일 밤 실행되는 백업이 클라우드 스토리지로 복제하지 못했습니다.

TrueNAS는 다릅니다! 데이터셋이 암호화되어 잠겨 있어도 전체 백업과 증분 백업을 만들 수 있습니다. 자주 접근하지 않는 데이터를 복호화된 상태로 유지하지 않고도 백업할 수 있는 좋은 방법으로 보였습니다.

저는 resticresticpy를 이용해 데이터를 클라우드 스토리지에 백업하는데, restic이 암호화된 ZFS 백업에 접근할 수 있는 방법이 필요했습니다. 약간의 삽질과 직접 작성한 bash 스크립트 끝에 결국 성공했습니다.

TrueNAS로 암호화된 데이터셋을 백업하기 (잘못된 방법)

제가 하려는 것을 보여드리기 위해 diary-entries라는 데이터셋을 만들었습니다.

TrueNAS의 diary-entries 데이터셋 스크린샷

자, 이 데이터셋에 파일을 하나 넣어 보겠습니다:

echo "I enjoy Taylor Swift, but I don't want anyone to know" 
  > /mnt/pool1/diary-entries/2022-07-05.txt

그리고 백업을 받을 diary-entries-backup이라는 새 데이터셋을 만들어야 합니다. 이미 암호화된 백업 위에 암호화를 한 번 더 할 필요는 없으니, 이 새 데이터셋에서는 암호화를 비활성화했습니다:

암호화가 비활성화된 TrueNAS 데이터셋 생성 화면 스크린샷

이제 diary-entries 데이터셋의 암호화된 스냅샷을 암호화되지 않은 diary-entries-backup 데이터셋으로 백업하는 복제 작업을 설정할 준비가 되었습니다. 이렇게 해두면 restic이 diary-entries-backup 데이터셋에 접근해 클라우드 스토리지로 복제할 수 있습니다.

복제 작업을 만들 때 TrueNAS가 암호화된 데이터셋을 복제하고 있다는 경고를 표시합니다. 괜찮습니다. 제가 원하는 것이 바로 그것이니까요. 암호화된 스냅샷을 그대로 암호화된 상태로 클라우드에 백업하고 싶습니다:

TrueNAS 경고: 다음 암호화된 데이터셋을 복제하고 있습니다: 'pool1/diary-entries'. 대상 데이터셋은 잠기며 원본 데이터셋의 암호화 키로 잠금을 해제할 수 있습니다

복제 작업을 시작했는데… 실패합니다:

암호화된 데이터셋 'pool1/diary-entries'를 기존의 암호화되지 않았거나 관련 없는 데이터셋 'pool1/diary-entries-backup'으로 전송할 수 없습니다.

오류 메시지는 다음과 같습니다:

Unable to send encrypted dataset ‘pool1/diary-entries’ to existing unencrypted or unrelated dataset ‘pool1/diary-entries-backup’.

아이고!

암호화된 데이터셋을 암호화되지 않은 데이터셋으로 복제하는 걸 허용하지 않습니다. 스냅샷 자체가 이미 암호화되어 잠겨 있는데, 그걸 담는 데이터셋이 암호화되어 있든 아니든 무슨 상관인지 좀 의아했습니다.

참고: 이 방법이 동작하지 않은 건 ZFS 복제에 대한 제 이해가 잘못됐기 때문입니다. 올바른 모델은 뒤에서 설명하겠습니다.

명령줄 인터페이스로 ZFS 사용하기

TrueNAS는 기본적으로 ZFS를 감싼 친절한 UI입니다. 일을 더 쉽게 하기 위해 TrueNAS를 건너뛰고 ZFS의 더 강력한 명령줄 인터페이스(CLI)로 직접 들어갔습니다.

ZFS 문서에는 데이터셋을 복제하는 예제 명령어가 있습니다:

zfs send pool/fs@a | zfs receive poolB/received/fs@a

@a는 이름이 a인 스냅샷을 의미하므로, 2022-07-05라는 이름의 스냅샷을 만들어 보겠습니다:

zfs snapshot pool1/diary-entries@2022-07-05

그리고 diary-entriesdiary-entries-backup으로 복제해 보겠습니다:

$ zfs send pool1/diary-entries@2022-07-05 \
  | zfs receive pool1/diary-entries-backup
cannot receive new filesystem stream: destination 'pool1/diary-entries-backup' exists
must specify -F to overwrite it

기존 데이터셋으로는 복제할 수 없다는 거군요? 그럼 diary-entries-backup2라는 새 데이터셋 이름을 지정해 보겠습니다:

$ zfs send pool1/diary-entries@2022-07-05 \
  | zfs receive pool1/diary-entries-backup
warning: cannot send 'pool1/diary-entries@2022-07-05': dataset key must be loaded
cannot receive: failed to read from stream

diary-entries가 복호화되지 않으면 복제를 거부하는 건가요? 암호화된 데이터셋도 복제할 수 있다고 생각했는데…

ZFS 문서를 다시 보니 --raw 플래그가 있었습니다:

-w, --raw 암호화된 데이터셋의 경우 디스크에 존재하는 그대로 데이터를 전송합니다.

좋습니다, 시도해 보겠습니다:

$ zfs send --raw pool1/diary-entries@2022-07-05 \
  | zfs receive pool1/diary-entries-backup2

성공입니다!

TrueNAS 웹 UI로 돌아가서 무엇이 생성됐는지 확인해 보겠습니다:

TrueNAS의 diary-entries-backup2 스크린샷, 암호화된 데이터셋으로 표시됨

이런, 원하던 결과가 아닙니다.

ZFS가 또 다른 암호화된 데이터셋을 만들어 버렸습니다. 제가 원하는 건 암호화되지 않은 데이터셋 위에 놓인 암호화된 백업 파일인데, ZFS는 그런 방법을 제공하지 않는 것 같았습니다.

깨달음: 출력을 파일로 리다이렉트할 수 있다

ZFS 복제 명령어를 다시 보니 뭔가 눈에 띄었습니다:

$ zfs send --raw pool1/diary-entries@2022-07-05 \
  | zfs receive pool1/diary-entries-backup2

zfs send 명령어의 출력을 zfs receive 명령어로 파이프하는 구조인데, zfs receive로 파이프하는 대신 그냥 파일로 쓰면 어떨까 하는 생각이 들었습니다.

$ zfs send --raw pool1/diary-entries@2022-07-05 \
  > /mnt/pool1/diary-entries-backup/snapshot@2022-07-05

오, 됐습니다! 암호화되지 않은 diary-entries-backup 데이터셋에 24KB짜리 백업 파일을 만들었습니다:

$ du -h /mnt/pool1/diary-entries-backup/*
24K    /mnt/pool1/diary-entries-backup/snapshot@2022-07-05

이제 암호화되지 않은 데이터셋에 파일 형태로 백업이 있으니, restic이 다른 파일처럼 클라우드에 백업할 수 있습니다.

하지만 먼저 zfs receive 명령어로 이 백업으로부터 diary-entries의 데이터를 복원할 수 있는지 테스트해 보겠습니다:

$ zfs receive pool1/diary-entries-backup3 \
  < /mnt/pool1/diary-entries-backup/snapshot@2022-07-05

성공했고, 풀에 새 데이터셋이 생성되었습니다:

암호화된 데이터셋으로 표시된 diary-entries-backup3 스크린샷

진짜 중요한 순간입니다! diary-entries에 썼던 것과 같은 비밀번호로 diary-entries-backup3을 복호화했을 때 동일한 데이터가 들어 있다면, diary-entries-backup/snapshot@2022-07-05 파일이 2022-07-05 스냅샷 시점의 diary-entries 데이터셋을 완전히 백업한 것이라는 걸 알 수 있습니다.

그래서 diary-entries-backup3을 같은 비밀번호로 복호화하고 내용을 확인했습니다:

$ cat /mnt/pool1/diary-entries-backup3/2022-07-05.txt
I enjoy Taylor Swift, but I don’t want anyone to know

만세! 성공했습니다.

암호화된 데이터셋을 한 번도 잠금 해제하지 않고도 암호화된 백업 파일을 성공적으로 만들 수 있게 된 것입니다.

증분 백업 만들기

이 방식으로 백업하려는 데이터셋 중 하나는 스크린캐스트 영상 캡처용입니다. 현재 12GB이고 앞으로 더 커질 예정인데, 매일 백업할 때마다 12GB짜리 파일을 새로 만들고 싶지는 않습니다.

다행히 ZFS는 증분 백업을 지원합니다. 월요일에 데이터셋을 스냅샷하고 화요일에 다시 스냅샷하면, 월요일과 화요일 모두에 대해 전체 백업 파일을 만들 필요가 없습니다. 대신 화요일 백업은 월요일 이후 변경된 차이만 담으면 됩니다.

보여드리기 위해 diary-entries 데이터셋에 데이터를 조금 더 추가해 보겠습니다:

echo "Upon reflection, I'm not ashamed of how much I enjoy You Belong with Me" \
  > /mnt/pool1/diary-entries/2022-07-06.txt

그리고 최신 항목을 포함한 새 스냅샷을 만들겠습니다:

zfs snapshot pool1/diary-entries@2022-07-06

마지막으로 -i 플래그로 기준 스냅샷을 지정해 2022-07-05 스냅샷을 기준으로 한 증분 백업을 만들겠습니다:

zfs send \
  --raw \
  --verbose \
  -i pool1/diary-entries@2022-07-05 \
  pool1/diary-entries@2022-07-06 \
  > /mnt/pool1/diary-entries-backup/snapshot@2022-07-05-to-2022-07-06

성공입니다! 명령어가 새로운 증분 백업을 만들었습니다:

$ du -h /mnt/pool1/diary-entries-backup/*
 24K    /mnt/pool1/diary-entries-backup/snapshot@2022-07-05
6.5K    /mnt/pool1/diary-entries-backup/snapshot@2022-07-05-to-2022-07-06

이 데모에서는 파일이 워낙 작아 좀 우스꽝스럽지만, 두 번째 스냅샷이 첫 번째보다 훨씬 작은 걸 확인할 수 있습니다. 2022-07-05 스냅샷 이후 변경된 내용만 담고 있기 때문입니다.

백업으로부터 원본 데이터를 복원해야 테스트가 끝이니, 증분 백업을 이용해 새 데이터셋을 만들어 보겠습니다:

# Recover from full backup.
zfs receive pool1/diary-entries-backup4@2022-07-05 \
  < /mnt/pool1/diary-entries-backup/snapshot@2022-07-05
# Add changes since incremental backup.
zfs receive pool1/diary-entries-backup4 \
  < /mnt/pool1/diary-entries-backup/snapshot@2022-07-05-to-2022-07-06

복원했습니다!

암호화된 데이터셋으로 표시된 diary-entries-backup3 스크린샷

그리고 두 파일이 모두 있습니다:

$ tail -n +1 /mnt/pool1/diary-entries-backup4/*
==> /mnt/pool1/diary-entries-backup4/2022-07-05.txt <==
I enjoy Taylor Swift, but I don't want anyone to know

==> /mnt/pool1/diary-entries-backup4/2022-07-06.txt <==
Upon reflection, I'm not ashamed of how much I enjoy Blank Space

먼저 전체 백업으로부터 복원한 뒤 증분 백업으로 업데이트해야 한다는 점에 유의하세요. 증분 백업으로 바로 복원을 시작하려고 하면 ZFS가 오류를 내며 실패합니다:

# This isn't going to work because it's an incremental backup.
$ zfs receive pool1/diary-entries-backup5 \
  < /mnt/pool1/diary-entries-backup/snapshot@2022-07-05-to-2022-07-06
cannot receive incremental stream: destination 'pool1/diary-entries-backup5' does not exist

백업 스크립트 작성하기

이제 ZFS로 데이터셋을 복제하는 원리를 이해했으니, 반복적인 백업 작업을 자동화할 수 있도록 셸 스크립트를 만들 차례입니다.

먼저 시스템별로 달라지는 값들을 정의하는 settings.sh라는 파일을 만들겠습니다:

readonly POOL="mypool"
readonly BASE_DIR="/mnt/${POOL}/encrypted-backups"
readonly FULL_SNAPSHOTS_DIR="${BASE_DIR}/full-snapshots"
readonly INCREMENTAL_SNAPSHOTS_DIR="${BASE_DIR}/incremental-snapshots"

DATASETS=()
DATASETS+=("documents")
DATASETS+=("music")
DATASETS+=("emails")
readonly DATASETS

이제 데이터셋의 전체 백업을 만드는 replicate-full-snapshots.sh라는 스크립트를 만들겠습니다:

#!/bin/bash

# Create full snapshots of datasets in DATASETS array.

set -eux

. settings.sh

mkdir -p "${FULL_SNAPSHOTS_DIR}"

TIMESTAMP="$(date -Iseconds | sed 's/://g' | sed 's/+0000/Z/g')"
readonly TIMESTAMP

for DATASET in "${DATASETS[@]}"; do
  # Take a snapshot.
  SNAPSHOT_NAME="${POOL}/${DATASET}@${TIMESTAMP}"
  zfs snapshot "${SNAPSHOT_NAME}"

  # Write the snapshot to a file.
  OUTPUT_FILENAME="${SNAPSHOT_NAME//${POOL}\/}"
  zfs send --raw --verbose "${SNAPSHOT_NAME}" > "${FULL_SNAPSHOTS_DIR}/${OUTPUT_FILENAME}"
done

이 스크립트는 settings.sh에서 정의한 각 데이터셋을 순회하며 새로운 스냅샷을 만들고, 각 스냅샷의 전체 백업을 생성합니다.

다음으로 증분 백업을 만드는 replicate-incremental-snapshots.sh 스크립트를 만들겠습니다:

#!/bin/bash

# Create incremental snapshots of datasets in DATASETS array relative to their
# last full snapshot.

set -eux

. settings.sh

mkdir -p "${INCREMENTAL_SNAPSHOTS_DIR}"

TIMESTAMP="$(date -Iseconds | sed 's/://g' | sed 's/+0000/Z/g')"
readonly TIMESTAMP

for DATASET in "${DATASETS[@]}"; do
  # Take a snapshot.
  INCREMENTAL_SNAPSHOT="${POOL}/${DATASET}@${TIMESTAMP}"
  zfs snapshot "${INCREMENTAL_SNAPSHOT}"

  # Find the most recent full snapshot.
  BASE_SNAPSHOT_FILENAME="$(basename "$(ls -tr "${FULL_SNAPSHOTS_DIR}/${DATASET}"* | tail -1)")"
  BASE_SNAPSHOT="${POOL}/${BASE_SNAPSHOT_FILENAME}"

  # Write the incremental snapshot to a file.
  OUTPUT_FILENAME="${INCREMENTAL_SNAPSHOT//${POOL}\/}"
  OUTPUT_PATH="${INCREMENTAL_SNAPSHOTS_DIR}/${OUTPUT_FILENAME}"
  zfs send --raw --verbose -i "${BASE_SNAPSHOT}" "${INCREMENTAL_SNAPSHOT}" \
    > "${OUTPUT_PATH}"
done

replicate-incremental-snapshots.sh는 각 데이터셋의 가장 최근 전체 백업을 찾아 그것을 기준으로 증분 백업을 만듭니다.

replicate-incremental-snapshots.sh는 단순함을 위해 디스크 공간을 다소 낭비합니다. 항상 마지막 전체 백업을 기준으로 증분 백업을 만들고, 더 최근의 증분 백업은 무시합니다. 즉 월요일에 전체 백업을 만들고 그 다음 5일 동안 증분 백업을 만든다면, 수요일 백업에는 화요일 백업과 중복되는 데이터가 포함될 가능성이 높아 공간이 낭비됩니다. 증분 백업 위에 또 증분 백업을 쌓는 방식도 고려했지만, 백업 시스템에서 원하지 않을 정도로 복잡성과 실수 가능성이 커진다고 판단했습니다.

마지막으로, 복원할 수 없으면 백업은 별 의미가 없으니, 백업 파일을 다시 ZFS 데이터셋으로 변환하는 snapshot-to-dataset.sh라는 편의 스크립트를 만들었습니다:

#!/bin/bash
#
# Recover a dataset from an encrypted snapshot.
#
# Usage:
#   ./snapshot-to-dataset.sh new-dataset-name full-snapshot-path [incremental-snapshot-path]

set -ex

. settings.sh

NEW_DATASET_NAME="$1"
readonly NEW_DATASET_NAME

FULL_SNAPSHOT_PATH="$2"
readonly FULL_SNAPSHOT_PATH

INCREMENTAL_SNAPSHOT_PATH="$3"
readonly INCREMENTAL_SNAPSHOT_PATH

set -u

# Restore from base snapshot
zfs receive "${POOL}/${NEW_DATASET_NAME}" < "${FULL_SNAPSHOT_PATH}"

if [[ -n "${INCREMENTAL_SNAPSHOT_PATH}" ]]; then
  # Update dataset to latest incremental snapshot
  zfs receive "${POOL}/${NEW_DATASET_NAME}" < "${INCREMENTAL_SNAPSHOT_PATH}"
fi

이 스크립트들은 GitHub에서 볼 수 있습니다:

편의 스크립트 실행해 보기

제 스크립트가 어떻게 동작하는지 보여드리기 위해 diary-entries 예제 데이터셋으로 시연해 보겠습니다:

settings.sh 파일은 다음과 같습니다:

readonly POOL="pool1"
readonly BASE_DIR="/mnt/${POOL}/secure-backups"
readonly FULL_SNAPSHOTS_DIR="${BASE_DIR}/full-snapshots"
readonly INCREMENTAL_SNAPSHOTS_DIR="${BASE_DIR}/incremental-snapshots"

DATASETS=()
DATASETS+=("diary-entries")
readonly DATASETS

이제 전체 백업을 실행해 보겠습니다:

./replicate-full-snapshots.sh

잘 됐을까요?

$ du -h /mnt/pool1/secure-backups/full-snapshots/diary-entries*
24K    /mnt/pool1/secure-backups/full-snapshots/diary-entries@2022-07-27T073416-0400

좋네요, 예상대로 백업 파일이 생성되었습니다.

이제 새 데이터를 추가해 보겠습니다:

echo "I've got a blank space, so I'll write a new diary entry" \
  > /mnt/pool1/diary-entries/2022-07-27.txt

다음으로 2022-07-27.txt를 포함하는 증분 백업을 만들겠습니다:

./replicate-incremental-snapshots.sh

이제 incremental-snapshots 폴더에 새 파일이 생겼을 것입니다:

$ du -h /mnt/pool1/secure-backups/incremental-snapshots/diary-entries*
12K    /mnt/pool1/secure-backups/incremental-snapshots/diary-entries@2022-07-27T074246-0400

그리고 이걸로 복원할 수 있는지 확인해 보겠습니다. 제 snapshot-to-dataset.sh 스크립트의 사용법은 다음과 같다는 걸 기억하세요:

./snapshot-to-dataset.sh new-dataset-name full-backup-file [incremental-backup-file]

그럼 이걸로 백업으로부터 복원을 시도해 보겠습니다:

./snapshot-to-dataset.sh \
  diary-entries-backup5 \
  /mnt/pool1/secure-backups/full-snapshots/diary-entries@2022-07-27T073416-0400 \
  /mnt/pool1/secure-backups/incremental-snapshots/diary-entries@2022-07-27T074246-0400

성공입니다! 모든 파일이 들어 있는 새 데이터셋이 생성되었습니다:

tail -n +1 /mnt/pool1/diary-entries-backup5/*
==> /mnt/pool1/diary-entries-backup5/2022-07-05.txt <==
I enjoy Taylor Swift, but I don't want anyone to know

==> /mnt/pool1/diary-entries-backup5/2022-07-06.txt <==
Upon reflection, I'm not ashamed of how much I enjoy Blank Space

==> /mnt/pool1/diary-entries-backup5/2022-07-27.txt <==
I've got a blank space, so I'll write a new diary entry

백업 스케줄링

이제 백업을 스크립트로 만들었으니 정기적으로 실행되도록 예약 작업을 만들 수 있습니다. 다행히 TrueNAS 웹 UI에서 쉽게 할 수 있어서, 작업 > Cron 작업에서 작업을 만들면 됩니다.

첫 번째 cron 작업은 전체 백업을 만드는 월간 작업입니다:

명령어가 '/mnt/pool1/secure-backups/scripts/replicate-full-snapshots.sh'이고 일정이 '0 0 3 * *'인 TrueNAS Cron 작업

매월 1일 새벽 3시에 시작하도록 예약했는데, 그 시간이 제가 가장 확실하게 잠들어 있는 시간이기 때문입니다.

다음으로 월간 스냅샷을 기준으로 증분 백업을 만드는 일일 작업을 만들고 싶습니다. 새벽 3시의 전체 백업이 끝날 시간을 확보하기 위해 4시에 시작하도록 하겠습니다:

명령어가 '/mnt/pool1/secure-backups/scripts/replicate-incremental-snapshots.sh'이고 일정이 '0 0 4 * *'인 TrueNAS Cron 작업

cron 작업이 성공적으로 실행되고 있는지 확인하려면 /var/log/cron의 로그를 확인하면 됩니다:

$ tail /var/log/cron
Jul 28 05:45:03 truenas 1 2022-07-28T08:45:03.757011-04:00 truenas.local cron 302 - - + OUTPUT_PATH=/mnt/pool1/secure-backups/incremental-snapshots/videos@2022-07-28T084502-0400
Jul 28 05:45:03 truenas 1 2022-07-28T08:45:03.757087-04:00 truenas.local cron 302 - - + [[ -f /mnt/pool1/secure-backups/incremental-snapshots/videos@2022-07-28T084502-0400 ]]
Jul 28 05:45:03 truenas 1 2022-07-28T08:45:03.757168-04:00 truenas.local cron 302 - - + zfs send --raw --verbose -i pool1/videos@2022-07-28T080351-0400 pool1/videos@2022-07-28T084502-0400
Jul 28 05:45:03 truenas 1 2022-07-28T08:45:03.761156-04:00 truenas.local cron 302 - - send from pool1/videos@2022-07-28T080351-0400 to pool1/videos@2022-07-28T084502-0400 estimated size is 624B
Jul 28 05:45:03 truenas 1 2022-07-28T08:45:03.761291-04:00 truenas.local cron 302 - - total estimated size is 624
Jul 28 05:45:03 truenas 1 2022-07-28T08:45:03.761877-04:00 truenas.local cron 302 - - + echo 'Finished replicating incremental snapshots'
Jul 28 05:45:03 truenas 1 2022-07-28T08:45:03.761958-04:00 truenas.local cron 302 - - Finished replicating incremental snapshots

백업 실패 알림

두 달 뒤에 백업이 실패하기 시작하면 어떻게 될까요? 매일 로그를 들여다보며 백업이 잘 되고 있는지 확인할 수는 없습니다.

다행히 예약된 작업이 실행되지 않았을 때 알려주는 서비스가 여러 가지 있습니다. 저는 무료 티어가 넉넉하고 설정이 쉬운 Cronitor를 선택했습니다.

Cronitor에서 TrueNAS 서버의 전체 백업 일정과 동일한 0 0 3 * * 일정으로 새 모니터를 만들었습니다:

이름이 truenas-full-backups이고 일정이 0 0 3 * *인 새 Cronitor 모니터

Cronitor는 이 모니터에 대해 다음과 같은 고유 URL을 생성합니다:

https://cronitor.link/p/88e0dba70a87424b83c5fd3e9227ac92/1bBG6q

전체 백업 cron 작업이 성공을 보고하도록, 백업이 성공적으로 완료되면 Cronitor에 성공 신호를 보내는 curl 명령어를 cron 작업에 추가합니다:

/mnt/pool1/secure-backups/scripts/replicate-full-snapshots.sh && curl --silent https://cronitor.link/p/[내 텔레메트리 ID]?state=complete

증분 백업 작업에도 같은 과정을 반복하면 끝입니다!

이제 암호화된 ZFS 데이터셋의 백업을 만드는 견고한 시스템을 갖추었고, 작업이 실패하면 Cronitor로부터 알림을 받게 됩니다.

주의: 암호화 루트를 백업하세요

ZFS를 다른 ZFS 시스템이 아닌 파일로 백업할 때의 중요한 함정을 댓글에서 지적해 주신 @Invisible님과 @adamkf님께 감사드립니다.

항상 데이터셋의 암호화 루트를 백업하세요.

암호화된 데이터셋의 하위 데이터셋을 백업하는 경우, 하위 데이터셋에 대한 zfs send는 다른 TrueNAS 시스템에서 스냅샷을 복원하는 데 필요한 모든 데이터를 담지 못하므로 백업이 무용지물이 됩니다.

데이터셋의 암호화 루트를 확인하려면 zfs get -r encryptionroot pool/dataset을 실행하세요. 데이터셋에 부모 암호화가 없으면, 해당 데이터셋 자체가 암호화 루트임을 보여주는 출력이 나타납니다:

$ zfs get -r encryptionroot pool1/diary-entries | head -n 2
NAME                                     PROPERTY        VALUE                SOURCE
pool1/diary-entries                      encryptionroot  pool1/diary-entries  -

데이터셋 자체가 암호화 루트라면 추가로 백업해야 할 데이터셋은 없습니다.

스냅샷 파일로부터 복원할 수 있는지 검증하기 위해 별도의 ZFS 시스템, 심지어 TrueNAS VM에서도 백업을 테스트해 보시길 권장합니다.

소스 코드

편의 스크립트를 GitHub에 공개했습니다:

원문은 Michael Lynch님이 에 게재했습니다.

이 글은 muse-spark-1.2-contributor 모델을 사용해 번역했습니다.