Run 8091 and 8092 dashboards with Docker
This commit is contained in:
@@ -7,5 +7,5 @@ matching.db
|
|||||||
csv
|
csv
|
||||||
*.png
|
*.png
|
||||||
*.xlsx
|
*.xlsx
|
||||||
*.txt
|
gitea-api.txt
|
||||||
data
|
data
|
||||||
|
|||||||
27
Dockerfile
27
Dockerfile
@@ -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"]
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
BIN
matching.db
BIN
matching.db
Binary file not shown.
@@ -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'
|
||||||
|
|||||||
Reference in New Issue
Block a user