AI 연동에 필요한 환경변수 두 개가 운영 배포 계약에 없다. #101과 같은 뿌리(운영 주입 계약 누락)이지만 고치는 값과 결정 주체가 달라서 따로 남긴다.
#101과 순서가 얽혀 있다. 아래 2번 때문에 #101의 SPRING_PROFILES_ACTIVE=prod를 먼저 켜면 파드가 기동에 실패한다. 두 이슈를 같이 봐야 한다.
@cherry-go-round 주입 쪽, @colosair 주소 결정 쪽을 봐 주면 좋겠다.
1. PINLOG_AI_BASE_URL — 운영에서 localhost로 해석된다
back/src/main/resources/application.yml:79
pinlog:
ai:
base-url: ${PINLOG_AI_BASE_URL:http://localhost:8000}
application-prod.yml에 pinlog.ai override가 없고, 인프라도 이 변수를 주입하지 않는다. 그래서 운영 파드는 자기 자신의 8000 포트로 AI를 호출한다.
실패 모드가 완전히 무음이다. 연결이 거부되면 AiProcessClient가 예외를 삼키고, Context 상태는 PENDING으로 남고, 재스캔은 아직 없다(#99). 결과는 파드는 뜨고, API는 200을 주고, 임베딩만 하나도 생기지 않는 상태다 — 이 연동이 애초에 막으려던 상태와 똑같다.
이 지적은 PR #82 리뷰(2026-07-29)에서 이미 나왔는데 반영되지 않았다. 당시 제안은 "application-prod.yml에 주소를 적어라"였지만, #101에서 확인된 대로 prod 프로파일 자체가 활성화되어 있지 않아 그렇게 고쳐도 적용되지 않는다. 리뷰가 프로파일이 켜져 있다고 전제했다.
2. PINLOG_AI_INTERNAL_SECRET — 프로파일을 켜는 순간 기동을 막는다
AiProcessClient의 requireSecret은 JwtKeyProvider와 같은 기준으로 갈린다 — 운영 프로파일이면 기동 실패, 그 외는 경고 후 빈 값.
운영 프로파일에는 pinlog.ai.internal-secret(PINLOG_AI_INTERNAL_SECRET)이 필요하다.
인프라가 이 값을 주입하지 않는다. 따라서 #101에서 SPRING_PROFILES_ACTIVE=prod를 넣는 순간, JWT 키를 제대로 넣었더라도 이 값이 없어서 파드가 뜨지 않는다.
지금 프로파일이 꺼져 있어서 이 fail-fast도 무력화된 상태다. 현재 운영 파드는 빈 시크릿으로 동작하고 있고, FastAPI가 모든 호출을 401로 거절하며, 그 실패는 삼켜진다. 1번과 합쳐 두 겹으로 무음이다.
확인한 것
| 확인 대상 |
상태 |
back/.../application.yml:79, :82 |
둘 다 기본값 있음 — http://localhost:8000, 빈 문자열 |
back/.../application-prod.yml |
pinlog.ai 블록 없음 |
infra/ 전체 |
PINLOG_AI_BASE_URL·PINLOG_AI_INTERNAL_SECRET 주입 없음 (걸리는 것은 .github/workflows/ai-image-update.yaml의 GitHub Actions 토큰들뿐, 무관하다) |
infra/apps/ |
prod에는 back만 있다. AI 서비스는 dev에만 배포되어 있다 (apps/dev/ai) |
back/docs/development/configuration.md:82-86 |
인프라 요청 대상 표에 PINLOG_AI_INTERNAL_SECRET이 없다 (PR #82 리뷰 지적, 미반영) |
먼저 정해야 하는 것
운영에서 back이 어느 AI 서비스를 호출하는가. apps/prod에 AI가 없으니 주소를 적을 수가 없다. 세 가지 중 하나를 정해야 한다.
- AI를
prod에도 배포한다 → 주소는 http://ai.pinlog-prod.svc.cluster.local:8000 형태
- 운영 back이
dev의 AI를 호출한다 → 네임스페이스를 가로지르는 주소, 그리고 그렇게 해도 되는지 판단이 필요하다
- 운영에서는 AI 연동을 끈다 → 그러면 지금처럼 조용히 실패하게 두지 않고 명시적으로 끄는 방법이 필요하다(현재 그런 스위치는 없다)
이건 AI 파트·인프라 결정이라 백엔드가 단독으로 정하지 않는다.
해야 할 일
백엔드 (주소가 정해진 뒤)
application-prod.yml에 pinlog.ai.base-url을 적는다. 설정 규약대로 주소는 비밀이 아니므로 파일에 박고, 환경변수 이름을 새로 만들지 않는다(configuration.md "비밀값과 자격증명 주입"). application.yml의 ${PINLOG_AI_BASE_URL:http://localhost:8000}은 로컬 기본값으로 남긴다
configuration.md의 인프라 요청 표에 PINLOG_AI_INTERNAL_SECRET을 넣는다
인프라
PINLOG_AI_INTERNAL_SECRET을 SealedSecret으로 만들어 apps/prod/back/values.yaml의 env:에 넣는다. 값은 AI 쪽과 공유하는 시크릿이라 양쪽이 같아야 한다(헤더 이름 X-Internal-Secret, 원본은 ai 레포 app/core/security.py)
- #101의
SPRING_PROFILES_ACTIVE=prod보다 먼저 들어가야 한다. 순서가 뒤바뀌면 파드가 기동에 실패한다
참고
AI 연동에 필요한 환경변수 두 개가 운영 배포 계약에 없다. #101과 같은 뿌리(운영 주입 계약 누락)이지만 고치는 값과 결정 주체가 달라서 따로 남긴다.
#101과 순서가 얽혀 있다. 아래 2번 때문에 #101의
SPRING_PROFILES_ACTIVE=prod를 먼저 켜면 파드가 기동에 실패한다. 두 이슈를 같이 봐야 한다.@cherry-go-round 주입 쪽, @colosair 주소 결정 쪽을 봐 주면 좋겠다.
1.
PINLOG_AI_BASE_URL— 운영에서localhost로 해석된다back/src/main/resources/application.yml:79application-prod.yml에pinlog.aioverride가 없고, 인프라도 이 변수를 주입하지 않는다. 그래서 운영 파드는 자기 자신의 8000 포트로 AI를 호출한다.실패 모드가 완전히 무음이다. 연결이 거부되면
AiProcessClient가 예외를 삼키고, Context 상태는PENDING으로 남고, 재스캔은 아직 없다(#99). 결과는 파드는 뜨고, API는 200을 주고, 임베딩만 하나도 생기지 않는 상태다 — 이 연동이 애초에 막으려던 상태와 똑같다.이 지적은 PR #82 리뷰(2026-07-29)에서 이미 나왔는데 반영되지 않았다. 당시 제안은 "
application-prod.yml에 주소를 적어라"였지만, #101에서 확인된 대로prod프로파일 자체가 활성화되어 있지 않아 그렇게 고쳐도 적용되지 않는다. 리뷰가 프로파일이 켜져 있다고 전제했다.2.
PINLOG_AI_INTERNAL_SECRET— 프로파일을 켜는 순간 기동을 막는다AiProcessClient의requireSecret은JwtKeyProvider와 같은 기준으로 갈린다 — 운영 프로파일이면 기동 실패, 그 외는 경고 후 빈 값.인프라가 이 값을 주입하지 않는다. 따라서 #101에서
SPRING_PROFILES_ACTIVE=prod를 넣는 순간, JWT 키를 제대로 넣었더라도 이 값이 없어서 파드가 뜨지 않는다.지금 프로파일이 꺼져 있어서 이 fail-fast도 무력화된 상태다. 현재 운영 파드는 빈 시크릿으로 동작하고 있고, FastAPI가 모든 호출을 401로 거절하며, 그 실패는 삼켜진다. 1번과 합쳐 두 겹으로 무음이다.
확인한 것
back/.../application.yml:79,:82http://localhost:8000, 빈 문자열back/.../application-prod.ymlpinlog.ai블록 없음infra/전체PINLOG_AI_BASE_URL·PINLOG_AI_INTERNAL_SECRET주입 없음 (걸리는 것은.github/workflows/ai-image-update.yaml의 GitHub Actions 토큰들뿐, 무관하다)infra/apps/prod에는back만 있다. AI 서비스는dev에만 배포되어 있다 (apps/dev/ai)back/docs/development/configuration.md:82-86PINLOG_AI_INTERNAL_SECRET이 없다 (PR #82 리뷰 지적, 미반영)먼저 정해야 하는 것
운영에서 back이 어느 AI 서비스를 호출하는가.
apps/prod에 AI가 없으니 주소를 적을 수가 없다. 세 가지 중 하나를 정해야 한다.prod에도 배포한다 → 주소는http://ai.pinlog-prod.svc.cluster.local:8000형태dev의 AI를 호출한다 → 네임스페이스를 가로지르는 주소, 그리고 그렇게 해도 되는지 판단이 필요하다이건 AI 파트·인프라 결정이라 백엔드가 단독으로 정하지 않는다.
해야 할 일
백엔드 (주소가 정해진 뒤)
application-prod.yml에pinlog.ai.base-url을 적는다. 설정 규약대로 주소는 비밀이 아니므로 파일에 박고, 환경변수 이름을 새로 만들지 않는다(configuration.md"비밀값과 자격증명 주입").application.yml의${PINLOG_AI_BASE_URL:http://localhost:8000}은 로컬 기본값으로 남긴다configuration.md의 인프라 요청 표에PINLOG_AI_INTERNAL_SECRET을 넣는다인프라
PINLOG_AI_INTERNAL_SECRET을 SealedSecret으로 만들어apps/prod/back/values.yaml의env:에 넣는다. 값은 AI 쪽과 공유하는 시크릿이라 양쪽이 같아야 한다(헤더 이름X-Internal-Secret, 원본은 ai 레포app/core/security.py)SPRING_PROFILES_ACTIVE=prod보다 먼저 들어가야 한다. 순서가 뒤바뀌면 파드가 기동에 실패한다참고
JWT_PRIVATE_KEY미주입,prod프로파일 미활성. 프로파일 활성화 선행 조건이 이 이슈다docs/backend/implements/BI-22-2026-07-29-context-ai-enqueue.md— AI 처리 접수 구현