RSS듀오랩스

Vercel·Supabase 이전 1단계: 계획을 코드로 다시 확인한 이유

웹 인프라글: , Duolabs4분 읽기blogmigrationsupabasetechnical-notevercel

저는 이전 계획표에 번역과 이미지 변환을 기존 서버 유지로 적어뒀습니다. 둘 다 백그라운드 작업이니 상시 실행되는 서버가 필요할 것이라고 생각했습니다.

실행에 들어가기 전 코드를 다시 열어보니 이야기가 달라졌습니다. 서버에 남겨야 한다는 판단 중 일부는 기술적인 제약이 아니라 지금까지 그렇게 운영해 왔다는 익숙함에서 나온 것이었습니다.

서버에 남길 이유가 사라진 두 작업

반복 작업부터 성격별로 나눴습니다. DB 안에서 끝나는 작업은 Supabase의 pg_cron, 기존 서비스 로직을 호출해야 하는 작업은 Vercel Cron으로 옮길 수 있었습니다. 조회수처럼 약간의 유실을 허용하는 집계는 기존 Redis 방식을 Upstash로 바꾸면 됐습니다.

애매했던 건 번역과 이미지 변환이었습니다.

번역 코드를 확인하니 이미 로컬 모델과 외부 API를 선택할 수 있는 provider 구조가 있었습니다. 로컬 모델을 사용한 것은 비용을 줄이기 위한 선택이었을 뿐, 시스템이 온프레미스 환경을 반드시 요구하는 것은 아니었습니다.

이미지 변환도 로컬 디스크나 GPU를 사용하지 않았습니다. 오브젝트 스토리지에서 이미지를 읽어 메모리에서 변환한 뒤 다시 저장하고 있었습니다. 이 작업은 다른 서버로 옮기기보다 요청 시점에 이미지를 변환하도록 바꾸는 편이 단순했습니다. 워커와 재시도 상태까지 함께 없앨 수 있기 때문입니다.

옮길 장소를 찾던 두 작업 중 하나는 설정 변경으로 해결됐고, 다른 하나는 작업 자체를 제거하는 방향으로 바뀌었습니다. 이 시점에서 상시 서버를 유지할 이유도 사라졌습니다.

S3 호환에서 드러난 예외

저장소를 Cloudflare R2로 바꾸는 부분에서는 반대 상황이 나왔습니다. R2는 S3 호환 API를 제공하지만 AWS S3의 모든 헤더와 기능을 그대로 지원하지는 않습니다.

기존 업로드 코드는 presigned 요청에 AWS 체크섬 헤더를 포함하고 있었습니다. Cloudflare의 S3 API 호환표와 실제 요청 코드를 대조하니 엔드포인트만 바꿔서는 안 됐습니다. R2가 지원하는 체크섬 방식에 맞춰 업로드 요청과 서명을 함께 수정해야 했습니다.

이미지 변환 위치도 다시 봤습니다. 원본은 R2에 두면서 변환만 다른 클라우드에서 처리하면 캐시가 없을 때마다 원본을 가져오는 경로가 생깁니다. 원본과 변환을 같은 Cloudflare 네트워크에 두고, Next.js에서는 이미지 loader만 교체하는 구조가 더 단순했습니다. 이 판단에서는 단가표보다 데이터가 이동하는 경로를 먼저 봤습니다.

첫 단계는 무상태화

실제 1단계는 계정이나 외부 인프라가 필요 없는 무상태화 작업으로 잡았습니다.

이 과정에서 배포 환경값을 읽는 방식에 숨어 있던 문제를 발견했습니다. 기존 환경에서는 값이 다른 경로로 먼저 주입돼 문제가 보이지 않았지만, Vercel로 옮기면 잘못된 값이 사용될 수 있었습니다. 인프라를 바꾸지 않았다면 계속 가려져 있었을 문제였습니다.

리버스 프록시에 있던 보안 설정은 Next.js 설정으로 옮겼고, 헬스체크는 프로세스뿐 아니라 DB 연결과 배포 버전도 확인하도록 바꿨습니다. 인메모리 캐시는 여러 인스턴스에서 문제가 없는 읽기 전용 데이터인지 확인했습니다. 타입 검사와 빌드, 테스트를 통과시킨 뒤 첫 단계를 마쳤습니다.

코드를 다시 읽은 뒤 계획표에서 가장 많이 바뀐 문구는 기존 서버 유지였습니다. 반대로 쉽게 넘겼던 S3 호환에는 실제 수정할 코드가 숨어 있었습니다.

다음 단계에서는 빈 Supabase 프로젝트에 전체 마이그레이션을 실행해 인덱스와 직접 작성한 SQL까지 그대로 동작하는지 확인할 예정입니다.

마지막 수정:

공유하실 때는 출처(Duolabs)와 원문 주소를 표시해 주세요.