#!/usr/bin/env bash set -euo pipefail ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" PKG_ROOT="$ROOT_DIR" ENV_EX="$PKG_ROOT/compose/.env.example" ENV_OUT="$PKG_ROOT/compose/.env" info(){ echo -e "\033[34m[CONFIG]\033[0m $*"; } err(){ echo -e "\033[31m[ERROR]\033[0m $*" >&2; } require(){ local ok=1; for c in "$@"; do command -v "$c" >/dev/null 2>&1 || { err "缺少依赖: $c"; ok=0; }; done; [[ $ok -eq 1 ]]; } # Compose 检测:优先 docker compose(v2),回退 docker-compose(v1) require_compose(){ if docker compose version >/dev/null 2>&1; then return 0; fi if command -v docker-compose >/dev/null 2>&1 && docker-compose version >/dev/null 2>&1; then return 0; fi err "未检测到 Docker Compose,请安装 docker compose v2 或 docker-compose v1"; exit 1 } require docker curl jq awk sed tar gzip require_compose # 磁盘空间检查(MB) check_disk(){ local p="$1"; local need=10240; local free free=$(df -Pm "$p" | awk 'NR==2{print $4+0}') if [[ -z "$free" || "$free" -lt "$need" ]]; then err "磁盘空间不足: $p 剩余 ${free:-0}MB (<${need}MB)"; return 1; fi } check_disk "$PKG_ROOT"; check_disk "/var/lib/docker" || true # 读取/生成 SWARM_MANAGER_ADDR SWARM_MANAGER_ADDR=${SWARM_MANAGER_ADDR:-} if [[ -z "${SWARM_MANAGER_ADDR}" ]]; then read -rp "请输入本机管理地址 SWARM_MANAGER_ADDR: " SWARM_MANAGER_ADDR fi info "SWARM_MANAGER_ADDR=$SWARM_MANAGER_ADDR" # 校验 IP 属于本机网卡 if ! ip -o addr | awk '{print $4}' | cut -d'/' -f1 | grep -qx "$SWARM_MANAGER_ADDR"; then err "SWARM_MANAGER_ADDR 非本机地址: $SWARM_MANAGER_ADDR"; exit 1; fi info "开始分配服务端口(起始=20000,避免系统占用与相互冲突)" is_port_used(){ local p="$1"; ss -tulnH 2>/dev/null | awk '{print $5}' | sed 's/.*://g' | grep -qx "$p"; } declare -A PRESENT=() CHOSEN=() USED=() START_PORT="${START_PORT:-20000}"; cur=$START_PORT ORDER=(MASTER_PORT ES_HTTP_PORT KIBANA_PORT PROMETHEUS_PORT GRAFANA_PORT ALERTMANAGER_PORT \ WEB_PROXY_PORT_8080 WEB_PROXY_PORT_8081 WEB_PROXY_PORT_8082 WEB_PROXY_PORT_8083 WEB_PROXY_PORT_8084 WEB_PROXY_PORT_8085 \ FTP_PORT FTP_DATA_PORT) # 标记 .env.example 中实际存在的键 for key in "${ORDER[@]}"; do if grep -q "^${key}=" "$ENV_EX"; then PRESENT[$key]=1; fi done next_free(){ local p="$1"; while :; do if [[ -n "${USED[$p]:-}" ]] || is_port_used "$p"; then p=$((p+1)); else echo "$p"; return; fi; done; } for key in "${ORDER[@]}"; do [[ -z "${PRESENT[$key]:-}" ]] && continue p=$(next_free "$cur"); CHOSEN[$key]="$p"; USED[$p]=1; cur=$((p+1)) done info "端口分配结果:MASTER=${CHOSEN[MASTER_PORT]:-} ES=${CHOSEN[ES_HTTP_PORT]:-} KIBANA=${CHOSEN[KIBANA_PORT]:-} PROM=${CHOSEN[PROMETHEUS_PORT]:-} GRAFANA=${CHOSEN[GRAFANA_PORT]:-} ALERT=${CHOSEN[ALERTMANAGER_PORT]:-} WEB_PROXY(8080..8085)=${CHOSEN[WEB_PROXY_PORT_8080]:-}/${CHOSEN[WEB_PROXY_PORT_8081]:-}/${CHOSEN[WEB_PROXY_PORT_8082]:-}/${CHOSEN[WEB_PROXY_PORT_8083]:-}/${CHOSEN[WEB_PROXY_PORT_8084]:-}/${CHOSEN[WEB_PROXY_PORT_8085]:-}" cp "$ENV_EX" "$ENV_OUT" # 覆盖端口(按唯一化结果写回) for key in "${ORDER[@]}"; do val="${CHOSEN[$key]:-}" [[ -z "$val" ]] && continue sed -i -E "s#^$key=.*#$key=${val}#" "$ENV_OUT" done info "已写入 compose/.env 的端口配置" # 覆盖/补充 Overlay 名称 grep -q '^ARGUS_OVERLAY_NET=' "$ENV_OUT" || echo 'ARGUS_OVERLAY_NET=argus-sys-net' >> "$ENV_OUT" # 以当前执行账户 UID/GID 写入(避免误选 docker 组) RUID=$(id -u) PRIMARY_GID=$(id -g) PRIMARY_GRP=$(id -gn) USER_NAME=$(id -un) # 若主组名被解析为 docker,尝试用与用户名同名的组的 GID;否则回退主 GID if [[ "$PRIMARY_GRP" == "docker" ]]; then RGID=$(getent group "$USER_NAME" | awk -F: '{print $3}' 2>/dev/null || true) [[ -z "$RGID" ]] && RGID="$PRIMARY_GID" else RGID="$PRIMARY_GID" fi info "使用构建账户 UID:GID=${RUID}:${RGID} (user=$USER_NAME primary_group=$PRIMARY_GRP)" if grep -q '^ARGUS_BUILD_UID=' "$ENV_OUT"; then sed -i -E "s#^ARGUS_BUILD_UID=.*#ARGUS_BUILD_UID=${RUID}#" "$ENV_OUT" else echo "ARGUS_BUILD_UID=${RUID}" >> "$ENV_OUT" fi if grep -q '^ARGUS_BUILD_GID=' "$ENV_OUT"; then sed -i -E "s#^ARGUS_BUILD_GID=.*#ARGUS_BUILD_GID=${RGID}#" "$ENV_OUT" else echo "ARGUS_BUILD_GID=${RGID}" >> "$ENV_OUT" fi CI="$PKG_ROOT/cluster-info.env" if [[ -f "$CI" ]]; then if grep -q '^SWARM_MANAGER_ADDR=' "$CI"; then sed -i -E "s#^SWARM_MANAGER_ADDR=.*#SWARM_MANAGER_ADDR=${SWARM_MANAGER_ADDR}#" "$CI" else echo "SWARM_MANAGER_ADDR=${SWARM_MANAGER_ADDR}" >> "$CI" fi else echo "SWARM_MANAGER_ADDR=${SWARM_MANAGER_ADDR}" > "$CI" fi info "已生成 compose/.env 并更新 cluster-info.env 的 SWARM_MANAGER_ADDR。" info "下一步可执行: scripts/install.sh"