ci(itms): CI/CD 배포 아티팩트 추가 (적용 대기·산출물 준비형)
zioinfo.co.kr 피저빌리티 게이트 결과 ITMS 실기동(Tier2)은 이 환경 불가
(런타임 DB MariaDB/Oracle 도달 불가 + JDK17 부재 + Boot2.6.2 Java21 미지원)
→ 서버 미변경, 배포 대상 환경에서 적용할 준비된 산출물만 생성.
- deploy/deploy_server_itms_block.py: deploy_server.py 에 붙일 itms 블록
(Tier1 빌드+커밋별 아카이브; Tier2 재기동은 주석 처리, 기존 블록 불변, 자격증명 env 주입)
- deploy/build.sh: common 선행 → 5모듈 bootWar (JDK17)
- deploy/systemd/itms-{auth,api,front,batch,datatrans}.service: 4포트 WAR+데몬 유닛 템플릿
- deploy/env/itms.env.example: SPRING_PROFILES_ACTIVE 등 (실 시크릿 미포함)
- deploy/gitea-webhook.md: webhook 3대 함정(url·secret·ALLOWED_HOST_LIST) 반영 생성 가이드(미실행)
- deploy/README.md: 특수성·적용 절차·피저빌리티 근거
보안: AES 암호문·DB 접속정보·NCP 키·Gitea 비번 하드코딩 0(env 주입). 기존 단일-jar 배포 무영향.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
53a7891aee
commit
08e634c3a5
48
deploy/README.md
Normal file
48
deploy/README.md
Normal file
@ -0,0 +1,48 @@
|
||||
# ITMS CI/CD 배포 아티팩트 (적용 대기)
|
||||
|
||||
> 생성: 2026-07-17 (itms-cicd 하네스, 산출물 준비형) | 대상 저장소: Gitea `ythong/itms`
|
||||
> **상태: 적용 대기(NOT applied).** 이 디렉터리는 배포 대상 환경에서 적용할 준비된 산출물이다. 서버는 변경되지 않았다.
|
||||
|
||||
## 왜 "적용 대기"인가 (피저빌리티 게이트)
|
||||
|
||||
GUARDiA 인프라 서버(zioinfo.co.kr)에서 실측한 결과, **ITMS 앱의 실기동(Tier2)은 이 환경에서 불가**하다:
|
||||
- api/batch/datatrans 런타임 DB(MariaDB `ur_itms_db`·Oracle XE)가 GUARDiA 인프라에서 **도달 불가**(고객사 전용망 DB).
|
||||
- 서버 런타임 JDK가 **21뿐**(JDK17 부재). ITMS는 Boot 2.6.2로 **Java 21 미지원**.
|
||||
|
||||
따라서 실배포는 **고객사 배포 환경**(대상 기관 DB망 + 기관 프로파일 시크릿 + JDK17)에서 아래 아티팩트를 적용해 수행한다. Tier1(빌드 자동화)만 별도로 쓰려면 빌드 서버에 JDK17을 두고 `deploy_server_itms_block.py`의 빌드 단계만 사용한다.
|
||||
|
||||
## 구성 특수성
|
||||
|
||||
ITMS는 단일-jar가 아니라 **4포트 독립 WAR 스택 + 데몬**:
|
||||
|
||||
| 모듈 | 포트 | 산출물 | 런타임 의존 | systemd |
|
||||
|---|---|---|---|---|
|
||||
| auth | 11000 | bootWar | (RSA jwtkey) | itms-auth.service |
|
||||
| api | 11010 | bootWar | MariaDB ur_itms_db | itms-api.service |
|
||||
| front | 11020 | bootWar | DB 무접속(REST만) | itms-front.service |
|
||||
| batch | 11030 | bootWar | MariaDB + Oracle XE + 메일/알림톡 | itms-batch.service |
|
||||
| datatrans | (데몬) | bootWar | kccfnova/uac_cltr_db + NAS | itms-datatrans.service |
|
||||
| common | — | 라이브러리(선행 빌드) | — | — |
|
||||
| legacy/nlib | — | Maven·Java8, **CI 제외** | — | — |
|
||||
|
||||
## 파일
|
||||
|
||||
| 파일 | 용도 |
|
||||
|---|---|
|
||||
| `deploy_server_itms_block.py` | `scripts/deploy/deploy_server.py`의 `_deploy()`에 붙여넣을 `elif repo == "itms":` 블록(Tier1 빌드+아카이브; 기존 블록 불변) |
|
||||
| `build.sh` | 모듈별 gradle 빌드(common 선행 → 5모듈 bootWar) — JDK17 필요 |
|
||||
| `systemd/itms-*.service` | 모듈별 systemd 유닛 템플릿(Tier2, 활성화 조건 충족 시) |
|
||||
| `env/itms-*.env.example` | 모듈별 env 템플릿(`SPRING_PROFILES_ACTIVE`=기관) — **실 시크릿은 여기 넣지 말고 서버 로컬에서 관리** |
|
||||
| `gitea-webhook.md` | Gitea `ythong/itms` push webhook 생성 가이드 + 스크립트(미실행) |
|
||||
|
||||
## 적용 절차 (고객사/배포 대상 환경)
|
||||
|
||||
1. **선결:** JDK17 설치, 런타임 DB(MariaDB/Oracle) 연결, 기관 프로파일 시크릿(keystore·yml) 배치.
|
||||
2. **CI:** `deploy_server_itms_block.py`를 배포 서버 deploy_server.py에 병합 → deploy 서비스 재시작. Gitea webhook 생성(`gitea-webhook.md`).
|
||||
3. **빌드:** `build.sh`(또는 deploy 블록)로 `common` 선행 → 5모듈 bootWar. 산출물 `*/build/libs/*.war`.
|
||||
4. **CD(Tier2):** `env/itms-<module>.env`에 `SPRING_PROFILES_ACTIVE=<기관>` 설정 → `systemd/itms-*.service` 배치 → `systemctl daemon-reload && enable --now`.
|
||||
5. **헬스체크:** 11000/11010/11020 도달, batch/datatrans 로그 라이브니스.
|
||||
|
||||
## 보안 불변
|
||||
- 이 디렉터리 어떤 파일에도 AES 암호문·DB 접속정보·NCP/카카오 키·Gitea 비번·SSH 계정을 **하드코딩 금지**. 자격증명은 env/서버 로컬에서만.
|
||||
- force push 금지. 기존 단일-jar 솔루션 배포에 무영향(deploy_server는 itms 블록만 추가).
|
||||
21
deploy/build.sh
Normal file
21
deploy/build.sh
Normal file
@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env bash
|
||||
# ITMS 모듈별 빌드 (JDK17 필요). common 선행 → 5모듈 bootWar. legacy/nlib 제외.
|
||||
# 사용: JAVA_HOME=/path/to/jdk17 deploy/build.sh (repo 루트에서 실행)
|
||||
set -euo pipefail
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
if [ -z "${JAVA_HOME:-}" ]; then
|
||||
echo "WARN: JAVA_HOME 미설정 — JDK17 경로를 지정하세요 (ITMS 는 Boot 2.6.2·Java17)." >&2
|
||||
fi
|
||||
|
||||
echo "== gradle: common build + 5모듈 bootWar =="
|
||||
./gradlew --no-daemon \
|
||||
:common:build \
|
||||
:auth:bootWar :api:bootWar :front:bootWar :batch:bootWar :datatrans:bootWar \
|
||||
-x test
|
||||
|
||||
echo "== 산출물 =="
|
||||
for m in auth api front batch datatrans; do
|
||||
ls -1 "$m"/build/libs/*.war 2>/dev/null || echo " ($m: war 없음)"
|
||||
done
|
||||
echo "완료. WAR 를 systemd(itms-*.service)로 기동하려면 런타임 DB·기관 프로파일 시크릿 확보 필요."
|
||||
50
deploy/deploy_server_itms_block.py
Normal file
50
deploy/deploy_server_itms_block.py
Normal file
@ -0,0 +1,50 @@
|
||||
# =====================================================================
|
||||
# ITMS CI/CD 블록 — scripts/deploy/deploy_server.py 의 _deploy(self, repo) 에
|
||||
# 기존 elif 체인 말미에 그대로 붙여넣는다. (기존 블록은 변경하지 않는다.)
|
||||
#
|
||||
# 특수성: ITMS 는 Gradle 멀티모듈(Boot 2.6.2·Java17) 4포트 WAR 스택.
|
||||
# - Tier1(빌드 자동화): common 선행 → 5모듈 bootWar → 커밋별 아카이브. DB 불필요.
|
||||
# - Tier2(기동): 런타임 DB(MariaDB/Oracle)·기관 시크릿·JDK17 확보 환경에서만
|
||||
# 아래 (restart ...) 단계 주석을 해제하여 systemd 재기동. 기본은 빌드+아카이브까지.
|
||||
#
|
||||
# 선결: 배포 서버에 JDK17 설치(예: /usr/lib/jvm/java-17-openjdk-amd64) 후 JAVA17 경로 지정.
|
||||
# 자격증명: Gitea 클론 URL 의 사용자/토큰은 서버 환경변수로 주입한다(하드코딩 금지).
|
||||
# 예) 서버 deploy_server 환경에 GITEA_CLONE_CRED='user:token' 를 두고 아래 f-string 에서 사용.
|
||||
# =====================================================================
|
||||
|
||||
elif repo == "itms":
|
||||
SRC = "/opt/itms/repo"
|
||||
ARTIF = "/opt/itms/artifacts"
|
||||
JAVA17 = "/usr/lib/jvm/java-17-openjdk-amd64" # 배포 대상 환경의 JDK17 경로로 수정
|
||||
# GITEA_CLONE_CRED 는 서버 env 에서 주입(예: 'ythong:<token>'). 코드/커밋에 비번 금지.
|
||||
CRED = os.environ.get("GITEA_CLONE_CRED", "") # 미설정 시 기존 리모트/캐시 사용
|
||||
CLONE = (f"git clone 'http://{CRED}@127.0.0.1:9003/ythong/itms.git' {SRC}"
|
||||
if CRED else f"echo 'GITEA_CLONE_CRED 미설정 — 기존 {SRC} 사용' ")
|
||||
ok = run_steps(repo, [
|
||||
("git pull", ["bash", "-c",
|
||||
f"[ -d {SRC}/.git ] && git -C {SRC} fetch origin main && git -C {SRC} reset --hard origin/main"
|
||||
f" || ( mkdir -p /opt/itms && {CLONE} )"]),
|
||||
# common 선행 + 5모듈 bootWar (JDK17 지정). legacy/nlib 제외.
|
||||
("gradle build", ["bash", "-c",
|
||||
f"cd {SRC} && JAVA_HOME={JAVA17} ./gradlew --no-daemon "
|
||||
f":common:build :auth:bootWar :api:bootWar :front:bootWar :batch:bootWar :datatrans:bootWar "
|
||||
f"-x test"]),
|
||||
# 커밋 해시별 산출물 아카이브(롤백 대비)
|
||||
("archive war", ["bash", "-c",
|
||||
f"H=$(git -C {SRC} rev-parse --short HEAD); D={ARTIF}/$H; mkdir -p $D; "
|
||||
f"for m in auth api front batch datatrans; do "
|
||||
f"cp {SRC}/$m/build/libs/*.war $D/itms-$m.war 2>/dev/null || true; done; "
|
||||
f"ln -sfn $D {ARTIF}/current; ls -l {ARTIF}/current"]),
|
||||
# --- Tier2 (기동): DB/시크릿/JDK17 확보 환경에서만 주석 해제 ---
|
||||
# ("restart auth", ["bash","-c","systemctl restart itms-auth 2>/dev/null || true"]),
|
||||
# ("restart api", ["bash","-c","systemctl restart itms-api 2>/dev/null || true"]),
|
||||
# ("restart front", ["bash","-c","systemctl restart itms-front 2>/dev/null || true"]),
|
||||
# ("restart batch", ["bash","-c","systemctl restart itms-batch 2>/dev/null || true"]),
|
||||
# ("restart datatrans", ["bash","-c","systemctl restart itms-datatrans 2>/dev/null || true"]),
|
||||
# ("health check", ["bash","-c","sleep 6 && for p in 11000 11010 11020; do "
|
||||
# "curl -sf -o /dev/null http://127.0.0.1:$p/ && echo \"$p UP\" || echo \"$p DOWN\"; done"]),
|
||||
])
|
||||
if ok:
|
||||
notify_itsm(True, "✅ itms 빌드/아카이브 완료 (Tier1)")
|
||||
else:
|
||||
notify_itsm(False, "❌ itms 빌드 실패")
|
||||
7
deploy/env/itms.env.example
vendored
Normal file
7
deploy/env/itms.env.example
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
# ITMS 모듈 env 템플릿 — /etc/itms/itms-<module>.env 로 복사해 사용.
|
||||
# 실 시크릿(DB 접속정보·keystore 비번·NCP 키)은 여기 넣지 말고 프로파일 yml/keystore + 서버 로컬로 관리.
|
||||
# 기관 프로파일 선택(파일·키 불변): 배포 대상 기관명으로 지정.
|
||||
SPRING_PROFILES_ACTIVE=local
|
||||
# JVM 옵션(선택)
|
||||
JAVA_OPTS=-Xms256m -Xmx512m
|
||||
# 필요 시 추가 환경변수(예: 외부 keystore 경로)를 여기에. 비밀번호 평문 금지.
|
||||
31
deploy/gitea-webhook.md
Normal file
31
deploy/gitea-webhook.md
Normal file
@ -0,0 +1,31 @@
|
||||
# Gitea webhook — ythong/itms (적용 대기)
|
||||
|
||||
push 시 배포 서버 deploy_server(port 9999)로 알리는 webhook. **아직 생성하지 않음.**
|
||||
|
||||
## 3대 함정 (GUARDiA 기지 교훈 — 반드시 준수)
|
||||
1. **url**: NAT 헤어핀 회피 위해 `http://127.0.0.1:9999/`(localhost) 로 지정.
|
||||
2. **secret**: 배포 서버 deploy_server 의 검증 secret 과 **일치**시킬 것(불일치 시 403). 값은 서버 운영 시크릿 — 여기에 적지 말 것.
|
||||
3. **ALLOWED_HOST_LIST**: Gitea app.ini `[webhook] ALLOWED_HOST_LIST` 에 loopback 포함(없으면 localhost 웹훅 차단).
|
||||
|
||||
## 생성 (배포 대상 환경에서 실행; 자격증명·secret 은 env 로 주입)
|
||||
```bash
|
||||
# GITEA_TOKEN, DEPLOY_SECRET 를 환경변수로 주입(하드코딩 금지)
|
||||
curl -s -X POST "https://git.zioinfo.co.kr/api/v1/repos/ythong/itms/hooks" \
|
||||
-H "Authorization: token ${GITEA_TOKEN}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"type": "gitea",
|
||||
"active": true,
|
||||
"events": ["push"],
|
||||
"config": {
|
||||
"url": "http://127.0.0.1:9999/",
|
||||
"content_type": "json",
|
||||
"secret": "'"${DEPLOY_SECRET}"'"
|
||||
}
|
||||
}'
|
||||
```
|
||||
- branch 필터가 필요하면 deploy_server 측에서 `ref == refs/heads/main` 확인(현행 deploy_server 는 repo 이름으로 분기).
|
||||
- 생성 후 Gitea UI 의 "Test Delivery" 로 발화 → deploy_server 로그에서 `repo=itms` 수신 확인.
|
||||
|
||||
## deploy_server 반영
|
||||
`deploy_server_itms_block.py` 를 배포 서버 `deploy_server.py` 의 `_deploy()` elif 체인에 병합 → 서버 사본 반영 → deploy 서비스 재시작. (교훈: 서버 사본 미반영/미재시작 시 웹훅 로그 '완료'여도 1ms no-op = 블록 부재.)
|
||||
14
deploy/systemd/itms-api.service
Normal file
14
deploy/systemd/itms-api.service
Normal file
@ -0,0 +1,14 @@
|
||||
[Unit]
|
||||
Description=ITMS Api (OAuth2 resource server, :11010)
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
[Service]
|
||||
Type=simple
|
||||
EnvironmentFile=/etc/itms/itms-api.env
|
||||
ExecStart=/usr/lib/jvm/java-17-openjdk-amd64/bin/java -jar /opt/itms/artifacts/current/itms-api.war
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
User=itms
|
||||
Group=itms
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
14
deploy/systemd/itms-auth.service
Normal file
14
deploy/systemd/itms-auth.service
Normal file
@ -0,0 +1,14 @@
|
||||
[Unit]
|
||||
Description=ITMS Auth (OAuth2 authorization server, :11000)
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
[Service]
|
||||
Type=simple
|
||||
EnvironmentFile=/etc/itms/itms-auth.env
|
||||
ExecStart=/usr/lib/jvm/java-17-openjdk-amd64/bin/java -jar /opt/itms/artifacts/current/itms-auth.war
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
User=itms
|
||||
Group=itms
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
14
deploy/systemd/itms-batch.service
Normal file
14
deploy/systemd/itms-batch.service
Normal file
@ -0,0 +1,14 @@
|
||||
[Unit]
|
||||
Description=ITMS Batch (Quartz clustered, :11030)
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
[Service]
|
||||
Type=simple
|
||||
EnvironmentFile=/etc/itms/itms-batch.env
|
||||
ExecStart=/usr/lib/jvm/java-17-openjdk-amd64/bin/java -jar /opt/itms/artifacts/current/itms-batch.war
|
||||
Restart=on-failure
|
||||
RestartSec=8
|
||||
User=itms
|
||||
Group=itms
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
14
deploy/systemd/itms-datatrans.service
Normal file
14
deploy/systemd/itms-datatrans.service
Normal file
@ -0,0 +1,14 @@
|
||||
[Unit]
|
||||
Description=ITMS DataTrans (NCMS->IAMS ETL @Scheduled daemon)
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
[Service]
|
||||
Type=simple
|
||||
EnvironmentFile=/etc/itms/itms-datatrans.env
|
||||
ExecStart=/usr/lib/jvm/java-17-openjdk-amd64/bin/java -jar /opt/itms/artifacts/current/itms-datatrans.war
|
||||
Restart=on-failure
|
||||
RestartSec=10
|
||||
User=itms
|
||||
Group=itms
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
14
deploy/systemd/itms-front.service
Normal file
14
deploy/systemd/itms-front.service
Normal file
@ -0,0 +1,14 @@
|
||||
[Unit]
|
||||
Description=ITMS Front (JSP/Tiles web tier, :11020)
|
||||
After=network-online.target itms-auth.service itms-api.service
|
||||
Wants=network-online.target
|
||||
[Service]
|
||||
Type=simple
|
||||
EnvironmentFile=/etc/itms/itms-front.env
|
||||
ExecStart=/usr/lib/jvm/java-17-openjdk-amd64/bin/java -jar /opt/itms/artifacts/current/itms-front.war
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
User=itms
|
||||
Group=itms
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
Loading…
Reference in New Issue
Block a user