코로케이션으로 옮긴 서버에서 배포 계정을 바꾸면서 옛 경로 /home/deploy 가 박힌 곳을 한 번에 /srv/app 으로 바꾸려 했다. grep -rl '/home/deploy' /srv | wc -l 로 세어 보니 천 개가 넘었다.
Table of contents
Open Table of contents
증상 — 천 개가 넘는다는 숫자
그 숫자를 보고 잠깐 멈췄는데 이 서비스에 설정 파일이 그렇게 많을 리가 없었다. --exclude-dir={.git,node_modules,logs,releases} 로 저장소 메타와 의존성 폴더와 로그와 배포 이력 폴더를 제외하고 다시 셌다.
한 개가 나왔고 그마저도 원격에서 ls -l 을 돌린 출력을 붙여 둔 임시 파일이었다. 나머지는 전부 Logstash 가 아직 안 걷어 간 실행 로그와 releases/DEPLOY.log 배포 이력이었다.
판단 기준 — 설정값과 사실의 차이
여기서 구분이 갈렸다. application.yml 에 적힌 경로는 앞으로 무엇을 쓸지를 정하는 값이므로 바뀌면 바꿔야 한다.
로그에 적힌 경로는 그때 실제로 그 경로였다는 기록이다. 같은 문자열인데 하나는 앞으로의 지시이고 다른 하나는 지나간 사실이라 성격이 정반대다.
조치 — 실행 순서를 뒤집었다
두 가지 방법이 있었다. 원래 순서대로 sed -i 로 전체를 치환하고 결과를 확인하는 것과, 제외 조건을 걸어 진짜 대상 건수를 먼저 산출하고 남은 건이 코드인지 기록인지 문맥까지 확인한 뒤에 치환하는 것이다. 뒤쪽을 골랐다. 이유는 로그는 치환하면 원래 값이 그 로그에만 있어 되돌릴 수 없어서다. 대신 몇 분이 더 드는 것을 감수했다.
앞의 두 단계를 합쳐도 몇 분이었다. 그 몇 분이 천 개의 기록을 지키는 값이었다.
주의 — 이진 파일이라는 함정
검색에 -I 를 붙인 것에도 이유가 있다. grep 매뉴얼대로 -I 는 이진 파일을 일치 없는 것으로 다루는데, 그 옵션이 없으면 jar 나 이미지 안의 우연한 일치까지 목록에 들어오고 치환하면 파일이 깨진다.
빌드 산출물이나 캐시가 섞여 있으면 특히 그렇다. 다시 만들면 되는 것들이라 깨져도 그 자리에서는 티가 안 나다가 나중에 원인 모를 오류로 나온다.
되돌릴 수 있는 것과 없는 것
application.yml 치환은 잘못돼도 원래 값을 알고 있으므로 다시 바꾸면 된다. 로그 치환은 원래 값이 그 로그에만 있었으므로 바꾸는 순간 원본이 사라진다.
치환한 이력을 근거로 판단하는 사람은 일어나지 않은 일을 사실로 읽게 된다. 되돌릴 수 없는 쪽에 해당하면 실행 전에 한 번 더 세는데 이번 건은 세어 보니 결국 아무것도 치환하지 않았다.
정리
- 경로 일괄 치환의 대상은 코드와
application.yml뿐이다 - 로그의 경로는 설정값이 아니라 그때의 사실이다
- 같은 문자열이 앞으로의 지시와 지나간 사실로 갈린다
- 치환하면 존재한 적 없는 이력이 만들어진다
- 일괄 치환 전에
--exclude-dir을 걸어 진짜 대상 건수를 산출한다 - 남은 건이 코드인지 기록인지 문맥까지 확인한다
- 이진 파일은
-I로 제외해야 우연한 일치를 안 건드린다 - 되돌릴 수 없는 치환은 실행 전에 한 번 더 센다