Compare commits
4 Commits
4fbfb31e97
...
a2e5bf4e10
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a2e5bf4e10 | ||
|
|
de2a2e2c35 | ||
|
|
f75ec77ccf | ||
|
|
9fa549285f |
230
deploy/check-nginx.sh
Executable file
230
deploy/check-nginx.sh
Executable file
@@ -0,0 +1,230 @@
|
||||
#!/bin/bash
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
NGINX_DIR="/data/training/nginx"
|
||||
PASS=0
|
||||
FAIL=0
|
||||
|
||||
# docker compose v1/v2 자동 감지
|
||||
if command -v docker-compose &>/dev/null; then
|
||||
DOCKER_COMPOSE="docker-compose"
|
||||
elif docker compose version &>/dev/null 2>&1; then
|
||||
DOCKER_COMPOSE="docker compose"
|
||||
else
|
||||
DOCKER_COMPOSE=""
|
||||
fi
|
||||
|
||||
GREEN='\033[0;32m'
|
||||
RED='\033[0;31m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
ok() { echo -e "${GREEN}[OK]${NC} $1"; ((PASS++)); }
|
||||
fail() { echo -e "${RED}[FAIL]${NC} $1"; ((FAIL++)); }
|
||||
warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
|
||||
section() { echo ""; echo "=== $1 ==="; }
|
||||
|
||||
# ──────────────────────────────────────────
|
||||
section "디렉토리 확인"
|
||||
# ──────────────────────────────────────────
|
||||
for dir in \
|
||||
/data/training/request \
|
||||
/data/training/request/tmp \
|
||||
/data/training/response \
|
||||
/data/training/response/v6-cls-checkpoints \
|
||||
/data/training/tmp \
|
||||
"$NGINX_DIR" \
|
||||
"$NGINX_DIR/ssl" \
|
||||
"$NGINX_DIR/logs"; do
|
||||
if [ -d "$dir" ]; then
|
||||
ok "$dir"
|
||||
else
|
||||
fail "$dir 없음"
|
||||
fi
|
||||
done
|
||||
|
||||
# ──────────────────────────────────────────
|
||||
section "nginx 파일 확인"
|
||||
# ──────────────────────────────────────────
|
||||
for f in \
|
||||
"$NGINX_DIR/nginx.conf" \
|
||||
"$NGINX_DIR/docker-compose-nginx.yml" \
|
||||
"$NGINX_DIR/ssl/train-kamco.com.crt" \
|
||||
"$NGINX_DIR/ssl/train-kamco.com.key" \
|
||||
"$NGINX_DIR/ssl/openssl.cnf"; do
|
||||
if [ -f "$f" ]; then
|
||||
ok "$f"
|
||||
else
|
||||
fail "$f 없음"
|
||||
fi
|
||||
done
|
||||
|
||||
# ──────────────────────────────────────────
|
||||
section "파일 권한 확인"
|
||||
# ──────────────────────────────────────────
|
||||
SSL_DIR_PERM=$(stat -c "%a" "$NGINX_DIR/ssl" 2>/dev/null)
|
||||
KEY_PERM=$(stat -c "%a" "$NGINX_DIR/ssl/train-kamco.com.key" 2>/dev/null)
|
||||
CRT_PERM=$(stat -c "%a" "$NGINX_DIR/ssl/train-kamco.com.crt" 2>/dev/null)
|
||||
|
||||
[ "$SSL_DIR_PERM" = "700" ] && ok "ssl/ 권한 700" || fail "ssl/ 권한 오류 (현재: $SSL_DIR_PERM, 기대: 700)"
|
||||
[ "$KEY_PERM" = "600" ] && ok "train-kamco.com.key 권한 600" || fail "key 권한 오류 (현재: $KEY_PERM, 기대: 600)"
|
||||
[ "$CRT_PERM" = "644" ] && ok "train-kamco.com.crt 권한 644" || fail "crt 권한 오류 (현재: $CRT_PERM, 기대: 644)"
|
||||
|
||||
# ──────────────────────────────────────────
|
||||
section "소유권 확인 (kcomu:kcomu)"
|
||||
# ──────────────────────────────────────────
|
||||
OWNER=$(stat -c "%U:%G" /data/training 2>/dev/null)
|
||||
[ "$OWNER" = "kcomu:kcomu" ] && ok "/data/training 소유권 kcomu:kcomu" || fail "/data/training 소유권 오류 (현재: $OWNER)"
|
||||
|
||||
# ──────────────────────────────────────────
|
||||
section "SSL 인증서 유효성"
|
||||
# ──────────────────────────────────────────
|
||||
if command -v openssl &>/dev/null && [ -f "$NGINX_DIR/ssl/train-kamco.com.crt" ]; then
|
||||
EXPIRY=$(openssl x509 -in "$NGINX_DIR/ssl/train-kamco.com.crt" -noout -enddate 2>/dev/null | cut -d= -f2)
|
||||
EXPIRY_EPOCH=$(date -d "$EXPIRY" +%s 2>/dev/null || date -j -f "%b %d %T %Y %Z" "$EXPIRY" +%s 2>/dev/null)
|
||||
NOW_EPOCH=$(date +%s)
|
||||
if [ "$EXPIRY_EPOCH" -gt "$NOW_EPOCH" ]; then
|
||||
ok "인증서 유효 (만료: $EXPIRY)"
|
||||
else
|
||||
fail "인증서 만료됨 (만료: $EXPIRY)"
|
||||
fi
|
||||
|
||||
SAN=$(openssl x509 -in "$NGINX_DIR/ssl/train-kamco.com.crt" -noout -text 2>/dev/null | grep -A1 "Subject Alternative Name" | tail -1)
|
||||
echo " SAN: $SAN"
|
||||
else
|
||||
warn "openssl 없음 또는 인증서 파일 없음 - 인증서 검증 스킵"
|
||||
fi
|
||||
|
||||
# ──────────────────────────────────────────
|
||||
section "Docker 확인"
|
||||
# ──────────────────────────────────────────
|
||||
if command -v docker &>/dev/null && docker info &>/dev/null 2>&1; then
|
||||
ok "Docker 실행 중"
|
||||
|
||||
# Docker network
|
||||
if docker network ls --format '{{.Name}}' | grep -q "^kamco-cds$"; then
|
||||
ok "Docker network kamco-cds 존재"
|
||||
else
|
||||
fail "Docker network kamco-cds 없음 (setup.sh 재실행 필요)"
|
||||
fi
|
||||
|
||||
# nginx 컨테이너 상태
|
||||
CONTAINER_STATUS=$(docker inspect --format '{{.State.Status}}' kamco-train-nginx 2>/dev/null)
|
||||
if [ "$CONTAINER_STATUS" = "running" ]; then
|
||||
ok "kamco-train-nginx 컨테이너 실행 중"
|
||||
elif [ -z "$CONTAINER_STATUS" ]; then
|
||||
warn "kamco-train-nginx 컨테이너 없음 (아직 미실행)"
|
||||
else
|
||||
fail "kamco-train-nginx 컨테이너 상태: $CONTAINER_STATUS"
|
||||
fi
|
||||
else
|
||||
fail "Docker 미실행 또는 설치 안 됨"
|
||||
fi
|
||||
|
||||
# ──────────────────────────────────────────
|
||||
section "nginx 설정 문법 검사"
|
||||
# ──────────────────────────────────────────
|
||||
if command -v docker &>/dev/null && docker info &>/dev/null 2>&1; then
|
||||
echo " docker run으로 nginx -t 실행 중..."
|
||||
# kamco-cds 네트워크가 있으면 연결 (upstream DNS 조회 가능)
|
||||
NETWORK_OPT=""
|
||||
if docker network ls --format '{{.Name}}' | grep -q "^kamco-cds$"; then
|
||||
NETWORK_OPT="--network kamco-cds"
|
||||
fi
|
||||
if docker run --rm $NETWORK_OPT \
|
||||
-v "$NGINX_DIR/nginx.conf:/etc/nginx/nginx.conf:ro,Z" \
|
||||
-v "$NGINX_DIR/ssl:/etc/nginx/ssl:ro,Z" \
|
||||
nginx:alpine nginx -t 2>&1; then
|
||||
ok "nginx 설정 문법 OK"
|
||||
else
|
||||
fail "nginx 설정 문법 오류"
|
||||
fi
|
||||
else
|
||||
warn "Docker 없음 - nginx 문법 검사 스킵"
|
||||
fi
|
||||
|
||||
# ──────────────────────────────────────────
|
||||
section "/etc/hosts 확인"
|
||||
# ──────────────────────────────────────────
|
||||
for domain in api.train-kamco.com train-kamco.com; do
|
||||
HOSTS_LINE=$(grep "$domain" /etc/hosts | grep -v "^#" | head -1)
|
||||
if [ -n "$HOSTS_LINE" ]; then
|
||||
ok "$domain 등록됨 → $HOSTS_LINE"
|
||||
else
|
||||
fail "$domain /etc/hosts 미등록"
|
||||
fi
|
||||
done
|
||||
|
||||
# ──────────────────────────────────────────
|
||||
section "도메인 해석 확인"
|
||||
# ──────────────────────────────────────────
|
||||
for domain in api.train-kamco.com train-kamco.com; do
|
||||
RESOLVED=$(getent hosts "$domain" 2>/dev/null | awk '{print $1}' | head -1)
|
||||
if [ -n "$RESOLVED" ]; then
|
||||
ok "$domain → $RESOLVED"
|
||||
else
|
||||
fail "$domain 해석 실패 (DNS 또는 hosts 문제)"
|
||||
fi
|
||||
done
|
||||
|
||||
# ──────────────────────────────────────────
|
||||
section "포트 연결 확인 (80 / 443)"
|
||||
# ──────────────────────────────────────────
|
||||
for port in 80 443; do
|
||||
if command -v nc &>/dev/null; then
|
||||
if nc -z -w3 api.train-kamco.com "$port" 2>/dev/null; then
|
||||
ok "api.train-kamco.com:$port 열림"
|
||||
else
|
||||
warn "api.train-kamco.com:$port 닫힘 (nginx 미실행일 수 있음)"
|
||||
fi
|
||||
elif command -v curl &>/dev/null; then
|
||||
HTTP_CODE=$(curl -sk -o /dev/null -w "%{http_code}" --connect-timeout 3 \
|
||||
"$([ "$port" = "443" ] && echo https || echo http)://api.train-kamco.com/" 2>/dev/null)
|
||||
if [ -n "$HTTP_CODE" ] && [ "$HTTP_CODE" != "000" ]; then
|
||||
ok "api.train-kamco.com:$port 응답 (HTTP $HTTP_CODE)"
|
||||
else
|
||||
warn "api.train-kamco.com:$port 응답 없음 (nginx 미실행일 수 있음)"
|
||||
fi
|
||||
else
|
||||
warn "nc/curl 없음 - 포트 확인 스킵"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# ──────────────────────────────────────────
|
||||
section "HTTPS 헬스체크"
|
||||
# ──────────────────────────────────────────
|
||||
if command -v curl &>/dev/null; then
|
||||
for url in \
|
||||
"https://api.train-kamco.com/monitor/health" \
|
||||
"https://train-kamco.com/monitor/health"; do
|
||||
HTTP_CODE=$(curl -sk -o /dev/null -w "%{http_code}" --connect-timeout 5 "$url" 2>/dev/null)
|
||||
if [ "$HTTP_CODE" = "200" ]; then
|
||||
ok "$url → HTTP $HTTP_CODE"
|
||||
elif [ "$HTTP_CODE" = "000" ] || [ -z "$HTTP_CODE" ]; then
|
||||
warn "$url → 응답 없음 (nginx 미실행일 수 있음)"
|
||||
else
|
||||
warn "$url → HTTP $HTTP_CODE"
|
||||
fi
|
||||
done
|
||||
else
|
||||
warn "curl 없음 - HTTPS 헬스체크 스킵"
|
||||
fi
|
||||
|
||||
# ──────────────────────────────────────────
|
||||
section "결과 요약"
|
||||
# ──────────────────────────────────────────
|
||||
echo ""
|
||||
echo -e " ${GREEN}PASS: $PASS${NC} / ${RED}FAIL: $FAIL${NC}"
|
||||
echo ""
|
||||
if [ $FAIL -eq 0 ]; then
|
||||
echo -e "${GREEN}모든 체크 통과. nginx 실행 준비 완료.${NC}"
|
||||
if [ -n "$DOCKER_COMPOSE" ]; then
|
||||
echo " cd $NGINX_DIR && $DOCKER_COMPOSE -f docker-compose-nginx.yml up -d"
|
||||
else
|
||||
echo " [WARN] docker-compose / docker compose 를 찾을 수 없습니다."
|
||||
fi
|
||||
else
|
||||
echo -e "${RED}$FAIL 개 항목 실패. 위 오류를 확인하세요.${NC}"
|
||||
exit 1
|
||||
fi
|
||||
25
deploy/docker-compose-nginx.yml
Normal file
25
deploy/docker-compose-nginx.yml
Normal file
@@ -0,0 +1,25 @@
|
||||
services:
|
||||
nginx:
|
||||
image: nginx:alpine
|
||||
container_name: kamco-train-nginx
|
||||
user: "1000:1000"
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
volumes:
|
||||
- ./nginx.conf:/etc/nginx/nginx.conf:ro,Z
|
||||
- ./ssl:/etc/nginx/ssl:ro,Z
|
||||
- ./logs:/var/log/nginx:Z
|
||||
networks:
|
||||
- kamco-cds
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "--no-check-certificate", "https://localhost/monitor/health"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 10s
|
||||
|
||||
networks:
|
||||
kamco-cds:
|
||||
external: true
|
||||
170
deploy/nginx.conf
Normal file
170
deploy/nginx.conf
Normal file
@@ -0,0 +1,170 @@
|
||||
pid /var/log/nginx/nginx.pid;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
# 로그 설정
|
||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||
|
||||
access_log /var/log/nginx/access.log main;
|
||||
error_log /var/log/nginx/error.log warn;
|
||||
|
||||
sendfile on;
|
||||
keepalive_timeout 65;
|
||||
|
||||
# user 1000:1000 실행 시 /var/cache/nginx 접근 불가 → logs 경로로 우회
|
||||
client_body_temp_path /var/log/nginx/client_temp;
|
||||
proxy_temp_path /var/log/nginx/proxy_temp;
|
||||
fastcgi_temp_path /var/log/nginx/fastcgi_temp;
|
||||
uwsgi_temp_path /var/log/nginx/uwsgi_temp;
|
||||
scgi_temp_path /var/log/nginx/scgi_temp;
|
||||
|
||||
# 업로드 파일 크기 / 타임아웃 (10GB, 10분)
|
||||
client_max_body_size 10G;
|
||||
client_body_timeout 600s;
|
||||
|
||||
# Docker 내부 DNS - 시작 시 upstream 조회 실패 방지
|
||||
resolver 127.0.0.11 valid=30s ipv6=off;
|
||||
|
||||
# HTTP → HTTPS 리다이렉트 서버
|
||||
server {
|
||||
listen 80;
|
||||
server_name api.train-kamco.com train-kamco.com;
|
||||
|
||||
# 모든 HTTP 요청을 HTTPS로 리다이렉트
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
|
||||
# HTTPS 서버 설정
|
||||
server {
|
||||
listen 443 ssl;
|
||||
http2 on;
|
||||
server_name api.train-kamco.com;
|
||||
|
||||
ssl_certificate /etc/nginx/ssl/train-kamco.com.crt;
|
||||
ssl_certificate_key /etc/nginx/ssl/train-kamco.com.key;
|
||||
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384';
|
||||
ssl_prefer_server_ciphers off;
|
||||
|
||||
ssl_session_cache shared:SSL:10m;
|
||||
ssl_session_timeout 10m;
|
||||
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
|
||||
# CORS 헤더
|
||||
add_header Access-Control-Allow-Origin "https://train-kamco.com" always;
|
||||
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, PATCH, OPTIONS" always;
|
||||
add_header Access-Control-Allow-Headers "Authorization, Content-Type, Cookie, X-Requested-With" always;
|
||||
add_header Access-Control-Allow-Credentials "true" always;
|
||||
|
||||
location / {
|
||||
if ($request_method = OPTIONS) {
|
||||
return 204;
|
||||
}
|
||||
|
||||
set $api http://kamco-train-api:8080;
|
||||
proxy_pass $api;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Host $server_name;
|
||||
proxy_pass_request_headers on;
|
||||
proxy_set_header Cookie $http_cookie;
|
||||
proxy_set_header Authorization $http_authorization;
|
||||
|
||||
proxy_connect_timeout 600s;
|
||||
proxy_send_timeout 600s;
|
||||
proxy_read_timeout 600s;
|
||||
|
||||
proxy_request_buffering off;
|
||||
proxy_buffering off;
|
||||
}
|
||||
|
||||
location /monitor/health {
|
||||
set $api http://kamco-train-api:8080;
|
||||
proxy_pass $api/monitor/health;
|
||||
access_log off;
|
||||
}
|
||||
}
|
||||
|
||||
# HTTPS 서버 설정 - Next.js Web Application
|
||||
server {
|
||||
listen 443 ssl;
|
||||
http2 on;
|
||||
server_name train-kamco.com;
|
||||
|
||||
ssl_certificate /etc/nginx/ssl/train-kamco.com.crt;
|
||||
ssl_certificate_key /etc/nginx/ssl/train-kamco.com.key;
|
||||
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384';
|
||||
ssl_prefer_server_ciphers off;
|
||||
|
||||
ssl_session_cache shared:SSL:10m;
|
||||
ssl_session_timeout 10m;
|
||||
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
|
||||
location /api/ {
|
||||
set $api http://kamco-train-api:8080;
|
||||
proxy_pass $api/api/;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Host $server_name;
|
||||
proxy_pass_request_headers on;
|
||||
proxy_set_header Cookie $http_cookie;
|
||||
|
||||
proxy_connect_timeout 600s;
|
||||
proxy_send_timeout 600s;
|
||||
proxy_read_timeout 600s;
|
||||
|
||||
proxy_request_buffering off;
|
||||
proxy_buffering off;
|
||||
}
|
||||
|
||||
location / {
|
||||
set $web http://kamco-train-web:3002;
|
||||
proxy_pass $web;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Host $server_name;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
|
||||
proxy_connect_timeout 600s;
|
||||
proxy_send_timeout 600s;
|
||||
proxy_read_timeout 600s;
|
||||
|
||||
proxy_buffering on;
|
||||
proxy_buffer_size 4k;
|
||||
proxy_buffers 8 4k;
|
||||
proxy_busy_buffers_size 8k;
|
||||
}
|
||||
}
|
||||
}
|
||||
38
deploy/setup-groups.sh
Executable file
38
deploy/setup-groups.sh
Executable file
@@ -0,0 +1,38 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
GREEN='\033[0;32m'
|
||||
RED='\033[0;31m'
|
||||
NC='\033[0m'
|
||||
|
||||
ok() { echo -e "${GREEN}[OK]${NC} $1"; }
|
||||
fail() { echo -e "${RED}[FAIL]${NC} $1"; exit 1; }
|
||||
|
||||
echo "=== GID 1000 그룹 설정 ==="
|
||||
|
||||
# GID 1000 그룹 없으면 생성
|
||||
if ! getent group 1000 &>/dev/null; then
|
||||
groupadd -g 1000 docker-users
|
||||
ok "GID 1000 그룹(docker-users) 생성 완료"
|
||||
else
|
||||
GROUP_NAME=$(getent group 1000 | cut -d: -f1)
|
||||
ok "GID 1000 그룹 이미 존재: $GROUP_NAME"
|
||||
fi
|
||||
|
||||
GROUP_NAME=$(getent group 1000 | cut -d: -f1)
|
||||
|
||||
# kcomu, docker 를 GID 1000 그룹에 추가
|
||||
for user in kcomu docker; do
|
||||
if id "$user" &>/dev/null; then
|
||||
usermod -aG "$GROUP_NAME" "$user"
|
||||
ok "$user → $GROUP_NAME($GROUP_NAME) 그룹 추가 완료"
|
||||
else
|
||||
echo " [SKIP] $user 유저 없음"
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "현재 $GROUP_NAME 그룹 멤버:"
|
||||
getent group "$GROUP_NAME"
|
||||
echo ""
|
||||
echo "※ 그룹 변경은 재로그인 후 적용됩니다."
|
||||
97
deploy/setup.sh
Executable file
97
deploy/setup.sh
Executable file
@@ -0,0 +1,97 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
NGINX_DIR="/data/training/nginx"
|
||||
|
||||
# docker compose v1/v2 자동 감지
|
||||
if command -v docker-compose &>/dev/null; then
|
||||
DOCKER_COMPOSE="docker-compose"
|
||||
elif docker compose version &>/dev/null 2>&1; then
|
||||
DOCKER_COMPOSE="docker compose"
|
||||
else
|
||||
DOCKER_COMPOSE=""
|
||||
fi
|
||||
|
||||
echo "=== 디렉토리 생성 ==="
|
||||
mkdir -p /data/training/request
|
||||
mkdir -p /data/training/request/tmp
|
||||
mkdir -p /data/training/response
|
||||
mkdir -p /data/training/response/v6-cls-checkpoints
|
||||
mkdir -p /data/training/tmp
|
||||
mkdir -p "$NGINX_DIR/ssl"
|
||||
mkdir -p "$NGINX_DIR/logs"
|
||||
echo "완료"
|
||||
|
||||
echo "=== nginx 파일 복사 ==="
|
||||
cp "$SCRIPT_DIR/nginx.conf" "$NGINX_DIR/"
|
||||
cp "$SCRIPT_DIR/docker-compose-nginx.yml" "$NGINX_DIR/"
|
||||
echo "완료"
|
||||
|
||||
echo "=== SSL 파일 복사 ==="
|
||||
cp "$SCRIPT_DIR/ssl/openssl.cnf" "$NGINX_DIR/ssl/"
|
||||
cp "$SCRIPT_DIR/ssl/train-kamco.com.crt" "$NGINX_DIR/ssl/"
|
||||
cp "$SCRIPT_DIR/ssl/train-kamco.com.key" "$NGINX_DIR/ssl/"
|
||||
echo "완료"
|
||||
|
||||
echo "=== SSL 권한 설정 ==="
|
||||
chmod 700 "$NGINX_DIR/ssl"
|
||||
chmod 600 "$NGINX_DIR/ssl/train-kamco.com.key"
|
||||
chmod 644 "$NGINX_DIR/ssl/train-kamco.com.crt"
|
||||
echo "완료"
|
||||
|
||||
echo "=== 소유권 설정 (kcomu:kcomu) ==="
|
||||
chown -R kcomu:kcomu /data/training
|
||||
echo "완료"
|
||||
|
||||
echo "=== 그룹 설정 (setup-groups.sh) ==="
|
||||
bash "$SCRIPT_DIR/setup-groups.sh"
|
||||
|
||||
echo "=== docker-compose-nginx.yml 소유권 설정 (1000:1000) ==="
|
||||
chown 1000:1000 "$NGINX_DIR/docker-compose-nginx.yml"
|
||||
echo "완료"
|
||||
|
||||
echo "=== docker-compose 래퍼 설정 ==="
|
||||
if command -v docker-compose &>/dev/null; then
|
||||
echo "docker-compose 이미 설치됨 (스킵)"
|
||||
elif docker compose version &>/dev/null 2>&1; then
|
||||
cat > /usr/local/bin/docker-compose << 'EOF'
|
||||
#!/bin/bash
|
||||
exec docker compose "$@"
|
||||
EOF
|
||||
chmod +x /usr/local/bin/docker-compose
|
||||
echo "docker-compose → docker compose 래퍼 생성 완료"
|
||||
DOCKER_COMPOSE="docker-compose"
|
||||
else
|
||||
echo "[WARN] docker compose 를 찾을 수 없습니다. Docker 설치를 확인하세요."
|
||||
fi
|
||||
|
||||
echo "=== Docker network 설정 ==="
|
||||
if docker network ls --format '{{.Name}}' | grep -q "^kamco-cds$"; then
|
||||
echo "kamco-cds 네트워크 이미 존재 (스킵)"
|
||||
else
|
||||
docker network create kamco-cds
|
||||
echo "kamco-cds 네트워크 생성 완료"
|
||||
fi
|
||||
|
||||
echo "=== /etc/hosts 설정 ==="
|
||||
if grep -q "train-kamco.com" /etc/hosts; then
|
||||
echo "이미 설정되어 있음 (스킵)"
|
||||
else
|
||||
echo "127.0.0.1 api.train-kamco.com train-kamco.com" >> /etc/hosts
|
||||
echo "추가 완료"
|
||||
fi
|
||||
echo "현재 hosts 설정:"
|
||||
grep "train-kamco" /etc/hosts
|
||||
|
||||
echo ""
|
||||
echo "=== 설치 완료 ==="
|
||||
echo "생성된 디렉토리:"
|
||||
find /data -type d | sort
|
||||
echo ""
|
||||
echo "=== nginx 실행 방법 ==="
|
||||
if [ -n "$DOCKER_COMPOSE" ]; then
|
||||
echo "cd $NGINX_DIR && $DOCKER_COMPOSE -f docker-compose-nginx.yml up -d"
|
||||
else
|
||||
echo "[WARN] docker-compose / docker compose 를 찾을 수 없습니다. Docker 설치를 확인하세요."
|
||||
fi
|
||||
21
deploy/ssl/openssl.cnf
Normal file
21
deploy/ssl/openssl.cnf
Normal file
@@ -0,0 +1,21 @@
|
||||
[req]
|
||||
default_bits = 4096
|
||||
prompt = no
|
||||
default_md = sha256
|
||||
distinguished_name = dn
|
||||
req_extensions = v3_req
|
||||
|
||||
[dn]
|
||||
C=KR
|
||||
ST=Seoul
|
||||
L=Seoul
|
||||
O=KAMCO
|
||||
OU=Training
|
||||
CN=api.train-kamco.com
|
||||
|
||||
[v3_req]
|
||||
subjectAltName = @alt_names
|
||||
|
||||
[alt_names]
|
||||
DNS.1 = api.train-kamco.com
|
||||
DNS.2 = train-kamco.com
|
||||
38
docker-compose-dev-0420.yml
Normal file
38
docker-compose-dev-0420.yml
Normal file
@@ -0,0 +1,38 @@
|
||||
services:
|
||||
kamco-changedetection-api:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile-dev
|
||||
image: kamco-cd-training-api:${IMAGE_TAG:-latest}
|
||||
container_name: kamco-cd-training-api
|
||||
deploy:
|
||||
resources:
|
||||
reservations:
|
||||
devices:
|
||||
- driver: nvidia
|
||||
count: all
|
||||
capabilities: [gpu]
|
||||
ports:
|
||||
- "7200:8080"
|
||||
environment:
|
||||
- SPRING_PROFILES_ACTIVE=dev
|
||||
- TZ=Asia/Seoul
|
||||
volumes:
|
||||
- /mnt/nfs_share/images:/app/original-images
|
||||
- /mnt/nfs_share/model_output:/app/model-outputs
|
||||
- /mnt/nfs_share/train_dataset:/app/train-dataset
|
||||
- /home/kcomu/data:/home/kcomu/data
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
networks:
|
||||
- kamco-cds
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: [ "CMD", "curl", "-f", "http://localhost:8080/monitor/health" ]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 40s
|
||||
|
||||
networks:
|
||||
kamco-cds:
|
||||
external: true
|
||||
@@ -1,10 +1,7 @@
|
||||
services:
|
||||
kamco-changedetection-api:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile-dev
|
||||
image: kamco-cd-training-api:${IMAGE_TAG:-latest}
|
||||
container_name: kamco-cd-training-api
|
||||
image: kamco-train-app:latest
|
||||
container_name: kamco-train-api
|
||||
deploy:
|
||||
resources:
|
||||
reservations:
|
||||
@@ -12,16 +9,13 @@ services:
|
||||
- driver: nvidia
|
||||
count: all
|
||||
capabilities: [gpu]
|
||||
ports:
|
||||
- "7200:8080"
|
||||
environment:
|
||||
- SPRING_PROFILES_ACTIVE=dev
|
||||
- TZ=Asia/Seoul
|
||||
- cors.allowed-origins=*
|
||||
- cors.allowed-origins[0]=*
|
||||
volumes:
|
||||
- /mnt/nfs_share/images:/app/original-images
|
||||
- /mnt/nfs_share/model_output:/app/model-outputs
|
||||
- /mnt/nfs_share/train_dataset:/app/train-dataset
|
||||
- /home/kcomu/data:/home/kcomu/data
|
||||
- /data/training:/data/training
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
networks:
|
||||
- kamco-cds
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
services:
|
||||
kamco-train-api:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
image: kamco-train-api:${IMAGE_TAG:-latest}
|
||||
kamco-changedetection-api:
|
||||
image: kamco-train-app:latest
|
||||
container_name: kamco-train-api
|
||||
deploy:
|
||||
resources:
|
||||
@@ -17,9 +14,10 @@ services:
|
||||
environment:
|
||||
- SPRING_PROFILES_ACTIVE=prod
|
||||
- TZ=Asia/Seoul
|
||||
- cors.allowed-origins=*
|
||||
- cors.allowed-origins[0]=*
|
||||
volumes:
|
||||
- ./app/model_output:/app/model-outputs
|
||||
- ./app/train_dataset:/app/train-dataset
|
||||
- /data/training:/data/training
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
networks:
|
||||
- kamco-cds
|
||||
|
||||
@@ -20,14 +20,8 @@ http {
|
||||
# 업로드 파일 크기 제한 (10GB)
|
||||
client_max_body_size 10G;
|
||||
|
||||
# Upstream 설정
|
||||
upstream api_backend {
|
||||
server kamco-train-api:8080;
|
||||
}
|
||||
|
||||
upstream web_backend {
|
||||
server kamco-train-web:3002;
|
||||
}
|
||||
# Docker 내부 DNS - 시작 시 upstream 조회 실패 방지
|
||||
resolver 127.0.0.11 valid=30s ipv6=off;
|
||||
|
||||
# HTTP → HTTPS 리다이렉트 서버
|
||||
server {
|
||||
@@ -66,7 +60,8 @@ http {
|
||||
|
||||
# 프록시 설정
|
||||
location / {
|
||||
proxy_pass http://api_backend;
|
||||
set $api http://kamco-train-api:8080;
|
||||
proxy_pass $api;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
# 프록시 헤더 설정
|
||||
@@ -95,7 +90,8 @@ http {
|
||||
|
||||
# 헬스체크 엔드포인트
|
||||
location /monitor/health {
|
||||
proxy_pass http://api_backend/monitor/health;
|
||||
set $api http://kamco-train-api:8080;
|
||||
proxy_pass $api/monitor/health;
|
||||
access_log off;
|
||||
}
|
||||
}
|
||||
@@ -128,7 +124,8 @@ http {
|
||||
|
||||
# API 프록시 설정 (Web에서 API 호출 시)
|
||||
location /api/ {
|
||||
proxy_pass http://api_backend/api/;
|
||||
set $api http://kamco-train-api:8080;
|
||||
proxy_pass $api/api/;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
# 프록시 헤더 설정
|
||||
@@ -150,7 +147,8 @@ http {
|
||||
|
||||
# 프록시 설정
|
||||
location / {
|
||||
proxy_pass http://web_backend;
|
||||
set $web http://kamco-train-web:3002;
|
||||
proxy_pass $web;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
# 프록시 헤더 설정
|
||||
|
||||
@@ -30,20 +30,45 @@ token:
|
||||
swagger:
|
||||
local-port: 8080
|
||||
|
||||
# file:
|
||||
# dataset-dir: /home/kcomu/data/request/
|
||||
# dataset-tmp-dir: ${file.dataset-dir}tmp/
|
||||
|
||||
# pt-path: /home/kcomu/data/response/v6-cls-checkpoints/
|
||||
# pt-FileName: yolov8_6th-6m.pt
|
||||
|
||||
# train:
|
||||
# docker:
|
||||
# image: kamco-cd-train:latest
|
||||
# base_path: /home/kcomu/data
|
||||
# request_dir: ${train.docker.base_path}/request
|
||||
# response_dir: ${train.docker.base_path}/response
|
||||
# symbolic_link_dir: ${train.docker.base_path}/tmp
|
||||
# container_prefix: kamco-cd-train
|
||||
# shm_size: 16g
|
||||
# ipc_host: true
|
||||
|
||||
|
||||
file:
|
||||
dataset-dir: /home/kcomu/data/request/
|
||||
dataset-dir: /data/training/request/
|
||||
dataset-tmp-dir: ${file.dataset-dir}tmp/
|
||||
|
||||
pt-path: /home/kcomu/data/response/v6-cls-checkpoints/
|
||||
pt-path: /data/training/response/v6-cls-checkpoints/
|
||||
pt-FileName: yolov8_6th-6m.pt
|
||||
|
||||
train:
|
||||
docker:
|
||||
image: kamco-cd-train:latest
|
||||
base_path: /home/kcomu/data
|
||||
base_path: /data/training
|
||||
request_dir: ${train.docker.base_path}/request
|
||||
response_dir: ${train.docker.base_path}/response
|
||||
symbolic_link_dir: ${train.docker.base_path}/tmp
|
||||
container_prefix: kamco-cd-train
|
||||
shm_size: 16g
|
||||
ipc_host: true
|
||||
|
||||
hyper:
|
||||
parameter:
|
||||
gpus: 1
|
||||
gpu-ids: 0
|
||||
batch-size: 10
|
||||
Reference in New Issue
Block a user