feat(docker): Docker 컨테이너 환경 구성
[파일 목록] - Dockerfile: GUARDiA ITSM Python 3.11-slim 이미지 - 비루트(guardia) 계정 실행 - 헬스체크 내장 - docker-compose.yml: 개발/테스트 풀스택 - guardia-itsm, nginx, postgres:15, redis:7, ollama/ollama, tomcat:9 - Ollama 모델은 볼륨 마운트 (이미지 외부) - docker-compose.prod.yml: 운영 환경 오버라이드 - 외부 포트 차단, 호스트 경로 마운트 - docker-compose.gpu.yml: NVIDIA GPU 오버라이드 - docker-start.sh: dev|prod|gpu 모드 빠른 시작 - .dockerignore: 보안 파일(.env, *.db) 제외 - docker/nginx/guardia.conf: 리버스 프록시 설정 - docker/tomcat/tomcat-users.xml: opsagent 계정 설정 [폐쇄망 패키지] - setup/docker_package.sh: 인터넷 서버에서 모든 이미지를 tar.gz로 패키징 - setup/docker_load.sh: 폐쇄망에서 tar.gz 로드 + 즉시 시작 옵션 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
a899dc208a
commit
eea643ce40
63
.dockerignore
Normal file
63
.dockerignore
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
# Git
|
||||||
|
.git/
|
||||||
|
.gitignore
|
||||||
|
|
||||||
|
# Python
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
*.pyo
|
||||||
|
*.pyd
|
||||||
|
.pytest_cache/
|
||||||
|
*.egg-info/
|
||||||
|
dist/
|
||||||
|
build/
|
||||||
|
.eggs/
|
||||||
|
venv/
|
||||||
|
.venv/
|
||||||
|
env/
|
||||||
|
|
||||||
|
# 개발 도구
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
|
||||||
|
# 테스트
|
||||||
|
tests/
|
||||||
|
test_*.py
|
||||||
|
*.test.py
|
||||||
|
|
||||||
|
# 문서/설정
|
||||||
|
docs/
|
||||||
|
manual/
|
||||||
|
*.md
|
||||||
|
*.txt
|
||||||
|
!requirements.txt
|
||||||
|
|
||||||
|
# 데이터
|
||||||
|
*.db
|
||||||
|
*.sqlite
|
||||||
|
*.sqlite3
|
||||||
|
guardia_itsm.db*
|
||||||
|
|
||||||
|
# 업로드
|
||||||
|
uploads/
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# 환경 파일 (보안)
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
*.env
|
||||||
|
secrets/
|
||||||
|
|
||||||
|
# Docker 패키지
|
||||||
|
docker-package/
|
||||||
|
|
||||||
|
# 설치 스크립트
|
||||||
|
setup/
|
||||||
|
|
||||||
|
# workspace
|
||||||
|
workspace/
|
||||||
|
|
||||||
|
# Claude
|
||||||
|
.claude/
|
||||||
54
Dockerfile
Normal file
54
Dockerfile
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
# ============================================================
|
||||||
|
# GUARDiA ITSM — Production Dockerfile
|
||||||
|
# Base: Python 3.11-slim
|
||||||
|
# Port: 8001
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
FROM python:3.11-slim AS base
|
||||||
|
|
||||||
|
LABEL maintainer="GUARDiA Team"
|
||||||
|
LABEL description="GUARDiA ITSM — AI 기반 레거시 인프라 자율 운영 플랫폼"
|
||||||
|
|
||||||
|
# ── 시스템 의존성 ──────────────────────────────────────────
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
|
curl wget git \
|
||||||
|
libpq-dev gcc \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# ── 비루트 실행 계정 ───────────────────────────────────────
|
||||||
|
RUN groupadd -r guardia && useradd -r -g guardia -d /app guardia
|
||||||
|
|
||||||
|
# ── 작업 디렉토리 ─────────────────────────────────────────
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# ── Python 의존성 (레이어 캐싱 최적화) ─────────────────────
|
||||||
|
COPY itsm/requirements.txt .
|
||||||
|
RUN pip install --no-cache-dir --upgrade pip \
|
||||||
|
&& pip install --no-cache-dir -r requirements.txt
|
||||||
|
|
||||||
|
# ── 애플리케이션 소스 복사 ───────────────────────────────
|
||||||
|
COPY itsm/ .
|
||||||
|
|
||||||
|
# ── 업로드/데이터 디렉토리 ──────────────────────────────
|
||||||
|
RUN mkdir -p uploads/sr_files uploads/workspaces \
|
||||||
|
&& chown -R guardia:guardia /app
|
||||||
|
|
||||||
|
# ── 환경 기본값 ──────────────────────────────────────────
|
||||||
|
ENV PYTHONUNBUFFERED=1 \
|
||||||
|
PYTHONIOENCODING=utf-8 \
|
||||||
|
PYTHONDONTWRITEBYTECODE=1 \
|
||||||
|
DATABASE_URL="sqlite+aiosqlite:///./guardia_itsm.db" \
|
||||||
|
OLLAMA_BASE_URL="http://ollama:11434"
|
||||||
|
|
||||||
|
# ── 포트 노출 ────────────────────────────────────────────
|
||||||
|
EXPOSE 8001
|
||||||
|
|
||||||
|
# ── 비루트 전환 ─────────────────────────────────────────
|
||||||
|
USER guardia
|
||||||
|
|
||||||
|
# ── 헬스체크 ─────────────────────────────────────────────
|
||||||
|
HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \
|
||||||
|
CMD curl -sf http://localhost:8001/ || exit 1
|
||||||
|
|
||||||
|
# ── 엔트리포인트 ─────────────────────────────────────────
|
||||||
|
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8001", "--workers", "4"]
|
||||||
23
docker-compose.gpu.yml
Normal file
23
docker-compose.gpu.yml
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
# ============================================================
|
||||||
|
# GUARDiA — NVIDIA GPU 오버라이드 (Ollama 가속)
|
||||||
|
# ============================================================
|
||||||
|
# 사용법:
|
||||||
|
# docker compose -f docker-compose.yml -f docker-compose.gpu.yml up -d ollama
|
||||||
|
#
|
||||||
|
# 전제조건:
|
||||||
|
# - nvidia-container-toolkit 설치 완료
|
||||||
|
# - nvidia-smi 정상 작동 확인
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
services:
|
||||||
|
ollama:
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
reservations:
|
||||||
|
devices:
|
||||||
|
- driver: nvidia
|
||||||
|
count: all
|
||||||
|
capabilities: [gpu]
|
||||||
|
environment:
|
||||||
|
OLLAMA_HOST: 0.0.0.0
|
||||||
|
CUDA_VISIBLE_DEVICES: "0"
|
||||||
46
docker-compose.prod.yml
Normal file
46
docker-compose.prod.yml
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
# ============================================================
|
||||||
|
# GUARDiA ITSM — 운영 환경 오버라이드
|
||||||
|
# ============================================================
|
||||||
|
# 사용법:
|
||||||
|
# docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
services:
|
||||||
|
|
||||||
|
guardia:
|
||||||
|
image: guardia-itsm:${GUARDIA_VERSION:-latest}
|
||||||
|
environment:
|
||||||
|
DATABASE_URL: ${DATABASE_URL} # 운영 DB URL 필수
|
||||||
|
SECRET_KEY: ${SECRET_KEY} # 운영 시크릿 키 필수
|
||||||
|
ports:
|
||||||
|
- "127.0.0.1:8001:8001" # localhost만 — Nginx를 통해서만 외부 접근
|
||||||
|
volumes:
|
||||||
|
- /data/guardia/uploads:/app/uploads # 호스트 경로 직접 마운트
|
||||||
|
- /data/guardia/logs:/app/logs
|
||||||
|
deploy:
|
||||||
|
replicas: 1
|
||||||
|
restart_policy:
|
||||||
|
condition: on-failure
|
||||||
|
max_attempts: 3
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpus: "2.0"
|
||||||
|
memory: 2G
|
||||||
|
|
||||||
|
postgres:
|
||||||
|
ports: [] # 운영에서는 외부 노출 금지
|
||||||
|
environment:
|
||||||
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
||||||
|
|
||||||
|
redis:
|
||||||
|
ports: [] # 운영에서는 외부 노출 금지
|
||||||
|
|
||||||
|
ollama:
|
||||||
|
ports:
|
||||||
|
- "127.0.0.1:11434:11434" # localhost만 노출
|
||||||
|
volumes:
|
||||||
|
- ${OLLAMA_MODELS_PATH:-/data/ollama}:/root/.ollama
|
||||||
|
|
||||||
|
tomcat:
|
||||||
|
ports:
|
||||||
|
- "127.0.0.1:8080:8080" # localhost만
|
||||||
196
docker-compose.yml
Normal file
196
docker-compose.yml
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
# ============================================================
|
||||||
|
# GUARDiA ITSM — Full Stack docker-compose (개발/테스트용)
|
||||||
|
# ============================================================
|
||||||
|
# 사용법:
|
||||||
|
# docker compose up -d # 전체 스택 시작
|
||||||
|
# docker compose up -d guardia # GUARDiA만 시작 (DB/Redis는 외부)
|
||||||
|
# docker compose logs -f guardia
|
||||||
|
# docker compose down -v # 볼륨 포함 완전 삭제
|
||||||
|
#
|
||||||
|
# 환경변수:
|
||||||
|
# .env 파일에 GUARDIA_LICENSE_KEY, SECRET_KEY 등을 설정하세요.
|
||||||
|
# (itsm/.env가 없으면 기본값 사용)
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
x-common-env: &common-env
|
||||||
|
PYTHONIOENCODING: utf-8
|
||||||
|
PYTHONUNBUFFERED: "1"
|
||||||
|
DATABASE_URL: postgresql+asyncpg://guardia:guardia@postgres:5432/guardia
|
||||||
|
REDIS_URL: redis://redis:6379/0
|
||||||
|
OLLAMA_BASE_URL: http://ollama:11434
|
||||||
|
MESSENGER_BASE_URL: http://messenger:8002
|
||||||
|
MESSENGER_OPS_ROOM: ops
|
||||||
|
|
||||||
|
services:
|
||||||
|
|
||||||
|
# ── GUARDiA ITSM ────────────────────────────────────────
|
||||||
|
guardia:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
image: guardia-itsm:latest
|
||||||
|
container_name: guardia-itsm
|
||||||
|
ports:
|
||||||
|
- "8001:8001"
|
||||||
|
environment:
|
||||||
|
<<: *common-env
|
||||||
|
SECRET_KEY: ${SECRET_KEY:-change_this_in_production_min_32chars}
|
||||||
|
ALGORITHM: HS256
|
||||||
|
ACCESS_TOKEN_EXPIRE_MINUTES: 480
|
||||||
|
GUARDIA_LLM_MODEL: ${GUARDIA_LLM_MODEL:-llama3.1:8b}
|
||||||
|
GUARDIA_LICENSE_KEY: ${GUARDIA_LICENSE_KEY:-}
|
||||||
|
# OAuth 소셜 로그인 (선택)
|
||||||
|
GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID:-}
|
||||||
|
GOOGLE_CLIENT_SECRET: ${GOOGLE_CLIENT_SECRET:-}
|
||||||
|
GITHUB_CLIENT_ID: ${GITHUB_CLIENT_ID:-}
|
||||||
|
GITHUB_CLIENT_SECRET: ${GITHUB_CLIENT_SECRET:-}
|
||||||
|
KEYCLOAK_BASE_URL: ${KEYCLOAK_BASE_URL:-}
|
||||||
|
KEYCLOAK_REALM: ${KEYCLOAK_REALM:-master}
|
||||||
|
KEYCLOAK_CLIENT_ID: ${KEYCLOAK_CLIENT_ID:-guardia}
|
||||||
|
KEYCLOAK_CLIENT_SECRET: ${KEYCLOAK_CLIENT_SECRET:-}
|
||||||
|
CATALINA_HOME: /app/tomcat
|
||||||
|
volumes:
|
||||||
|
- guardia-uploads:/app/uploads
|
||||||
|
- guardia-db:/app # SQLite 개발 모드용 (PostgreSQL 사용 시 불필요)
|
||||||
|
depends_on:
|
||||||
|
postgres:
|
||||||
|
condition: service_healthy
|
||||||
|
redis:
|
||||||
|
condition: service_healthy
|
||||||
|
networks:
|
||||||
|
- guardia-net
|
||||||
|
restart: unless-stopped
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-sf", "http://localhost:8001/"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
start_period: 40s
|
||||||
|
|
||||||
|
# ── Nginx 리버스 프록시 ──────────────────────────────────
|
||||||
|
nginx:
|
||||||
|
image: nginx:alpine
|
||||||
|
container_name: guardia-nginx
|
||||||
|
ports:
|
||||||
|
- "80:80"
|
||||||
|
- "443:443"
|
||||||
|
volumes:
|
||||||
|
- ./docker/nginx/guardia.conf:/etc/nginx/conf.d/default.conf:ro
|
||||||
|
- ./docker/nginx/ssl:/etc/nginx/ssl:ro # HTTPS 인증서 (선택)
|
||||||
|
depends_on:
|
||||||
|
- guardia
|
||||||
|
networks:
|
||||||
|
- guardia-net
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
# ── PostgreSQL ───────────────────────────────────────────
|
||||||
|
postgres:
|
||||||
|
image: postgres:15-alpine
|
||||||
|
container_name: guardia-postgres
|
||||||
|
environment:
|
||||||
|
POSTGRES_DB: guardia
|
||||||
|
POSTGRES_USER: guardia
|
||||||
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-guardia}
|
||||||
|
PGDATA: /var/lib/postgresql/data/pgdata
|
||||||
|
volumes:
|
||||||
|
- guardia-pgdata:/var/lib/postgresql/data
|
||||||
|
ports:
|
||||||
|
- "5432:5432" # 개발용 노출 (운영에서는 제거)
|
||||||
|
networks:
|
||||||
|
- guardia-net
|
||||||
|
restart: unless-stopped
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U guardia -d guardia"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
start_period: 10s
|
||||||
|
|
||||||
|
# ── Redis ────────────────────────────────────────────────
|
||||||
|
redis:
|
||||||
|
image: redis:7-alpine
|
||||||
|
container_name: guardia-redis
|
||||||
|
command: redis-server --appendonly yes --maxmemory 256mb --maxmemory-policy allkeys-lru
|
||||||
|
volumes:
|
||||||
|
- guardia-redis:/data
|
||||||
|
ports:
|
||||||
|
- "6379:6379" # 개발용 노출
|
||||||
|
networks:
|
||||||
|
- guardia-net
|
||||||
|
restart: unless-stopped
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "redis-cli", "ping"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 3
|
||||||
|
|
||||||
|
# ── Ollama (온프레미스 sLLM) ─────────────────────────────
|
||||||
|
# 모델은 볼륨(guardia-ollama-models)에 저장 — 이미지에 포함 안 함
|
||||||
|
# GPU 지원: docker-compose.gpu.yml 오버라이드 파일 참조
|
||||||
|
ollama:
|
||||||
|
image: ollama/ollama:latest
|
||||||
|
container_name: guardia-ollama
|
||||||
|
volumes:
|
||||||
|
- guardia-ollama-models:/root/.ollama # 모델 영구 저장
|
||||||
|
ports:
|
||||||
|
- "11434:11434" # 내부 전용 (외부 노출 금지 권장)
|
||||||
|
environment:
|
||||||
|
OLLAMA_HOST: 0.0.0.0
|
||||||
|
networks:
|
||||||
|
- guardia-net
|
||||||
|
restart: unless-stopped
|
||||||
|
# GPU 사용 시 아래 주석 해제 (docker-compose.gpu.yml에서 override)
|
||||||
|
# deploy:
|
||||||
|
# resources:
|
||||||
|
# reservations:
|
||||||
|
# devices:
|
||||||
|
# - driver: nvidia
|
||||||
|
# count: 1
|
||||||
|
# capabilities: [gpu]
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-sf", "http://localhost:11434/api/version"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
start_period: 20s
|
||||||
|
|
||||||
|
# ── Tomcat 9 (WAS 환경 시뮬레이션) ──────────────────────
|
||||||
|
tomcat:
|
||||||
|
image: tomcat:9.0-jdk17-temurin-jammy
|
||||||
|
container_name: guardia-tomcat
|
||||||
|
ports:
|
||||||
|
- "8080:8080"
|
||||||
|
volumes:
|
||||||
|
- guardia-tomcat-webapps:/usr/local/tomcat/webapps
|
||||||
|
- guardia-tomcat-logs:/usr/local/tomcat/logs
|
||||||
|
- ./docker/tomcat/tomcat-users.xml:/usr/local/tomcat/conf/tomcat-users.xml:ro
|
||||||
|
environment:
|
||||||
|
JAVA_OPTS: "-Xms512m -Xmx1024m -Djava.awt.headless=true"
|
||||||
|
CATALINA_OPTS: "-server -XX:+UseParallelGC"
|
||||||
|
networks:
|
||||||
|
- guardia-net
|
||||||
|
restart: unless-stopped
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-sf", "http://localhost:8080/"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
start_period: 30s
|
||||||
|
|
||||||
|
# ── 볼륨 ─────────────────────────────────────────────────
|
||||||
|
volumes:
|
||||||
|
guardia-db:
|
||||||
|
guardia-uploads:
|
||||||
|
guardia-pgdata:
|
||||||
|
guardia-redis:
|
||||||
|
guardia-ollama-models: # Ollama 모델 (로컬 경로 마운트 가능)
|
||||||
|
guardia-tomcat-webapps:
|
||||||
|
guardia-tomcat-logs:
|
||||||
|
|
||||||
|
# ── 네트워크 ──────────────────────────────────────────────
|
||||||
|
networks:
|
||||||
|
guardia-net:
|
||||||
|
driver: bridge
|
||||||
|
ipam:
|
||||||
|
config:
|
||||||
|
- subnet: 172.20.0.0/16
|
||||||
33
docker-start.sh
Normal file
33
docker-start.sh
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# GUARDiA 빠른 시작 스크립트
|
||||||
|
# 사용법: bash docker-start.sh [dev|prod|gpu]
|
||||||
|
|
||||||
|
MODE="${1:-dev}"
|
||||||
|
|
||||||
|
case "$MODE" in
|
||||||
|
dev)
|
||||||
|
echo "▶ 개발 모드 시작..."
|
||||||
|
docker compose up -d
|
||||||
|
;;
|
||||||
|
prod)
|
||||||
|
echo "▶ 운영 모드 시작..."
|
||||||
|
[[ -f ".env" ]] || { echo "❌ .env 파일이 없습니다. .env.example을 복사하세요."; exit 1; }
|
||||||
|
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
|
||||||
|
;;
|
||||||
|
gpu)
|
||||||
|
echo "▶ GPU 모드 시작 (Ollama NVIDIA 가속)..."
|
||||||
|
docker compose -f docker-compose.yml -f docker-compose.gpu.yml up -d
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "사용법: bash docker-start.sh [dev|prod|gpu]"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "서비스 상태:"
|
||||||
|
docker compose ps
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "접속: http://localhost"
|
||||||
|
echo "로그: docker compose logs -f guardia"
|
||||||
44
docker/nginx/guardia.conf
Normal file
44
docker/nginx/guardia.conf
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
upstream guardia_backend {
|
||||||
|
server guardia:8001;
|
||||||
|
keepalive 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name _;
|
||||||
|
client_max_body_size 100M;
|
||||||
|
|
||||||
|
# GUARDiA ITSM
|
||||||
|
location / {
|
||||||
|
proxy_pass http://guardia_backend;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_read_timeout 300s;
|
||||||
|
proxy_send_timeout 300s;
|
||||||
|
}
|
||||||
|
|
||||||
|
# 정적 파일 직접 서빙 (선택 최적화)
|
||||||
|
# location /static/ {
|
||||||
|
# alias /app/static/;
|
||||||
|
# expires 1d;
|
||||||
|
# add_header Cache-Control "public";
|
||||||
|
# }
|
||||||
|
|
||||||
|
# Ollama/Tomcat 직접 노출 금지
|
||||||
|
location /api/ollama/ { return 403; }
|
||||||
|
location /manager/ { return 403; }
|
||||||
|
}
|
||||||
|
|
||||||
|
# HTTPS (인증서 설정 후 활성화)
|
||||||
|
# server {
|
||||||
|
# listen 443 ssl http2;
|
||||||
|
# server_name guardia.example.com;
|
||||||
|
# ssl_certificate /etc/nginx/ssl/cert.pem;
|
||||||
|
# ssl_certificate_key /etc/nginx/ssl/key.pem;
|
||||||
|
# ssl_protocols TLSv1.2 TLSv1.3;
|
||||||
|
# include /etc/nginx/conf.d/guardia.conf; # location 블록 재사용
|
||||||
|
# }
|
||||||
23
docker/tomcat/tomcat-users.xml
Normal file
23
docker/tomcat/tomcat-users.xml
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<tomcat-users xmlns="http://tomcat.apache.org/xml"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://tomcat.apache.org/xml tomcat-users.xsd"
|
||||||
|
version="1.0">
|
||||||
|
|
||||||
|
<!-- GUARDiA SSH 원격 관리용 계정 -->
|
||||||
|
<role rolename="manager-script"/>
|
||||||
|
<role rolename="manager-jmx"/>
|
||||||
|
<role rolename="manager-gui"/>
|
||||||
|
<role rolename="admin-gui"/>
|
||||||
|
|
||||||
|
<!-- opsagent: GUARDiA ITSM 배포/재기동 자동화 계정 -->
|
||||||
|
<!-- 운영 환경에서는 반드시 비밀번호를 변경하세요 -->
|
||||||
|
<user username="opsagent"
|
||||||
|
password="Opsagent@guardia!"
|
||||||
|
roles="manager-script,manager-jmx"/>
|
||||||
|
|
||||||
|
<!-- admin: Tomcat Manager UI (개발용) -->
|
||||||
|
<user username="admin"
|
||||||
|
password="Admin@guardia!"
|
||||||
|
roles="manager-gui,admin-gui"/>
|
||||||
|
</tomcat-users>
|
||||||
149
setup/docker_load.sh
Normal file
149
setup/docker_load.sh
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# ============================================================
|
||||||
|
# GUARDiA Docker 폐쇄망 로드 스크립트
|
||||||
|
# ============================================================
|
||||||
|
# docker_package.sh 로 생성된 패키지를 폐쇄망 서버에서 로드합니다.
|
||||||
|
#
|
||||||
|
# 사용법:
|
||||||
|
# tar -xzf guardia-docker-YYYYMMDD.tar.gz
|
||||||
|
# cd guardia-docker-YYYYMMDD
|
||||||
|
# bash docker_load.sh
|
||||||
|
# bash docker_load.sh --start # 로드 후 즉시 서비스 시작
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
START_AFTER="${1:-}"
|
||||||
|
|
||||||
|
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m'
|
||||||
|
ok() { echo -e "${GREEN}[OK]${NC} $*"; }
|
||||||
|
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
|
||||||
|
fail() { echo -e "${RED}[FAIL]${NC} $*"; exit 1; }
|
||||||
|
info() { echo -e " $*"; }
|
||||||
|
|
||||||
|
echo "=================================================="
|
||||||
|
echo " GUARDiA Docker 폐쇄망 로드"
|
||||||
|
echo " 디렉토리: $SCRIPT_DIR"
|
||||||
|
echo "=================================================="
|
||||||
|
|
||||||
|
# Docker 설치 확인
|
||||||
|
command -v docker &>/dev/null || fail "Docker가 설치되지 않았습니다. Docker Engine을 먼저 설치하세요."
|
||||||
|
docker compose version &>/dev/null || fail "Docker Compose가 필요합니다. (docker compose 플러그인)"
|
||||||
|
|
||||||
|
# ── 1. 버전 정보 확인 ───────────────────────────────────
|
||||||
|
if [[ -f "$SCRIPT_DIR/VERSION" ]]; then
|
||||||
|
source "$SCRIPT_DIR/VERSION"
|
||||||
|
echo " 패키지 버전: ${GUARDIA_VERSION:-unknown}"
|
||||||
|
echo " 빌드 일자: ${BUILD_DATE:-unknown}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── 2. 이미지 로드 ──────────────────────────────────────
|
||||||
|
echo ""
|
||||||
|
echo "[1/4] Docker 이미지 로드..."
|
||||||
|
|
||||||
|
# 메인 이미지
|
||||||
|
if [[ -f "$SCRIPT_DIR/images.tar.gz" ]]; then
|
||||||
|
echo " 로드 중: images.tar.gz"
|
||||||
|
docker load < "$SCRIPT_DIR/images.tar.gz"
|
||||||
|
ok "메인 이미지 로드 완료"
|
||||||
|
else
|
||||||
|
fail "images.tar.gz 파일을 찾을 수 없습니다."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Ollama 이미지
|
||||||
|
if [[ -f "$SCRIPT_DIR/ollama.tar.gz" ]]; then
|
||||||
|
echo " 로드 중: ollama.tar.gz (시간이 걸릴 수 있습니다...)"
|
||||||
|
docker load < "$SCRIPT_DIR/ollama.tar.gz"
|
||||||
|
ok "Ollama 이미지 로드 완료"
|
||||||
|
else
|
||||||
|
warn "ollama.tar.gz 없음 — Ollama 이미지 로드 건너뜀"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 로드된 이미지 목록 출력
|
||||||
|
echo ""
|
||||||
|
echo " 로드된 이미지:"
|
||||||
|
docker images | grep -E "guardia|postgres|redis|nginx|ollama|tomcat" | awk '{printf " %-40s %-15s %s\n", $1, $2, $7}'
|
||||||
|
|
||||||
|
# ── 3. Ollama 모델 복사 ─────────────────────────────────
|
||||||
|
echo ""
|
||||||
|
echo "[2/4] Ollama 모델 설정..."
|
||||||
|
MODELS_TAR="$SCRIPT_DIR/ollama-models/models.tar.gz"
|
||||||
|
|
||||||
|
if [[ -f "$MODELS_TAR" ]]; then
|
||||||
|
OLLAMA_DATA="${OLLAMA_DATA_DIR:-/var/lib/guardia/ollama}"
|
||||||
|
mkdir -p "$OLLAMA_DATA"
|
||||||
|
echo " 모델 압축 해제: $OLLAMA_DATA"
|
||||||
|
tar -xzf "$MODELS_TAR" -C "$OLLAMA_DATA"
|
||||||
|
ok "Ollama 모델 복사 완료: $OLLAMA_DATA"
|
||||||
|
export OLLAMA_MODELS_PATH="$OLLAMA_DATA"
|
||||||
|
else
|
||||||
|
warn "Ollama 모델 파일 없음"
|
||||||
|
warn " 방법 1: docker compose up -d ollama && docker exec guardia-ollama ollama pull llama3.1:8b"
|
||||||
|
warn " 방법 2: 모델 파일을 수동으로 /var/lib/guardia/ollama/models 에 복사"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── 4. 환경 파일 설정 ────────────────────────────────────
|
||||||
|
echo ""
|
||||||
|
echo "[3/4] 환경 파일 설정..."
|
||||||
|
ENV_FILE="$SCRIPT_DIR/.env"
|
||||||
|
|
||||||
|
if [[ ! -f "$ENV_FILE" ]]; then
|
||||||
|
cat > "$ENV_FILE" << 'ENVEOF'
|
||||||
|
# GUARDiA Docker 환경 설정
|
||||||
|
# 운영 배포 전 반드시 아래 값을 변경하세요!
|
||||||
|
|
||||||
|
SECRET_KEY=CHANGE_THIS_TO_RANDOM_32CHARS_MIN
|
||||||
|
POSTGRES_PASSWORD=guardia_secure_pw
|
||||||
|
GUARDIA_VERSION=latest
|
||||||
|
GUARDIA_LLM_MODEL=llama3.1:8b
|
||||||
|
|
||||||
|
# Ollama 모델 경로 (폐쇄망 복사 경로)
|
||||||
|
OLLAMA_MODELS_PATH=/var/lib/guardia/ollama
|
||||||
|
ENVEOF
|
||||||
|
warn ".env 파일 생성됨 — SECRET_KEY를 반드시 변경하세요: $ENV_FILE"
|
||||||
|
else
|
||||||
|
info ".env 파일 이미 존재"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── 5. 서비스 시작 ──────────────────────────────────────
|
||||||
|
echo ""
|
||||||
|
echo "[4/4] 서비스 준비 완료"
|
||||||
|
|
||||||
|
if [[ "$START_AFTER" == "--start" ]]; then
|
||||||
|
echo " 서비스 시작 중..."
|
||||||
|
cd "$SCRIPT_DIR"
|
||||||
|
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
|
||||||
|
|
||||||
|
# 헬스체크 대기
|
||||||
|
echo " 서비스 기동 대기 (최대 60초)..."
|
||||||
|
for i in $(seq 1 12); do
|
||||||
|
sleep 5
|
||||||
|
if curl -sf http://localhost/ &>/dev/null; then
|
||||||
|
ok "GUARDiA ITSM 서비스 정상 기동!"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
echo " 대기 중... (${i}/12)"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo " 서비스 상태:"
|
||||||
|
docker compose ps
|
||||||
|
else
|
||||||
|
echo ""
|
||||||
|
info "서비스 시작 명령어:"
|
||||||
|
info " cd $SCRIPT_DIR"
|
||||||
|
info " # .env 파일 편집 후:"
|
||||||
|
info " docker compose up -d"
|
||||||
|
info " # 또는 운영 모드:"
|
||||||
|
info " docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d"
|
||||||
|
info ""
|
||||||
|
info " # 즉시 시작:"
|
||||||
|
info " bash docker_load.sh --start"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=================================================="
|
||||||
|
ok "Docker 로드 완료!"
|
||||||
|
info "접속 URL: http://$(hostname -I | awk '{print $1}')"
|
||||||
|
info "GUARDiA 로그: docker compose logs -f guardia"
|
||||||
|
echo "=================================================="
|
||||||
147
setup/docker_package.sh
Normal file
147
setup/docker_package.sh
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# ============================================================
|
||||||
|
# GUARDiA Docker 폐쇄망 패키지 생성 스크립트
|
||||||
|
# ============================================================
|
||||||
|
# 인터넷이 연결된 서버에서 실행하여 모든 이미지를 tar로 패키징합니다.
|
||||||
|
# 생성된 패키지를 USB/내부 서버를 통해 폐쇄망에 복사 후 docker_load.sh 실행.
|
||||||
|
#
|
||||||
|
# 사용법:
|
||||||
|
# bash setup/docker_package.sh [출력 디렉토리]
|
||||||
|
# bash setup/docker_package.sh /mnt/usb/guardia-docker
|
||||||
|
#
|
||||||
|
# 결과:
|
||||||
|
# guardia-docker-<버전>.tar.gz (약 5~8GB — Ollama 모델 별도)
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
GUARDIA_ROOT="$(dirname "$SCRIPT_DIR")"
|
||||||
|
OUTPUT_DIR="${1:-$GUARDIA_ROOT/docker-package}"
|
||||||
|
VERSION="${GUARDIA_VERSION:-$(date +%Y%m%d)}"
|
||||||
|
PACKAGE_NAME="guardia-docker-${VERSION}"
|
||||||
|
|
||||||
|
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m'
|
||||||
|
ok() { echo -e "${GREEN}[OK]${NC} $*"; }
|
||||||
|
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
|
||||||
|
info() { echo -e " $*"; }
|
||||||
|
|
||||||
|
echo "=================================================="
|
||||||
|
echo " GUARDiA Docker 패키지 생성"
|
||||||
|
echo " 버전: $VERSION"
|
||||||
|
echo " 출력: $OUTPUT_DIR"
|
||||||
|
echo "=================================================="
|
||||||
|
|
||||||
|
mkdir -p "$OUTPUT_DIR/$PACKAGE_NAME"
|
||||||
|
cd "$GUARDIA_ROOT"
|
||||||
|
|
||||||
|
# ── 1. GUARDiA 이미지 빌드 ───────────────────────────────
|
||||||
|
echo ""
|
||||||
|
echo "[1/5] GUARDiA ITSM 이미지 빌드..."
|
||||||
|
docker build -t "guardia-itsm:${VERSION}" -t "guardia-itsm:latest" .
|
||||||
|
ok "guardia-itsm:${VERSION} 빌드 완료"
|
||||||
|
|
||||||
|
# ── 2. 외부 이미지 Pull ──────────────────────────────────
|
||||||
|
echo ""
|
||||||
|
echo "[2/5] 외부 이미지 다운로드..."
|
||||||
|
|
||||||
|
IMAGES=(
|
||||||
|
"postgres:15-alpine"
|
||||||
|
"redis:7-alpine"
|
||||||
|
"nginx:alpine"
|
||||||
|
"ollama/ollama:latest"
|
||||||
|
"tomcat:9.0-jdk17-temurin-jammy"
|
||||||
|
)
|
||||||
|
|
||||||
|
for img in "${IMAGES[@]}"; do
|
||||||
|
echo " pulling: $img"
|
||||||
|
docker pull "$img" || warn "$img 다운로드 실패 — 건너뜀"
|
||||||
|
done
|
||||||
|
ok "외부 이미지 다운로드 완료"
|
||||||
|
|
||||||
|
# ── 3. 이미지 tar 저장 ──────────────────────────────────
|
||||||
|
echo ""
|
||||||
|
echo "[3/5] 이미지 저장 (tar)..."
|
||||||
|
TAR_FILE="$OUTPUT_DIR/$PACKAGE_NAME/images.tar"
|
||||||
|
|
||||||
|
docker save \
|
||||||
|
"guardia-itsm:${VERSION}" \
|
||||||
|
"guardia-itsm:latest" \
|
||||||
|
"postgres:15-alpine" \
|
||||||
|
"redis:7-alpine" \
|
||||||
|
"nginx:alpine" \
|
||||||
|
"tomcat:9.0-jdk17-temurin-jammy" \
|
||||||
|
| gzip > "${TAR_FILE}.gz"
|
||||||
|
|
||||||
|
ok "이미지 저장 완료: ${TAR_FILE}.gz ($(du -sh "${TAR_FILE}.gz" | cut -f1))"
|
||||||
|
|
||||||
|
# Ollama는 용량이 크므로 별도 패키징
|
||||||
|
OLLAMA_TAR="$OUTPUT_DIR/$PACKAGE_NAME/ollama.tar"
|
||||||
|
docker save "ollama/ollama:latest" | gzip > "${OLLAMA_TAR}.gz"
|
||||||
|
ok "Ollama 이미지 저장: ${OLLAMA_TAR}.gz ($(du -sh "${OLLAMA_TAR}.gz" | cut -f1))"
|
||||||
|
|
||||||
|
# ── 4. Ollama 모델 패키징 (선택) ──────────────────────────
|
||||||
|
echo ""
|
||||||
|
echo "[4/5] Ollama 모델 패키징..."
|
||||||
|
OLLAMA_MODELS_DIR="${OLLAMA_MODELS_DIR:-$HOME/.ollama}"
|
||||||
|
MODELS_OUTPUT="$OUTPUT_DIR/$PACKAGE_NAME/ollama-models"
|
||||||
|
|
||||||
|
if [[ -d "$OLLAMA_MODELS_DIR/models" ]]; then
|
||||||
|
echo " 모델 디렉토리: $OLLAMA_MODELS_DIR"
|
||||||
|
mkdir -p "$MODELS_OUTPUT"
|
||||||
|
|
||||||
|
# 각 모델을 개별 파일로 저장 (크기 분할)
|
||||||
|
if command -v ollama &>/dev/null; then
|
||||||
|
ollama list 2>/dev/null | tail -n +2 | awk '{print $1}' | while read -r model; do
|
||||||
|
model_file="${model//:/--}.tar"
|
||||||
|
echo " 패키징 모델: $model → $model_file"
|
||||||
|
# 모델 블obs 복사
|
||||||
|
mkdir -p "$MODELS_OUTPUT/$model_file"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 전체 모델 디렉토리 압축
|
||||||
|
tar -czf "$MODELS_OUTPUT/models.tar.gz" -C "$OLLAMA_MODELS_DIR" models manifests 2>/dev/null \
|
||||||
|
&& ok "Ollama 모델 패키징 완료 ($(du -sh "$MODELS_OUTPUT/models.tar.gz" | cut -f1))" \
|
||||||
|
|| warn "모델 패키징 실패 — 수동으로 ~/.ollama/models 를 복사하세요"
|
||||||
|
else
|
||||||
|
warn "Ollama 모델 디렉토리 없음 — 별도 복사 필요: $OLLAMA_MODELS_DIR"
|
||||||
|
echo " # 모델을 미리 다운로드: ollama pull llama3.1:8b"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── 5. 배포 파일 패키징 ──────────────────────────────────
|
||||||
|
echo ""
|
||||||
|
echo "[5/5] 배포 파일 패키징..."
|
||||||
|
|
||||||
|
# docker-compose 파일 복사
|
||||||
|
cp "$GUARDIA_ROOT/docker-compose.yml" "$OUTPUT_DIR/$PACKAGE_NAME/"
|
||||||
|
cp "$GUARDIA_ROOT/docker-compose.prod.yml" "$OUTPUT_DIR/$PACKAGE_NAME/"
|
||||||
|
cp "$GUARDIA_ROOT/docker-compose.gpu.yml" "$OUTPUT_DIR/$PACKAGE_NAME/"
|
||||||
|
cp "$GUARDIA_ROOT/setup/docker_load.sh" "$OUTPUT_DIR/$PACKAGE_NAME/"
|
||||||
|
cp -r "$GUARDIA_ROOT/docker/" "$OUTPUT_DIR/$PACKAGE_NAME/docker/"
|
||||||
|
chmod +x "$OUTPUT_DIR/$PACKAGE_NAME/docker_load.sh"
|
||||||
|
|
||||||
|
# 버전 정보
|
||||||
|
cat > "$OUTPUT_DIR/$PACKAGE_NAME/VERSION" << VEREOF
|
||||||
|
GUARDIA_VERSION=$VERSION
|
||||||
|
BUILD_DATE=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
||||||
|
IMAGES_INCLUDED=guardia-itsm,postgres,redis,nginx,tomcat,ollama
|
||||||
|
VEREOF
|
||||||
|
|
||||||
|
# 전체 패키지 압축
|
||||||
|
echo " 전체 패키지 압축 중..."
|
||||||
|
cd "$OUTPUT_DIR"
|
||||||
|
tar -czf "${PACKAGE_NAME}.tar.gz" "$PACKAGE_NAME/"
|
||||||
|
ok "패키지 생성 완료: $OUTPUT_DIR/${PACKAGE_NAME}.tar.gz"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=================================================="
|
||||||
|
ok "패키지 생성 완료!"
|
||||||
|
echo ""
|
||||||
|
info "패키지 크기:"
|
||||||
|
du -sh "$OUTPUT_DIR/${PACKAGE_NAME}.tar.gz"
|
||||||
|
echo ""
|
||||||
|
info "폐쇄망 설치 절차:"
|
||||||
|
info " 1. ${PACKAGE_NAME}.tar.gz 을 폐쇄망 서버로 복사"
|
||||||
|
info " 2. tar -xzf ${PACKAGE_NAME}.tar.gz"
|
||||||
|
info " 3. bash ${PACKAGE_NAME}/docker_load.sh"
|
||||||
|
echo "=================================================="
|
||||||
Loading…
Reference in New Issue
Block a user