- 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>
157 lines
5.5 KiB
Python
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')
|