# csv.wise.ai.kr 배포 구성 ## 전체 구조 ``` [개발 PC] │ git push ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ 웹서버 175.118.124.176 (utimsurpai.cafe24.com, Rocky 8, SSH :9271) │ │ Gitea git.wise.ai.kr (127.0.0.1:9003) │ │ act_runner `arko-web:host` → JDK8+Maven 3.6.3 으로 WAR 빌드 │ │ Apache httpd → https://csv.wise.ai.kr │ └───────────┬──────────────────────────────────┬──────────────────────┘ │ ① scp WAR + 배포 스크립트 (SSH) │ ② SSH 터널 :11060 ▼ ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ WAS 27.255.76.2 (Ubuntu 22.04, 64코어) │ │ arko-tomcat 컨테이너 127.0.0.1:11060 ← ROOT 전개 │ │ arko-mariadb 컨테이너 127.0.0.1:11061 DB `csv` │ │ /opt/arko-app (webapps · config · upload · backup · logs) │ └─────────────────────────────────────────────────────────────────────┘ ``` WAS 는 27 → 인터넷 방향으로만 열려 있고, 웹서버를 거쳐야 닿는다. Tomcat 은 127.0.0.1 에만 바인딩되며 **인터넷에 직접 노출되지 않는다** — 웹서버가 아웃바운드 SSH 터널로 자기 쪽 11060 을 WAS 의 Tomcat 에 잇는다. ## 배포 흐름 ```bash git push # 이하 전부 자동 ``` ``` push → 웹서버에서 빌드(JDK8) → 바이트코드 major=51 검증 → WAR md5 대조 전송 → WAS 에서 ROOT 재전개 + 환경설정 주입 + Tomcat 재기동 + 헬스체크 → 실패 시 직전 백업으로 자동 롤백 → https://csv.wise.ai.kr 공개 확인 ``` ## 왜 이런 구조인가 **빌드를 WAS 에서 하지 않는 이유** — WAS 는 64코어지만 llama-server 가 200G+ 를 점유해 **가용 메모리가 3G 안팎**이다. 여기서 Maven(힙 1G)을 돌리면 LLM 서비스가 OOM 될 수 있다. 웹서버(4코어 / 여유 4G)는 빌드 외 부하가 없다. **컨테이너로 설치한 이유** — WAS 의 `claudeops` 계정은 **sudo 를 쓸 수 없고** docker 그룹에만 속한다. 패키지 설치가 불가능해 Tomcat·MariaDB 를 컨테이너로 올렸다. 같은 서버의 다른 서비스(urpai 등)와 같은 관행이다. **배포 스크립트를 매번 덮어쓰는 이유** — 이전 파이프라인에서 서버 사본과 저장소본이 갈라져, 저장소에서 고친 내용이 배포에 반영되지 않는 사고가 있었다. 워크플로가 매 실행마다 `deploy/wise/arko-deploy.sh` 를 WAS 로 복사하므로 **저장소가 유일한 원본**이다. ## 포트 | 포트 | 위치 | 용도 | |---|---|---| | 9271 | 웹서버 | SSH | | 9003 | 웹서버 127.0.0.1 | Gitea | | 11060 | WAS 127.0.0.1 | Tomcat (웹서버는 터널로 접근) | | 11061 | WAS 127.0.0.1 | MariaDB | 11000~11050 은 같은 서버의 다른 서비스가 쓰고 있다. 포트를 새로 잡을 때 겹치지 않게 할 것. ## 파일 | 파일 | 설치 위치 | 역할 | |---|---|---| | `01-was-setup.sh` | WAS | 컨테이너 2기 최초 생성 (재실행 안전) | | `arko-deploy.sh` | WAS `/opt/arko-app/deploy/` | 재전개·설정주입·기동·헬스체크·롤백 | | `mariadb.cnf` | WAS `/opt/arko-app/conf/` | MariaDB 설정 (`lower_case_table_names=1` 주의) | | `csv.wise.ai.kr.conf` | 웹 `/etc/httpd/conf.d/` | Apache vhost (80→443, 터널로 프록시) | | `arko-was-tunnel.service` | 웹 `/etc/systemd/system/` | SSH 터널 (자동 재연결) | | `arko-runner.service` | 웹 `/etc/systemd/system/` | arko 전용 act_runner | | `arko-runner-config.yaml` | 웹 `/opt/arko-runner/config.yaml` | 러너 설정 | ## 환경설정 (저장소에 없음) `globals-dev.properties` / `globals-live.properties` 는 `.gitignore` 대상이라 저장소에도 WAR 에도 들어가지 않는다. **WAS 의 `/opt/arko-app/config/` 에만 두고** 배포 때 `WEB-INF/classes/egovframework/egovProps/` 로 주입한다. `context-datasource.xml` 이 `globals-dev.properties` 를 읽으므로 이 주입이 없으면 기동 실패한다. WAS 값에서 로컬과 다른 부분: ```properties Globals.OsType =UNIX Globals.DriverClassName =org.mariadb.jdbc.Driver Globals.Url =jdbc:mariadb://arko-mariadb:3306/csv?useUnicode=true&characterEncoding=UTF-8&useSSL=false Globals.fileStorePath =/app/upload/ Globals.home.url =https://csv.wise.ai.kr Globals.home.base =/usr/local/tomcat/webapps/ROOT Globals.privacyDownloadPath=/app/privacy-download/ ``` ## 운영 명령 ```bash # 웹서버 (ssh -p 9271 root@175.118.124.176) systemctl status arko-runner arko-was-tunnel # 502 가 나면 터널부터 확인 tail -f /var/log/httpd/csv_error.log # WAS (ssh 는 웹서버를 경유한다) docker ps --filter name=arko- docker logs -f --tail 100 arko-tomcat tail -f /opt/arko-app/logs/deploy.log docker exec -it arko-mariadb mariadb -ucsv -pcsv csv # 수동 재배포 (Gitea 1.22 는 수동 실행 버튼이 없다) bash /opt/arko-app/deploy/arko-deploy.sh /opt/arko-app/incoming/arko.war ``` ## 알려진 제약 - **Gitea 1.22.3 은 `workflow_dispatch` 를 지원하지 않는다.** 넣으면 워크플로가 Actions 목록에 아예 뜨지 않는다. 재배포는 실제 파일을 바꿔 push 하거나 WAS 에서 직접 실행한다. - **Maven 은 3.6.3 을 쓴다.** 3.8+ 는 HTTP 저장소를 차단하는데 eGov 2.7 은 HTTP 저장소 (terracotta 등)에 의존해 의존성 해석부터 실패한다. - **메모리가 빠듯하다.** 두 컨테이너 합쳐 1.75G 상한이다. 올리기 전 `free -g` 로 확인할 것. - **DB 는 MariaDB 다.** 원본(MySQL 8)의 `utf8mb4_0900_ai_ci` 는 MariaDB 에 없어 `utf8mb4_general_ci` 로 변환해 이관했다. 한글 정렬 결과는 같다(코드포인트 순).