티스토리 뷰

반응형

Python으로 공부하는 OpenAI 16편 — 운영 배포에서 제일 많이 터지는 건 코드보다 설정이다

여기까지 오면 보통 이런 착각이 생깁니다.

“이제 기능은 다 붙였으니까, 배포만 하면 되겠네.”

근데 이상하게 실제 운영에서 제일 많이 사고 나는 건
모델 품질보다도, 프롬프트보다도, 오히려 환경변수, 비밀키, 환경 분리, 로그, 권한 같은 데서 터집니다.

이거 좀 허무해요.
몇 주 동안 공들여 만든 기능은 잘 도는데,
정작 운영 첫날에:

  • dev 키가 prod에 들어가 있고
  • 로그에 API 키 비슷한 값이 찍히고
  • staging과 production이 같은 벡터 스토어를 바라보고
  • 관리자 키를 워커까지 다 같이 쓰고
  • 테스트용 .env가 이미지 안에 들어가 있고
  • 장애 나서 로그 보려는데 민감정보까지 같이 남아 있고

이런 식으로 망가지는 경우가 정말 많습니다.

그래서 이번 글은 코드를 더 똑똑하게 만드는 내용이 아니라,
배포할 때 덜 망가지는 구조를 만드는 내용입니다.

OpenAI 공식 문서는 API 키를 코드나 공개 저장소에 두지 말고, 환경변수나 secret manager로 주입하라고 권장합니다. FastAPI 공식 문서도 설정은 BaseSettings와 .env, 그리고 @lru_cache()를 이용해 다루는 방식을 안내합니다. 또 FastAPI 배포 개념 문서는 HTTPS, startup, restart, replication, memory 같은 운영 관점을 별도로 강조합니다. (OpenAI Developers)


1. 제일 먼저 해야 할 분리: dev / stage / prod

이건 너무 기본 같아서 대충 넘어가기 쉬운데,
운영 사고의 절반은 여기서 시작합니다.

처음엔 다 비슷하게 갑니다.

  • 내 로컬에서 .env 하나로 돌림
  • 서버에도 비슷하게 .env 하나 넣음
  • 모델명, API 키, vector store id, DB URL 다 거기 있음

근데 서비스가 조금만 커지면 이 구조가 금방 위험해집니다.

왜냐하면 환경마다 다른 게 너무 많거든요.

  • API 키
  • 모델명
  • 로그 레벨
  • DB 주소
  • Redis 주소
  • vector store id
  • 파일 저장 버킷
  • webhook endpoint
  • allowed origins
  • docs 공개 여부

FastAPI 문서는 설정과 환경변수를 분리해서 다루고, .env와 Pydantic Settings를 함께 쓰는 패턴을 보여줍니다. 환경변수는 코드 밖에 존재하므로 Git에 커밋하지 않고도 설정을 바꿀 수 있습니다. (FastAPI)

제가 추천하는 건 아주 단순합니다.

  • local/dev
  • staging
  • production

이 세 환경은 최소한 나눠두세요.

특히 OpenAI 기능 붙인 서비스라면
staging과 production이 같은 vector store나 같은 프로젝트 키를 바라보는 건 정말 위험합니다.
테스트 파일이 운영 검색 결과에 섞이는 순간, 답변 품질이 이상해지기 시작하거든요.


2. API 키는 “동작만 하면 된다”가 아니라 “누가, 어디까지 쓸 수 있나”로 봐야 합니다

이건 꽤 중요합니다.

예전엔 그냥 OPENAI_API_KEY=... 하나 넣고 끝내는 식이 많았죠.
근데 지금은 OpenAI 쪽도 프로젝트, 서비스 계정, 권한 관리, 키 권한 설정을 더 세밀하게 가져갈 수 있습니다.

공식 문서에 따르면 프로젝트 단위 service account를 만들 수 있고, 서비스 계정 API 키는 기본적으로 프로젝트 리소스에 대한 read/write 권한을 갖지만 프로젝트 API Keys 설정에서 조정할 수 있습니다. 또 API 키 권한은 All, Restricted, Read Only 같은 수준으로 설정할 수 있습니다. RBAC 가이드는 권한이 조직/프로젝트 수준에서 일관되게 적용된다고 설명합니다. (OpenAI Help Center)

즉, 실무 감각으로 보면 이렇습니다.

개인 키

개발자 로컬 테스트용에는 가능하지만, 운영 서버에 오래 두는 건 추천하기 어렵습니다.

프로젝트 서비스 계정 키

서버, 워커, 배치 작업처럼 “사람이 아니라 서비스가 쓰는 키”엔 훨씬 자연스럽습니다. (OpenAI Help Center)

키 권한 제한

정말 필요한 범위만 열어두는 쪽이 낫습니다.
운영 서버 전체에 full 권한 키 하나를 돌려쓰는 건 편해 보여도 사고 나면 크게 납니다. (OpenAI Help Center)

개인적으로는 이 원칙을 추천합니다.

  • 로컬 개발자는 개인 키
  • staging 서버는 staging 프로젝트 서비스 계정
  • production 서버는 production 프로젝트 서비스 계정
  • 가능하면 키 권한도 restricted 기준으로 설계

이렇게 나누면 나중에 문제 생겼을 때 범위를 훨씬 좁힐 수 있습니다.


3. API 키는 코드에 넣지 말고, 진짜로 “주입”해야 합니다

이건 너무 많이 말해서 식상하지만, 여전히 사고가 많습니다.

OpenAI Quickstart와 Libraries 문서는 API 키를 안전한 위치에 저장하고, 터미널이나 환경에서 환경변수로 export해서 쓰라고 안내합니다. Production best practices도 키를 코드나 공개 저장소에 넣지 말고 환경변수나 secret management service로 애플리케이션에 노출하라고 강조합니다. API key safety 문서는 팀원마다 고유 키를 쓰고, 개인 키를 공유하지 말라고 말합니다. (OpenAI Developers)

즉, 아래는 피해야 합니다.

client = OpenAI(api_key="sk-여기에직접넣기")

이건 당장은 편한데,
나중에 Git 히스토리, 에러 스크린샷, 로그, 협업 과정에서 새어 나가기 너무 쉽습니다.

대신 이렇게 갑니다.

app/core/config.py

from functools import lru_cache

from pydantic_settings import BaseSettings, SettingsConfigDict


class Settings(BaseSettings):
    app_name: str = "OpenAI FastAPI App"
    app_env: str = "dev"

    openai_api_key: str
    openai_model: str = "gpt-5.4-mini"

    database_url: str
    redis_url: str | None = None

    openai_vector_store_id: str | None = None
    log_level: str = "INFO"
    enable_docs: bool = True

    model_config = SettingsConfigDict(
        env_file=".env",
        extra="ignore",
    )


@lru_cache
def get_settings() -> Settings:
    return Settings()

FastAPI는 이 방식으로 설정을 다루는 걸 공식적으로 안내합니다. @lru_cache()를 쓰면 요청마다 dotenv를 다시 읽지 않으면서도 테스트에서 override하기 쉬워집니다. (FastAPI)

여기서 중요한 건,
애플리케이션은 키 값을 알기보다 키 이름을 통해 주입받는다는 감각입니다.


4. .env는 개발 도구지, 운영 배포의 종착지는 아닙니다

이 부분도 진짜 많이 헷갈립니다.

.env는 로컬 개발에 정말 좋습니다.
근데 운영에선 그 자체가 정답은 아닙니다.

FastAPI 문서는 .env 사용을 보여주지만, 환경변수 자체는 운영체제 바깥에서 주입할 수도 있다고 설명합니다. OpenAI production best practices도 secret manager 사용을 권장합니다. (FastAPI)

실무 감각으로 정리하면:

로컬

.env 써도 좋음

Docker / 서버 / 클라우드 운영

  • 플랫폼 secret
  • container env
  • secret manager
  • CI/CD secret store

이 쪽이 더 자연스럽습니다.

즉, 추천 흐름은 이렇습니다.

  • 개발: .env
  • 운영: secret manager 또는 배포 플랫폼 secret
  • 코드: 둘 다 BaseSettings로 읽기

그리고 .env 파일은 진짜로 .gitignore에 들어가 있어야 합니다.
이건 당연한 얘기인데, 이상하게 처음 프로젝트 만들 때 한 번 빠뜨리면 나중에 꽤 피곤해집니다.


5. prod에서는 “같은 코드, 다른 설정”이 핵심입니다

운영 환경 분리에서 자주 하는 실수가
코드를 환경마다 다르게 갖고 가는 겁니다.

근데 보통 건강한 구조는 이거예요.

코드는 같고, 설정만 다르다.

예를 들면:

  • OPENAI_API_KEY
  • OPENAI_MODEL
  • DATABASE_URL
  • OPENAI_VECTOR_STORE_ID
  • ENABLE_DOCS
  • LOG_LEVEL

같은 코드라도 이 값들만 바뀌면
dev / stage / prod가 갈리게 만드는 편이 좋습니다. FastAPI 환경변수 문서도 설정은 코드 밖에서 바꾸고, 코드에서는 읽기만 하도록 설명합니다. (FastAPI)

이게 왜 좋냐면,

  • 배포 artifact를 하나로 유지할 수 있고
  • 실수로 “운영용 코드”와 “개발용 코드”가 갈라지는 걸 막고
  • 버그 재현도 쉬워집니다

6. 운영에서 docs, playground성 기능, debug 로그는 기본 공개가 아니어야 합니다

FastAPI는 기본적으로 docs가 참 편합니다.
근데 운영에서 그대로 열어두는 건 서비스 성격에 따라 다시 봐야 합니다.

FastAPI는 OpenAPI/docs를 자동으로 제공하지만, 배포 관점 문서는 보안과 HTTPS를 강조합니다. 운영에서는 공개 범위를 의식해야 한다는 뜻으로 받아들이는 게 맞습니다. (FastAPI)

예를 들어 저는 보통 이렇게 봅니다.

dev

  • docs 열기
  • verbose logging
  • 테스트용 endpoint 허용 가능

staging

  • docs는 내부 접근만
  • 디버그 로그는 제한
  • 테스트 endpoint 최소화

production

  • docs 비활성 또는 보호된 내부 경로
  • debug 수준 로그 금지
  • 민감한 테스트 라우트 제거

이걸 설정으로 제어하는 게 좋습니다.

app/main.py

from fastapi import FastAPI

from app.core.config import get_settings

settings = get_settings()

app = FastAPI(
    title=settings.app_name,
    docs_url="/docs" if settings.enable_docs else None,
    redoc_url="/redoc" if settings.enable_docs else None,
    openapi_url="/openapi.json" if settings.enable_docs else None,
)

이 정도만 해도 운영에서 쓸데없는 노출을 꽤 줄일 수 있습니다.


7. 로그는 많이 남기는 것보다 “무엇을 절대 남기지 않을지”가 더 중요합니다

반응형

이건 진짜 중요합니다.

운영에서 로그는 필요합니다.
근데 AI 서비스는 잘못하면 민감정보가 너무 쉽게 찍힙니다.

예를 들면:

  • API 키
  • Authorization 헤더
  • 사용자 원문 프롬프트
  • 개인 정보가 들어간 업로드 문서 일부
  • 검색된 문서 원문 chunk
  • 전체 request body

OpenAI production best practices는 키를 노출하지 말라고 하고, Data controls 문서는 플랫폼 데이터와 보안/제어 옵션을 따로 다룹니다. 즉, 애플리케이션 쪽 로그와 데이터 처리도 최소한으로 설계하는 게 맞습니다. (OpenAI Developers)

그래서 운영 로그는 보통 이렇게 갑니다.

남겨도 좋은 것

  • request id
  • session id
  • endpoint
  • model 이름
  • token usage
  • latency
  • retrieved_chunk_count
  • status code
  • error type

조심해야 할 것

  • 원문 사용자 입력 전체
  • 문서 원문 전체
  • API key
  • Authorization header
  • webhook 서명 헤더
  • 전체 OpenAI raw response dump

특히 print(response) 같은 습관은 운영에선 진짜 조심해야 합니다.


8. 권한 분리는 생각보다 빨리 필요해집니다

OpenAI RBAC 가이드는 권한을 조직/프로젝트 수준에서 관리하고, API와 Dashboard 모두 같은 권한 체계를 사용한다고 설명합니다. 프로젝트 관리 문서는 service account와 프로젝트 멤버, 키 권한을 프로젝트 수준에서 운영할 수 있다고 안내합니다. (OpenAI Developers)

이 말은 곧 이런 뜻입니다.

  • 모든 개발자가 production 키를 볼 필요는 없음
  • 모든 워커가 full access 키를 가질 필요는 없음
  • 운영자와 개발자의 권한도 꼭 같을 필요는 없음

실무적으로는 최소한 이 정도 분리는 권합니다.

  • 개발자 로컬 키
  • staging 서비스 계정 키
  • prod API 서버 키
  • prod 배치/워커 키
  • 조직 관리자용 별도 관리 키가 필요한 기능은 더 엄격히 제한

권한을 한 번 나눠두면 처음엔 귀찮아도
사고 범위가 훨씬 줄어듭니다.


9. HTTPS, 시작 시 자동 실행, 재시작, 복제 수는 AI 기능이 붙을수록 더 중요합니다

FastAPI 배포 개념 문서는 보안(HTTPS), startup, restarts, replication, memory 같은 배포 판단 기준을 따로 설명합니다. (FastAPI)

이게 왜 AI 서비스에서 더 중요하냐면:

  • 업로드 파일이 있을 수 있고
  • webhook을 받을 수 있고
  • background worker가 있을 수 있고
  • 메모리 사용량이 일반 CRUD보다 큰 경우가 많고
  • RAG 인덱싱이나 스트리밍 때문에 연결/프로세스 부담이 다를 수 있기 때문입니다

즉, 배포 직전엔 최소한 이 질문들을 해야 합니다.

  • HTTPS가 적용됐나
  • 서버 재시작 후 자동으로 뜨나
  • 워커도 같이 재시작되나
  • 프로세스 수는 적절한가
  • 메모리 부족 시 죽지 않나
  • staging과 prod 리소스가 분리됐나

AI 기능이 붙었다고 해서 배포 기본기가 사라지는 게 아니라,
오히려 더 까다로워지는 느낌에 가깝습니다.


10. 프로젝트 단위 리소스 분리는 정말 중요합니다

이건 특히 OpenAI vector store, files, API key를 같이 쓰는 경우 중요합니다.

공식 프로젝트 관리 문서와 RBAC 문서는 프로젝트 수준으로 멤버, 서비스 계정, 키 권한을 관리할 수 있다고 설명합니다. 즉, 프로젝트 자체를 환경 분리 단위로 쓰기 좋다는 뜻입니다. (OpenAI Help Center)

그래서 환경별로 아예 이렇게 나누는 걸 추천합니다.

  • myapp-dev
  • myapp-staging
  • myapp-prod

그리고 각 환경마다:

  • API key
  • service account
  • vector store id
  • file uploads
  • webhook endpoint

를 분리해두는 거죠.

이렇게 하면 staging에서 넣은 테스트 문서가
prod 검색 결과에 섞일 가능성을 크게 줄일 수 있습니다.


11. 실제 배포 전에 점검해야 할 최소 체크리스트

이건 진짜 체크리스트처럼 보는 게 좋습니다.

설정 / 키

  • prod 키가 dev나 stage에 노출되지 않았는가
  • 개인 키 대신 서비스 계정 키를 쓸 수 있는가
  • 키 권한이 과도하지 않은가 (OpenAI Help Center)

환경 분리

  • DB, Redis, vector store, bucket이 prod와 stage에서 분리됐는가
  • 환경변수만 바뀌면 같은 코드로 동작하는가 (FastAPI)

보안

  • HTTPS가 적용됐는가
  • docs/openapi가 prod에서 불필요하게 열려 있지 않은가
  • 로그에 키/민감정보가 찍히지 않는가 (FastAPI)

운영

  • API 서버와 워커가 자동 시작/재시작되는가
  • health check가 있는가
  • 오류 알림 채널이 있는가
  • 사용량/비용 경고를 받아볼 수 있는가

여기서 마지막 항목도 은근 중요합니다. OpenAI 계정 보안 관련 도움말은 조직 또는 프로젝트 수준 예산 임계값과 이메일 알림 설정을 언급합니다. (OpenAI Help Center)


12. 운영용 설정 예제는 이렇게 시작하면 무난합니다

.env.example

APP_NAME=OpenAI FastAPI App
APP_ENV=dev

OPENAI_API_KEY=
OPENAI_MODEL=gpt-5.4-mini
OPENAI_VECTOR_STORE_ID=

DATABASE_URL=
REDIS_URL=

LOG_LEVEL=INFO
ENABLE_DOCS=true

이 파일은 실제 비밀값이 아니라
“무슨 설정이 필요한지”만 보여주는 용도입니다.

그리고 운영 플랫폼에서는 실제 값을 secret으로 주입합니다.

app/core/config.py

from functools import lru_cache

from pydantic_settings import BaseSettings, SettingsConfigDict


class Settings(BaseSettings):
    app_name: str = "OpenAI FastAPI App"
    app_env: str = "dev"

    openai_api_key: str
    openai_model: str = "gpt-5.4-mini"
    openai_vector_store_id: str | None = None

    database_url: str
    redis_url: str | None = None

    log_level: str = "INFO"
    enable_docs: bool = False

    model_config = SettingsConfigDict(
        env_file=".env",
        extra="ignore",
    )


@lru_cache
def get_settings() -> Settings:
    return Settings()

이 구조는 로컬에서는 .env, 운영에서는 environment/secret injection으로 그대로 이어갈 수 있어서 좋습니다. FastAPI 공식 설정 패턴과도 잘 맞습니다. (FastAPI)


13. 자주 하는 실수들

실수 1. prod도 개인 키로 돌린다

당장은 되지만, 권한 관리와 추적이 불편합니다. 프로젝트 서비스 계정과 권한 분리가 더 낫습니다. (OpenAI Help Center)

실수 2. staging과 prod가 같은 vector store를 본다

테스트 데이터가 운영 검색 품질을 망칠 수 있습니다.

실수 3. .env를 Docker 이미지 안에 넣어 배포한다

로컬 편의성과 운영 보안은 다릅니다.

실수 4. 로그에 request body를 통째로 남긴다

AI 서비스는 사용자 문서와 프롬프트가 그대로 섞일 수 있어서 위험합니다.

실수 5. docs를 prod에 그냥 연다

편하지만 노출 면적이 커집니다. 운영에선 다시 판단해야 합니다. (FastAPI)

실수 6. 키를 팀이 같이 공유한다

OpenAI API key safety 문서는 팀원마다 고유 키를 쓰라고 권장합니다. (OpenAI Help Center)


14. 오늘 글의 핵심 요약

이번 글에서 꼭 가져가야 할 건 이것입니다.

운영 배포에서 제일 중요한 건 코드가 아니라, 환경 분리와 비밀 관리와 권한 관리다.

정리하면:

  • OpenAI 키는 코드에 넣지 말고 환경변수나 secret manager로 주입해야 합니다. (OpenAI Developers)
  • FastAPI는 BaseSettings와 .env, @lru_cache() 기반 설정 구조가 잘 맞습니다. (FastAPI)
  • 프로젝트, 서비스 계정, 키 권한 분리를 이용하면 운영 범위를 더 안전하게 나눌 수 있습니다. (OpenAI Developers)
  • 운영에서는 HTTPS, restart, replication, memory 같은 기본 배포 개념을 꼭 챙겨야 합니다. (FastAPI)
  • staging과 prod는 코드가 아니라 리소스와 설정에서 분리되어야 합니다. (FastAPI)

기능을 잘 만드는 것도 중요하지만,
운영에서는 결국 비밀을 어떻게 숨기고, 환경을 어떻게 나누고, 사고 범위를 어떻게 줄였는가가 훨씬 오래 갑니다.


다음 편 예고

다음 글에서는 여기서 더 실무적으로 들어가겠습니다.

Python + FastAPI에서 OpenAI 기능에 관측성(observability)을 붙여, 로그·메트릭·알림으로 운영하는 방법

이 주제로,

  • 무엇을 로그로 남기고 무엇을 남기면 안 되는지
  • 토큰, 지연, 실패율을 어떤 단위로 봐야 하는지
  • 알림 기준을 어디에 걸어야 하는지
  • 운영자가 “지금 이상하다”를 빨리 감지하는 구조

까지 이어가보겠습니다.


출처

  • FastAPI Settings and Environment Variables — BaseSettings, .env, @lru_cache() 기반 설정 패턴. (FastAPI)
  • FastAPI Environment Variables — 환경변수는 코드 밖에서 주입하고 코드에서는 읽는 구조. (FastAPI)
  • FastAPI Deployment Concepts — HTTPS, startup, restarts, replication, memory 등 배포 핵심 개념. (FastAPI)
  • OpenAI Production best practices — API 키를 코드/공개 저장소에 두지 말고 환경변수나 secret manager로 주입. (OpenAI Developers)
  • OpenAI Quickstart / Libraries — API 키를 안전한 위치에 두고 환경변수로 export해서 사용. (OpenAI Developers)
  • OpenAI RBAC 가이드 — 권한은 조직/프로젝트 수준에서 관리 가능. (OpenAI Developers)
  • OpenAI Projects 관리 문서 — 프로젝트 서비스 계정과 프로젝트 수준 API 키 운영. (OpenAI Help Center)
  • OpenAI API key permissions — All, Restricted, Read Only 권한 수준. (OpenAI Help Center)
  • OpenAI API key safety — 팀원마다 고유 키 사용, 키 공유 비권장. (OpenAI Help Center)
  • OpenAI Error codes — 잘못된 키나 조직 문제는 401 등으로 나타날 수 있음. (OpenAI Developers)
  • OpenAI 계정 보안 관련 도움말 — 프로젝트/조직 수준 예산 임계값 알림 설정 언급. (OpenAI Help Center)

Python, OpenAI, FastAPI, 환경변수, secret management, API key security, Pydantic Settings, 서비스 계정, RBAC, 운영 배포, staging 분리, production 보안, AI 백엔드 운영, 주니어 개발자, FastAPI deployment

※ 이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2026/05   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
글 보관함
반응형