배포했는데도 옛 코드가 도는 일이 있었고 php artisan config:clear 뒤에 php-fpm 을 재시작하니 해결됐다. 왜 그랬는지는 모른 채로 넘어갔는데 다음 배포에서 같은 일이 그대로 다시 났다.
Table of contents
Open Table of contents
배경 — 지우니 되는데 원인은 모르는 상태
지우고 재시작해서 증상이 풀리면 그 자리에서는 일이 끝난 것으로 보인다. 다만 왜 옛것이 남아 있었는지를 안 보면 다음 배포에서 같은 상태가 다시 만들어진다.
같은 일을 두 번 겪고 나서야 bootstrap/cache/config.php 가 언제 만들어지는지를 들여다봤다. 같은 증상이 반복된다는 것 자체가 원인을 안 봤다는 신호였다.
원인 — 캐시를 만드는 시점
config:cache 로 설정을 한 파일로 미리 만들어 두는 단계가 deploy.sh 안에 들어 있었다. 그런데 그 단계가 git pull 보다 앞에 놓여 있었다.
받기 전에 만들면 옛 설정으로 만든 파일이 새 코드와 함께 남으므로 배포가 끝나도 옛 설정이 이긴다. 순서를 바꿔서 받은 뒤에 만들게 하고 순서가 중요하다는 것을 주석으로 남겼다.
조치 — 지울 것과 안 지울 것
두 가지 방법이 있었는데 cache:clear 까지 포함해 전부 지우는 것과 config:clear 만 만들기 전에 넣는 것이다. 뒤쪽을 골랐다. 이유는 Redis 의 데이터 캐시까지 지우면 배포 직후에 모든 조회가 다시 채워지느라 응답이 느려져서다. 대신 데이터 캐시에 옛 구조의 값이 남아 있으면 그것은 따로 지워야 하는 것을 감수했다.
지울 것과 안 지울 것을 가르는 것이 이 단계의 판단이었다.
주의 — 빌드 시점과 실행 시점
컨테이너 안을 보니 이미지에 config.php 캐시가 이미 들어 있었고 Dockerfile 의 RUN 단계에서 만들어진 것이었다. 빌드 시점의 설정으로 만들어졌으므로 실행할 때 환경 변수를 줘도 그 파일이 이긴다.
그래서 빌드에서 그 단계를 빼고 entrypoint.sh 로 옮겼다. 설정이 실행 환경에서 정해지는 값이면 캐시도 실행 시점에 만들어져야 했다.
검증 — 파일 캐시와 프로세스 캐시
설정 캐시는 파일이라 지우면 다음 요청부터 반영되지만 OPcache 는 프로세스 메모리에 있어서 재시작이 필요했다. PHP 매뉴얼대로 opcache.validate_timestamps 를 끄면 파일이 바뀌어도 opcache_reset() 이나 웹 서버 재시작 전에는 반영되지 않기 때문이다.
배포 스크립트 끝에 /health 를 불러 APP_VERSION 이 기대값과 같은지 보게 하고 다르면 실패로 끝나게 했다. 그리고 지우고 재시작한 사건은 원인과 함께 기록하게 했는데 기록하지 않으면 같은 것을 반복하기 때문이다.
정리
- 지우고 재시작해서 풀려도 왜 그랬는지를 본다
- 반복 자체가 원인을 안 봤다는 신호다
- 캐시를 만드는 시점이 코드를 받는 시점보다 앞이면 옛것이 이긴다
- 만들기 전에 지우면 남을 자리가 없어진다
- 지울 것과 안 지울 것을 가른다
- 빌드 시점에 만들면 실행 환경 값이 안 들어간다
- 파일 캐시와 프로세스 메모리 캐시는 반영 방식이 다르다
- 배포 표시로 반영을 확인하고 사건을 원인과 함께 기록한다