웹앱 실무 시리즈에서 배포 이야기를 시작하게 됐어요. 폼, 에디터, 국제화, 실시간까지 만드는 이야기를 실컷 나눴으니, 이제는 그 만든 걸 사용자한테 실제로 내보내는 일을 다뤄 볼 차례거든요. 저는 배포라는 단어가 현장에서 참 흐릿하게 쓰인다고 늘 느껴요. 누구는 코드를 서버에 올리는 순간을 배포라 부르고, 누구는 빌드가 끝난 시점을 배포라 부르죠. 이 첫 편에서는 그 흐릿한 개념부터 또렷하게 정리해 보려 해요.
배포가 뭔지 정확히 알아야, 앞으로 이어질 파이프라인이나 무중단, 롤백 같은 이야기가 제자리를 찾거든요. 이번 편에서는 빌드랑 배포가 어떻게 다른지, 왜 한 번 만든 걸 여러 번 올려야 하는지, 정적이냐 서버냐가 왜 갈리는지, 그리고 배포를 잘한다는 게 뭘로 판단되는지를 제 실패담을 곁들여 풀어 볼게요. 배포가 화려한 마법이 아니라 반복되는 규율에 가깝다는 걸 같이 느껴 보면 좋겠어요.
배포가 정확히 뭐예요?
가장 먼저 바로잡고 싶은 건 빌드랑 배포를 뭉뚱그리는 습관이에요. 빌드는 우리가 쓴 소스코드를 실제로 돌릴 수 있는 산출물로 바꾸는 과정이에요. 사람이 읽기 좋은 코드를 기계랑 브라우저가 다루기 좋은 형태로 바꾸고, 여러 파일을 묶고, 필요 없는 부분을 덜어 내죠. 반면 배포는 그렇게 만들어진 산출물을 서버나 배포망에 올려서 사용자가 닿게 하는 일이에요. 빌드는 무언가를 만드는 일이고, 배포는 그 만든 걸 세상에 잇는 일이거든요.
예를 들어 npm run build를 돌리면 소스가 산출물 폴더로 바뀌어요. 여기까지가 빌드예요. 그다음 그 폴더를 wrangler pages deploy dist 같은 명령으로 호스팅에 올리는 순간이 배포죠. 두 단계는 이어져 있지만 엄연히 다른 사건이라, 각각 성공과 실패를 따로 봐야 해요. 저는 이 구분을 흐릿하게 뒀다가 여러 번 사고를 겪었어요.
왜 이 구분이 중요하냐면, 빌드가 됐다고 배포가 된 게 아니거든요. 산출물은 멀쩡히 만들어졌는데, 올리는 과정에서 설정이 빠지거나 서버가 준비 검사를 통과 못 해 배포가 엎어지는 일이 흔해요. 두 단계를 하나로 뭉치면 어디서 뭐가 어긋났는지 진단하기가 어려워져요. 그래서 저는 후배들한테 늘 빌드 기록이랑 배포 기록을 갈라서 보라고 말해요. 화면이 옛날 그대로 보인다는 문제가 났을 때, 원인이 만드는 단계인지 올리는 단계인지부터 갈라야 하거든요.
그래서 저는 프로젝트를 시작할 때부터 빌드 명령이랑 배포 명령을 항상 따로 정의해 둬요. 하나의 뭉뚱그린 스크립트로 두 일을 동시에 처리하면 당장은 편해 보여도, 장애가 났을 때 원인을 좁히기가 참 어려워요. 두 일을 갈라 두는 이 사소한 습관이, 나중에 급박한 상황에서 큰 차이를 만들어요.
덧붙이면, 배포라는 말에는 사실 여러 단계가 뭉쳐 있어요. 산출물을 서버에 얹는 전개, 그 새 버전으로 사용자 요청을 흘려보내는 출시가 실은 서로 다른 순간이거든요. 새 버전을 올려 두되 아직 아무한테도 안 보여 주다가, 준비가 되면 그제야 흐름을 돌리는 식으로 둘을 갈라 두면 배포가 훨씬 안전해져요. 지금은 이런 결이 있다는 것만 알아 두시고, 뒤에 무중단이랑 롤백 편에서 이 갈래를 다시 만나게 될 거예요.
왜 한 번 만들어 여러 번 올려요?
배포를 이해하는 데 가장 중요한 원칙 하나만 꼽으라면, 저는 한 번 빌드하고 여러 번 배포한다는 걸 들어요. 개발 환경, 검증 환경, 운영 환경으로 순서대로 올리되, 환경마다 다시 빌드하지 않고 똑같은 산출물 하나를 그대로 승격시키는 거예요. 이게 안 지켜지면 재현성이 무너져요. 환경마다 빌드를 다시 돌리면, 그새 딸린 꾸러미 버전이 미묘하게 달라지거나 설정이 바뀌어 서로 다른 결과물이 나올 수 있거든요.
검증에선 멀쩡했는데 운영에서만 깨지는 사고, 그 상당수가 바로 여기서 나와요. 저도 예전에 검증이랑 운영을 각각 따로 빌드하게 짜 뒀다가 크게 당했어요. 검증에선 아무 문제 없었는데 운영에 올리자마자 화면이 깨졌거든요. 파고들어 보니 두 빌드가 서로 다른 시점에 돌면서 미세하게 다른 산출물을 만든 거였어요. 그 뒤로 저는 산출물은 딱 한 번만 만든다는 규칙을 절대 안 어겨요.
실무에서는 이 원칙을 산출물 저장으로 구현해요. 자동화 과정에서 산출물을 한 번 만들어 어딘가에 보관해 두고, 이후 각 환경으로 배포할 때는 그 보관된 걸 내려받아 그대로 올리는 거죠. 이렇게 하면 검증에서 확인한 그 산출물이 글자 하나 안 틀리고 운영으로 넘어가요. 검증을 통과했다는 사실이 운영에서도 통한다는 믿음으로 이어지죠.
이 원칙은 단순해 보여도 실무에서 지키기가 은근히 까다로워요. 환경마다 필요한 설정이 다르니까, 산출물은 그대로 두되 설정만 밖에서 주입하는 구조를 갖춰야 하거든요. 이 설정 분리는 뒤에 환경 분리랑 환경 변수 편에서 자세히 풀 거예요. 지금은 산출물은 하나, 설정은 환경별로라는 큰 그림만 기억해 두시면 돼요.
이 원칙이 주는 또 하나의 선물은 디버깅이 쉬워진다는 거예요. 검증에선 되고 운영에선 안 될 때, 산출물이 같다는 게 보장되면 우리는 코드 말고 환경만 의심하면 되거든요. 설정이 잘못 들어갔나, 접근 권한이 다른가, 바깥 연결이 막혔나. 의심 범위가 확 좁아지죠. 반대로 산출물이 매번 다르면 코드부터 환경까지 모든 게 용의자가 되니, 원인 찾기가 미궁으로 빠져요. 저는 이 원칙을 불확실성을 줄이는 장치라고 부르기도 해요.
정적이냐 서버냐가 왜 갈려요?
배포를 조금 넓게 보면, 그건 우리가 만든 결과물이랑 실제 사용자 사이를 잇는 다리를 놓는 일이에요. 아무리 잘 만든 산출물도 사용자한테 못 닿으면 아무 값어치가 없거든요. 그런데 이 다리를 놓는 방식은 산출물의 성격에 따라 크게 갈려요. 화면이랑 자원만으로 된 정적 산출물은 배포망에 파일을 올리면 끝이에요. 반면 서버에서 계속 돌아야 하는 산출물은 실행 중인 프로세스를 새 버전으로 갈아 끼워야 하니 훨씬 조심스럽죠.
저는 이 차이를 초기에 뼈아프게 배웠어요. 정적 파일 다루던 감각으로 서버 산출물을 배포했다가, 갈아 끼우는 순간 잠깐이지만 서비스가 끊기는 순단을 냈거든요. 파일을 덮어쓰는 일이랑, 살아 움직이는 프로세스를 갈아 끼우는 일은 완전히 다른 난이도예요. 정적 파일은 새 파일이 옛 파일을 덮어도 사용자한테 큰 탈이 없지만, 실행 중인 서버는 그 짧은 틈에 요청이 몰리면 그대로 실패로 이어져요.
그래서 배포를 설계할 때 저는 먼저 무엇을 배포하는가부터 물어요. 정적 자원인가, 실행되는 서버인가, 아니면 둘이 섞인 형태인가. 이 답에 따라 전략이랑 주의점이 완전히 달라지거든요. 이 시리즈에서도 정적 배포랑 서버 배포를 각각 별도 편으로 나눠 다룰 거예요. 지금은 둘의 결이 다르다는 것만 짚어 둘게요.
또 하나 잊지 말아야 할 건, 배포가 끝난 시점이 곧 성공은 아니라는 점이에요. 배포 명령이 오류 없이 끝났다고 해도, 실제 사용자가 여는 화면이 정상인지는 별개의 문제거든요. 그래서 배포의 마지막에는 늘 진짜 잘 도는지 확인하는 검증이 따라붙어야 해요. 다리를 놓았다고 끝이 아니라, 그 위로 사람이 안전하게 건너는지 봐야 완성인 거죠. 이 검증 이야기는 뒤 전용 편에서 깊이 다룰게요.
배포 잘한다는 건 뭘로 알아요?
배포를 잘한다는 건 뭘로 판단할까요. 막연한 감이 아니라 널리 쓰이는 네 가지 지표가 있어요. 배포를 얼마나 자주 하는가, 코드 변경이 사용자한테 닿기까지 얼마나 걸리는가, 배포한 변경 중 문제를 일으키는 비율이 얼마인가, 문제가 났을 때 복구까지 얼마나 걸리는가예요. 앞의 둘은 처리량에 관한 거고, 뒤의 둘은 안정성에 관한 거죠.
재밌는 건 이 네 지표가 서로 상충하지 않는다는 거예요. 흔히 자주 배포하면 그만큼 위험이 커질 거라 생각하지만, 실제론 반대거든요. 작게 자주 배포하는 팀일수록 변경 하나의 크기가 작아 문제를 찾기 쉽고, 그래서 실패율도 낮고 복구도 빨라요. 처리량이랑 안정성이 함께 좋아지는 거죠.
저도 이걸 경험으로 확인했어요. 예전엔 변경을 잔뜩 모아 한 달에 한 번씩 크게 배포했는데, 그럴 때마다 문제가 터지면 원인을 찾느라 며칠을 헤맸어요. 변경이 워낙 많으니 어느 게 범인인지 특정하기 어려웠거든요. 배포를 잘게 쪼개 자주 하기 시작하니, 문제가 나도 방금 올린 작은 변경만 들여다보면 되니 복구가 훨씬 빨라졌어요.
다만 이 지표들을 목표 그 자체로 삼는 건 경계해야 해요. 배포 빈도라는 숫자만 올리려고 의미 없는 배포를 남발하면, 지표는 좋아 보여도 실속이 없거든요. 저는 이 지표를 도달할 목적지가 아니라 나침반으로 써요. 지난달보다 조금 더 자주, 조금 더 안정적으로 되고 있다면 그걸로 충분하죠. 네 지표가 함께 좋아지는 균형을 잃지 않는 게 핵심이에요.
이 지표를 실제로 재려면 특별한 도구가 필요할 것 같지만, 사실 배포 기록만 꾸준히 남겨도 대부분 얻을 수 있어요. 언제 무엇을 올렸는지, 그중 어떤 게 되돌려졌는지, 문제가 언제 시작돼 언제 끝났는지를 적어 두면 네 지표가 자연스럽게 그려지거든요. 저는 팀에 배포 일지 하나 두는 것부터 권해요. 거창한 대시보드보다 솔직한 기록이 먼저예요. 숫자를 재는 목적은 자랑이 아니라 어제보다 나아지기 위함이라는 걸 잊지 않으면 돼요.
배포를 어떤 마음으로 대해야 할까요?
마지막으로 저는 배포를 대하는 태도 이야기를 하고 싶어요. 기술보다 태도가 배포의 안정성을 더 크게 좌우한다고 믿거든요. 배포를 특별한 이벤트로 여기는 팀이랑, 숨 쉬듯 일상으로 여기는 팀은 사고를 다루는 방식부터 달라요. 배포를 두려워하는 팀은 배포를 미루고, 미루니 변경이 쌓이고, 쌓인 걸 한꺼번에 올리니 위험이 커지는 악순환에 빠지죠.
저도 처음엔 배포 날이 오면 온몸이 굳었어요. 손으로 파일을 옮기고, 혹시 뭘 빠뜨렸을까 몇 번씩 확인하고, 배포 후엔 한동안 화면을 새로고침하며 조마조마했죠. 이 긴장은 절차가 사람 손이랑 기억에 의존했기 때문에 생긴 거였어요. 절차를 자동화하고 언제든 되돌릴 안전장치를 갖추고 나서야, 저는 배포에서 두려움을 덜어낼 수 있었어요.
되돌릴 수 있다는 확신이 있으면 배포는 더 이상 돌이킬 수 없는 도박이 아니에요. 뭔가 잘못돼도 이전 상태로 돌아가면 그만이라는 믿음이, 배포를 대담하고 잦게 만들어요. 배포의 두려움은 배포를 자주 함으로써만 사라지거든요. 참 역설적이지만, 무서워서 안 하면 더 무서워지고 자꾸 하면 편안해지는 게 배포예요.
한 가지 더 말씀드리면, 저는 배포를 혼자 짊어지지 말라고도 얘기해요. 배포가 특정 한 사람의 머릿속에만 있으면, 그 사람이 자리를 비운 날 팀 전체가 마비되거든요. 절차를 글로 적어 두고, 누구나 같은 명령으로 같은 결과를 내게 만들어 두면, 배포는 개인기가 아니라 팀의 자산이 돼요. 제가 겪은 가장 아찔한 순간도, 배포를 아는 사람이 저 하나뿐이라 연차 중에 불려 나갔던 날이었어요. 그 뒤로 저는 배포 지식을 팀에 흩뿌리는 걸 최우선으로 둬요.
그래서 이 시리즈 전체를 관통하는 네 개의 기둥을 미리 밝혀 둘게요. 한 번 빌드해 여러 번 배포하는 재현성, 사람 손을 덜어내는 자동화된 관문, 문제가 나면 즉시 되돌리는 롤백, 그리고 지금 무슨 일이 벌어지는지 들여다보는 관측성이에요. 이 네 가지가 갖춰지면 배포는 안정적인 규율이 돼요. 앞으로 이어질 편들은 결국 이 네 기둥을 하나씩 세워 가는 과정이라고 봐도 좋아요. 다음 편에서는 배포 중 가장 단순하고 흔한 정적 사이트 배포부터 구체적으로 파고들어 볼게요.