LLM 엔지니어링21장 · AI 거버넌스와 보안, 온프레미스 인프라12 / 22← 이전목차다음 →MetaContents

21장. AI 거버넌스와 보안, 온프레미스 인프라

CI/CD 자동화

은행 본사가 새 규칙을 모든 창구에 내릴 때는, 점검표를 통과해야 배포 버튼이 눌립니다. CI/CD 는 코드를 고쳐 올릴 때마다 시험(CI)을 자동으로 돌리고, 통과하면 배포(CD)까지 이어서 하는 방식입니다. 19장의 품질 게이트와 이 장의 보안 시험을 여기에 넣습니다.

코드 올리기, 빠른 시험, 보안 점검, 품질 게이트, 배포의 다섯 단계 흐름도

1번에서 코드나 프롬프트를 저장소에 올리면, 2번 빠른 시험(문법, 단위 시험), 3번 보안 점검(공격 묶음, 개인정보, 접근 제어), 4번 품질 게이트(평가 묶음, 19~20차시)가 차례로 돕니다. 하나라도 실패하면 5번 배포는 일어나지 않습니다. 점검표가 2~4번, 배포 버튼이 5번입니다.

파이프라인 파일의 꼴

아래는 이 PC 에서 실행하지 않은 안내 코드입니다. 깃허브의 GitHub Actions 꼴로, 사내 GPU 서버에 둔 실행기(self-hosted runner)에서 점검 스크립트를 돌립니다. 사내 서버에서는 GitLab CI, Jenkins 같은 도구로 같은 일을 합니다.

출력
# .github/workflows/llm-check.yml
name: llm-check
on: [push]
jobs:
  check:
    runs-on: [self-hosted, gpu]          # 사내 GPU 서버의 실행기(Ollama 가 떠 있다)
    steps:
      - uses: actions/checkout@v4
      - run: pip install -r requirements.txt
      - run: python out_ci_check.py      # 실패하면 종료 코드 1 → 배포 단계로 넘어가지 않는다
  deploy:
    needs: check
    runs-on: [self-hosted, gpu]
    steps:
      - run: docker compose up -d --build

점검이 실패했을 때의 예상 출력(실행하지 않고 유추한 예시)입니다.

출력
check   ✗  Process completed with exit code 1.
deploy  ⊘  Skipped (needs: check)

단계를 차례로 돌리기

Python
def pipeline(stages):
    """단계를 차례로 돌리고, 실패하면 거기서 멈춘다"""
    for name, ok in stages:
        print(("통과" if ok else "실패"), name)
        if not ok:
            print("→ 배포하지 않습니다")
            return 1                          # 종료 코드 1: CI 도구가 실패로 본다
    print("→ 배포합니다")
    return 0


print("종료 코드", pipeline([("빠른 시험", True), ("보안 점검", False), ("품질 게이트", True)]))

코드에 나오는 함수

코드쉬운 뜻
for name, ok in stages(단계 이름, 통과 여부) 짝을 하나씩 꺼낸다
return 1실패하면 1 을 돌려주고 바로 끝낸다. 뒤의 단계는 돌지 않는다
return 0모두 통과하면 0 을 돌려준다
종료 코드(exit code)프로그램이 끝나며 남기는 숫자다. 0 은 성공, 0 이 아니면 실패로 보는 것이 약속이다. CI 도구는 이 숫자로 다음 단계를 할지 정한다

이 코드가 뜻하는 것

공항의 탑승 절차와 같습니다. 발권, 보안 검색, 탑승구를 차례로 지나고, 보안 검색에서 걸리면 탑승구까지 가지 않습니다. 여기서 발권, 보안 검색, 탑승구가 세 단계이고, 비행기에 타는 일이 배포입니다.

줄하는 일쉽게 말하면
for name, ok in stages:단계를 차례로 본다창구를 하나씩 지나기
if not ok: ... return 1실패하면 멈추고 1 을 돌려준다검색대에서 걸려 돌아가기
print("→ 배포합니다"), return 0모두 통과하면 배포비행기에 타기

결과에 "품질 게이트" 줄이 없습니다. 보안 점검에서 멈췄기 때문입니다. 마지막 줄의 종료 코드 1 이 CI 도구에 실패를 알립니다.

작게 줄여서 눈으로 보기

종료 코드가 실제로 다른 프로그램에 어떻게 전해지는지, 파이썬을 하나 더 띄워 봅니다. CI 도구가 점검 스크립트를 돌릴 때도 이렇게 숫자를 받습니다.

Python
import subprocess
import sys

# 파이썬을 하나 더 띄워 종료 코드 0 과 1 로 끝내 본다
for code in [0, 1]:
    r = subprocess.run([sys.executable, "-c", f"import sys; sys.exit({code})"])
    print(f"sys.exit({code}) → returncode {r.returncode}")
출력
sys.exit(0) → returncode 0
sys.exit(1) → returncode 1
결과읽는 법
sys.exit(0) → returncode 00 으로 끝낸 프로그램의 종료 코드를 바깥에서 0 으로 받았다. 성공이다
sys.exit(1) → returncode 11 로 끝내면 1 을 받는다. CI 도구는 이것을 실패로 보고 다음 단계를 건너뛴다

subprocess.run 은 subprocess(하위 프로세스), 곧 프로그램 안에서 다른 프로그램을 띄워 끝날 때까지 기다립니다. sys.executable 은 지금 쓰는 파이썬 실행 파일의 경로이고, -c 는 command(명령)로 뒤의 글을 코드로 실행합니다. sys.exit(n) 은 종료 코드 n 을 남기고 끝내며, returncode 가 그 숫자입니다.

주의할 점

  • LLM 의 답은 실행마다 조금씩 달라 시험이 가끔 들쭉날쭉합니다. 문턱에 여유를 두고, 실패하면 실패한 문항을 기록에 남겨 사람이 봅니다.
  • CI 에서 쓰는 비밀(API 키, 서버 주소)은 저장소에 적지 않고 CI 도구의 비밀 저장소에 둡니다.
← 이전 절21장 · GPU 클러스터와 온프레미스 아키텍처다음 절 →21장 · 실습 지도