14.8.1. 컨테이너 기반(Docker/Kubernetes) 오라클 실행 환경 구축

14.8.1. 컨테이너 기반(Docker/Kubernetes) 오라클 실행 환경 구축

거대 언어 모델(LLM)을 포함한 AI 네이티브 CI/CD 파이프라인에서 테스트 아키텍트가 흔히 겪게 되는 가장 끔찍한 악몽은, 야간 빌드 실패를 알리는 붉은 에러의 진짜 원인이 ‘모델 자체의 통계적 지능 퇴행(Regression)’ 때문인지, 아니면 그저 테스트를 돌리는 ‘CI/CD 빌드 에이전트 환경의 파이썬 패키지 의존성 버전 충돌’ 때문인지 도무지 로그만으로는 구분할 수 없게 되는 끔찍한 블라인드(Blind) 상황이다.

거친 비결정성(Nondeterminism)을 억압하고 논리적으로 통제해야 할 시스템 재판관인 결정론적 오라클 파이프라인 자체는, 문자 그대로 한 치의 환경 변수 오차도 허용하지 않는 ‘절대적으로 결정론적이고 통제된 격리 인프라 서버 환경’ 내부에서만 구동되어야만 한다.
이를 위해, 파이프라인 상의 모든 오라클 평가 스크립트 로직 모듈은 외부 호스트 OS 환경과 완전히 단절된 그들만의 견고한 파이썬 의존성(Dependencies) 트리를 가진 채, 완벽하게 밀봉된 도커(Docker) 컨테이너 패키지 플랫폼 안으로 영구 캡슐화(Encapsulation)되어야 한다.

나아가 단순히 컨테이너화하는 것을 넘어, **쿠버네티스(Kubernetes)**의 백엔드 분산 오케스트레이션(Orchestration) 권력을 통해, 실제 프로덕션 서버에 쏟아지는 방대한 라이브 트래픽 벤치마크 워크로드 스케일에 맞추어 무한히 동적으로 병렬 확장(Scale-out)될 수 있는 탄력형(Elastic) 구조를 갖춰야만 한다.

1. 독립적인 오라클 도커(Docker) 빌드 전략과 격리벽 강화

아키텍처 관점에서 오라클 컨테이너는 메인 비즈니스 애플리케이션(LLM API 백엔드 서빙 서버) 컨테이너 클러스터와 완벽히 물리적/논리적으로 분리되어, 독자적인 라이프사이클(Lifecycle) 버전을 가져야 한다. 하나의 거대한 뚱뚱한 모놀리식(Monolithic) Dockerfile 하나에 메인 서비스 서빙 로직과 별도의 테스트 검증 오라클 로직을 한 솥에 섞어 끓이는 쩨쩨한 인프라 절감 행위는, CI 러너 메모리를 무의미하게 터뜨리고 프로덕션 웹 보안 공격 표면(Attack Surface)을 쓸데없이 넓히는 전형적인 마이크로서비스 안티 패턴(Anti-pattern)이다.

# Dockerfile.oracle
# 오라클 빌드 베이스는 무거운 GPU 드라이버 이미지 대신 가볍고 보안 패치가 확실한 슬림 CLI 이미지를 채택한다.
FROM python:3.11-slim-bullseye

WORKDIR /oracle_runner

# 1. 오라클 전용의 깐깐한 의존성만 칼같이 격리 설치 (메인 서버의 무거운 서빙 프레임워크 패키지는 철저히 배제)
# Pydantic (스키마 포맷 강제 검증), OpenAI SDK (LLM-as-a-Judge 평가 체인 호출용), Pytest (어설션 러너) 등 최소 필수 단위 목록
COPY requirements-oracle.txt .
RUN pip install --no-cache-dir -r requirements-oracle.txt

# 2. 메인 앱이 아닌 오직 버전 관리된 개별 오라클 검증 스크립트만 복사
COPY /oracle_scripts /oracle_runner/scripts

# 3. 비특권(Non-root) 사용자 계정 설정 및 루트 권한 드롭(Drop)으로 해킹 방지 및 격리 보안 극대화
RUN useradd -m oracle_user
USER oracle_user

# 4. CI/CD 환경에서 오버라이드(Override) 가능한 유연한 엔트리포인트 (기본값: 전체 팩트 체크 회귀 스위트 -n 옵션 병렬 실행)
ENTRYPOINT ["python", "-m", "pytest", "-n", "auto", "scripts/fact_check_suite.py"]

이렇게 CI 서버 상단 단계에서 독립적으로 자동 빌드되어 사내 프라이빗 레지스트리에 푸시(Push)된 태그 ai-oracle-runner:v2.1 불변(Immutable) 컨테이너 이미지는, 로컬 주니어 개발자의 랩톱 로컬호스트이든, 깃허브 클라우드 액션(GitHub Actions) 러너 서버이든, 무거운 트래픽의 프로덕션 쿠버네티스 클러스터 노드이든 간에, 지구상 그 어떤 호스트 머신에서 실행 방아쇠(Trigger)를 당겨도 항상 수학적으로 100% 한 치의 오차 없이 동일한 채점 잣대를 출력해 내는 난공불락의 움직이는 가드레일 요새(Fortress)가 된다.

2. 쿠버네티스(Kubernetes) Job API를 이용한 압도적 동적 오라클 병렬 격발

단순히 소규모 로컬에서 5개짜리 단위 테스트를 점검하는 것이라면 CI 러너 스텝에서 단일 컨테이너 셸 스크립트를 한 줄 띡 순차 실행하는 것으로 족할지 모른다. 그러나 수십만 건의 프롬프트 섀도우 트래픽(Shadow Traffic)이나 수천 개의 엣지 케이스 골든 데이터셋 스위트를 론칭 전 하룻밤 사이에 전부 검증하고 채점해야 하는 치열한 디플로이 단계의 거대한 딥러닝 블루-그린(Blue-Green) 배포 트래픽 오픈 상황 앞에서는, CI 에이전트 노드 하나에 대충 떠 있는 깡통 독립 컨테이너의 싱글 스레드만으로는 턱없이 메모리가 부족하며 끔찍한 병목 시간(Bottleneck Queue) 데드록에 처참하게 직면하게 된다.

이때 쿠버네티스의 선언형 Job 혹은 CronJob 리소스 API 아키텍처를 영리하게 백엔드에서 활용하면, 가벼운 단일 오라클 도커 컨테이너 복제본 수백 개를 CI/CD 컨트롤러가 일순간에 유휴 워커 노드(Worker Node) 풀에 무자비하게 동시 스폰(Spawn) 시킬 수 있다. 이렇게 분산 클러스터를 오라클 전용으로 징발하면, 순차 실행 시 십수 시간이 걸릴 방대한 LLM 모델의 대규모 채점 벤치마크 시간을 단 몇 분 단위로 기하급수적으로 부수고 압착 단축해버릴 수 있다.

# oracle-shadow-evaluation-job.yaml
apiVersion: batch/v1
kind: Job
metadata:
  name: oracle-shadow-evaluation-suite-v2
spec:
  parallelism: 50       # 50개의 독립적인 오라클 심판 파드(Pod) 복제본을 병렬(Parallel)로 스레드 단위 통제 없이 동시 격발
  completions: 50       # 전체 50개의 워커 분산 글로벌 큐가 할당량 채점 커밋을 전부 완료할 때까지 마스터 컨트롤러가 동기 방식으로 대기 보장
  backoffLimit: 3       # LLM 외부 API Rate Limit 일시적 과부하로 인한 실패 시, 쿠버네티스 파드 레벨에서 최대 3번까지 자가 재시도 복구(Self-Healing) 트리거
  template:
    spec:
      containers:
      - name: oracle-eval-worker
        image: my-internal-registry.com/ai-oracle-runner:v2.1
        resources:
          requests:
            cpu: "500m"
            memory: "512Mi"
        env:
        - name: TARGET_API_URL
          value: "http://green-model-service.namespace.svc.cluster.local:8000"
        - name: KAFKA_BROKER
          value: "kafka-cluster:9092"   # 비동기로 LLM 채점 통계 스코어 결과를 쏟아낼 실시간 이벤트 메시지 큐
      restartPolicy: Never

이 압도적이고 선언적인 단 하나의 쿠버네티스 매니페스트(Manifest) 파일 정의를 통해, CD 파이프라인의 컨트롤러 데몬은 인가 버튼 클릭과 동시에 50개의 오라클 클론 복제본 파드들을 텅 빈 노드 레이어 메모리 위에 순간적으로 융단 폭격하듯 동시 배포 전개한다.

배포된 복제 기계 오라클들은, 메인 애플리케이션 유저를 서빙하는 메인 스레드에 어떠한 일체 물리적 응답 지연(Latency Penalty) 영향도 주지 않는 완벽히 안전하고 격리된 파드(Pod) 컨테이너 메모리 샌드박스 안에서만 구동된다. 그 밀실에서, 백엔드 타겟 LLM 모델 체인이 갓 토해낸 자연어 텍스트 텐서 덩어리들을 미친 듯한 속도로 해부하고 채점한 후, 그 성공 여부 누적 통계 결과(Pass/Fail) 메트릭을 대시보드용 카프카(Kafka) 파이프라인 데이터 큐로 비동기적으로 던져놓고는 장렬하고 깔끔하게 자동 소멸(Garbage Collection / Auto Termination)된다.

이러한 독립적인 도커 기반의 아키텍처 환경 변수 무결성과, 쿠버네티스를 통한 폭발적인 클러스터 레벨의 스케일 아웃 파워가 파이프라인 백엔드에 완벽하게 보장될 때 비로소, 나약하고 하찮아 보이던 단순한 파이썬 테스트 스크립트 뭉치인 오라클 엔진은, 전 세계 엔터프라이즈의 거대한 생성 AI 라이브 트래픽 광기를 무자비하게 통제하고 막아내는 **‘진정한 엔터프라이즈 인프라스트럭처 수준의 방탄 철옹성 관문’**으로 당당하게 격상되는 것이다.