#!/bin/bash
# =============================================================
# GUARDiA ITSM 설치 스크립트 — RHEL 8 / RHEL 9
# =============================================================
# 전제조건: 순수 RHEL OS (최소 설치), 유효한 RH 서브스크립션
# 실행 방법: sudo bash setup_rhel.sh
# 설치 테스트: bash setup_rhel.sh --test
# =============================================================
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
GUARDIA_ROOT="$(dirname "$SCRIPT_DIR")"
LOG_FILE="/var/log/guardia_install.log"
TEST_MODE="${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 " $*"; }
exec > >(tee -a "$LOG_FILE") 2>&1
echo "=================================================="
echo " GUARDiA ITSM 설치 — RHEL 8/9"
echo " 시작: $(date)"
echo "=================================================="
[[ $EUID -eq 0 ]] || fail "root 권한으로 실행하세요: sudo bash $0"
# ── 테스트 모드 ──────────────────────────────────────────────
if [[ "$TEST_MODE" == "--test" ]]; then
echo "=== 설치 검증 모드 ==="
PASS=0; FAIL=0
check() {
local desc="$1"; shift
if "$@" &>/dev/null; then
ok "$desc"; ((PASS++))
else
echo -e "${RED}[FAIL]${NC} $desc"; ((FAIL++))
fi
}
check "Java 17 (OpenJDK)" java -version
check "Python 3.11+" python3.11 --version
check "PostgreSQL" pg_isready -q
check "Redis" redis-cli ping
check "Tomcat 9 서비스" systemctl is-active tomcat9
check "Tomcat HTTP" bash -c 'curl -sf http://localhost:8080/ -o /dev/null'
check "GUARDiA 서비스" systemctl is-active guardia-itsm
check "GUARDiA HTTP" bash -c 'curl -sf http://localhost:8001/ -o /dev/null'
check "GUARDiA 로그인 API" bash -c 'curl -sf -X POST http://localhost:8001/api/auth/login \
-H "Content-Type: application/json" -d "{\"username\":\"admin\",\"password\":\"1111\"}" -o /dev/null'
check "Nginx" nginx -t
check "SELinux httpd_can_network_connect" bash -c 'getsebool httpd_can_network_connect | grep -q on'
check "Python UTF-8" bash -c 'PYTHONIOENCODING=utf-8 python3.11 -c "print(\"OK\")" > /dev/null'
echo ""
echo "검증 결과: 성공 $PASS / 실패 $FAIL"
[[ $FAIL -eq 0 ]] && ok "모든 검사 통과" || fail "일부 실패 — 로그: $LOG_FILE"
exit 0
fi
# ── RHEL 버전 확인 ────────────────────────────────────────
RHEL_VER=$(rpm -E %{rhel})
echo "RHEL 버전: $RHEL_VER"
# ── 1. 저장소 활성화 ─────────────────────────────────────────
echo ""
echo "[1/9] RHEL 저장소 활성화..."
subscription-manager repos --enable=rhel-${RHEL_VER}-for-x86_64-appstream-rpms 2>/dev/null || \
warn "서브스크립션 저장소 활성화 실패 — EPEL로 대체 시도"
# EPEL (구독 없이도 사용 가능한 경우)
dnf install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-${RHEL_VER}.noarch.rpm 2>/dev/null || true
ok "저장소 설정 완료"
# ── 2. 패키지 설치 ──────────────────────────────────────────
echo ""
echo "[2/11] 시스템 패키지 설치..."
dnf install -y \
curl wget git gcc make openssl-devel libffi-devel \
python3.11 python3.11-devel python3-pip \
java-17-openjdk java-17-openjdk-devel \
postgresql-server postgresql-contrib \
redis nginx lsof unzip jq
# JAVA_HOME 설정
JAVA_HOME_PATH=$(alternatives --list 2>/dev/null | grep jre_17 | awk '{print $3}' | head -1)
[ -z "$JAVA_HOME_PATH" ] && JAVA_HOME_PATH=$(dirname $(dirname $(readlink -f $(which java))))
cat > /etc/profile.d/java.sh << JHEOF
export JAVA_HOME=$JAVA_HOME_PATH
export PATH=\$JAVA_HOME/bin:\$PATH
JHEOF
source /etc/profile.d/java.sh
ok "시스템 패키지 + OpenJDK 17 설치 완료"
# ── 3. Tomcat 9 설치 ─────────────────────────────────────────
echo ""
echo "[3/11] Tomcat 9 설치..."
TOMCAT_VER="${TOMCAT_VER:-9.0.98}"
TOMCAT_HOME="/app/tomcat"
TOMCAT_USER="tomcat"
id $TOMCAT_USER &>/dev/null || useradd -r -s /bin/false -d "$TOMCAT_HOME" $TOMCAT_USER
TOMCAT_TAR="apache-tomcat-${TOMCAT_VER}.tar.gz"
MIRROR="${TOMCAT_MIRROR:-https://archive.apache.org/dist/tomcat/tomcat-9/v${TOMCAT_VER}/bin}"
if [[ ! -d "$TOMCAT_HOME/bin" ]]; then
wget -q "$MIRROR/$TOMCAT_TAR" -O /tmp/$TOMCAT_TAR \
|| fail "Tomcat 다운로드 실패. TOMCAT_MIRROR 환경변수를 설정하세요."
mkdir -p "$TOMCAT_HOME"
tar -xzf /tmp/$TOMCAT_TAR -C "$TOMCAT_HOME" --strip-components=1
chmod +x "$TOMCAT_HOME/bin/"*.sh
fi
mkdir -p "$TOMCAT_HOME/logs" "$TOMCAT_HOME/temp"
chown -R $TOMCAT_USER:$TOMCAT_USER "$TOMCAT_HOME"
USERS_XML="$TOMCAT_HOME/conf/tomcat-users.xml"
if [[ -f "$USERS_XML" ]] && ! grep -q "opsagent" "$USERS_XML"; then
sed -i 's|| \n \n \n|' "$USERS_XML"
fi
# SELinux: Tomcat 포트 허용
semanage port -a -t http_port_t -p tcp 8080 2>/dev/null || true
cat > /etc/systemd/system/tomcat9.service << TCEOF
[Unit]
Description=Apache Tomcat 9
After=network.target
[Service]
Type=forking
User=$TOMCAT_USER
Group=$TOMCAT_USER
Environment="JAVA_HOME=$JAVA_HOME_PATH"
Environment="CATALINA_HOME=$TOMCAT_HOME"
Environment="CATALINA_BASE=$TOMCAT_HOME"
Environment="CATALINA_PID=$TOMCAT_HOME/temp/tomcat.pid"
Environment="CATALINA_OPTS=-Xms512M -Xmx1024M -server -XX:+UseParallelGC"
Environment="JAVA_OPTS=-Djava.awt.headless=true -Djava.security.egd=file:/dev/./urandom"
ExecStart=$TOMCAT_HOME/bin/startup.sh
ExecStop=$TOMCAT_HOME/bin/shutdown.sh
Restart=on-failure
RestartSec=10
SuccessExitStatus=143
[Install]
WantedBy=multi-user.target
TCEOF
systemctl daemon-reload
systemctl enable tomcat9
systemctl start tomcat9
ok "Tomcat 9 서비스 등록 완료"
# ── 4. Python 가상환경 ──────────────────────────────────────
echo ""
echo "[4/11] Python 가상환경 설정..."
mkdir -p /opt/guardia
python3.11 -m venv /opt/guardia/venv
source /opt/guardia/venv/bin/activate
pip install --upgrade pip -q
pip install -r "$GUARDIA_ROOT/itsm/requirements.txt" -q
ok "Python 환경 준비 완료"
# ── 4. PostgreSQL 초기화 ────────────────────────────────────
echo ""
echo "[5/11] PostgreSQL 설정..."
postgresql-setup --initdb 2>/dev/null || true
systemctl start postgresql
systemctl enable postgresql
sudo -u postgres psql -tc "SELECT 1 FROM pg_user WHERE usename='guardia'" | grep -q 1 || \
sudo -u postgres psql -c "CREATE USER guardia WITH PASSWORD 'guardia_secure_pw';"
sudo -u postgres psql -tc "SELECT 1 FROM pg_database WHERE datname='guardia'" | grep -q 1 || \
sudo -u postgres psql -c "CREATE DATABASE guardia OWNER guardia;"
# RHEL: pg_hba.conf 수정 (md5 인증)
PG_HBA=$(find /var/lib/pgsql -name pg_hba.conf 2>/dev/null | head -1)
if [[ -n "$PG_HBA" ]]; then
sed -i 's/ident/md5/g; s/peer/md5/g' "$PG_HBA" 2>/dev/null || true
systemctl restart postgresql
fi
ok "PostgreSQL 설정 완료"
# ── 5. Redis ────────────────────────────────────────────────
echo ""
echo "[6/11] Redis 시작..."
systemctl start redis
systemctl enable redis
ok "Redis 완료"
# ── 6. 환경 파일 ────────────────────────────────────────────
echo ""
echo "[7/11] 환경 설정 파일..."
ENV_FILE="$GUARDIA_ROOT/itsm/.env"
if [[ ! -f "$ENV_FILE" ]]; then
cat > "$ENV_FILE" << 'ENVEOF'
DATABASE_URL=postgresql+asyncpg://guardia:guardia_secure_pw@localhost:5432/guardia
SECRET_KEY=change_this_secret_key_in_production_min_32chars
ALGORITHM=HS256
ACCESS_TOKEN_EXPIRE_MINUTES=480
REDIS_URL=redis://localhost:6379/0
OLLAMA_BASE_URL=http://localhost:11434
GUARDIA_LLM_MODEL=llama3.1:8b
MESSENGER_BASE_URL=http://localhost:8002
MESSENGER_OPS_ROOM=ops
ENVEOF
warn ".env 생성됨 — SECRET_KEY 필수 변경: $ENV_FILE"
fi
# ── 7. DB 초기화 (스키마 불일치 자동 감지·복구) ─────────────────────────
echo ""
echo "[8/11] DB 초기화..."
cd "$GUARDIA_ROOT/itsm"
source /opt/guardia/venv/bin/activate
if ss -tlnp 2>/dev/null | grep -q ':8001'; then
warn "포트 8001 사용 중 — 기존 프로세스 종료..."
fuser -k 8001/tcp 2>/dev/null || true; sleep 2
fi
PYTHONIOENCODING=utf-8 python tools/db_init.py --force \
&& ok "DB 초기화 완료" || fail "DB 초기화 실패"
# ── 8. systemd ──────────────────────────────────────────────
echo ""
echo "[9/11] systemd 서비스..."
systemctl stop guardia-itsm 2>/dev/null || true
cat > /etc/systemd/system/guardia-itsm.service << SVCEOF
[Unit]
Description=GUARDiA ITSM Server
After=network.target postgresql.service redis.service
[Service]
Type=exec
User=nginx
WorkingDirectory=$GUARDIA_ROOT/itsm
Environment="PATH=/opt/guardia/venv/bin"
Environment="PYTHONIOENCODING=utf-8"
Environment="PYTHONUNBUFFERED=1"
EnvironmentFile=$GUARDIA_ROOT/itsm/.env
ExecStart=/opt/guardia/venv/bin/uvicorn main:app --host 0.0.0.0 --port 8001 --workers 4
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
SVCEOF
systemctl daemon-reload
systemctl enable guardia-itsm
systemctl start guardia-itsm
ok "systemd 서비스 완료"
# ── 9. Nginx + SELinux ──────────────────────────────────────
echo ""
echo "[10/11] Nginx + SELinux 설정..."
cat > /etc/nginx/conf.d/guardia.conf << 'NGXEOF'
server {
listen 80;
server_name _;
client_max_body_size 100M;
location / {
proxy_pass http://127.0.0.1:8001;
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_read_timeout 300s;
}
}
NGXEOF
# SELinux: 네트워크 연결 허용
setsebool -P httpd_can_network_connect 1 || warn "SELinux 설정 실패 (수동 설정 필요)"
semanage port -a -t http_port_t -p tcp 8001 2>/dev/null || true
systemctl enable nginx
systemctl start nginx
# 방화벽
firewall-cmd --permanent --add-service=http 2>/dev/null || true
firewall-cmd --permanent --add-service=https 2>/dev/null || true
firewall-cmd --reload 2>/dev/null || true
ok "Nginx + SELinux 완료"
echo ""
echo "=================================================="
ok "GUARDiA ITSM 설치 완료 — RHEL ${RHEL_VER}"
echo ""
info "접속 URL: http://$(hostname -I | awk '{print $1}')"
info "설치 로그: $LOG_FILE"
info "검증: sudo bash $0 --test"
echo "=================================================="