harness/plugins/zio-harness/knowledge/guardia/operations-cicd.md
DESKTOP-TKLFCPR\ython 1ef2235939 feat(zio-harness): v1.1.0 — auto source analysis + GUARDiA/KINTEX knowledge base
- SessionStart hook (scripts/graphify_setup.py): auto-install graphifyy[sql],
  build knowledge graph on first run (graphify extract --code-only, local AST),
  incremental graphify update thereafter — install-only smartness
- knowledge/kintex/: all 183 KINTEX md docs bundled (planning/design/analysis)
- knowledge/guardia/: distilled GUARDiA-wide knowledge from 2,483 md files
  (solutions-catalog, standard-framework, operations-cicd, lessons-learned;
  credentials/IP-free curated)
- SKILL.md: graph-first codebase query rules + knowledge base loading guide

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 23:15:35 +09:00

17 KiB

GUARDiA 운영·CI/CD 지식 문서

출처: workspace/guardia-docs/ 운영·배포 가이드(19·20·21·43·48번 등) + 루트 CLAUDE.md 하네스 변경이력 + docs/가디아_운영_노하우_전수.md 작성: 2026-07-12 | 대상: GUARDiA 전 솔루션 운영·배포 담당 에이전트/개발자 보안: 이 문서에는 비밀번호·API 키·webhook secret·SSH 자격증명을 기재하지 않는다. 서버는 "GUARDiA 인프라 서버"(zioinfo.co.kr) 로 표기한다.


1. 배포 파이프라인 전체 흐름

1.1 표준 흐름 (한 줄 요약)

workspace 소스 수정 → 모노레포 git commit
    ↓ .git/hooks/post-commit 자동 실행
git archive (추적 파일만 추출) → repos/{시스템}/ 동기화
    ↓
repos/{시스템} → Gitea(git.zioinfo.co.kr) push
    ↓ Gitea webhook (POST http://127.0.0.1:9999)
deploy_server.py (GUARDiA 인프라 서버, 포트 9999)
    ↓ 레포별 배포 블록 실행
서버 /opt/{시스템}/src git pull → 빌드(npm/mvn/pip) → 산출물 복사
    ↓
systemctl restart {서비스} → health 게이트 확인

1.2 단계별 상세

단계 위치 내용
① 소스 수정 C:\GUARDiA\workspace\<시스템>\ 모든 개발은 workspace에서만. repos/ 직접 수정 금지
② 모노레포 커밋 C:\GUARDiA (.git) commit 시 post-commit 훅이 자동 발동
③ repos 동기화 C:\GUARDiA\repos\<시스템>\ git archive HEAD workspace/{시스템}/ | tar -x추적 파일만 추출되므로 node_modules 유입 원천 차단
④ Gitea push git.zioinfo.co.kr/zio/<repo> repos/는 각각 독립 git repo (모노레포 .gitignore 처리)
⑤ webhook 수신 서버 /opt/zioinfo/deploy_server.py :9999 systemd 서비스 zioinfo-deploy. 로그: /var/log/zioinfo/deploy.log
⑥ 배포 실행 서버 /opt/<시스템>/ 레포별 블록: git pull → 빌드 → 산출물 복사 → 서비스 재시작
⑦ health 게이트 각 서비스 health 엔드포인트 200/UP 확인 후 배포 완료 판정. 실패 시 롤백 검토

1.3 시스템별 배포 블록 (deploy_server.py)

  • zioinfo-web(홈페이지): git pull → frontend npm run build(Vite outDir = backend/src/main/resources/static/) → 정적 파일 /var/www/zioinfo/ 복사 → mvn package → app.jar 교체 → systemctl restart zioinfo
  • guardia-itsm(FastAPI): git pull → rsync -a --delete(__pycache__·.git 제외) /opt/guardia/src/ → /opt/guardia/app/ → venv pip install → systemctl restart guardia
  • guardia-manager: git pull → npm build → dist를 /var/www/manager/ 복사 → 백엔드 rsync → 재시작 (★한때 프론트만 배포되는 결함이 있어 백엔드 rsync 단계가 추가됨 — 2026-07-04)
  • Spring Boot 단일 jar 솔루션(ERP·CRM·OCR·BI·PMS·RPA·Groupware·Portal·Mall·CMS·MES·ESN 등): frontend → backend static 번들 → 단일 jar 빌드 → jar 교체 → systemd 재시작
  • guardia-rag(Python): git pull → pip → restart → health (2026-07-04 파이프라인 완성)

1.4 수동 배포 (자동 배포 불가 시)

# 개발 PC에서 — 특정 시스템/전체
python scripts/deploy/manual_deploy.py guardia-itsm   # 별칭 itsm/web 가능
python scripts/deploy/manual_deploy.py                # 전체

# 서버에서 직접 (가장 확실) — 예: zioinfo-web
SRC=/opt/zioinfo/src
git -C $SRC fetch origin main && git -C $SRC reset --hard origin/main
cd $SRC/frontend && npm run build --silent
cp -rf $SRC/backend/src/main/resources/static/. /var/www/zioinfo/
cd $SRC/backend && mvn clean package -DskipTests -q
cp $SRC/backend/target/zioinfo-web-*.jar /opt/zioinfo/app/app.jar
systemctl restart zioinfo && sleep 5 && systemctl is-active zioinfo
  • ITSM 웹 UI에서도 배포 트리거 가능: POST /api/cicd/deploy(JWT 인증), GET /api/cicd/status
  • Windows Task Scheduler: GUARDiA-AutoDeploy-Hourly(1시간마다 manual_deploy 전체), GUARDiA-DailyParent(매일 09:00 건강검진·성장일지)

2. 배포 함정·체크리스트 (실사고 기반)

2.1 파이프라인 인프라 함정

# 함정 증상 해법
1 deploy_server.py 서버 사본 미반영 로컬에서 deploy_server.py를 고쳐도 서버는 구버전 실행 수정 시 반드시 서버 /opt/zioinfo/deploy_server.py에 반영 + systemctl restart zioinfo-deploy. 백업본(.bak) 생성 후 교체
2 배포 블록 부재 = 1ms no-op 배포 로그에 '완료'가 찍혀도 처리 시간이 1ms 수준이면 해당 repo 블록이 deploy_server.py에 없는 것 로그의 소요 시간 확인. 신규 솔루션 추가 시 deploy_server.py에 배포 블록 추가 필수 (guardia-rag 사례: 웹훅 수신은 됐지만 블록 부재로 무동작)
3 Gitea webhook 자체 부재 push해도 :9999에 요청이 안 옴 신규 repo는 Gitea에 webhook 등록 필수 (URL=localhost:9999, push 이벤트, main 브랜치, secret 일치). hook test API로 검증
4 webhook 로컬 차단 webhook 발송 실패 /etc/gitea/app.ini [webhook] ALLOW_LOCAL_NETWORKS = true 필수. loopback을 ALLOWED_HOST_LIST에 포함
5 webhook URL이 외부 도메인 NAT 헤어핀으로 전달 실패/지연 webhook URL은 http://localhost:9999(서버 내부 루프백)로 설정
6 webhook secret 불일치 (403) deploy_server가 403 반환 Gitea webhook secret과 deploy_server 설정값 일치 확인 (값은 문서에 기재 금지)
7 서버 /opt 소스가 git 체크아웃이 아님 webhook이 와도 git pull이 no-op /opt/<시스템>/src는 반드시 Gitea repo의 git 체크아웃이어야 함 (guardia-rag 사례: 미git화 → git 체크아웃 전환)
8 remote에 구버전 자격증명 git pull 인증 실패로 자동배포 중단 서버 /opt/*/src remote URL의 자격증명 일관성 점검 (2026-06-12 itsm/web/manager/docs 복구 사례)

2.2 빌드·소스 함정

# 함정 해법
9 수동 배포 후 자동 배포 미작동 — 서버 커밋이 Gitea와 어긋나 이후 webhook이 '변경 없음' 처리 git fetch origin main && git reset --hard origin/main으로 서버 소스를 origin에 강제 정렬
10 node_modules 실수 커밋 .gitignore에 node_modules/·dist/·build/ 추가. post-commit이 git archive를 쓰므로 추적 파일만 넘어가는 구조 유지
11 nginx/브라우저 정적 캐시 — 배포해도 화면 미반영 정적 파일 강제 복사 + systemctl reload nginx; JS/CSS는 Vite 해시로 자동 무효화; 최종적으로 Ctrl+Shift+R
12 Vite outDir 착각 — dist/를 찾다 파일 없음 zioinfo-web은 outDir이 backend/src/main/resources/static/ — 그 경로에서 복사
13 로컬 rollup win32 크래시 로컬 빌드 실패해도 서버 빌드(npm+mvn)를 신뢰하는 경로로 진행 (esbuild 대체 검증 병행)
14 공유 트리 교차 커밋 여러 트랙이 같은 트리를 만질 때는 파일 단위 커밋으로 교차 오염 방지 (kintex 표준)

2.3 DB·스키마 함정

# 함정 해법
15 Flyway/DDL 마이그레이션 배포 사고 배포 전 라이브 DB에 dry-run(BEGIN…ROLLBACK) 필수 (kintex 표준화 교훈)
16 sql.init.mode: never + schema.sql 후행 확장 = 누락 테이블 초기 배포 후 schema.sql에 테이블을 추가해도 재적용 안 됨 → 런타임 relation does not exist 500. 표준 수복: 시드 멱등화(유니크 인덱스) + mode=always + continue-on-error + DataAccessException 핸들러(스택트레이스 누출 차단)
17 MyBatis 매퍼 빈 누락 크래시 @MapperScan(annotationClass = Mapper.class) 사용 (OCR TemplateMapper 사례)
18 시크릿 미주입 기동 실패 배포 전 시크릿 fail-fast 프로파일 확인 — env(systemd drop-in EnvironmentFile) 주입 여부 점검

2.4 배포 전 체크리스트 (요약)

□ workspace에서만 수정했고 repos/ 직접 수정 없음
□ 파일 단위 커밋 (공유 트리 교차 방지)
□ DDL 변경 시 라이브 Flyway dry-run(BEGIN…ROLLBACK) 통과
□ deploy_server.py 변경 시 서버 사본 반영 + zioinfo-deploy 재시작
□ 신규 repo면: Gitea webhook 등록 + deploy_server 배포 블록 + /opt git 체크아웃 3종 세트
□ push 후 /var/log/zioinfo/deploy.log 에서 소요 시간 확인 (1ms면 블록 부재 의심)
□ 서비스 health 엔드포인트 200/UP 확인 (health 게이트)
□ 배포 후 회귀: run_full_test.py 통과

3. 서비스 운영 맵

3.1 접속 체계

  • 공개 접근은 서브도메인 + nginx 리버스 프록시: zioinfo.co.kr(홈페이지) / itsm. / manager. / mail. / git.(Gitea) / jenkins. / docs. / kintex.(킨텍스) 등
  • nginx 설정: /etc/nginx/sites-available/{subdomain}.zioinfo.co.kr
  • SSL: Let's Encrypt(certbot 자동 갱신) 기본, 일부 ZeroSSL(acme.sh). 신규 서브도메인은 certbot --nginx -d {sub}.zioinfo.co.kr 발급

3.2 포트 맵 (GUARDiA 인프라 서버 내부)

포트 서비스 비고
9001 GUARDiA ITSM (FastAPI) 허브. 전 솔루션 연동 기준점
8002/8090 GUARDiA Manager ITSM JWT 재사용
8082 zioinfo-web (홈페이지 Spring Boot) 정적은 /var/www/zioinfo + nginx
8003~8013 ERP·CRM·OCR·BI·PMS·RPA·Groupware·Portal·Mall·CMS·MES Spring Boot 단일 jar, DB {sol}_db
8015/8016 zioinfo-ESN / GUARDiA ESN ESL 플랫폼
8018/8019 MRO / Signage(e-SignBoard)
8021 KINTEX kintex.zioinfo.co.kr
8025/8026 웹메일 (SMTP UI/백엔드) Postfix/Dovecot 연동
8080 Jenkins 보조 CI (주력은 deploy_server)
9003 Gitea 내부 외부는 git.zioinfo.co.kr(443) 경유
9999 deploy_server.py (webhook) systemd zioinfo-deploy
11434 Ollama 온프레미스 AI. RAM 제약으로 소형 모델(qwen3:1.7b·llama3.2:1b·moondream) 운용
guardia-rag (중앙 RAG) 전 솔루션 AI 질의 경유점 (LangChain+ChromaDB)

3.3 systemd 서비스 구성 개요

  • 명명: guardia(ITSM)·zioinfo(홈페이지)·guardia-manager·zioinfo-mail·zioinfo-deploy(webhook)·gitea·jenkins·postgresql·ollama + 솔루션별 guardia-{sol}.service (예: guardia-ocr) — 총 17개+ active
  • 경로 규약: 소스 /opt/{sol}/src/, 실행 /opt/{sol}/app/(또는 jar), 정적 /var/www/{sol}/
  • AI env 주입: 전 서비스에 systemd drop-in(ai-env.conf, EnvironmentFile 추가) 방식 — 기존 ExecStart 불변. 시크릿은 /opt/guardia/secrets/(root 600) + env 파일에서만 로드, 코드·커밋·로그 기재 금지
  • 로그: journalctl -u {서비스} -n 100 --no-pager / 배포 로그 tail -50 /var/log/zioinfo/deploy.log
# 전체 상태 빠른 점검
for svc in nginx zioinfo guardia guardia-manager zioinfo-mail gitea jenkins postgresql ollama; do
  printf "%-22s %s\n" $svc "$(systemctl is-active $svc 2>/dev/null)"
done

3.4 health 엔드포인트 패턴

계열 패턴 판정
FastAPI (ITSM·mail 등) GET /health 또는 GET /api/health JSON status 필드
Spring Boot 솔루션 GET /api/health (또는 actuator health) UP/200
배포 게이트 재시작 후 sleep 4~5초 → health 200 확인 실패 시 배포 실패 처리
  • health 게이트 원칙: 직렬 배포(솔루션 다수 동시 배포 시)에서 각 단계마다 health 통과 후 다음 진행. RAM이 빠듯한 서버 특성상 동시 재시작 금지·직렬 빌드가 표준.

3.5 DB 운영 요점

  • PostgreSQL: 솔루션별 DB 격리(erp_db·crm_db·ocr_db·… , 각 {sol}_user), Hikari max 3 (RAM 제약)
  • 홈페이지는 SQLite(/opt/zioinfo/app/data/zioinfo.db)
  • 백업: pg_dump(PostgreSQL) / 파일 복사(SQLite) — 일일 백업 루틴 대상

4. 테스트 체계

4.1 상시 전체 테스트 — run_full_test.py

  • 실행: python3 C:\GUARDiA\scripts\check\run_full_test.py (paramiko로 서버 내부에서 curl 실행)
  • 규모: 22개 그룹 — 현재 126개 테스트(초기 69 → 93 → 126으로 성장). service_health 그룹이 각 서비스 health를 우선 검사
  • 인증: admin 비밀번호를 서버 암호화 저장소(root 전용 복호 헬퍼)에서 서버 내부 셸 변수로만 조달 — 값을 로컬로 가져오지 않고 출력·저장하지 않음
  • 결과 저장: .claude/agents/_workspace/test_results/latest.json
  • 트리거: "테스트 해줘"·"검증해줘"·"배포 확인"·"회귀 테스트" → test-orchestrator 스킬 (에이전트 api-tester)

4.2 배포와의 결합

  • 배포 후 필수 회귀: 배포 작업(특히 다중 솔루션·deploy_server 변경·스키마 변경) 뒤에는 반드시 126/126 통과를 확인하고 종료 (2026-07-04 WISE 전 솔루션 배포·홈페이지 리뉴얼 모두 이 게이트로 마감)
  • 스모크: 각 솔루션에 개별 스모크 스크립트가 있으면 우선 실행 후 전체 테스트 (guardia-rag 스모크 3종 사례)
  • E2E 검증 표준: push → webhook 수신 → git pull → 빌드 → restart → health → HEAD 커밋 자동 갱신 확인까지가 "자동배포 검증 완료"의 정의

5. 운영 점검 루틴 — guardia-ops-check

정기/요청 시 수행하는 통합 헬스체크. 트리거: "운영 점검"·"서버 기동 확인"·"전체 상태 확인"·"테이블 누락 확인" → guardia-ops-check-orchestrator 스킬.

5.1 3단 점검 구성

단계 에이전트 내용
① Git 정합 git-ops-dev Gitea 자격증명 설정 상태·repo clone/원격 정합·workspace↔repos↔Gitea↔서버 4-way 동기화 (system-sync-orchestrator와 연계: deploy-verifier/deploy-fixer)
② 서비스 기동 server-health-checker 전 solution systemd active + health 엔드포인트 응답 전수 확인
③ 스키마 무결성 schema-audit-dev (schema-integrity 재사용) 매퍼가 참조하는 테이블/컬럼 vs 라이브 DB 전수 대조 → relation does not exist 예방. 수복은 schema-fix-dev(멱등 ALTER/CREATE + mode=always + 누출 차단 패턴)

5.2 일상 운영 루틴 요약

# 1) 서비스 전수 상태
systemctl is-active {서비스들}          # 3.3 스니펫

# 2) 배포 최신성
tail -20 /var/log/zioinfo/deploy.log    # 최근 배포 + 소요시간(1ms 의심)
git -C /opt/{sol}/src log --oneline -3  # 서버 HEAD가 Gitea와 일치하는지

# 3) webhook 경로 생존
ss -tlnp | grep 9999                    # deploy_server 리스닝
curl -s -X POST http://127.0.0.1:9999 -H 'Content-Type: application/json' \
  -d '{"repository":{"name":"zioinfo-web"},"ref":"refs/heads/main"}'   # "Deploy queued" 기대

# 4) 리소스 (RAM 제약 서버)
free -h                                 # Ollama 모델 로드 여부에 민감 — avail 감시

# 5) 전체 회귀
python3 scripts/check/run_full_test.py  # 126/126

5.3 장애 대응 우선순위

  1. health 실패 서비스 → journalctl -u {svc} -n 100으로 원인 (기동 실패 최다 원인: 시크릿 env 미주입·스키마 누락 테이블·RAM 부족 OOM)
  2. 자동배포 불통 → §2.1 함정 표 순서대로 (블록 부재 → webhook 부재 → ALLOW_LOCAL_NETWORKS → secret → /opt git화 → remote 자격증명)
  3. AI 기능 불능 → Ollama RAM 제약 우선 의심 (7B+ 모델은 서버에서 로드 불가 — 소형 모델 폴백 체인: Claude→Qwen3→소형 Ollama). ollama-health-orchestrator 하네스 참조
  4. 화면 미반영 → 캐시/정적 복사(§2.2 #11) → 그래도 안 되면 서버 HEAD 확인(§2.2 #9)

5.4 부속 정기 루틴

  • 부모 역할 하네스(guardia-parent): 매일 건강검진(테스트·자가 수복)·성장일지 기록 — Task Scheduler GUARDiA-DailyParent 09:00
  • SSL: certbot 자동 갱신 + 만료 임박 도메인 월 1회 certbot certificates 확인
  • 백업: DB pg_dump/파일 백업 일일, 배포 전 산출물(.bak) 백업 습관화

부록 A. 신규 솔루션 배포 온보딩 절차 (표준)

  1. workspace/<sol>/ 소스 완성 → repos/ fresh init → Gitea zio/<sol> repo 생성 + push
  2. 서버: /opt/<sol>/src git clone(체크아웃), DB {sol}_db/{sol}_user 생성, systemd guardia-<sol>.service 등록(setup__service.py 패턴)
  3. AI env drop-in(ai-env.conf) 적용 (시크릿은 env 파일에서만)
  4. Gitea webhook 등록 (localhost:9999·push·main·secret) + hook test
  5. deploy_server.py에 배포 블록 추가 → 서버 사본 반영 + zioinfo-deploy 재시작
  6. push→자동배포 E2E 검증 (HEAD 갱신·health 200) → run_full_test.py 회귀
  7. guardia-docs 운영가이드 + 루트 CLAUDE.md 하네스 변경이력 갱신

부록 B. 보안 불변 규칙 (운영 문서 공통)

  • 자격증명(비밀번호·API 키·secret·SSH 계정)은 문서·코드·커밋·로그·API 응답에 절대 기재/노출 금지 — 서버 env 및 암호화 저장소(AES-256-GCM)에서만 조달
  • 에러 응답에 스택트레이스 미노출 (DataAccessException 핸들러 등 누출 차단)
  • 외부 API 금지 원칙 유지 (예외: Anthropic Claude API 단일 경로 — 소유자 승인, 키는 서버 env에서만 로드, 실패 시 Ollama 폴백)
  • Gitea 전용 운영 — GitHub push 금지