커밋하면 알아서 배포되게 만들기
처음에는 코드를 고칠 때마다 서버에 원격 접속해서 파일을 올리고, 빌드하고, 컨테이너를 다시 띄웠습니다. 몇 번은 할 만하지만 반복되면 손이 무거워집니다. 고쳐야 할 게 보여도 "나중에 몰아서 하자"가 됩니다. 결국 배포가 번거로우면 개선이 느려진다는 걸 체감하고 자동화를 붙였습니다.
흐름은 단순하게
목표는 하나였습니다. 내 PC에서 커밋하면, 그 다음은 알아서. 흐름은 이렇습니다. 형상관리 서버에 커밋이 들어오면, 저장소에 걸어둔 훅이 빌드 서버를 호출합니다. 빌드 서버는 최신 소스를 내려받아 배포 경로에 복사하고, 컨테이너 이미지를 다시 만들어 기존 컨테이너와 교체합니다. 제가 하는 일은 커밋 버튼을 누르는 것뿐입니다.
자동 빌드가 안 걸리던 이유
처음에는 커밋을 해도 빌드가 시작되지 않았습니다. 수동으로 실행하면 잘 되는데 자동만 안 됐습니다. 로그를 열어보니 일정 시각 이후로 변경 감지가 아예 멈춰 있었습니다. 빌드 서버 컨테이너를 새로 만들면서 주기적으로 저장소를 확인하는 설정이 다시 등록되지 않은 게 원인이었습니다.
그래서 "주기적으로 확인"에 의존하지 않고, 커밋 순간에 곧바로 빌드 서버를 호출하는 방식으로 바꿨습니다. 저장소의 커밋 후 훅에서 빌드 URL을 한 번 호출하게 하는 아주 단순한 스크립트입니다. 이걸 붙이고 나서는 커밋과 거의 동시에 빌드가 시작됩니다. 여기서도 사소한 함정이 있었습니다. 호출 대상 작업 이름을 실제와 다르게 적어두는 바람에 한동안 엉뚱한 곳을 부르고 있었습니다.
"성공"인데 반영이 안 되는 배포
가장 헷갈렸던 건 빌드는 성공이라고 뜨는데 사이트에는 아무 변화가 없던 경우였습니다. 로그를 끝까지 내려보니 배포 명령이 실행되지 못하고 조용히 넘어가 있었습니다. 빌드 서버 컨테이너 안에 배포에 필요한 명령어가 설치돼 있지 않았던 겁니다. 스크립트가 중간에 실패해도 멈추지 않고 끝까지 진행한 뒤 "완료"를 찍고 있었습니다.
두 가지를 고쳤습니다. 첫째, 필요한 도구를 이미지 자체에 포함시켜 컨테이너를 새로 만들어도 사라지지 않게 했습니다. 둘째, 배포 스크립트가 중간에 실패하면 즉시 멈추고 실패로 표시되게 했습니다. 성공이라고 적힌 초록불을 믿을 수 없다면 자동화의 의미가 없으니까요.
복사되지 않는 파일이 있었다
배포는 소스를 통째로 복사하는 방식이었는데, 여기에 함정이 있었습니다. 점으로 시작하는 숨김 파일은 복사 대상에서 빠집니다. 하필 접속 정보와 비밀값을 담은 설정 파일이 그런 이름이었습니다. 그 파일은 처음부터 서버에만 두고 저장소에는 올리지 않는 것으로 정리했습니다. 어차피 비밀값을 저장소에 넣지 않는 게 맞으니 결과적으로는 잘된 일이었지만, 원인을 찾기 전까지는 "왜 로컬에선 되는데 서버에선 접속이 안 되지"를 한참 붙들었습니다.
새로 만든 숨김 파일이 커밋에서 통째로 누락된 적도 있습니다. 형상관리에 새 파일을 등록하는 걸 잊으면 내 PC에서는 멀쩡하고 서버에서만 없습니다. 로그에 에러로 남지 않으니 눈치채기까지 며칠이 걸렸습니다.
스크립트가 자기 자신을 복사하고 있었다
배포 단계가 길어지자 명령들을 스크립트 파일 하나로 묶었습니다. 그런데 어느 날부터 배포가 첫 줄에서 조용히 끝나 있었습니다. 빌드는 여전히 성공으로 표시됐고요. 원인은 허무했습니다. 빌드 서버가 이미 소스를 배포 경로로 옮긴 뒤에 그 안에서 스크립트를 실행하다 보니, 스크립트의 첫 단계인 "소스 복사"가 같은 파일을 자기 자신 위에 덮어쓰려다 오류를 낸 것입니다. 실패하면 즉시 멈추게 해둔 설정 때문에 거기서 끝난 거죠.
실행 위치를 확인해 원본과 목적지가 같으면 복사를 건너뛰도록 고쳤습니다. 여기서 하나 더 알게 된 건, 바깥에서 부르는 스크립트에 실패 중단 설정이 없으면 안쪽 실패가 성공으로 보인다는 점이었습니다. 그래서 배포 로그를 볼 때는 마지막 줄이 아니라 도커 명령이 실제로 찍혔는지를 봅니다.
빌드 컨테이너는 데이터베이스를 볼 수 없다
더 근본적인 문제도 있었습니다. 관리 화면에서 글을 써도 사이트에는 반영되지 않았습니다. 글은 데이터베이스에 잘 저장돼 있는데 화면에 나오는 건 예전 내용이었습니다. 빌드할 때 데이터베이스에서 최신 내용을 가져와 정적 파일로 굳히는 단계가 있었는데, 격리된 빌드 환경 안에서는 데이터베이스에 접근할 수 없어 그 단계가 매번 조용히 건너뛰어졌습니다. 대신 예전에 커밋해 둔 파일이 쓰였고요.
결국 구조를 바꿨습니다. 정적 페이지를 만드는 코드를 함수로 떼어내, 빌드할 때와 서버가 돌고 있을 때 같은 코드를 쓰도록 했습니다. 관리 화면에서 글을 저장하면 서버가 그 자리에서 정적 파일을 다시 만들어 공유 폴더에 씁니다. 웹서버는 그 폴더를 먼저 보고, 없으면 빌드할 때 구워둔 파일로 넘어갑니다. 재생성이 실패해도 사이트는 멀쩡하고, 글을 쓰면 재배포 없이 반영됩니다.
남은 교훈
자동 배포를 붙이고 나서 확실히 달라진 건 고치는 속도였습니다. 오타 하나도 부담 없이 바로 고쳐 올립니다. 대신 배포가 쉬워진 만큼 잘못된 변경도 순식간에 반영되므로, 빌드가 통과하는지 먼저 확인하는 습관이 더 중요해졌습니다. 자동화는 손을 덜어주는 것이지, 확인을 대신해 주지는 않았습니다.
지금은 배포가 끝나면 세 가지를 봅니다. 컨테이너가 전부 떠 있는지, 바뀐 파일이 실제로 컨테이너 안에 들어갔는지, 공개 주소에서 응답이 기대한 대로인지. 이 셋이면 대부분 걸러집니다.