Run 8091 and 8092 dashboards with Docker

This commit is contained in:
2026-06-11 16:35:09 +09:00
parent 0c052abfa7
commit 7477a803e9
5 changed files with 83 additions and 35 deletions

View File

@@ -7,5 +7,5 @@ matching.db
csv csv
*.png *.png
*.xlsx *.xlsx
*.txt gitea-api.txt
data data

View File

@@ -2,18 +2,33 @@ FROM python:3.12-slim
ENV PYTHONDONTWRITEBYTECODE=1 \ ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \ PYTHONUNBUFFERED=1 \
PORT=8090 PORT=8091 \
CHROME_PATH=/usr/bin/chromium
WORKDIR /app WORKDIR /app
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
chromium \
fonts-noto-cjk \
nodejs \
npm \
&& rm -rf /var/lib/apt/lists/*
COPY requirements.txt ./ COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt RUN pip install --no-cache-dir -r requirements.txt
COPY app.py index.html detail-view.html detail-view-project.html ./ RUN npm install --omit=dev playwright-core
# matching.db는 볼륨으로 마운트해서 데이터 보존 COPY mysql_preview_server.py \
VOLUME ["/app/data"] index.html \
detail-view.html \
detail-view-project.html \
mysql-preview.html \
people-unified.html \
project-codes.html \
./
EXPOSE 8090 EXPOSE 8091 8092
CMD ["sh", "-c", "ln -sf /app/data/matching.db /app/matching.db 2>/dev/null || true; python3 app.py"] CMD ["python3", "mysql_preview_server.py"]

View File

@@ -1,13 +1,12 @@
version: "3.9"
services: services:
manhour-dashboard: jh-people-8091:
build: . build: .
container_name: manhour-dashboard container_name: jh-people-8091
ports: ports:
- "8090:8090" - "8091:8091"
environment: environment:
PORT: "8090" PORT: "8091"
STARTUP_MAINTENANCE: "1"
MYSQL_HOST: "${MYSQL_HOST:-172.16.42.111}" MYSQL_HOST: "${MYSQL_HOST:-172.16.42.111}"
MYSQL_PORT: "${MYSQL_PORT:-3306}" MYSQL_PORT: "${MYSQL_PORT:-3306}"
MYSQL_USER: "${MYSQL_USER:-root}" MYSQL_USER: "${MYSQL_USER:-root}"
@@ -20,5 +19,30 @@ services:
INTRANET_LOGIN_ID: "${INTRANET_LOGIN_ID:-G25001}" INTRANET_LOGIN_ID: "${INTRANET_LOGIN_ID:-G25001}"
INTRANET_LOGIN_PW: "${INTRANET_LOGIN_PW:-00000}" INTRANET_LOGIN_PW: "${INTRANET_LOGIN_PW:-00000}"
volumes: volumes:
- ./data:/app/data - ./matching.db:/app/matching.db
restart: unless-stopped
jh-project-8092:
build: .
container_name: jh-project-8092
ports:
- "8092:8092"
environment:
PORT: "8092"
STARTUP_MAINTENANCE: "0"
MYSQL_HOST: "${MYSQL_HOST:-172.16.42.111}"
MYSQL_PORT: "${MYSQL_PORT:-3306}"
MYSQL_USER: "${MYSQL_USER:-root}"
MYSQL_PASSWORD: "${MYSQL_PASSWORD:-hanmacerp!}"
MYSQL_DB: "${MYSQL_DB:-jangheon_manhour}"
ERP_BASE_URL: "${ERP_BASE_URL:-http://erp.jangheon.co.kr/projt_mng}"
ERP_LOGIN_ID: "${ERP_LOGIN_ID:-g25001}"
ERP_LOGIN_PW: "${ERP_LOGIN_PW:-00000}"
INTRANET_BASE_URL: "${INTRANET_BASE_URL:-http://erp.jangheon.co.kr/intranet/}"
INTRANET_LOGIN_ID: "${INTRANET_LOGIN_ID:-G25001}"
INTRANET_LOGIN_PW: "${INTRANET_LOGIN_PW:-00000}"
volumes:
- ./matching.db:/app/matching.db
depends_on:
- jh-people-8091
restart: unless-stopped restart: unless-stopped

Binary file not shown.

View File

@@ -439,9 +439,10 @@ def resolve_naver_address_token(address):
const { chromium } = require('playwright-core'); const { chromium } = require('playwright-core');
const address = process.argv[1]; const address = process.argv[1];
(async () => { (async () => {
const executablePath = process.env.CHROME_PATH || '/usr/bin/google-chrome';
const browser = await chromium.launch({ const browser = await chromium.launch({
headless: true, headless: true,
executablePath: '/usr/bin/google-chrome', executablePath,
args: ['--no-sandbox', '--disable-dev-shm-usage'], args: ['--no-sandbox', '--disable-dev-shm-usage'],
}); });
const page = await browser.newPage(); const page = await browser.newPage();
@@ -472,8 +473,13 @@ const address = process.argv[1];
}); });
""" """
env = os.environ.copy() env = os.environ.copy()
npx_node_path = '/home/hyein/.npm/_npx/9833c18b2d85bc59/node_modules' node_paths = [
env['NODE_PATH'] = f"{npx_node_path}:{env.get('NODE_PATH', '')}" if env.get('NODE_PATH') else npx_node_path os.path.join(BASE_DIR, 'node_modules'),
'/home/hyein/.npm/_npx/9833c18b2d85bc59/node_modules',
]
existing_node_paths = [path for path in node_paths if os.path.isdir(path)]
if existing_node_paths:
env['NODE_PATH'] = ':'.join(existing_node_paths + ([env['NODE_PATH']] if env.get('NODE_PATH') else []))
try: try:
completed = subprocess.run( completed = subprocess.run(
['node', '-e', node_script, cleaned], ['node', '-e', node_script, cleaned],
@@ -4583,24 +4589,27 @@ if __name__ == '__main__':
os.makedirs(BASE_DIR, exist_ok=True) os.makedirs(BASE_DIR, exist_ok=True)
with open_db_connection() as conn: with open_db_connection() as conn:
init_db(conn) init_db(conn)
try: if os.environ.get('STARTUP_MAINTENANCE', '1') not in ('0', 'false', 'False', 'no'):
alias_rows = load_project_alias_from_erp() try:
print(f'Loaded project aliases from ERP: {len(alias_rows)}') alias_rows = load_project_alias_from_erp()
replace_project_alias(conn, alias_rows) print(f'Loaded project aliases from ERP: {len(alias_rows)}')
except Exception as e: replace_project_alias(conn, alias_rows)
print(f'Load project aliases from ERP failed, keep existing aliases: {e}') except Exception as e:
# 직급은 MySQL member.rankCode -> systemconfig 매핑 기반으로 /api/load 시 반영 print(f'Load project aliases from ERP failed, keep existing aliases: {e}')
try: # 직급은 MySQL member.rankCode -> systemconfig 매핑 기반으로 /api/load 시 반영
fixed = backfill_daily_hours_if_needed(conn) try:
if fixed: fixed = backfill_daily_hours_if_needed(conn)
print(f'Backfilled hour columns for {fixed} rows.') if fixed:
rebuilt = rebuild_work_calendar_tables(conn) print(f'Backfilled hour columns for {fixed} rows.')
print(f"Rebuilt work calendar tables: days={rebuilt['days']}, details={rebuilt['details']}") rebuilt = rebuild_work_calendar_tables(conn)
except sqlite3.OperationalError as e: print(f"Rebuilt work calendar tables: days={rebuilt['days']}, details={rebuilt['details']}")
if 'locked' in str(e).lower(): except sqlite3.OperationalError as e:
print(f'Skip startup rebuild because database is locked: {e}') if 'locked' in str(e).lower():
else: print(f'Skip startup rebuild because database is locked: {e}')
raise else:
raise
else:
print('Skip startup maintenance by STARTUP_MAINTENANCE=0')
port = int(os.environ.get('PORT', '8091')) port = int(os.environ.get('PORT', '8091'))
host = '0.0.0.0' host = '0.0.0.0'