LabHub
배우기 러닝패스 코스

SSHとファイル転送

rsyncで同期する

LabHub 에서 이어서 보기

한국어 원문으로 표시합니다.

목표

rsync 의 핵심 옵션을 손으로 확인합니다. 특히 후행 슬래시 규칙, --delete 의 위험과 가드, --link-dest 세대 백업 세 가지를 직접 만듭니다.

왜 중요한가

rsync 는 가장 많이 쓰고 가장 많이 틀리는 도구입니다. -a 가 ACL·확장 속성·하드 링크를 포함하지 않는다는 사실, 원본 경로 끝의 슬래시 하나가 디렉터리 깊이를 바꾼다는 사실, --delete 가 원본이 비어 있을 때 대상을 전멸시킨다는 사실 — 이 셋은 전부 실제 사고로 이어진 적이 있습니다. --link-dest 는 반대로 rsync 의 가장 아름다운 기능입니다. 각 세대가 전체 스냅샷처럼 보이면서 디스크는 변경분만 차지합니다.

단계

  1. /root/sync/src 아래에 다음을 만드세요. app/main.py, app/util.py, conf/app.yaml, logs/app.log, logs/error.log. 각 파일에는 아무 내용이나 한 줄 이상 넣으세요.
  2. /root/sync/src//root/sync/dst1/ 로 동기화하는 dry-run 을 변경 내역 표시와 함께 실행해 /root/sync/dryrun.txt 로 저장하세요.
  3. 같은 동기화를 SSH 를 통해 실제로 수행하세요. 대상은 root@127.0.0.1:/root/sync/dst1/ 이고 포트 2222, 키는 /root/.ssh/id_labhub 입니다. 완료 후 /root/sync/dst1/app/main.py 가 존재해야 합니다.
  4. 후행 슬래시 차이를 실증하세요. /root/sync/src (슬래시 없음)를 /root/sync/dst2/ 로 보내면 /root/sync/dst2/src/app/main.py 가 생겨야 합니다.
  5. /root/sync/backup.sh 스크립트를 작성하세요. set -euo pipefail 로 시작하고, 원본이 비어 있으면 종료 코드 1로 중단하는 검사를 포함하고, --delete 를 써서 /root/sync/src//root/sync/dst3/ 로 동기화해야 합니다. 원본 경로는 첫 번째 인자로 받고, 인자가 없으면 /root/sync/src/ 를 씁니다 — 채점기가 빈 디렉터리를 첫 인자로 넘겨 가드가 실제로 도는지 확인합니다. 스크립트를 실행해 /root/sync/dst3 를 만드세요.
  6. logs/ 아래를 제외하고 /root/sync/src//root/sync/dst4/ 로 동기화하세요. /root/sync/dst4/logs 는 존재하면 안 됩니다.
  7. 세대 백업을 만드세요. 먼저 /root/sync/gen/daily.1/ 로 전체 동기화한 뒤, --link-dest/root/sync/gen/daily.0/ 를 만드세요. 바뀌지 않은 파일은 두 세대가 같은 inode 를 공유해야 합니다.
  8. /root/sync/final.txt 를 다음 3줄로 만드세요. PENDING=<3번과 같은 동기화를 다시 dry-run 했을 때 전송 예정 파일 수> / DST4_HAS_LOGS=no / SHARED_INODE=yes PENDING 은 0 이어야 합니다.

참고

원본 트리 만들기

/root/sync/src 아래에 다음을 만드세요. app/main.py, app/util.py, conf/app.yaml, logs/app.log, logs/error.log. 각 파일에는 아무 내용이나 한 줄 이상 넣으세요.

하위 디렉터리와 로그 파일을 섞어 두면 뒤 단계의 제외 규칙이 의미를 갖습니다.

먼저 시뮬레이션

/root/sync/src//root/sync/dst1/ 로 동기화하는 dry-run 을 변경 내역 표시와 함께 실행해 /root/sync/dryrun.txt 로 저장하세요.

실제 변경 없이 무엇이 바뀔지만 보여 주는 옵션과, 변경 내용을 한 줄씩 표시하는 옵션을 함께 씁니다.

SSH 위로 실제 동기화

같은 동기화를 SSH 를 통해 실제로 수행하세요. 대상은 root@127.0.0.1:/root/sync/dst1/ 이고 포트 2222, 키는 /root/.ssh/id_labhub 입니다. 완료 후 /root/sync/dst1/app/main.py 가 존재해야 합니다.

rsync 에는 원격 셸 명령을 통째로 지정하는 옵션이 있습니다. 포트와 키를 그 안에 넣으세요.

후행 슬래시 차이 실증

후행 슬래시 차이를 실증하세요. /root/sync/src (슬래시 없음)를 /root/sync/dst2/ 로 보내면 /root/sync/dst2/src/app/main.py 가 생겨야 합니다.

같은 원본을 슬래시 유무만 바꿔 두 대상에 각각 보내고 결과 구조를 비교하세요.

가드가 있는 --delete

/root/sync/backup.sh 스크립트를 작성하세요. set -euo pipefail 로 시작하고, 원본이 비어 있으면 종료 코드 1로 중단하는 검사를 포함하고, --delete 를 써서 /root/sync/src//root/sync/dst3/ 로 동기화해야 합니다. 원본 경로는 첫 번째 인자로 받고, 인자가 없으면 /root/sync/src/ 를 씁니다 — 채점기가 빈 디렉터리를 첫 인자로 넘겨 가드가 실제로 도는지 확인합니다. 스크립트를 실행해 /root/sync/dst3 를 만드세요.

원본이 비어 있으면 즉시 중단하는 검사를 스크립트 앞에 넣으세요. set -euo pipefail 도 함께.

제외 규칙 적용

logs/ 아래를 제외하고 /root/sync/src//root/sync/dst4/ 로 동기화하세요. /root/sync/dst4/logs 는 존재하면 안 됩니다.

제외 패턴은 여러 번 지정할 수도 있고 파일에서 읽을 수도 있습니다. 로그 파일이 대상에 없어야 합니다.

하드 링크 세대 백업

세대 백업을 만드세요. 먼저 /root/sync/gen/daily.1/ 로 전체 동기화한 뒤, --link-dest/root/sync/gen/daily.0/ 를 만드세요. 바뀌지 않은 파일은 두 세대가 같은 inode 를 공유해야 합니다.

--link-dest 는 상대 경로로 주면 대상 기준으로 해석됩니다. 절대 경로가 안전합니다. 확인은 stat 의 링크 수로 합니다.

동기화 완료 증명

/root/sync/final.txt 를 다음 3줄로 만드세요. PENDING=<3번과 같은 동기화를 다시 dry-run 했을 때 전송 예정 파일 수> / DST4_HAS_LOGS=no / SHARED_INODE=yes PENDING 은 0 이어야 합니다.

제대로 동기화됐다면 같은 명령을 다시 dry-run 으로 돌렸을 때 전송할 것이 없어야 합니다.