- users → user in SQL contexts (94 occurrences) - robeings → robeing in SQL contexts - user_preferences → user_preference (14 files) - slack_workspaces → slack_workspace in SQL contexts (17 files) All table names now correctly match PostgreSQL schema
12 KiB
12 KiB
PostgreSQL SSH 터널 및 데이터베이스 접속 가이드
📋 목차
SSH 터널 설정
1. 현재 SSH 터널 확인
# 실행 중인 SSH 터널 확인
ps aux | grep "ssh.*5433" | grep -v grep
# 특정 포트 사용 확인
netstat -tlnp | grep 5433
lsof -i :5433
2. SSH 터널 생성
# 기본 SSH 터널 생성 (백그라운드 실행)
ssh -f -N -L 5433:localhost:5432 admin@124.55.18.179 -p 51123
# StrictHostKeyChecking 비활성화 (테스트용)
ssh -o StrictHostKeyChecking=no -f -N -L 5433:localhost:5432 admin@124.55.18.179 -p 51123
# 옵션 설명:
# -f : 백그라운드 실행
# -N : 원격 명령 실행하지 않음 (포트 포워딩만)
# -L : 로컬 포트 포워딩 (로컬포트:원격호스트:원격포트)
# -p : SSH 포트 지정
3. SSH 터널 종료
# 프로세스 ID 찾기
ps aux | grep "ssh.*5433"
# 프로세스 종료
sudo kill [PID]
# 또는 한 번에
sudo pkill -f "ssh.*5433"
PostgreSQL 접속
1. 연결 정보
Host: localhost (SSH 터널 사용시) 또는 192.168.219.45 (직접 연결)
Port: 5433 (터널 로컬 포트) 또는 5432 (직접 연결)
Database: main_db (기존 auth_db는 더 이상 사용 안함)
Username: robeings
Password: robeings
2. psql 명령어로 접속
# psql 설치 (Ubuntu/Debian)
sudo apt-get install postgresql-client
# DB 접속 (51123 서버에서 직접)
psql postgresql://robeings:robeings@localhost:5432/main_db
# 또는 (51124 서버에서 SSH 터널 사용)
psql postgresql://robeings:robeings@localhost:5433/main_db
# 또는
psql -h localhost -p 5432 -U robeings -d main_db
3. psql 기본 명령어
-- 테이블 목록 보기
\dt
-- 특정 테이블 구조 보기
\d gmail_token
\d users
-- 데이터베이스 목록
\l
-- 현재 데이터베이스 정보
\conninfo
-- 종료
\q
Python으로 DB 조회
1. 필요한 패키지 설치
pip install psycopg2-binary
2. 기본 연결 및 조회
import psycopg2
import json
# DB 연결 (51123 서버에서)
conn = psycopg2.connect('postgresql://robeings:robeings@localhost:5432/main_db')
# DB 연결 (51124 서버에서 SSH 터널 사용)
conn = psycopg2.connect('postgresql://robeings:robeings@localhost:5433/main_db')
cur = conn.cursor()
# 쿼리 실행
cur.execute("SELECT * FROM user LIMIT 5")
rows = cur.fetchall()
for row in rows:
print(row)
# 연결 종료
cur.close()
conn.close()
3. 안전한 쿼리 실행 (파라미터 바인딩)
# SQL Injection 방지를 위해 항상 파라미터 바인딩 사용
user_id = 'b6ea2ee0-a15a-5cf4-93a9-a9ca20d4c4a0'
cur.execute(
"SELECT * FROM user WHERE id = %s",
(user_id,) # 튜플로 전달
)
주요 테이블 구조
1. users 테이블
CREATE TABLE user (
id UUID PRIMARY KEY,
email VARCHAR UNIQUE,
name VARCHAR,
picture VARCHAR,
oauth_provider VARCHAR,
oauth_id VARCHAR,
is_active BOOLEAN,
created_at TIMESTAMP,
updated_at TIMESTAMP,
last_login_at TIMESTAMP,
username VARCHAR
);
2. gmail_token 테이블
CREATE TABLE gmail_token (
id SERIAL PRIMARY KEY,
user_id UUID REFERENCES user(id),
slack_id VARCHAR(100), -- Slack 사용자 ID (새로 추가)
is_equipped BOOLEAN,
has_token BOOLEAN, -- token_data 존재 여부
access_token TEXT, -- 개별 컬럼으로 분리
refresh_token TEXT, -- 개별 컬럼으로 분리
token_type VARCHAR,
expires_at FLOAT,
token_data JSONB, -- 레거시 호환용
oauth_config JSONB, -- OAuth 설정 정보
scopes JSONB, -- Gmail API 권한 목록
metadata JSONB,
expiry TIMESTAMP,
created_at TIMESTAMP,
updated_at TIMESTAMP,
robeing_id VARCHAR, -- 로빙 ID (rb8001 등)
equipped_to VARCHAR
);
3. conversation_log 테이블
CREATE TABLE conversation_log (
id SERIAL PRIMARY KEY,
robeing_id VARCHAR,
channel_id VARCHAR,
message VARCHAR,
response VARCHAR,
intent VARCHAR,
confidence DOUBLE PRECISION,
timestamp TIMESTAMP,
user_id UUID REFERENCES user(id), -- NULL 허용으로 변경됨
slack_user_id VARCHAR(100) -- Slack ID 직접 저장 (새로 추가)
);
4. slack_user_mapping 테이블
CREATE TABLE slack_user_mapping (
id UUID PRIMARY KEY,
slack_user_id VARCHAR(100) NOT NULL,
slack_workspace_id UUID,
user_id UUID REFERENCES user(id),
workspace_member_id UUID,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
자주 사용하는 쿼리
1. Gmail 토큰 확인
import psycopg2
import json
conn = psycopg2.connect('postgresql://robeings:robeings@localhost:5432/main_db')
cur = conn.cursor()
# Gmail 토큰 상태 확인
query = """
SELECT
u.username,
u.email,
g.user_id,
g.is_equipped,
g.robeing_id,
g.token_data,
g.scopes
FROM gmail_token g
JOIN user u ON g.user_id = u.id
ORDER BY g.created_at DESC
"""
cur.execute(query)
rows = cur.fetchall()
for row in rows:
print(f"\nUser: {row[0]} ({row[1]})")
print(f" UUID: {row[2]}")
print(f" Equipped: {row[3]}")
print(f" Robeing: {row[4]}")
token_data = row[5] if row[5] else {}
if token_data and 'access_token' in token_data:
access_token = token_data.get('access_token', '')
if access_token.startswith('ya29'):
print(f" Token: 실제 OAuth 토큰 있음")
else:
print(f" Token: 테스트 토큰")
scopes = row[6] if row[6] else []
if scopes:
print(f" Scopes: {len(scopes)}개")
cur.close()
conn.close()
2. Slack User ID를 UUID로 변환
import uuid
def slack_id_to_uuid(slack_user_id):
"""Slack User ID를 일관된 UUID로 변환"""
namespace = uuid.UUID('6ba7b810-9dad-11d1-80b4-00c04fd430c8')
# 51123 매핑 API 호출로 UUID 조회
return call_mapping_api(slack_user_id)
# 예시
slack_id = 'U091UNVE41M'
user_uuid = slack_id_to_uuid(slack_id)
print(f"Slack ID: {slack_id}")
print(f"UUID: {user_uuid}")
# 출력: b6ea2ee0-a15a-5cf4-93a9-a9ca20d4c4a0
3. 사용자별 Gmail 토큰 추가/업데이트
import psycopg2
import json
import uuid
def add_gmail_token(slack_user_id, email, access_token, refresh_token):
"""Gmail 토큰 추가 또는 업데이트"""
# Slack ID를 UUID로 변환
namespace = uuid.UUID('6ba7b810-9dad-11d1-80b4-00c04fd430c8')
# 51123 매핑 API를 통해 UUID 조회
user_uuid = await get_uuid_from_mapping_api(slack_user_id)
conn = psycopg2.connect('postgresql://robeings:robeings@localhost:5432/main_db')
cur = conn.cursor()
try:
# 1. users 테이블에 사용자 추가 (없으면)
cur.execute("""
INSERT INTO user (id, email, username, created_at)
VALUES (%s, %s, %s, NOW())
ON CONFLICT (id) DO UPDATE SET email = EXCLUDED.email
""", (user_uuid, email, slack_user_id))
# 2. gmail_token 추가 또는 업데이트
token_data = {
"access_token": access_token,
"refresh_token": refresh_token,
"token_type": "Bearer"
}
cur.execute("""
INSERT INTO gmail_token (user_id, token_data, is_equipped, robeing_id, created_at)
VALUES (%s, %s::jsonb, true, 'rb8001', NOW())
ON CONFLICT (user_id) DO UPDATE
SET token_data = EXCLUDED.token_data,
updated_at = NOW()
""", (user_uuid, json.dumps(token_data)))
conn.commit()
print(f"✅ Gmail 토큰 저장 완료: {email}")
except Exception as e:
conn.rollback()
print(f"❌ 오류 발생: {e}")
finally:
cur.close()
conn.close()
문제 해결
1. SSH 터널이 연결되지 않을 때
# 기존 터널 프로세스 종료
sudo pkill -f "ssh.*5433"
# 포트 사용 확인
lsof -i :5433
# 다시 연결
ssh -f -N -L 5433:localhost:5432 admin@124.55.18.179 -p 51123
2. psycopg2 설치 오류
# Ubuntu/Debian
sudo apt-get install libpq-dev python3-dev
pip install psycopg2
# 또는 바이너리 버전 사용
pip install psycopg2-binary
3. UUID 타입 오류
# UUID 문자열을 PostgreSQL UUID 타입으로 변환
import uuid
# 방법 1: 직접 캐스팅
cur.execute(
"SELECT * FROM user WHERE id = %s::uuid",
('b6ea2ee0-a15a-5cf4-93a9-a9ca20d4c4a0',)
)
# 방법 2: uuid 객체 사용
user_uuid = uuid.UUID('b6ea2ee0-a15a-5cf4-93a9-a9ca20d4c4a0')
cur.execute(
"SELECT * FROM user WHERE id = %s",
(str(user_uuid),)
)
4. JSONB 필드 처리
import json
# JSONB 데이터 삽입
data = {"key": "value", "nested": {"field": "data"}}
cur.execute(
"INSERT INTO table_name (jsonb_column) VALUES (%s::jsonb)",
(json.dumps(data),)
)
# JSONB 데이터 조회
cur.execute("SELECT jsonb_column FROM table_name")
row = cur.fetchone()
json_data = row[0] # 자동으로 Python dict로 변환됨
환경 변수 설정
.env 파일에 추가:
# PostgreSQL Connection (51123 서버 직접 연결)
POSTGRES_CONNECTION_STRING=postgresql://robeings:robeings@localhost:5432/main_db
# PostgreSQL Connection (51124 서버 SSH 터널)
POSTGRES_CONNECTION_STRING=postgresql://robeings:robeings@localhost:5433/main_db
# SSH Tunnel Config
SSH_HOST=124.55.18.179
SSH_PORT=51123
SSH_USER=admin
LOCAL_PORT=5433
REMOTE_PORT=5432
Python에서 사용:
import os
from dotenv import load_dotenv
load_dotenv()
conn_string = os.getenv('POSTGRES_CONNECTION_STRING')
conn = psycopg2.connect(conn_string)
자동화 스크립트
SSH 터널 자동 재연결 스크립트
#!/bin/bash
# /home/heejae/scripts/ssh_tunnel_monitor.sh
LOCAL_PORT=5433
SSH_CMD="ssh -f -N -L 5433:localhost:5432 admin@124.55.18.179 -p 51123"
# 터널이 살아있는지 확인
if ! nc -z localhost $LOCAL_PORT 2>/dev/null; then
echo "SSH tunnel is down. Restarting..."
# 기존 프로세스 종료
pkill -f "ssh.*$LOCAL_PORT"
# 새 터널 생성
$SSH_CMD
echo "SSH tunnel restarted"
else
echo "SSH tunnel is running"
fi
crontab에 추가 (5분마다 체크):
*/5 * * * * /home/heejae/scripts/ssh_tunnel_monitor.sh
참고 링크
서버별 DB 연결 상태 (2025-08-26 현재)
51123 서버 (192.168.219.45)
- PostgreSQL: 로컬 실행 중 (포트 5432)
- 데이터베이스: main_db
- 직접 연결:
postgresql://robeings:robeings@localhost:5432/main_db
51124 서버 (192.168.219.52)
- PostgreSQL: 없음 (51123 서버 DB 사용)
- 연결 방법: SSH 터널
- 터널 설정:
ssh -N -L 5433:localhost:5432 admin@192.168.219.45 - 연결 문자열:
postgresql://robeings:robeings@localhost:5433/main_db
주요 서비스별 DB 연결
| 서비스 | 서버 | DB 연결 방법 |
|---|---|---|
| auth-server | 51123 | 직접 연결 (localhost:5432) |
| robeing-gateway | 51123 | 직접 연결 (localhost:5432) |
| rb8001 | 51124 | SSH 터널 (localhost:5433) |
| State Service | 51124 | SSH 터널 (localhost:5433) |
| skill-email | 51124 | SSH 터널 (localhost:5433) |
주의사항
- auth_db는 더 이상 사용하지 않음 (main_db로 통합)
- State Service의 DATABASE_URL이 auth_db를 참조하면 main_db로 수정 필요
- SSH 터널은 시스템 재시작 시 재생성 필요
마지막 업데이트: 2025-08-26