배포
- master 병합 시 Jenkins가 대기 색상 스택을 빌드 → Trivy 보안 스캔 → 기동 → 헬스체크 → nginx 트래픽 전환
- HIGH·CRITICAL 취약점이 나오거나 헬스체크가 실패하면 전환하지 않음
- 배포 후 5분간 로그에서 error · exception · fatal 패턴을 찾아 Mattermost 알림에 포함
엑셀로 받던 신청을
하나의 서비스로 옮겼어요.
교육생의 교육용 기자재(교보재) 신청부터 승인·지급까지 한 곳에서 처리하고, 과거 신청 사례를 RAG로 검색하는 웹 서비스예요. 교육생이 실제로 쓰는 운영 도구라서 무중단 배포와 보안 경계를 먼저 설계했어요.
처음엔 교보재 가격을 자동으로 찾아주는 기능을 우선 후보로 봤어요. 그런데 기존 재고 1,723건을 분석해 보니 구매 링크가 있는 건 9.7%, 가격 정보가 있는 건 7.9%뿐이었어요. 조회할 원천 정보가 대부분 비어 있었던 거예요. 그래서 우선순위를 신청·승인 절차를 한 곳으로 모으는 쪽으로 바꿨어요.
사내 GitLab 저장소라 비공개예요. 저장소의 실제 설정 파일에서 판단이 담긴 부분만 옮겼어요.
Jenkinsfile · Health Check 단계 발췌
# 서비스 포트는 보안상 127.0.0.1에만 바인딩 # → Jenkins 컨테이너 밖에서는 닿지 않으므로 # 각 컨테이너 안에서 직접 호출 compose exec -T backend curl --fail \ http://127.0.0.1:8080/api/health || { echo 'Backend health check failed' compose logs --tail=50; exit 1; } compose exec -T ai python -c \ "urllib.request.urlopen( 'http://127.0.0.1:8000/health', timeout=2)"
docker-compose.yml 발췌
backend:
ports:
- "127.0.0.1:${BACKEND_PORT:-8080}:8080"
frontend:
ports:
- "127.0.0.1:${FRONTEND_PORT:-3000}:8080"
ai:
# 외부 포트 없음 · backend 내부망에서만 호출
healthcheck:
test: ["CMD", "python", "-c", "... /health"]저장소 커밋 기록 기준
Jenkins 파이프라인이 컨테이너 기동까지는 통과하는데 헬스체크 단계에서만 실패했어요. 처음엔 포트나 방화벽 문제라고 생각했어요.
Jenkins도 컨테이너로 돌고 있었어요. Jenkins 안에서 부른 127.0.0.1은 배포 서버가 아니라 Jenkins 컨테이너 자기 자신이었어요.
헬스체크를 docker compose exec로 각 컨테이너 안에서 호출하도록 바꿨고, 보안을 위한 127.0.0.1 바인딩은 그대로 유지했어요.
포트를 더 열지 않고도 배포 파이프라인이 끝까지 돌게 됐어요.
docker compose build가 'requires buildx' 오류로 멈췄어요.
Jenkins 기본 이미지에 compose와 buildx가 들어 있지 않았어요.
Jenkins용 Dockerfile을 따로 만들어 둘을 설치했고, http로 박혀 있던 Jenkins URL도 https로 고쳤어요.
같은 날 빌드가 SUCCESS로 돌아왔어요.