1. 시작하게 된 계기
사이드 프로젝트 팀에서 우리는 코드 리뷰 프로세스의 효율성을 높이기 위해 다양한 방법을 고민하던 중이었다.
팀원들은 종종 PR이 너무 많이 쌓여 시간 내에 리뷰를 완료하기 힘들다는 문제를 제기했고, 코드 리뷰를 자동화할 수 있는 방안을 모색하게 되었다.
그 중, 자연어 처리 기술인 LLM(Large Language Model)을 활용해 코드 리뷰를 자동화하는 아이디어가 나왔다.
LLM은 주로 텍스트 분석에 사용되지만, 최근에는 코드 이해 및 생성 능력까지 발전하고 있어, 이를 통해 PR 리뷰 과정에서 코드의 품질을 평가하고, 개선할 수 있는 피드백을 제공할 수 있을 것이라고 생각했다. 이를 기반으로 우리는 LLM을 활용한 자동화 코드 리뷰 시스템을 구축하기로 했다.
2. 아키텍처
이 프로젝트의 기본 아키텍처는 비교적 간단하다.
- PR이 발생하면 GitHub Actions가 자동으로 트리거된다.
- 이때, Actions는 PR에서 변경된 git diff 내역을 추출하고, 이를 Kubernetes 클러스터 내에 배포된 LLM 서버로 전송한다.
- LLM 서버는 사전에 설정된 프롬프트와 git diff 내역을 바탕으로 코드 리뷰를 수행하고, 개선할 점에 대해 피드백을 제공한다.
- 마지막으로 이를 PR에 코멘트로 남긴다.
3. 구성
그럼 이제 아키텍처에 맞게 환경을 구성해자. 각 구성 요소와 설정 파일에 대한 설명을 포함하여 진행한다.
3.1. LLM K8S에 Pod로 서빙하기 w. Ollama
LLM을 Kubernetes 클러스터에서 서빙하기 위해 네임스페이스, 퍼시스턴트 볼륨, Ollama LLM 배포 및 서비스 설정을 단계별로 설명하겠다.
1. Namespace 생성 (ollama_ns.yaml
)
Ollama LLM 관련 리소스를 별도의 네임스페이스 ollama-ns
에 배포하여 다른 워크로드와의 충돌을 방지하고 리소스를 격리한다.
apiVersion: v1
kind: Namespace
metadata:
name: ollama
2. PV 및 PVC 생성 (llama3_pv.yaml
)
LLM 서버가 사용하는 LLM 모델 파일(예: GGUF 파일), 프롬프트, 파라미터 및 설정 값이 명시된 Modelfile 등을 지속적으로 저장하고 참조할 수 있도록 퍼시스턴트 볼륨(Persistent Volume, PV)을 설정한다.
apiVersion: v1
kind: PersistentVolume
metadata:
name: llama3-pv
namespace: ollama
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteMany
nfs:
path: /srv/nfs/models/llama3
server: k8s-master01
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: llama3-pvc
namespace: ollama
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 10Gi
- PersistentVolume: llama3-pv는 NFS(Network File System)를 사용하여 모델 파일을 저장할 경로 /srv/nfs/models/llama3에 10Gi의 용량을 할당한다. 이 경로는 NFS 서버 k8s-master01에 위치하고 있다. ReadWriteMany 모드를 사용하여 여러 Pod에서 동시에 읽고 쓸 수 있도록 설정한다.
- PersistentVolumeClaim: llama3-pvc는 퍼시스턴트 볼륨을 요청하는 PVC로, 10Gi 용량을 요청하며, 마찬가지로 ReadWriteMany 모드로 여러 Pod가 동시에 접근할 수 있도록 설정한다. 이를 통해 Ollama LLM이 사용하는 모델 파일 및 설정을 지속적으로 저장하고, 여러 Pod에서 공유할 수 있게 한다.
3. Ollama LLM 배포 (llama3_ollama_deploy.yaml
)
이 Deployment는 Ollama LLM 컨테이너를 Kubernetes에 배포하고, LLM 모델 파일과 설정을 /models/llama3 경로로 마운트하여 사용한다. 컨테이너가 시작되면 모델 파일이 있는 디렉토리로 이동하여 Modelfile에 정의된 모델을 자동으로 생성하도록 설정되어 있다.
나의 경우 MLP-KTLim/llama-3-Korean-Bllossom-8B-gguf-Q4_K_M 의 모델을 사용했고, 이를 /srv/nfs/llama3 에 저장하여 사용했다.
또한, Ollama의 경우 시스템프롬프트와 파라미터를 정의하는 Modelfile이 필요하여 작성 후 /srv/nfs/llama3 에 저장했다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: ollama
namespace: ollama
spec:
selector:
matchLabels:
name: ollama
template:
metadata:
labels:
name: ollama
spec:
containers:
- name: ollama
image: ollama/ollama:latest
ports:
- name: ollamaport
containerPort: 11434
protocol: TCP
env:
- name: OLLAMA_HOST
value: "0.0.0.0:11434"
- name: OLLAMA_ORIGINS
value: "*"
volumeMounts:
- name: llama3-model-files
mountPath: /models/llama3
lifecycle:
postStart:
exec:
command: ["sh", "-c", "cd /models/llama3 && ollama create llama-3-Korean-Bllossom-8B-Q4_K_M -f Modelfile_llama-3-Korean-Bllossom-8B-Q4_K_M"]
volumes:
- name: llama3-model-files
persistentVolumeClaim:
claimName: llama3-pvc
4. 서비스 설정 (ollama_service.yaml
)
ollama-service는 ollama 레이블을 가진 Pod에 트래픽을 전달한다. 외부에서 접근할 때 30778번 포트를 사용하여 내부의 11434번 포트로 포워딩한다. 이를 통해 Kubernetes 클러스터 외부에서 Ollama LLM에 접근할 수 있게 한다.
apiVersion: v1
kind: Service
metadata:
name: ollama
namespace: ollama
spec:
type: NodePort
selector:
name: ollama
ports:
- port: 11434
name: ollamaport
targetPort: ollamaport
protocol: TCP
nodePort: 30778
5. 포트 포워딩을 통한 외부 접근 설정
Ollama LLM 서버에 외부에서 접근할 수 있도록 추가적으로 kubectl port-forward 명령어를 사용하여 서비스를 외부에 노출시킬 수 있다. 이 방법을 사용하면 외부 API 요청이 가능하다.
nohup kubectl port-forward --address=0.0.0.0 svc/ollama -n ollama 11434:11434 &
ollama 서비스를 포트 포워딩하여 외부에서 0.0.0.0:11434로 접근할 수 있도록 설정한다. 이를 통해 API 서버가 외부 요청을 처리할 수 있게 된다.
환경이 온프레미스인지라, LoadBalancer를 따로 구축해야하는 번거로움이 있기 때문에, 테스트 용도로 사용하였다.
(추후 LoadBalancer로 적용할 예정)
3.2. GitHub Actions 연동하기 (code-review.yml
)
이제 Kubernetes에 배포된 Ollama LLM 서버와 GitHub Actions를 연동하여 PR이 발생했을 때 자동으로 코드 리뷰가 수행되도록 설정해보자.
1. GitHub Actions 설정 (code-review.yml
)
PR이 발생하거나 업데이트될 때, git diff
를 추출하고 LLM 서버로 전송하여 코드 리뷰 결과를 받는 GitHub Actions 설정 파일이다.
Gihub Actions 파일은 코드리뷰를 진행할 레포지토리의 .github/workflows/code-review.yml 로 추가해야한다.
각 secrets 변수 값들은 레포지토리 -> Settings -> Secrets and variables -> Actions 에서 추가한다.
name: CodeReview
on:
pull_request:
branches:
- release
- dev
jobs:
code_review:
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Set Server Info
run: |
echo "REVIEW_API_URL=${{ secrets.REVIEW_API_URL }}" >> $GITHUB_ENV
- name: Get Git Diff
id: git_diff
run: |
git fetch origin
git diff --unified=3 ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }} > diff.txt
DIFF_CONTENT=$(cat diff.txt)
echo "Diff content length: $(wc -c < diff.txt)"
echo "DIFF_CONTENT<<EOF" >> $GITHUB_ENV
echo "$DIFF_CONTENT" >> $GITHUB_ENV
echo "EOF" >> $GITHUB_ENV
echo "Diff added to GITHUB_ENV"
- name: API calling for CodeReview
id: api_call
run: |
ESCAPED_DIFF=$(echo "$DIFF_CONTENT" | jq -sRr @json)
REQUEST_BODY=$(jq -n \
--arg model "${{ secrets.REVIEW_MODEL_NAME }}" \
--arg prompt "Review the following code changes and provide feedback:$ESCAPED_DIFF" \
'{model: $model, prompt: $prompt, stream: false}')
FULL_RESPONSE=$(curl -X POST ${REVIEW_API_URL} \
-H "Content-Type: application/json" \
-d "$REQUEST_BODY")
REVIEW_RESPONSE=$(echo $FULL_RESPONSE | jq -r '.response')
echo "Review Response: $REVIEW_RESPONSE"
echo "REVIEW_RESPONSE<<EOF" >> $GITHUB_ENV
echo "$REVIEW_RESPONSE" >> $GITHUB_ENV
echo "EOF" >> $GITHUB_ENV
- name: Add review to pull request
uses: actions/github-script@v6
env:
DIFF_CONTENT: ${{ env.DIFF_CONTENT }}
with:
github-token: ${{ secrets.REVIEW_BOT_TOKEN }}
script: |
const diff = process.env.DIFF_CONTENT;
const response = process.env.REVIEW_RESPONSE;
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `${response}`
});
1. PR 이벤트 감지: PR이 생성되거나 업데이트될 때(예: release, dev 브랜치에서), GitHub Actions가 자동으로 트리거된다.
2. 코드 체크아웃 및 git diff 추출: git diff 명령을 실행하여 변경된 코드를 diff.txt로 저장하고, 그 내용을 환경 변수에 추가한다.
3. LLM 서버에 코드 리뷰 요청: curl 명령을 사용해 git diff 내용을 LLM 서버로 전송한다. 이 서버는 PR에서 변경된 코드를 분석하고 피드백을 생성한다.
4. 리뷰 결과 PR 코멘트로 추가: LLM 서버에서 받은 리뷰 결과를 PR 코멘트로 작성하여 자동으로 피드백을 제공한다.
4. 테스트
아래 예시처럼 이 설정을 통해 PR이 생성될 때마다 자동으로 LLM을 활용한 코드 리뷰가 수행되며, 결과가 PR 코멘트로 피드백된다.
해당 링크에서 직접 확인할 수 있다.
팀원들로부터는 놓친 부분을 리마인드하는 데 도움이 된다는 긍정적인 피드백이 있었다. 그러나 다음 두 가지 이유로 인해 지속적인 개선이 필요할 것 같다:
- 프로젝트 전체 코드가 아닌, git diff 부분만을 확인하는 점
- 시스템 프롬프트의 완성도가 아직 미흡한 점
따라서 사용을 지속하면서 이러한 부분들을 개선해 나가야 할 것이다.