359afb3a59
Infrastructure configs for GMKtec K11 (Docker, vLLM, LocalAI, ComfyUI, control-plane, gpu-fan agent, Server UI with CLI/file explorer/GPU fan curve). Co-authored-by: Cursor <cursoragent@cursor.com>
108 lines
3.1 KiB
Bash
Executable File
108 lines
3.1 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Install Server UI as Docker container (profile server-ui).
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
STACK_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
|
CONTROL_PLANE_STACK="$(cd "${STACK_DIR}/../control-plane" && pwd)"
|
|
SERVICE_NAME="server-ui.service"
|
|
UI_PORT="${SERVER_UI_PORT:-8091}"
|
|
ENV_FILE="${CONTROL_PLANE_STACK}/.env"
|
|
|
|
if [[ "${EUID}" -ne 0 ]]; then
|
|
echo "Run as root: sudo ${SCRIPT_DIR}/install-docker.sh"
|
|
exit 1
|
|
fi
|
|
|
|
set_env_var() {
|
|
local file="$1" key="$2" val="$3"
|
|
if grep -q "^${key}=" "${file}"; then
|
|
sed -i "s|^${key}=.*|${key}=${val}|" "${file}"
|
|
else
|
|
echo "${key}=${val}" >> "${file}"
|
|
fi
|
|
}
|
|
|
|
detect_repo_root() {
|
|
if [[ -n "${REPO_ROOT:-}" ]]; then
|
|
echo "${REPO_ROOT}"
|
|
return
|
|
fi
|
|
local candidate
|
|
candidate="$(cd "${STACK_DIR}/../.." && pwd)"
|
|
if [[ -d "${candidate}/stacks/localai" ]]; then
|
|
echo "${candidate}"
|
|
return
|
|
fi
|
|
echo "${candidate}"
|
|
}
|
|
|
|
echo "=== Server UI — install (Docker) ==="
|
|
|
|
if ! command -v docker >/dev/null 2>&1; then
|
|
echo "ERROR: docker not found. Install Docker CE first."
|
|
exit 1
|
|
fi
|
|
|
|
bash "${SCRIPT_DIR}/setup-control-plane-env.sh"
|
|
|
|
REPO_ROOT_VAL="$(detect_repo_root)"
|
|
DOCKER_GID="$(getent group docker | cut -d: -f3 || echo 999)"
|
|
|
|
if [[ ! -f "${ENV_FILE}" ]]; then
|
|
cp "${CONTROL_PLANE_STACK}/.env.example" "${ENV_FILE}"
|
|
fi
|
|
|
|
set_env_var "${ENV_FILE}" "REPO_ROOT" "${REPO_ROOT_VAL}"
|
|
set_env_var "${ENV_FILE}" "SERVER_UI_HOST" "0.0.0.0"
|
|
set_env_var "${ENV_FILE}" "SERVER_UI_PORT" "${UI_PORT}"
|
|
set_env_var "${ENV_FILE}" "GPU_FAN_AGENT_URL" "http://host.docker.internal:18090"
|
|
set_env_var "${ENV_FILE}" "DOCKER_GID" "${DOCKER_GID}"
|
|
|
|
# Disable native systemd if present
|
|
if systemctl is-enabled "${SERVICE_NAME}" &>/dev/null; then
|
|
echo "Disabling native ${SERVICE_NAME}..."
|
|
systemctl disable --now "${SERVICE_NAME}" 2>/dev/null || true
|
|
fi
|
|
|
|
cd "${STACK_DIR}"
|
|
export REPO_ROOT="${REPO_ROOT_VAL}"
|
|
export DOCKER_GID
|
|
|
|
echo "Building server-ui image..."
|
|
docker compose --profile server-ui build
|
|
|
|
echo "Starting server-ui container..."
|
|
docker compose --profile server-ui up -d
|
|
|
|
sleep 2
|
|
|
|
LAN_IP="$(hostname -I 2>/dev/null | awk '{print $1}')"
|
|
API_KEY_VAL="$(grep '^API_KEY=' "${ENV_FILE}" | cut -d= -f2- || true)"
|
|
|
|
echo ""
|
|
echo "Runtime: Docker (profile server-ui)"
|
|
echo "Repo mount: ${REPO_ROOT_VAL} → /repo"
|
|
echo "Env: ${ENV_FILE}"
|
|
echo "Container: $(docker compose --profile server-ui ps --format '{{.Name}} {{.Status}}' 2>/dev/null || docker ps --filter name=server-ui --format '{{.Names}} {{.Status}}')"
|
|
echo ""
|
|
echo "Web UI (LAN):"
|
|
echo " http://${LAN_IP:-<server-ip>}:${UI_PORT}/"
|
|
echo ""
|
|
echo "API key:"
|
|
echo " grep ^API_KEY= ${ENV_FILE}"
|
|
echo ""
|
|
|
|
if [[ -n "${API_KEY_VAL}" ]]; then
|
|
HEALTH="$(curl -sf "http://127.0.0.1:${UI_PORT}/api/health" 2>/dev/null || echo '{"ok":false}')"
|
|
echo "Health: ${HEALTH}"
|
|
GF_HEALTH="$(curl -sf "http://127.0.0.1:${UI_PORT}/api/gpu-fan/health" -H "X-API-Key: ${API_KEY_VAL}" 2>/dev/null || echo '{"ok":false}')"
|
|
echo "GPU Fan proxy: ${GF_HEALTH}"
|
|
fi
|
|
|
|
echo ""
|
|
echo "Logs:"
|
|
echo " docker compose --profile server-ui logs -f"
|
|
echo "Stop:"
|
|
echo " docker compose --profile server-ui down"
|