나는 퍼블리싱을 맡고, 다른 프론트엔드 개발자님은 API 연결과 프론트 배포를 담당하고 있었다.
우리는 프론트엔드, 백엔드 배포 플랫폼는 Krampoline으로 통일했다.
개발이 거의 마무리 되자, 본격적으로 배포 환경을 설정하는 작업이 시작됐다.
여기서 '배포 환경'이란, 우리가 만든 웹사이트를 실제 사용자들이 볼 수 있도록 인터넷 서버에 올리는 과정이다.
Netlify, Vercel 같은 플랫폼을 쓰면 쉽게 배포할 수 있지만, 종종 환경변수, 보안 토큰, 설정 파일 등이 꼼꼼히 세팅되어야 제대로 작동한다.
각자 맡은 일을 차근차근 해결해나가며 마무리 단계에 접어들고 있었고, 아침 7시쯤 내가 잠깐 눈을 붙인 사이 API 연결도 깔끔하게 완료돼 있었다.
그런데... 예상치 못한 문제가 기다리고 있었다.
백엔드는 정상적으로 배포됐지만, 프론트엔드 배포가 계속 실패하고 있었던 것이다.
1. 구름톤 마지막 날
1) 반복되는 프론트 배포 실패
아무리 시도해도 배포가 완료되지 않았고, 결국 우리 팀은 멘토님께 도움을 요청하게 되었다. 나를 제외한 2명의 개발자는 멘토님과 함께 코드를 보며 배포 상태를 확인을 했다.
조금 뒤, 두 사람은 다소 머쓱한 표정으로 돌아왔다. 내가 "왜? 배포가 아직 안 됐어요?" 하고 묻자, 멘토님이 무언가 설명을 해주셨다고 했다.
그런데 그 설명을 들으면서도, 나는 도무지 무슨 말인지 이해가 되지 않았다.
밤샘 작업으로 머리는 멍하고,
집중도 흐려져 있었고,
무엇보다도 내가 놓친 맥락이 너무 많아서,
설명이 머릿속에 들어오질 않았다.
지금 생각해보면 내가 잘 몰라서 그랬던게 아니고 이해할 수 있는 상태가 아니었던 것 같다.
2) 발표 & 심사위원 피드백
제출을 마치고 밥을 먹은 후, 드디어 발표 시간이 다가왔다. 발표자는... 나!
특별한 이유는 없었지만, 그냥 내가 해야 할 것 같았다.
오히려 피곤한 상태라 긴장도 덜 됐고, 부담 없이 발표할 수 있었다.
첫마디는 "안녕하세요. 거멍불팀 발표자이자 광대 이서윤입니다!" 였다.
팀원들이 강조한 포인트를 빠트리지 않으려 또박또박 설명을 이어갔다.
우리가 만든 서비스 고치 멩글레는 제주 향토음식 문화를 보존하고 세대 간 공유를 촉진하기 위한 웹 서비스다.
향토음식을 단순한 요리법이 아닌 세대와 이야기가 담긴 콘텐츠로 바라보고, 이를 클래스로 만들어 누구나 참여할 수 있도록 했다.
클래스를 통해 사용자는 제주 어르신들에게 조리법과 이야기를 듣고, 경험을 함께 나눌 수 있다.
또한, 자신이 참여한 클래스를 확인하고 기록으로 남기는 기능도 함께 구현해 디지털 아카이브로의 역할도 기대할 수 있다.
하지만, 심사위원들은 조금 다른 시선에서 피드백을 주셨다.
"서비스의 시작은 좋았지만, 결과물이 정체성을 잃은 것 같다"는 평을 받았고,
특히 "한번 해녀의 부엌에 직접 가서 서비스를 경험해보라"는 조언이 인상 깊었다.
실제로 우리가 초기에 고민한 서비스 핵심은 ‘경험 기반의 공유’였지만,
개발을 진행하면서 UI 구현과 기능 정리에 몰두하다 보니 그 정체성이 흐려졌던 것 같다.
아쉽게도 수상은 하지 못했지만,
이번 피드백을 통해 해커톤에서는 완벽한 구현보다 목표와 정체성 유지가 더 중요하다는 것을 깊이 깨달았다.
2. 구름톤 종료 후
1) 배포 실패 원인 추적기
해커톤이 끝난 이후, 나는 여유를 가지고 배포 실패의 원인을 추적하기 시작했다.
내가 맡았던 배포는 아니었지만, 전체적인 구조를 점검해보고 싶었다.
배포 플랫폼을 Krampoline에서 Netlify로 바꾸면서 바로 그곳에서 단서를 발견했다.
1. 첫번째 문제: 토큰 유출
.npmrc 파일에 아래와 같은 라인이 포함되어 있었다.
//npm.pkg.github.com/:_authToken=ghp_깃허브토근값...
GitHub Packages 접근용 토큰이 .npmrc에 하드코딩된 상태로 커밋되어 있었던 것이다.
참고로 .npmrc는 GitHub Packages Registry 같은 외부 패키지 레지스트리에 접근할 때, 설치 경로와 인증 토큰 등을 지정하는 설정 파일이다. 우리 프로젝트에서 사용한 GDS 라이브러리는 GitHub Packages Registry에 등록되어 있었고, 설치를 위해 토큰 인증이 필요했다.
알고 보니, 우리가 작업하던 저장소는 한때 퍼블릭 상태였고, 이후에는 프라이빗으로 전환된 상태였다.
GitHub은 퍼블릭 저장소에 올라간 인증 정보를 자동으로 탐지하는 Secret Scanning 기능을 가지고 있다. 이 기능은 민감 정보가 감지되면 관련 서비스(npm, github 등)에 알려 해당 토큰을 즉시 폐기해버린다.
즉, 우리가 사용하는 토큰은 이미 무효화된 상태였던 것.
이 상태에서 Krampoline, Netlify 어떤 플랫폼에서든 정상적인 빌드가 될 리 없었다.
현재는 불필요한 민감 정보가 없는 것을 확인한 뒤, 내가 저장소를 다시 퍼블릭으로 전환했다.
이전에 토큰이 포함되어 있던 커밋은 캐시 삭제 및 이력 정리를 통해 모두 제거해 두었다.
당시에는 정확한 원인을 알지 못했지만, 슬랙으로 새 토큰 값을 공유받은 순간
"아, 이게 배포 실패 원인이었구나" 하고 짐작이 갔다.
그때는 명확히 설명할 수 없었지만, 지금 돌아보면 그 감이 맞았던 셈이다.
2. 두번째 문제: 환경 변수로 토큰 관리
캐시를 삭제한 뒤 다시 배포를 시도했지만, 또 다른 문제가 발생했다.
.npmrc 파일에 여전히 하드코딩된 토큰이 포함된 상태였고, 이로 인해 Netlify의 빌드 환경에서도 인증이 실패하며 빌드가 완료되지 않았다.
나는 .npmrc에서 토큰 값을 환경 변수로 치환하고, Netlify의 환경 변수 설정에서 해당 토큰을 NPM_TOKEN이라는 이름으로 등록했다.
//npm.pkg.github.com/:_authToken=${NPM_TOKEN}
이렇게 설정하자 빌드가 정상적으로 통과되었고, 프론트엔드도 무사히 배포할 수 있었다.
그런데 이 시점에서 Krampoline 쪽도 같은 방식으로 토큰을 넘겼어야 한다는 걸 떠올렸다.
크램폴린IDE ConfigMap, Secret 사용하기 문서를 확인해보니 프론트 작업한 GitHub 레포지토리에 Krampoline 배포용 환경 변수가 전혀 설정되어 있지 않았다.
Krampoline은 Kubernetes 기반의 배포 환경이라, `.yaml` 파일 내에 직접 환경 변수를 주입하거나, `Secret` 리소스를 생성해 연결하는 방식으로 설정을 해야 한다. 즉, `kubectl create secret`같은 명령어를 통해 민감 정보를 등록하고, 이를 `deployment.yaml`의 `env`에서 참조하도록 구성했어야 했다.
솔직히 말하면, 그 당시로 다시 돌아간다고 해도 내가 이 구조를 명확히 이해하고 대처했을 것 같지 않다. GDS도 처음, Tailwind v4도 처음, 거기에 Krampoline까지 새로 배워야 했던 상황이라 이 모든 걸 한 번에 소화하기엔 현실적으로 무리였다.
지금 와서 생각해보면, 프론트엔드 역할도 GDS 담당 / Krampoline 담당 식으로 나눴으면 더 효율적이지 않았을까 싶다. 교육 들을 때도 그런 식으로 나눴다면 훨씬 수월했을지도 모르겠다. 특히 백엔드 개발자분이 Kubernetes나 배포 경험이 거의 없었던 상황이라, Krampoline 관련 설정이 혼자 감당하기엔 꽤 벅찼을 것 같다.
지금 와서 보면 그 설정이 누락된 게 결국 Krampoline에서의 빌드 실패로 이어졌던 셈이다. 이제는 이런 구조를 처음부터 파악하고, 환경 변수 설정 여부를 체크하는 습관을 길러야겠다고 느꼈다.
2) 작지만 치명적인 실수
우리는 초반부터 프론트엔드 배포를 여러 차례 시도했지만, 좀처럼 성공하지 못했다. 당시에는 “프론트와 백엔드를 모두 배포하면 안 되고, 백엔드만 배포하면 된다”는 이야기를 듣고, 프론트 배포 실패를 단순한 설정 문제로만 여겼고, 큰 장애 요인으로 인식하지 못했다. 이번 경험은 작은 실수가 얼마나 큰 결과를 초래할 수 있는지 몸소 체감한 사건이었다.
- .npmrc 파일에 토큰을 직접 작성하는 것은 보안적으로 매우 위험하다는 점
- 해당 토큰이 GitHub 퍼블릭 저장소에 커밋되면, 자동으로 무효화되어 사용할 수 없다는 점
- CI 환경(Netlify, Krampoline 등)에서는 토큰을 환경 변수로 안전하게 관리해야 한다는 점
이제는 절대 .npmrc에 토큰을 직접 하드코딩하지 않을 것이다.
그리고 누군가가 비슷한 문제를 겪는다면, 나는 이렇게 말할 수 있을 것이다.
“혹시 .npmrc에 토큰 하드코딩한 적 있어요?”
3) 토큰 만료가 부른 UI 환승
배포 문제의 원인을 찾고, 다음 날 다시 빌드를 시도해 Dialog 컴포넌트 이슈를 해결하려 했지만(자세한 내용은 1부 참고), 빌드는 여전히 실패했다. 확인해보니, 토큰이 이미 만료된 상태였다.
나는 이 내용을 팀원들에게 빠르게 공유했고, 그 결과 shadcn/ui로의 교체 작업이 바로 이루어졌다.
shadcn/ui를 선택한 이유는, 강의 중 GDS(혹은 Vapor)를 UI 라이브러리 분류에서 어디쯤에 위치시킬 것인지에 대한 설명을 들은 적이 있었기 때문이다.
GDS는 커스터마이징 폭이 넓고, 스타일 가이드는 존재하지만 고정된 형태는 아니어서 유연하게 적용할 수 있는 구조였고, Radix는 완전히 스타일이 없는 Headless UI라, 컴포넌트 정의와 스타일링을 처음부터 직접 구성해야 했다.
그래서 나는 스타일이 있고 더 빠르게 적용할 수 있고, 구조도 익숙한 shadcn/ui를 선택하는 게 더 낫겠다고 판단했다.
특히 구름톤 전시관 제출 마감이 임박한 상황이었기 때문에, 단시간에 교체 작업이 가능한 shadcn/ui가 가장 현실적인 선택이었다.
처음에는 “생각보다 어렵지 않다”고 느꼈지만, 돌아보면 꽤 손이 많이 가는 작업이었다.
GDS에서는 Text 컴포넌트를 많이 사용하고 있었는데, 이를 일반 HTML 태그로 바꾸는 과정이 반복적으로 필요했고, 이 부분이 꽤 번거로웠다. Dialog처럼 구조가 비슷한 컴포넌트는 비교적 수월했지만, 전체적으로 shadcn과 GDS의 구조가 비슷하다고 해서 곧바로 쉽게 바꿀 수 있는 수준은 아니었다.
특히 shadcn은 npx shadcn@latest [컴포넌트] 명령어로 필요한 UI만 개별 다운로드하는 방식인데, 처음에는 이 방식 자체보다 다운로드한 컴포넌트를 내 서비스에 맞게 커스터마이징하는 작업이 더 어렵게 느껴졌다.
그리고 shadcn 기본 테마가 블랙이라, 내가 원하는 서비스 컬러에 맞춰 스타일을 다시 입히는 작업도 꼭 필요했고, 이 부분이 생각보다 까다로웠다.
결국, 이런 작업들이 까다롭게 느껴졌던 건... shadcn을 많이 사용해본 경험이 없었기 때문일지도 모르겠다. 사용법을 조금 더 익히고, 커스터마이징 패턴에 익숙해졌다면 훨씬 수월하게 교체할 수 있었을 거다. 이번 기회에 UI 라이브러리를 도구처럼 사용하는 게 아니라, 진짜 "내 서비스에 녹여내는 연습"이 얼마나 중요한지도 느낄 수 있었다.
3. 정리하며
우리는 게을러서 실패한 것이 아니다.
여러 차례 시도했고, 끝까지 포기하지 않았다.
하지만 이번 경험을 통해, 배포 환경과 보안 구조에 대한 이해가 얼마나 중요한지를 깊이 깨달을 수 있었다.
다음 해커톤에서는 아래 항목들을 꼭 실천할 것이다.
- 배포 실패 시 단순 재시도에 그치지 않고, 명확한 원인을 끝까지 추적할 것
- 토큰, 환경 변수 등 보안 관련 설정은 초기 단계부터 점검하고, 팀과 적극적으로 공유할 것
- 배포 성공 여부는 '화면이 실제로 뜨는지'까지 확인할 것
아쉬움도 있었고 부족한 점도 많았지만, 이번 구름톤 13기 활동을 회고하고 블로그 글로 정리하는 과정을 통해
스스로 한층 더 성장하고 있다는 걸 느낄 수 있었다.
기획자님과 디자이너님이 먼저 회고를 제안해주신 덕분에, 그동안 느꼈던 아쉬움과 감사함을 이렇게 글로 담아볼 수 있었다.
4. 프로젝트 관련 자료
참고로, 처음에는 Netlify로 배포하고 있었지만
이미지 로딩 속도 문제와 향후 Next.js 전환 계획 등을 고려해
최종적으로 Vercel로 배포 플랫폼을 변경했습니다.
'리뷰' 카테고리의 다른 글
[코드트리 2차 후기] 코딩 테스트가 점점 재미있어지다! (1) | 2025.03.09 |
---|---|
[구름톤 13기 후기] 1부: 프론트엔드의 GDS 도전과 새벽 3시의 고비 (0) | 2025.03.08 |
신난다! 즐겁다! 글또 프론트 모바일 반상회 후기 (8) | 2025.02.10 |
보여줄게, 완전히 달라진 나 - 초보자의 코드트리 개편 한 달 체험기 (0) | 2025.02.02 |
개발자를 위한 영어 공부: <개발자가 영어도 잘해야 하나요?> 책 리뷰 (0) | 2024.12.07 |