낯선 시스템 앞에서 · 만지지 않고 답 내기 · 실습
만지지 않고 답하고, 만졌으면 되돌린다
목표
고객 운영 서버에 대한 다섯 가지 질문에 읽기 전용 수단만으로 답한다. 그다음 디렉터리 상태를 지문으로 굳히고 견주는 도구를 만들어, 꼭 바꿔야 하는 설정 한 줄을 바꾸고 확인하고 실제로 되돌려 스냅샷과 내용이 다른 파일이 0개임을 증명한다.
왜 중요한가
조사 중에 무언가를 바꾸면 그 뒤로 보이는 값이 원래 값인지 우리가 만든 값인지 알 수 없게 된다. 고객이 그 사이에 본 지표도 오염되고, "언제부터 이렇게 됐죠" 라는 질문에 우리가 답의 일부가 된다.
작은 변경일수록 되돌리는 것을 잊는다. 그리고 되돌렸다고 믿는 것과 되돌렸다는 것이 증명되는 것은 다르다. "원래대로 했습니다" 는 검증할 수 없는 문장이고, "되돌린 뒤 스냅샷과 견주었더니 내용이 다른 파일이 0개입니다" 는 확인할 수 있는 문장이다.
그보다 먼저 물을 것은 정말 바꿔야 답이 나오는가다. 많은 경우 같은 질문에 읽기 전용으로 답하는 길이 있다. 읽기 전용인지 아닌지를 스스로 속이지 않는 방법은 쓴 명령을 기록하는 것이다.
이 실습은 고객 승인을 받아 반영하는 변경 작업과 다르다. 그 앞 단계 — 조사 중에 손이 미끄러지는 순간에 대한 첫 주의 규율이다.
채점기는 여러분이 적어 낸 문구를 믿지 않는다. 다섯 답은 채점기가 직접 다시 재고, 스냅샷 도구에는 파일을 더하고 지우고 내용을 바꾸고 권한만 바꾸고 시각만 바꾼 자리를 만들어 다섯 가지를 갈라내는지 본다.
단계
1. /root/readonly/gen_site.py 를 만들어 실행해 /root/readonly/site/ 를 만드세요. 설정·주문 원장 240행·로그 180줄·조회기가 들어갑니다.
2. 읽기 전용 수단만으로 다섯 질문에 답해 /root/readonly/answers.json 에 적으세요. 답마다 쓴 명령을 함께 남깁니다.
3. /root/readonly/snapshot.py 를 만들어 디렉터리를 훑어 파일마다 지문·크기·권한·수정 시각을 담고, 지금 상태를 /root/readonly/baseline.json 에 굳히세요.
4. --baseline <스냅샷> 을 더해 견준 결과를 내게 하세요. added·removed·changed·mtime_only·same 다섯으로 가릅니다.
5. 설정의 max_retry 를 3에서 5로 바꾸고, 무엇을 왜 바꾸는지와 되돌리는 명령을 /root/readonly/change.json 에 적으세요.
6. 조회기로 바꾼 효과를 확인해 /root/readonly/verify.json 에 적으세요.
7. 되돌리고, 스냅샷과 견준 결과를 /root/readonly/revert_diff.json 에 남기세요. 내용이 다른 파일이 0개여야 합니다.
8. /root/readonly/readonly_report.md 에 네 절로 적으세요.
참고
- 답할 다섯 질문의 id 는
app_version·pending_orders·log_errors·backoff_ms·oldest_pending_days입니다. 차례대로 설정의 버전, 원장에서 status 가 pending 인 주문 수, 로그에서 ERROR 가 든 줄 수, 설정의 backoff_ms, 가장 오래된 pending 주문이 2026-09-17 기준 며칠 됐는지입니다. - 답 파일:
{"answers": [{"id", "value", "how"}]}. value 는 숫자면 숫자로, 문자열이면 문자열로 적습니다. how 에는 실제로 쓴 명령을 그대로 적습니다 — 읽기 전용이 아닌 명령이 섞여 있으면 채점기가 잡습니다. - 스냅샷 실행 계약:
python3 /root/readonly/snapshot.py --dir <디렉터리> --out <스냅샷 JSON>은 한 줄 요약을 표준출력에 내고 0 으로 끝납니다. 디렉터리가 없으면 3 입니다. - 스냅샷 JSON:
{"root", "taken_at", "files": {상대경로: {"sha256", "bytes", "mode", "mtime"}}}. mode 는 8진수 세 자리 문자열(644), mtime 은 초 단위 정수입니다. 심볼릭 링크와 디렉터리는 담지 않습니다. - 견주기 실행 계약:
python3 /root/readonly/snapshot.py --dir <디렉터리> --baseline <스냅샷> --out <차이 JSON>. - 차이 JSON:
{"added": [경로...], "removed": [경로...], "changed": [{"path", "fields": [...]}], "mtime_only": [경로...], "same": 정수}. changed 의 fields 는 sha256·bytes·mode 중 달라진 것만 오름차순으로 담습니다. 내용과 크기와 권한이 같고 시각만 다르면 changed 가 아니라 mtime_only 입니다. - 변경 기록:
{"target_file", "key", "before", "after", "sha256_before", "sha256_after", "why", "approved_by", "baseline", "apply", "rollback"}. sha256 두 개는 바꾸기 전과 후의 대상 파일 지문이고, rollback 에는 원래 값이 들어 있어야 합니다. - 확인 기록:
{"question", "command", "before", "after", "confirmed"}. 조회기는python3 /root/readonly/site/bin/report.py --q retry_budget [--conf <설정>]으로 부르고, 재시도 예산은 max_retry 의 두 배입니다. - 흔한 실수: 스냅샷을 바꾼 뒤에 뜨기, 되돌리는 명령을 바꾼 뒤에 적기(원래 값이 흐려집니다), 수정 시각 차이를 숨기려고 시각까지 맞추기, 한 번에 두 가지를 바꾸기.
- 조회기 report.py 가 고객 서버에 이미 있다는 설정과 max_retry 를 5로 올린다는 값은 이 실습의 가정입니다.
- 참고 문서: [파이썬 hashlib 문서](https://docs.python.org/3/library/hashlib.html)와 [os 문서](https://docs.python.org/3/library/os.html)가 지문과 파일 정보를, [POSIX 의 sys/stat.h](https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/sys_stat.h.html)가 수정 시각과 권한 비트의 뜻을, [POSIX 의 touch](https://pubs.opengroup.org/onlinepubs/9799919799/utilities/touch.html)가 시각을 손대는 방법을 설명합니다.
단계 8개
- 운영 서버를 손에 쥐기
- 읽기만으로 답하기
- 바꾸기 전 상태를 굳히기
- 견주는 기능 더하기
- 한 건만, 되돌릴 준비를 하고
- 의도한 효과가 났는지 값으로 보기
- 되돌리고 증명하기
- 무엇을 만졌고 무엇을 되돌렸는지 적기