zioinfo-mail/workspace/guardia-manager/deploy_server.py
DESKTOP-TKLFCPR\ython cfe2901a55 refactor(structure): consolidate all projects under workspace/
- itsm/    -> workspace/guardia-itsm/
- manager/ -> workspace/guardia-manager/
- app/     -> workspace/guardia-messenger/
- manual/  -> workspace/guardia-docs/

workspace/zioinfo-web/ unchanged.
git mv preserves full commit history.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 23:50:56 +09:00

157 lines
5.5 KiB
Python

#!/usr/bin/env python3
"""GUARDiA Manager 서버 배포 스크립트"""
import paramiko, time, sys, os, io, zipfile
HOST = 'zioinfo.co.kr'; USER = 'root'; PASS = '1q2w3e!Q'
LOCAL_DIST = 'C:/GUARDiA/manager/dist'
LOCAL_BACKEND = 'C:/GUARDiA/manager/backend'
SEP = chr(92)
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect(HOST, username=USER, password=PASS, timeout=15)
sftp = client.open_sftp()
def run(label, cmd, timeout=60):
print(f'\n[{label}]')
chan = client.get_transport().open_session()
chan.set_combine_stderr(True)
chan.exec_command(cmd)
start = time.time()
while not chan.exit_status_ready():
if chan.recv_ready(): sys.stdout.buffer.write(chan.recv(4096)); sys.stdout.flush()
if time.time() - start > timeout: print('[TIMEOUT]'); break
time.sleep(0.2)
while chan.recv_ready(): sys.stdout.buffer.write(chan.recv(4096))
sys.stdout.flush()
rc = chan.recv_exit_status()
print(f'\n→ exit={rc}')
return rc
# 1. 서버 디렉터리 생성
run('디렉터리 생성',
'mkdir -p /var/www/manager /opt/manager/backend /opt/manager/logs && echo ok')
# 2. React 빌드 결과 zip → 업로드
print('\n[dist 파일 패키징...]')
zip_buf = io.BytesIO()
count = 0
with zipfile.ZipFile(zip_buf, 'w', zipfile.ZIP_DEFLATED) as zf:
for root, dirs, files in os.walk(LOCAL_DIST):
rel = os.path.relpath(root, LOCAL_DIST).replace(SEP, '/')
for f in files:
arc = f if rel == '.' else f'{rel}/{f}'
zf.write(os.path.join(root, f), arc); count += 1
zip_buf.seek(0)
with sftp.open('/tmp/manager-dist.zip', 'wb') as f: f.write(zip_buf.read())
print(f'{count}개 파일 업로드')
run('dist 배포', 'cd /var/www/manager && unzip -q -o /tmp/manager-dist.zip && echo "deployed" && ls | head -5')
# 3. 백엔드 소스 업로드
print('\n[백엔드 소스 업로드...]')
for item in os.listdir(LOCAL_BACKEND):
lp = os.path.join(LOCAL_BACKEND, item)
if os.path.isfile(lp) and item.endswith('.py'):
sftp.put(lp, f'/opt/manager/backend/{item}')
print(f' {item}')
# routers / core
for sub in ('routers', 'core'):
sub_dir = os.path.join(LOCAL_BACKEND, sub)
if not os.path.isdir(sub_dir): continue
run(f'{sub} 디렉터리', f'mkdir -p /opt/manager/backend/{sub}')
for fn in os.listdir(sub_dir):
if fn.endswith('.py'):
sftp.put(os.path.join(sub_dir, fn), f'/opt/manager/backend/{sub}/{fn}')
print(f' {sub}/{fn}')
# requirements + .env
for fn in ('requirements.txt', '.env'):
lp = os.path.join(LOCAL_BACKEND, fn)
if os.path.exists(lp):
sftp.put(lp, f'/opt/manager/backend/{fn}')
print(f' {fn}')
# 4. Python venv + 패키지
run('Python venv',
'python3 -m venv /opt/manager/venv && '
'/opt/manager/venv/bin/pip install -r /opt/manager/backend/requirements.txt -q && echo ok',
120)
# 5. .env 서버 JWT secret 동기화
run('.env JWT secret 동기화',
"GUARDIA_SECRET=$(grep GUARDIA_JWT_SECRET /opt/guardia/app/.env 2>/dev/null | cut -d= -f2-) && "
"if [ -n \"$GUARDIA_SECRET\" ]; then "
" sed -i \"s|GUARDIA_JWT_SECRET=.*|GUARDIA_JWT_SECRET=$GUARDIA_SECRET|\" /opt/manager/backend/.env && "
" echo 'JWT secret synced'; fi")
# 6. systemd 서비스
svc = """[Unit]
Description=GUARDiA Manager API Backend
After=network.target guardia.service
[Service]
User=root
WorkingDirectory=/opt/manager/backend
EnvironmentFile=-/opt/manager/backend/.env
ExecStart=/opt/manager/venv/bin/uvicorn main:app --host 127.0.0.1 --port 8002 --workers 1
Restart=on-failure
RestartSec=5
StandardOutput=append:/opt/manager/logs/backend.log
StandardError=append:/opt/manager/logs/backend.log
[Install]
WantedBy=multi-user.target
"""
with sftp.open('/etc/systemd/system/guardia-manager.service', 'w') as f: f.write(svc)
# 7. Nginx 설정
nginx_conf = r"""server {
listen 8090;
server_name _;
root /var/www/manager;
index index.html;
location / {
try_files $uri $uri/ /index.html;
add_header Cache-Control no-cache;
}
location /api/ {
proxy_pass http://127.0.0.1:8002;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_read_timeout 60s;
}
location /guardia-api/ {
proxy_pass http://127.0.0.1:8001/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
location ~* \.(js|css|png|ico|svg|woff2)$ {
expires 7d;
add_header Cache-Control "public, immutable";
}
gzip on;
gzip_types text/plain text/css application/javascript application/json;
}
"""
with sftp.open('/etc/nginx/sites-available/guardia-manager', 'w') as f: f.write(nginx_conf)
# 8. 서비스 시작
run('UFW 8090 오픈', 'ufw allow 8090/tcp && ufw allow 8002/tcp && echo ok')
run('systemd 등록 + 시작',
'systemctl daemon-reload && '
'systemctl enable guardia-manager && '
'systemctl restart guardia-manager && '
'sleep 5 && systemctl is-active guardia-manager')
run('Nginx 활성화',
'ln -sf /etc/nginx/sites-available/guardia-manager /etc/nginx/sites-enabled/ && '
'nginx -t && systemctl reload nginx && echo NGINX_OK')
# 9. 헬스체크
run('헬스체크', 'curl -s http://localhost:8002/health && echo "" && '
'curl -s -o /dev/null -w "Manager UI: HTTP %{http_code}" http://localhost:8090/')
sftp.close(); client.close()
print('\n\n=== 배포 완료 ===')
print('GUARDiA Manager: http://zioinfo.co.kr:8090')