Actions 빨간불이 전부 시크릿 문제는 아니다 — build 스키마 실패와 CLOUDFLARE_API_TOKEN 부재를 로그로 가르는 기록
main 푸시 후 라이브가 안 바뀌면 토큰부터 의심하기 쉽다. Notion 시드와 실제 Actions 실패 로그를 겹쳐, Deploy 시크릿 부재와 Build 스키마 오류를 구분하는 습관을 남긴다.

증상은 늘 비슷하다. main에 글을 올렸는데 seominhyuk.com은 예전 목록이다. Notion 시드에도 같은 문장이 있었다. “Actions는 build까지 가거나 deploy 단계에서 실패하고, 로컬 wrangler deploy는 되는데 CI만 깨진다.” 처음엔 거의 자동으로 CLOUDFLARE_API_TOKEN이 없다고 단정했다. 그런데 실제로 열어 본 빨간불 로그는 다른 이야기를 했다.
이 글의 각도는 시크릿 튜토리얼이 아니다. 바깥에서 보면 같은 ‘배포 안 됨’인데, Actions 로그를 읽기 전에는 원인을 고를 수 없다는 실측이다. 시드가 가리킨 토큰 부재 모드와, 이 레포에서 실제로 잡힌 빌드 스키마 실패를 한 줄에 겹쳐 둔다.
사실: 바깥 증상은 같고, 안쪽 스텝은 갈라진다
이 레포의 배포 줄기는 .github/workflows/deploy.yml 하나다. main push와 workflow_dispatch만 듣고, npm ci → npm run build → cloudflare/wrangler-action@v3의 command: deploy 순이다. Deploy 스텝은 시크릿 이름만 참조한다.
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
값은 커밋·본문·PR에 넣지 않는다(C.9). 이름만 남긴다. 로컬에서는 npm run deploy(= npm run build && wrangler deploy)가 되고, CI만 빨간불이면 “토큰이 CI에만 없다”는 가설이 자연스럽다. Notion 시드가 정리한 원인·조치도 그 가설과 같다. 시크릿을 Settings에 채우고, CI가 깨진 동안만 로컬 Wrangler 폴백, 새 슬러그는 Actions green 또는 curl -sI -L https://seominhyuk.com/posts/<slug> 200까지를 완료로 본다.
문제는 가설을 로그 없이 확정하는 습관이다. 라이브가 안 바뀌는 이유는 최소 세 갈래다.
- Actions가 아예 안 뜬다 — 브랜치 필터, 권한, 워크플로 파일 경로. 이쪽은 Wrangler 수동 배포와 Cloud Agent main 푸시 쪽에 가깝다.
- Build는 통과하고 Deploy만 실패 — 시크릿 부재·만료·Account ID 불일치. Notion 시드의 전형.
- Build 자체가 실패 — 콘텐츠 스키마, Astro 오류, 의존성. Deploy 스텝에 도달하지 못한다.
바깥에서 보면 1·2·3 모두 “푸시했는데 사이트가 그대로”다. 로그를 열기 전에는 토큰을 다시 붙여도 소용없는 날이 있다.
실측 1: 시크릿 이름은 지금 있다
글 쓰는 시점에 gh secret list로 저장소 시크릿 이름만 확인했다. CLOUDFLARE_API_TOKEN과 CLOUDFLARE_ACCOUNT_ID가 목록에 있다. 값은 출력하지 않는다. 최근 Actions 런도 대부분 success였다. 즉 “지금 이 순간 토큰이 없어서 매일 깨진다”는 상태는 아니다.
그래도 시드가 쓸모없는 것은 아니다. Cloud Agent나 새 포크·새 org로 옮기면 시크릿이 비는 날이 다시 온다. deploy.yml이 시크릿에 의존하는 한, 부재 모드는 항상 가능한 실패다. 다만 “빨간불 = 토큰”으로 점프하면, 다른 원인일 때 시간을 태운다.
실측 2: 9월 4일 빨간불은 스키마였다
같은 레포의 실패 런 33829019858(표시 제목: Reset blog to it-trials only…)의 failed 로그를 다시 열었다. Deploy Worker 스텝이 아니라 Build에서 죽었다. 요약하면 이렇다.
npm run build→astro build && pagefind --site dist/InvalidContentEntryDataErrorposts → abbott-libre-duo-dual-cgm-ketone-fda-2026category: Invalid input: expected "it-trials"
AdSense 저가치 콘텐츠 대응으로 카테고리를 it-trials만 남긴 직후, 아직 남아 있던 보조 카테고리 글이 스키마에 걸려 빌드가 깨진 것이다. 라이브가 안 바뀐 이유는 토큰이 없어서가 아니라, 배포 전에 Astro가 콘텐츠를 거부해서였다. 시크릿을 열 번도 다시 붙여도 Build 빨간불은 그대로였을 것이다.
이 한 건이 Notion 시드와 충돌하지 않는다. 시드는 “deploy 단계 실패”를 적어 두었고, 그날은 “build 단계 실패”였다. 같은 바깥 증상, 다른 스텝. 습관은 “시크릿부터”가 아니라 “어느 스텝이 빨간지”다.
재현: 로그에서 갈라 읽는 순서
다음부터는 이렇게 본다. 추측 순서가 아니라 확인 순서다.
- GitHub Actions에서 해당 SHA 런이 있는지. 없으면 트리거·브랜치 문제부터.
- 있으면 job 타임라인을 연다. Build가 빨간지, Deploy가 빨간지만 먼저 본다.
- Build 실패면 로그에
InvalidContentEntryDataError, 테스트 실패,npm ci오류가 있는지 읽는다. 시크릿 UI는 나중. - Deploy만 실패면 메시지에 authentication / missing token / account 관련 문구가 있는지 확인한다. 그래도 값은 로그에 찍히지 않게 둔다.
- Actions가 green인데 라이브가 예전 글이면 slug curl 검증으로 CDN·캐시·슬러그 오타를 본다.
로컬 폴백은 여전히 유효하다. CI가 Deploy에서 시크릿으로 막히고, 당장 라이브에 올려야 할 때만 npm run build 후 wrangler deploy를 쓴다. 기본 경로로 만들지는 않는다. Cloud Agent VM에 토큰이 없어도 main 푸시만 되면 CI 시크릿으로 배포가 이어진다는 전제는 Actions Wrangler 연결 이후의 정상 경로다. 전제가 깨졌을 때 폴백을 꺼낸다.
어디에 쓰지 않는가
이 습관을 팀 공통 “시크릿 점검 체크리스트”로 박아 두지 않는다. 체크리스트는 Build/Deploy를 구분하지 않은 채 토큰만 반복하게 만들기 쉽다. 또한 실패 로그 일부를 블로그·슬랙에 원문 붙여 넣는 것도 하지 않는다. 토큰 문자열, 내부 호스트, 미공개 계정 ID가 섞일 수 있다. 공개 가능한 것은 실패 스텝 이름과 에러 타입(스키마, auth, timeout) 정도다.
7카테고리 cron이 다시 스키마를 깨는 상황을 재현해 “실험”하지도 않는다. it-trials 전용 스키마는 AdSense 전략의 일부다. 고의로 잘못된 category를 넣어 빨간불을 만드는 것은 운영 비용만 늘린다.
평가: 시드는 맞고, 단정만 위험했다
Notion 시드의 교훈 — “푸시했다”와 “배포됐다”를 분리하고, Actions 또는 curl로 라이브를 확인한다 — 는 그대로 가져간다. 틀린 것은 시드가 아니라, 빨간불을 보자마자 시크릿으로 점프한 내 쪽이다. 9월 4일 실패는 스키마였고, 지금 시크릿 이름은 채워져 있으며, 최근 배포 런은 성공이다. 그럼에도 시드가 가리킨 Deploy-auth 모드는 언제든 다시 열린다. 두 모드를 한 문장으로 묶으면 이렇게 된다.
라이브가 안 바뀌면 먼저 Actions 타임라인에서 Build와 Deploy를 가른다. Deploy-auth면 시크릿·폴백, Build면 콘텐츠·스키마·의존성이다.
남긴 습관
푸시 직후 브라우저만 새로고침하지 않는다. Actions URL을 열고 스텝 색을 본다. Build가 초록인데도 사이트가 그대로면 curl로 slug 200을 본다. Deploy가 빨강이면 시크릿 이름 존재 여부만 확인하고, 값은 다시 발급·교체할 때 대시보드에서만 다룬다. 로컬 Wrangler는 비상 레일이다. “토큰이 없을 것 같다”는 감각은 가설로만 두고, 로그 한 줄이 확인하기 전까지는 Settings를 만지지 않는다.
출처
- Notion IT 시드: GitHub Actions에 CLOUDFLARE_API_TOKEN 없어 배포만 멈춤 (미발행 메모, 증상·원인·조치·검증·습관)
- 레포
.github/workflows/deploy.yml—CLOUDFLARE_API_TOKEN/CLOUDFLARE_ACCOUNT_ID참조 gh secret list— 시크릿 이름만 확인 (값 미출력)- GitHub Actions failed run
33829019858— Build 단계InvalidContentEntryDataError/ category expectedit-trials - 최근 Actions 성공 런 샘플 (2026-09-15
docs(ops): add regular blog cadence…) curl—https://seominhyuk.com/200 (글 작성 시점)