[Ollama — 온프레미스 sLLM 서버] - setup_ubuntu/centos/rhel/windows: Ollama 설치 단계 추가 - 환경변수 OLLAMA_INSTALL=online|offline|skip 지원 (망분리 환경) - 환경변수 OLLAMA_MODELS 으로 초기 모델 설정 (기본: llama3.1:8b) - 오프라인: OLLAMA_BIN_PATH로 바이너리 직접 지정 - SELinux 포트 허용 (RHEL), 방화벽 내부 전용 차단 (8080/11434) [보안·운영 도구] - Fail2ban: SSH 무차별 대입 방지 (5회 실패 시 1시간 차단) - Chrony/NTP: 감사 로그 타임스탬프 정합성 확보 - JDK 8/11: 레거시 WAS(Tomcat 7/8) 지원을 위한 다중 JDK - Logrotate: catalina.out 14일, *.log 8주 보관 [--test 검증 강화] - Ollama 서비스 + API + 모델 존재 여부 검사 - Fail2ban/Chrony 실행 상태 검사 [단계 수 업데이트] - Ubuntu: 10→13단계, CentOS: 10→13단계, RHEL: 11→13단계, Windows: 10단계 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
404 lines
15 KiB
Bash
404 lines
15 KiB
Bash
#!/bin/bash
|
|
# =============================================================
|
|
# GUARDiA ITSM 설치 스크립트 — CentOS 7 / CentOS Stream 8/9
|
|
# =============================================================
|
|
# 전제조건: 순수 CentOS OS (최소 설치)
|
|
# 실행 방법: sudo bash setup_centos.sh
|
|
# 설치 테스트: bash setup_centos.sh --test
|
|
# 환경변수:
|
|
# TOMCAT_VER=9.0.98 : Tomcat 버전
|
|
# TOMCAT_MIRROR=http:// : 내부 미러 URL (오프라인 환경)
|
|
# =============================================================
|
|
|
|
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 설치 — CentOS"
|
|
echo " 시작: $(date)"
|
|
echo "=================================================="
|
|
|
|
[[ $EUID -eq 0 ]] || fail "root 권한으로 실행하세요: sudo bash $0"
|
|
|
|
OS_VER=$(rpm -E %{rhel} 2>/dev/null || echo "7")
|
|
echo "감지된 CentOS 버전: $OS_VER"
|
|
|
|
# ── 테스트 모드 ──────────────────────────────────────────────
|
|
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 "Ollama 서비스" systemctl is-active ollama
|
|
check "Ollama API" bash -c 'curl -sf http://localhost:11434/api/version -o /dev/null'
|
|
check "Ollama 모델 존재" bash -c 'ollama list 2>/dev/null | grep -v NAME | grep -q .'
|
|
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 "Fail2ban" systemctl is-active fail2ban
|
|
check "Chrony NTP" chronyc tracking
|
|
check "Nginx" nginx -t
|
|
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
|
|
|
|
# ── 1. 시스템 패키지 ─────────────────────────────────────────
|
|
echo ""
|
|
echo "[1/10] 시스템 패키지 설치..."
|
|
yum install -y epel-release 2>/dev/null || dnf install -y epel-release 2>/dev/null || true
|
|
|
|
if [[ "$OS_VER" -ge 8 ]]; then
|
|
dnf install -y \
|
|
curl wget git gcc openssl-devel libffi-dev \
|
|
python3.11 python3.11-devel python3-pip \
|
|
java-17-openjdk java-17-openjdk-devel \
|
|
postgresql-server postgresql-contrib \
|
|
redis nginx lsof unzip jq
|
|
else
|
|
yum install -y centos-release-scl 2>/dev/null || true
|
|
yum install -y \
|
|
curl wget git gcc openssl-devel libffi-devel \
|
|
rh-python38 \
|
|
java-17-openjdk java-17-openjdk-devel \
|
|
postgresql-server postgresql-contrib \
|
|
redis nginx lsof unzip jq
|
|
fi
|
|
|
|
# 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 설치 완료"
|
|
|
|
# ── 2. Tomcat 9 설치 ─────────────────────────────────────────
|
|
echo ""
|
|
echo "[2/10] 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
|
|
|
|
# CentOS는 tomcat 패키지 버전이 낮을 수 있으므로 수동 설치 기본
|
|
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
|
|
warn "Tomcat ${TOMCAT_VER} 설치 중 (MIRROR: $MIRROR)..."
|
|
wget -q "$MIRROR/$TOMCAT_TAR" -O /tmp/$TOMCAT_TAR \
|
|
|| fail "Tomcat 다운로드 실패. TOMCAT_MIRROR=http://내부미러/... 로 설정하세요."
|
|
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"
|
|
|
|
# opsagent 계정 추가
|
|
USERS_XML="$TOMCAT_HOME/conf/tomcat-users.xml"
|
|
if [[ -f "$USERS_XML" ]] && ! grep -q "opsagent" "$USERS_XML"; then
|
|
sed -i 's|</tomcat-users>| <role rolename="manager-script"/>\n <role rolename="manager-jmx"/>\n <user username="opsagent" password="Opsagent@guardia!" roles="manager-script,manager-jmx"/>\n</tomcat-users>|' "$USERS_XML"
|
|
fi
|
|
|
|
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 서비스 등록 완료 (포트 8080)"
|
|
|
|
# ── 3. Python 가상환경 ──────────────────────────────────────
|
|
echo ""
|
|
echo "[3/10] Python 가상환경..."
|
|
PYTHON_BIN=$(command -v python3.11 || command -v python3.8 || command -v python3)
|
|
mkdir -p /opt/guardia
|
|
$PYTHON_BIN -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 "[4/10] PostgreSQL 초기화..."
|
|
if [[ "$OS_VER" -ge 8 ]]; then
|
|
postgresql-setup --initdb 2>/dev/null || true
|
|
else
|
|
postgresql-setup initdb 2>/dev/null || true
|
|
fi
|
|
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;"
|
|
ok "PostgreSQL 설정 완료"
|
|
|
|
# ── 5. Redis ────────────────────────────────────────────────
|
|
echo ""
|
|
echo "[5/10] Redis 시작..."
|
|
systemctl start redis
|
|
systemctl enable redis
|
|
ok "Redis 완료"
|
|
|
|
# ── 6. 환경 파일 ────────────────────────────────────────────
|
|
echo ""
|
|
echo "[6/10] 환경 설정 파일..."
|
|
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
|
|
CATALINA_HOME=/app/tomcat
|
|
ENVEOF
|
|
warn ".env 생성됨 — SECRET_KEY 필수 변경"
|
|
fi
|
|
|
|
# ── 7. DB 초기화 ─────────────────────────────────────────────
|
|
echo ""
|
|
echo "[7/10] 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 "[8/10] GUARDiA ITSM 서비스..."
|
|
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 tomcat9.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 "GUARDiA ITSM 서비스 완료"
|
|
|
|
# ── 9. Nginx ─────────────────────────────────────────────────
|
|
echo ""
|
|
echo "[9/10] Nginx..."
|
|
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
|
|
|
|
setsebool -P httpd_can_network_connect 1 2>/dev/null || true
|
|
systemctl enable nginx; systemctl start nginx
|
|
|
|
if systemctl is-active firewalld &>/dev/null; then
|
|
firewall-cmd --permanent --add-service=http
|
|
firewall-cmd --permanent --add-service=https
|
|
firewall-cmd --reload
|
|
fi
|
|
ok "Nginx 완료"
|
|
|
|
# ── 10. Ollama (온프레미스 sLLM) ──────────────────────────────
|
|
echo ""
|
|
echo "[10/13] Ollama (온프레미스 sLLM 서버) 설치..."
|
|
OLLAMA_INSTALL="${OLLAMA_INSTALL:-online}"
|
|
OLLAMA_MODELS="${OLLAMA_MODELS:-llama3.1:8b}"
|
|
|
|
if [[ "$OLLAMA_INSTALL" == "skip" ]]; then
|
|
warn "Ollama 설치 건너뜀 (OLLAMA_INSTALL=skip)"
|
|
else
|
|
if [[ "$OLLAMA_INSTALL" == "offline" ]]; then
|
|
BIN_PATH="${OLLAMA_BIN_PATH:-/tmp/ollama}"
|
|
[[ -f "$BIN_PATH" ]] || fail "오프라인: OLLAMA_BIN_PATH에 바이너리 필요"
|
|
cp "$BIN_PATH" /usr/local/bin/ollama && chmod +x /usr/local/bin/ollama
|
|
else
|
|
curl -fsSL https://ollama.com/install.sh | sh \
|
|
|| { warn "Ollama 설치 실패 — 수동 설치 필요"; OLLAMA_INSTALL=failed; }
|
|
fi
|
|
if [[ "$OLLAMA_INSTALL" != "failed" ]]; then
|
|
systemctl enable ollama 2>/dev/null || true
|
|
systemctl start ollama 2>/dev/null || true
|
|
sleep 3
|
|
if [[ "$OLLAMA_INSTALL" == "online" ]]; then
|
|
for model in $OLLAMA_MODELS; do
|
|
ollama pull "$model" 2>&1 | tail -3 \
|
|
|| warn "모델 $model 다운로드 실패 — 나중에: ollama pull $model"
|
|
done
|
|
fi
|
|
ok "Ollama 설치 완료 (http://localhost:11434)"
|
|
fi
|
|
fi
|
|
|
|
# ── 11. 보안·운영 도구 ───────────────────────────────────────
|
|
echo ""
|
|
echo "[11/13] 보안·운영 도구 (Fail2ban / Chrony / JDK 다중 버전 / Logrotate)..."
|
|
|
|
# Fail2ban
|
|
if [[ "$OS_VER" -ge 8 ]]; then
|
|
dnf install -y fail2ban 2>/dev/null || warn "fail2ban 설치 실패"
|
|
else
|
|
yum install -y fail2ban 2>/dev/null || warn "fail2ban 설치 실패"
|
|
fi
|
|
if command -v fail2ban-server &>/dev/null; then
|
|
cat > /etc/fail2ban/jail.local << 'F2BEOF'
|
|
[sshd]
|
|
enabled = true
|
|
maxretry = 5
|
|
bantime = 3600
|
|
findtime = 600
|
|
F2BEOF
|
|
systemctl enable fail2ban; systemctl start fail2ban
|
|
ok "Fail2ban 설치 완료"
|
|
fi
|
|
|
|
# Chrony NTP
|
|
if [[ "$OS_VER" -ge 8 ]]; then
|
|
dnf install -y chrony 2>/dev/null || true
|
|
else
|
|
yum install -y chrony 2>/dev/null || true
|
|
fi
|
|
systemctl enable chronyd 2>/dev/null || true
|
|
systemctl start chronyd 2>/dev/null || true
|
|
ok "Chrony NTP 설정 완료"
|
|
|
|
# JDK 8/11 (레거시 WAS 지원)
|
|
if [[ "$OS_VER" -ge 8 ]]; then
|
|
dnf install -y java-11-openjdk 2>/dev/null || warn "JDK 11 설치 실패"
|
|
dnf install -y java-1.8.0-openjdk 2>/dev/null || warn "JDK 8 설치 실패"
|
|
else
|
|
yum install -y java-11-openjdk java-1.8.0-openjdk 2>/dev/null || true
|
|
fi
|
|
ok "JDK 다중 버전 설치 완료 (alternatives --config java 로 전환)"
|
|
|
|
# Logrotate for Tomcat
|
|
cat > /etc/logrotate.d/tomcat9 << 'LREOF'
|
|
/app/tomcat/logs/catalina.out {
|
|
daily
|
|
rotate 14
|
|
compress
|
|
delaycompress
|
|
missingok
|
|
notifempty
|
|
}
|
|
/app/tomcat/logs/*.log {
|
|
weekly
|
|
rotate 8
|
|
compress
|
|
missingok
|
|
}
|
|
LREOF
|
|
ok "Logrotate 설정 완료 (catalina.out 14일 보관)"
|
|
|
|
# ── 12. 서비스 상태 확인 ─────────────────────────────────────
|
|
echo ""
|
|
echo "[12/13] 서비스 상태 확인..."
|
|
for svc in tomcat9 ollama guardia-itsm nginx postgresql redis; do
|
|
systemctl is-active "$svc" &>/dev/null && ok "$svc 실행 중" || warn "$svc 미실행"
|
|
done
|
|
|
|
echo ""
|
|
echo "=================================================="
|
|
ok "GUARDiA ITSM 설치 완료 — CentOS [13/13]"
|
|
info "GUARDiA URL: http://$(hostname -I | awk '{print $1}')"
|
|
info "Tomcat URL: http://$(hostname -I | awk '{print $1}'):8080 (내부 전용)"
|
|
info "Ollama URL: http://localhost:11434 (내부 전용)"
|
|
info "검증: sudo bash $0 --test"
|
|
echo "=================================================="
|