Compare commits
3 Commits
v1.0.0
...
af7cfbe74b
| Author | SHA1 | Date | |
|---|---|---|---|
| af7cfbe74b | |||
| 3e38770473 | |||
| d130924b1a |
1
deployment/.gitignore
vendored
Normal file
1
deployment/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
artifact/
|
||||
16
deployment/build/README.md
Normal file
16
deployment/build/README.md
Normal file
@@ -0,0 +1,16 @@
|
||||
# Deployment Build Toolkit
|
||||
|
||||
This folder provides scripts to produce offline server/client packages and publish the client package to FTP.
|
||||
|
||||
Commands
|
||||
- build_server_package.sh [--version YYYYMMDD]
|
||||
- build_client_package.sh [--version YYYYMMDD]
|
||||
- publish_client.sh --version YYYYMMDD --server <host> --user ftpuser --password <pass> [--port 21]
|
||||
|
||||
Outputs
|
||||
- deployment/artifact/server/<YYYYMMDD>/
|
||||
- deployment/artifact/client/<YYYYMMDD>/
|
||||
|
||||
Notes
|
||||
- Server package contains docker images (single all-images.tar.gz), compose/, scripts/, docs/, private/ skeleton.
|
||||
- Client package reuses all-in-one-full artifact, repacked as argus-metric_<YYYYMMDD>.tar.gz (compatible with setup.sh).
|
||||
56
deployment/build/build_client_package.sh
Normal file
56
deployment/build/build_client_package.sh
Normal file
@@ -0,0 +1,56 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
BUILD_DIR="$ROOT_DIR/deployment/build"
|
||||
ART_ROOT="$ROOT_DIR/deployment/artifact"
|
||||
|
||||
. "$BUILD_DIR/common.sh"
|
||||
|
||||
usage() { cat <<'EOF'
|
||||
Build Argus Client Offline Package
|
||||
|
||||
Usage: build_client_package.sh [--version YYYYMMDD] [--out DIR]
|
||||
|
||||
Produces: deployment/artifact/client/<YYYYMMDD>/argus-metric_<YYYYMMDD>.tar.gz
|
||||
EOF
|
||||
}
|
||||
|
||||
VERSION="$(today_version)"
|
||||
OUT_DIR=""
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--version) VERSION="$2"; shift 2;;
|
||||
--out) OUT_DIR="$2"; shift 2;;
|
||||
-h|--help) usage; exit 0;;
|
||||
*) err "unknown arg: $1"; usage; exit 1;;
|
||||
esac
|
||||
done
|
||||
|
||||
PKG_DIR="${OUT_DIR:-$ART_ROOT/client/$VERSION}"
|
||||
make_dir "$PKG_DIR"
|
||||
|
||||
log "Packaging client from all-in-one-full artifact"
|
||||
PLUGIN_DIR="$ROOT_DIR/src/metric/client-plugins/all-in-one-full"
|
||||
require_cmd bash tar gzip
|
||||
|
||||
(cd "$PLUGIN_DIR" && bash scripts/package_artifact.sh --force)
|
||||
|
||||
# pick latest artifact dir
|
||||
ART_BASE="$PLUGIN_DIR/artifact"
|
||||
latest_dir=$(ls -1dt "$ART_BASE"/*/ 2>/dev/null | head -n1 || true)
|
||||
[[ -n "$latest_dir" ]] || { err "no client artifact found in $ART_BASE"; exit 1; }
|
||||
|
||||
tmpdir=$(mktemp -d)
|
||||
trap 'rm -rf "$tmpdir"' EXIT
|
||||
rsync -a "$latest_dir" "$tmpdir/src" >/dev/null 2>&1 || cp -r "$latest_dir" "$tmpdir/src"
|
||||
|
||||
out_name="argus-metric_$(echo "$VERSION" | sed 's/\./_/g').tar.gz"
|
||||
|
||||
(cd "$tmpdir/src" && tar -czf "$PKG_DIR/$out_name" .)
|
||||
|
||||
log "Client package ready: $PKG_DIR/$out_name"
|
||||
echo "$VERSION" > "$PKG_DIR/LATEST_VERSION"
|
||||
|
||||
exit 0
|
||||
|
||||
116
deployment/build/build_server_package.sh
Normal file
116
deployment/build/build_server_package.sh
Normal file
@@ -0,0 +1,116 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
BUILD_DIR="$ROOT_DIR/deployment/build"
|
||||
ART_ROOT="$ROOT_DIR/deployment/artifact"
|
||||
|
||||
. "$BUILD_DIR/common.sh"
|
||||
|
||||
usage() { cat <<'EOF'
|
||||
Build Argus Server Offline Package
|
||||
|
||||
Usage: build_server_package.sh [--version YYYYMMDD] [--out DIR] [--resave-image]
|
||||
|
||||
Outputs into deployment/artifact/server/<YYYYMMDD>/ by default.
|
||||
EOF
|
||||
}
|
||||
|
||||
VERSION="$(today_version)"
|
||||
OUT_DIR=""
|
||||
RESAVE_IMAGE=false
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--version) VERSION="$2"; shift 2;;
|
||||
--out) OUT_DIR="$2"; shift 2;;
|
||||
--resave-image) RESAVE_IMAGE=true; shift;;
|
||||
-h|--help) usage; exit 0;;
|
||||
*) err "unknown arg: $1"; usage; exit 1;;
|
||||
esac
|
||||
done
|
||||
|
||||
PKG_DIR="${OUT_DIR:-$ART_ROOT/server/$VERSION}"
|
||||
STAGE="$(mktemp -d)"
|
||||
trap 'rm -rf "$STAGE"' EXIT
|
||||
|
||||
log "Version: $VERSION"
|
||||
log "Staging: $STAGE"
|
||||
|
||||
# 1) Layout
|
||||
make_dir "$STAGE/images"
|
||||
make_dir "$STAGE/compose"
|
||||
make_dir "$STAGE/scripts"
|
||||
make_dir "$STAGE/docs"
|
||||
make_dir "$STAGE/private/argus"
|
||||
|
||||
# 2) Compose: derive from sys/tests by removing test-only services
|
||||
SRC_COMPOSE="$ROOT_DIR/src/sys/tests/docker-compose.yml"
|
||||
[[ -f "$SRC_COMPOSE" ]] || { err "missing $SRC_COMPOSE"; exit 1; }
|
||||
awk -f "$BUILD_DIR/templates/docker-compose.filter.awk" -v remove="node-a,node-b,test-node,test-gpu-node" "$SRC_COMPOSE" > "$STAGE/compose/docker-compose.yml"
|
||||
cp "$BUILD_DIR/templates/.env.example" "$STAGE/compose/.env.example"
|
||||
|
||||
# 3) Images (reuse if already exported unless --resave-image)
|
||||
existing_images_tar="$PKG_DIR/images/all-images.tar.gz"
|
||||
if [[ "$RESAVE_IMAGE" == false && -f "$existing_images_tar" ]]; then
|
||||
log "Reusing existing images tar: $existing_images_tar"
|
||||
cp "$existing_images_tar" "$STAGE/images/"
|
||||
else
|
||||
require_cmd docker gzip
|
||||
images=(
|
||||
argus-bind9:latest
|
||||
argus-master:latest
|
||||
argus-elasticsearch:latest
|
||||
argus-kibana:latest
|
||||
argus-metric-ftp:latest
|
||||
argus-metric-prometheus:latest
|
||||
argus-metric-grafana:latest
|
||||
argus-alertmanager:latest
|
||||
argus-web-frontend:latest
|
||||
argus-web-proxy:latest
|
||||
)
|
||||
log "Saving images: ${#images[@]}"
|
||||
tarfile="$STAGE/images/all-images.tar"
|
||||
docker save -o "$tarfile" "${images[@]}"
|
||||
gzip -f "$tarfile"
|
||||
fi
|
||||
|
||||
# 4) Scripts & Docs
|
||||
copy_tree "$BUILD_DIR/templates/scripts" "$STAGE/scripts"
|
||||
cat > "$STAGE/docs/INSTALL_SERVER.md" << 'MD'
|
||||
# Argus Server Offline Installation
|
||||
|
||||
## Prerequisites
|
||||
- Ubuntu 22.04 x86_64
|
||||
- Docker & Docker Compose installed
|
||||
- Open ports: 32300,9200,5601,9090,9093,8080..8085,21,20,21100-21110 (or auto-fallback to high ports)
|
||||
|
||||
## Steps
|
||||
1. Extract this package to /opt/argus-deploy/versions/<YYYYMMDD>
|
||||
2. cd scripts && sudo ./server-install.sh
|
||||
3. Check status: ./server-status.sh
|
||||
4. Uninstall: ./server-uninstall.sh
|
||||
|
||||
## Notes
|
||||
- Selfcheck result is written to logs/selfcheck.json
|
||||
- DNS will be managed by internal bind; FTP dns.conf is auto-published to share/dns.conf
|
||||
MD
|
||||
|
||||
# 5) Manifests
|
||||
gen_manifest "$STAGE" "$STAGE/manifest.txt"
|
||||
checksum_dir "$STAGE" "$STAGE/checksums.txt"
|
||||
|
||||
# 6) Move to artifact
|
||||
make_dir "$PKG_DIR"
|
||||
rsync -a "$STAGE/" "$PKG_DIR/" 2>/dev/null || cp -r "$STAGE/." "$PKG_DIR/"
|
||||
log "Server package ready: $PKG_DIR"
|
||||
|
||||
echo "$VERSION" > "$PKG_DIR/version.json"
|
||||
|
||||
# 7) Create distributable tarball
|
||||
OUT_TAR_DIR="$(dirname "$PKG_DIR")"
|
||||
OUT_TAR="$OUT_TAR_DIR/server_${VERSION}.tar.gz"
|
||||
log "Creating tarball: $OUT_TAR"
|
||||
(cd "$PKG_DIR/.." && tar -czf "$OUT_TAR" "$(basename "$PKG_DIR")")
|
||||
log "Tarball ready: $OUT_TAR"
|
||||
|
||||
exit 0
|
||||
33
deployment/build/common.sh
Normal file
33
deployment/build/common.sh
Normal file
@@ -0,0 +1,33 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
log() { echo -e "\033[0;34m[INFO]\033[0m $*"; }
|
||||
warn() { echo -e "\033[1;33m[WARN]\033[0m $*"; }
|
||||
err() { echo -e "\033[0;31m[ERR ]\033[0m $*" >&2; }
|
||||
|
||||
require_cmd() {
|
||||
for c in "$@"; do
|
||||
command -v "$c" >/dev/null 2>&1 || { err "missing command: $c"; exit 1; }
|
||||
done
|
||||
}
|
||||
|
||||
today_version() {
|
||||
date +%Y%m%d
|
||||
}
|
||||
|
||||
checksum_dir() {
|
||||
local dir="$1"; local out="$2"; : > "$out";
|
||||
(cd "$dir" && find . -type f -print0 | sort -z | xargs -0 sha256sum) >> "$out"
|
||||
}
|
||||
|
||||
make_dir() { mkdir -p "$1"; }
|
||||
|
||||
copy_tree() {
|
||||
local src="$1" dst="$2"; rsync -a --delete "$src/" "$dst/" 2>/dev/null || cp -r "$src/." "$dst/";
|
||||
}
|
||||
|
||||
gen_manifest() {
|
||||
local root="$1"; local out="$2"; : > "$out";
|
||||
(cd "$root" && find . -maxdepth 3 -type f -printf "%p\n" | sort) >> "$out"
|
||||
}
|
||||
|
||||
57
deployment/build/publish_client.sh
Normal file
57
deployment/build/publish_client.sh
Normal file
@@ -0,0 +1,57 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
. "$ROOT_DIR/build/common.sh"
|
||||
|
||||
usage() { cat <<'EOF'
|
||||
Publish client package to FTP server
|
||||
|
||||
Usage: publish_client.sh --version YYYYMMDD --server HOST --user USER --password PASS [--port 21]
|
||||
|
||||
It uploads: setup.sh, argus-metric_<YYYYMMDD>.tar.gz, LATEST_VERSION to the FTP share root.
|
||||
EOF
|
||||
}
|
||||
|
||||
VERSION=""; HOST=""; USERNAME=""; PASSWORD=""; PORT=21
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--version) VERSION="$2"; shift 2;;
|
||||
--server) HOST="$2"; shift 2;;
|
||||
--user) USERNAME="$2"; shift 2;;
|
||||
--password) PASSWORD="$2"; shift 2;;
|
||||
--port) PORT="$2"; shift 2;;
|
||||
-h|--help) usage; exit 0;;
|
||||
*) err "unknown arg: $1"; usage; exit 1;;
|
||||
esac
|
||||
done
|
||||
|
||||
[[ -n "$VERSION" && -n "$HOST" && -n "$USERNAME" && -n "$PASSWORD" ]] || { usage; exit 1; }
|
||||
|
||||
CLIENT_DIR="$ROOT_DIR/artifact/client/$VERSION"
|
||||
TAR_NAME="argus-metric_${VERSION}.tar.gz"
|
||||
PKG="$CLIENT_DIR/$TAR_NAME"
|
||||
SETUP_SRC="$ROOT_DIR/../src/sys/tests/private/argus/metric/ftp/share/setup.sh"
|
||||
ALT_SETUP="$ROOT_DIR/../src/metric/client-plugins/all-in-one-full/scripts/setup.sh"
|
||||
|
||||
[[ -f "$PKG" ]] || { err "missing client package: $PKG"; exit 1; }
|
||||
if [[ ! -f "$SETUP_SRC" ]]; then
|
||||
if [[ -f "$ALT_SETUP" ]]; then
|
||||
SETUP_SRC="$ALT_SETUP"
|
||||
else
|
||||
err "missing setup.sh (checked $SETUP_SRC and $ALT_SETUP)"; exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
log "Uploading setup.sh"
|
||||
curl -u "$USERNAME:$PASSWORD" -sfT "$SETUP_SRC" "ftp://$HOST:$PORT/setup.sh"
|
||||
|
||||
log "Uploading client tar: $TAR_NAME"
|
||||
curl -u "$USERNAME:$PASSWORD" -sfT "$PKG" "ftp://$HOST:$PORT/$TAR_NAME"
|
||||
|
||||
log "Updating LATEST_VERSION -> $VERSION"
|
||||
printf "%s" "$VERSION" | curl -u "$USERNAME:$PASSWORD" -sfT - "ftp://$HOST:$PORT/LATEST_VERSION"
|
||||
|
||||
log "Publish done"
|
||||
|
||||
exit 0
|
||||
29
deployment/build/templates/.env.example
Normal file
29
deployment/build/templates/.env.example
Normal file
@@ -0,0 +1,29 @@
|
||||
# UID/GID for service processes
|
||||
ARGUS_BUILD_UID=1000
|
||||
ARGUS_BUILD_GID=1000
|
||||
|
||||
# Host ports (adjust if occupied)
|
||||
MASTER_PORT=32300
|
||||
ES_HTTP_PORT=9200
|
||||
KIBANA_PORT=5601
|
||||
NODE_A_PORT=2020
|
||||
NODE_B_PORT=2021
|
||||
PROMETHEUS_PORT=9090
|
||||
GRAFANA_PORT=3000
|
||||
ALERTMANAGER_PORT=9093
|
||||
WEB_PROXY_PORT_8080=8080
|
||||
WEB_PROXY_PORT_8081=8081
|
||||
WEB_PROXY_PORT_8082=8082
|
||||
WEB_PROXY_PORT_8083=8083
|
||||
WEB_PROXY_PORT_8084=8084
|
||||
WEB_PROXY_PORT_8085=8085
|
||||
|
||||
# FTP
|
||||
FTP_PORT=21
|
||||
FTP_DATA_PORT=20
|
||||
FTP_PASSIVE_HOST_RANGE=21100-21110
|
||||
FTP_PASSWORD=ZGClab1234!
|
||||
FTP_DOMAIN=ftp.metric.argus.com
|
||||
|
||||
# GPU profile disabled by default
|
||||
ENABLE_GPU=false
|
||||
41
deployment/build/templates/docker-compose.filter.awk
Normal file
41
deployment/build/templates/docker-compose.filter.awk
Normal file
@@ -0,0 +1,41 @@
|
||||
#!/usr/bin/awk -f
|
||||
# Remove specific service blocks from a docker-compose.yml by service name.
|
||||
# Usage: awk -f docker-compose.filter.awk -v remove="node-a,node-b,test-node,test-gpu-node" input.yml > output.yml
|
||||
|
||||
BEGIN{
|
||||
split(remove, rm, ",");
|
||||
for(i in rm) skipname[rm[i]] = 1;
|
||||
}
|
||||
|
||||
function starts_service_line(line, name) {
|
||||
if (match(line, /^\s{2}([a-zA-Z0-9_-]+):\s*$/, m)) {
|
||||
name = m[1];
|
||||
return name;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
{
|
||||
name = starts_service_line($0);
|
||||
if (name != "") {
|
||||
# detect top-level keys (networks:, services:, etc.)
|
||||
if ($0 ~ /^services:\s*$/) { in_services=1; print; next; }
|
||||
if ($0 ~ /^[a-zA-Z0-9_-]+:\s*$/ && $0 !~ /^\s/) {
|
||||
in_services= ($0 ~ /^services:\s*$/);
|
||||
}
|
||||
|
||||
if (in_services && (name in skipname)) {
|
||||
skipping=1; next;
|
||||
}
|
||||
}
|
||||
|
||||
# end skipping when next top-level service appears
|
||||
if (skipping) {
|
||||
if (starts_service_line($0) != "") { skipping=0; }
|
||||
else if ($0 ~ /^(networks|volumes):\s*$/) { skipping=0; }
|
||||
else { next; }
|
||||
}
|
||||
|
||||
print;
|
||||
}
|
||||
|
||||
72
deployment/build/templates/scripts/server-install.sh
Normal file
72
deployment/build/templates/scripts/server-install.sh
Normal file
@@ -0,0 +1,72 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PKG_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" # version root
|
||||
|
||||
PROJECT_NAME="argus-sys"
|
||||
|
||||
log() { echo -e "\033[0;34m[INSTALL]\033[0m $*"; }
|
||||
err() { echo -e "\033[0;31m[ERROR ]\033[0m $*" >&2; }
|
||||
|
||||
require() { command -v "$1" >/dev/null 2>&1 || { err "missing command: $1"; exit 1; }; }
|
||||
|
||||
require docker
|
||||
if docker compose version >/dev/null 2>&1; then COMPOSE=(docker compose); else require docker-compose; COMPOSE=(docker-compose); fi
|
||||
|
||||
ENV_FILE="$PKG_ROOT/compose/.env"
|
||||
ENV_TEMPLATE="$PKG_ROOT/compose/.env.example"
|
||||
|
||||
find_free_port() {
|
||||
local prefer="$1"; local start=${2:-20000}; local max=${3:-65000};
|
||||
if ! ss -ltnH 2>/dev/null | awk -v pat=":"$prefer"$" '$4 ~ pat{f=1} END{exit f?0:1}'; then echo "$prefer"; return; fi
|
||||
for ((p=start; p<=max; p++)); do
|
||||
if ! ss -ltnH 2>/dev/null | awk -v pat=":"$p"$" '$4 ~ pat{f=1} END{exit f?0:1}'; then echo "$p"; return; fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
prepare_env() {
|
||||
if [[ -f "$ENV_FILE" ]]; then log ".env exists, keep as-is"; return; fi
|
||||
[[ -f "$ENV_TEMPLATE" ]] || { err "missing $ENV_TEMPLATE"; exit 1; }
|
||||
cp "$ENV_TEMPLATE" "$ENV_FILE"
|
||||
# auto-assign ports if busy
|
||||
for key in MASTER_PORT ES_HTTP_PORT KIBANA_PORT NODE_A_PORT NODE_B_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; do
|
||||
val=$(grep -E "^${key}=" "$ENV_FILE" | tail -1 | cut -d= -f2)
|
||||
new=$(find_free_port "$val") || true
|
||||
if [[ -n "${new:-}" && "$new" != "$val" ]]; then
|
||||
sed -i "s/^${key}=.*/${key}=${new}/" "$ENV_FILE"
|
||||
log "port ${key} busy -> ${new}"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
load_images() {
|
||||
local tar="$PKG_ROOT/images/all-images.tar.gz"
|
||||
[[ -f "$tar" ]] || { err "missing images tar: $tar"; exit 1; }
|
||||
log "loading images from $(basename "$tar") (may take minutes)"
|
||||
gunzip -c "$tar" | docker load >/dev/null
|
||||
}
|
||||
|
||||
bring_up() {
|
||||
log "starting services via compose"
|
||||
(cd "$PKG_ROOT/compose" && "${COMPOSE[@]}" -p "$PROJECT_NAME" up -d)
|
||||
}
|
||||
|
||||
selfcheck() {
|
||||
log "running selfcheck"
|
||||
bash "$PKG_ROOT/scripts/server-selfcheck.sh" || { err "selfcheck failed"; exit 1; }
|
||||
}
|
||||
|
||||
main() {
|
||||
prepare_env
|
||||
load_images
|
||||
bring_up
|
||||
selfcheck
|
||||
log "install completed. See logs in $PKG_ROOT/logs/"
|
||||
}
|
||||
|
||||
main "$@"
|
||||
|
||||
75
deployment/build/templates/scripts/server-selfcheck.sh
Normal file
75
deployment/build/templates/scripts/server-selfcheck.sh
Normal file
@@ -0,0 +1,75 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
|
||||
log() { echo -e "\033[0;34m[CHECK]\033[0m $*"; }
|
||||
err() { echo -e "\033[0;31m[ERROR]\033[0m $*" >&2; }
|
||||
|
||||
ENV_FILE="$ROOT/compose/.env"; [[ -f "$ENV_FILE" ]] && set -a && source "$ENV_FILE" && set +a
|
||||
|
||||
wait_http() { local url="$1"; local attempts=${2:-120}; local i=1; while ((i<=attempts)); do curl -fsS "$url" >/dev/null 2>&1 && return 0; echo "[..] waiting $url ($i/$attempts)"; sleep 5; ((i++)); done; return 1; }
|
||||
code_for() { curl -s -o /dev/null -w "%{http_code}" "$1" || echo 000; }
|
||||
header_val() { curl -s -D - -o /dev/null "$@" | awk -F': ' 'BEGIN{IGNORECASE=1}$1=="Access-Control-Allow-Origin"{gsub("\r","",$2);print $2}'; }
|
||||
|
||||
mkdir -p "$ROOT/logs"
|
||||
OUT_JSON="$ROOT/logs/selfcheck.json"
|
||||
tmp=$(mktemp)
|
||||
|
||||
ok=1
|
||||
|
||||
log "checking Elasticsearch"
|
||||
if curl -fsS "http://localhost:${ES_HTTP_PORT:-9200}/_cluster/health?wait_for_status=yellow&timeout=1s" >/dev/null 2>&1; then es_ok=true; else es_ok=false; ok=0; fi
|
||||
|
||||
log "checking Kibana"
|
||||
kb_code=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:${KIBANA_PORT:-5601}/api/status" || echo 000)
|
||||
kb_ok=false
|
||||
if [[ "$kb_code" == "200" ]]; then body=$(curl -sS "http://localhost:${KIBANA_PORT:-5601}/api/status"); echo "$body" | grep -q '"level":"available"' && kb_ok=true; fi
|
||||
[[ "$kb_ok" == true ]] || ok=0
|
||||
|
||||
log "checking Master"
|
||||
wait_http "http://localhost:${MASTER_PORT:-32300}/readyz" 60 || ok=0
|
||||
|
||||
log "checking FTP"
|
||||
ftp_root="$ROOT/private/argus/metric/ftp/share"; [[ -d "$ftp_root" && -w "$ftp_root" ]] && ftp_ok=true || { ftp_ok=false; ok=0; }
|
||||
|
||||
log "checking Prometheus"
|
||||
wait_http "http://localhost:${PROMETHEUS_PORT:-9090}/-/ready" 60 || ok=0
|
||||
|
||||
log "checking Grafana"
|
||||
gf_code=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:${GRAFANA_PORT:-3000}/api/health" || echo 000)
|
||||
gf_ok=false; if [[ "$gf_code" == "200" ]]; then body=$(curl -sS "http://localhost:${GRAFANA_PORT:-3000}/api/health"); echo "$body" | grep -q '"database"\s*:\s*"ok"' && gf_ok=true; fi
|
||||
[[ "$gf_ok" == true ]] || ok=0
|
||||
|
||||
log "checking Alertmanager"
|
||||
wait_http "http://localhost:${ALERTMANAGER_PORT:-9093}/api/v2/status" 60 || ok=0
|
||||
|
||||
log "checking Web-Proxy"
|
||||
p8080=$(code_for "http://localhost:${WEB_PROXY_PORT_8080:-8080}/")
|
||||
p8083=$(code_for "http://localhost:${WEB_PROXY_PORT_8083:-8083}/")
|
||||
cors8084=$(header_val -H "Origin: http://localhost:${WEB_PROXY_PORT_8080:-8080}" "http://localhost:${WEB_PROXY_PORT_8084:-8084}/api/v2/status" || true)
|
||||
cors8085=$(header_val -H "Origin: http://localhost:${WEB_PROXY_PORT_8080:-8080}" "http://localhost:${WEB_PROXY_PORT_8085:-8085}/api/v1/master/nodes" || true)
|
||||
wp_ok=true
|
||||
[[ "$p8080" == 200 ]] || wp_ok=false
|
||||
([[ "$p8083" == 200 || "$p8083" == 302 ]]) || wp_ok=false
|
||||
[[ -n "$cors8084" && -n "$cors8085" ]] || wp_ok=false
|
||||
[[ "$wp_ok" == true ]] || ok=0
|
||||
|
||||
cat > "$tmp" <<JSON
|
||||
{
|
||||
"es": $es_ok,
|
||||
"kibana": $kb_ok,
|
||||
"master_readyz": true,
|
||||
"ftp_share_writable": $ftp_ok,
|
||||
"prometheus": true,
|
||||
"grafana": $gf_ok,
|
||||
"alertmanager": true,
|
||||
"web_proxy": $wp_ok,
|
||||
"timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||
}
|
||||
JSON
|
||||
|
||||
mv "$tmp" "$OUT_JSON"
|
||||
[[ "$ok" == 1 ]] && { log "selfcheck OK"; exit 0; } || { err "selfcheck FAILED (see $OUT_JSON)"; exit 1; }
|
||||
|
||||
28
deployment/build/templates/scripts/server-status.sh
Normal file
28
deployment/build/templates/scripts/server-status.sh
Normal file
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
|
||||
PROJECT_NAME="argus-sys"
|
||||
|
||||
if docker compose version >/dev/null 2>&1; then COMPOSE=(docker compose); else COMPOSE=(docker-compose); fi
|
||||
|
||||
echo "== Containers =="
|
||||
(cd "$ROOT/compose" && "${COMPOSE[@]}" -p "$PROJECT_NAME" ps)
|
||||
|
||||
echo
|
||||
echo "== Key Endpoints =="
|
||||
ENV_FILE="$ROOT/compose/.env"; [[ -f "$ENV_FILE" ]] && set -a && source "$ENV_FILE" && set +a
|
||||
printf "master http://localhost:%s/readyz\n" "${MASTER_PORT:-32300}"
|
||||
printf "es http://localhost:%s/_cluster/health\n" "${ES_HTTP_PORT:-9200}"
|
||||
printf "kibana http://localhost:%s/api/status\n" "${KIBANA_PORT:-5601}"
|
||||
printf "prom http://localhost:%s/-/ready\n" "${PROMETHEUS_PORT:-9090}"
|
||||
printf "grafana http://localhost:%s/api/health\n" "${GRAFANA_PORT:-3000}"
|
||||
printf "alert http://localhost:%s/api/v2/status\n" "${ALERTMANAGER_PORT:-9093}"
|
||||
printf "web http://localhost:%s/ (8080)\n" "${WEB_PROXY_PORT_8080:-8080}"
|
||||
|
||||
echo
|
||||
echo "== Selfcheck result =="
|
||||
cat "$ROOT/logs/selfcheck.json" 2>/dev/null || echo "(no selfcheck yet)"
|
||||
|
||||
16
deployment/build/templates/scripts/server-uninstall.sh
Normal file
16
deployment/build/templates/scripts/server-uninstall.sh
Normal file
@@ -0,0 +1,16 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PKG_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
|
||||
PROJECT_NAME="argus-sys"
|
||||
|
||||
log() { echo -e "\033[0;34m[UNINSTALL]\033[0m $*"; }
|
||||
|
||||
if docker compose version >/dev/null 2>&1; then COMPOSE=(docker compose); else COMPOSE=(docker-compose); fi
|
||||
|
||||
(cd "$PKG_ROOT/compose" && "${COMPOSE[@]}" -p "$PROJECT_NAME" down -v || true)
|
||||
log "compose stack removed"
|
||||
log "you may remove data under $PKG_ROOT/private if you want a clean slate"
|
||||
|
||||
@@ -1 +1 @@
|
||||
1.35.0
|
||||
1.38.0
|
||||
|
||||
@@ -48,6 +48,15 @@ if [[ ${#missing_files[@]} -gt 0 ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 防御:阻止将 Git LFS 指针文件打包
|
||||
for f in bin/dcgm-exporter bin/datacenter-gpu-manager_3.3.9_amd64.deb; do
|
||||
if head -n1 "$f" 2>/dev/null | grep -q '^version https://git-lfs.github.com/spec/v1$'; then
|
||||
echo "[ERROR] $f 是 Git LFS 指针文件,未还原为真实制品"
|
||||
echo " 请在仓库根目录执行: git lfs fetch --all && git lfs checkout"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
log_success "所有必要文件检查完成"
|
||||
|
||||
# 创建临时目录
|
||||
|
||||
@@ -47,6 +47,13 @@ if [[ ${#missing_files[@]} -gt 0 ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 防御:阻止将 Git LFS 指针文件打包
|
||||
if head -n1 bin/node_exporter 2>/dev/null | grep -q '^version https://git-lfs.github.com/spec/v1$'; then
|
||||
echo "[ERROR] bin/node_exporter 是 Git LFS 指针文件,未还原为真实二进制"
|
||||
echo " 请在仓库根目录执行: git lfs fetch --all && git lfs checkout"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_success "所有必要文件检查完成"
|
||||
|
||||
# 创建临时目录
|
||||
|
||||
@@ -216,6 +216,36 @@ if [[ ${#missing_components[@]} -gt 0 ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 额外校验:阻止将 Git LFS 指针文件打进安装包
|
||||
# 仅检查各组件目录下的 bin/ 内文件(常见为二进制或 .deb/.tar.gz 制品)
|
||||
is_lfs_pointer() {
|
||||
local f="$1"
|
||||
# 读取首行判断是否为 LFS pointer(无需依赖 file 命令)
|
||||
head -n1 "$f" 2>/dev/null | grep -q '^version https://git-lfs.github.com/spec/v1$'
|
||||
}
|
||||
|
||||
log_info "检查组件二进制是否已从 LFS 拉取..."
|
||||
while IFS= read -r component; do
|
||||
component_path=$(grep "^$component:" "$TEMP_DIR/component_paths.txt" | cut -d':' -f2-)
|
||||
bin_dir="$component_path/bin"
|
||||
[[ -d "$bin_dir" ]] || continue
|
||||
while IFS= read -r f; do
|
||||
# 只检查常见可执行/包后缀;无后缀的也检查
|
||||
case "$f" in
|
||||
*.sh) continue;;
|
||||
*) :;;
|
||||
esac
|
||||
if is_lfs_pointer "$f"; then
|
||||
log_error "检测到 Git LFS 指针文件: $f"
|
||||
log_error "请在仓库根目录执行: git lfs fetch --all && git lfs checkout"
|
||||
log_error "或确保 CI 在打包前已还原 LFS 大文件。"
|
||||
rm -rf "$TEMP_DIR"
|
||||
exit 1
|
||||
fi
|
||||
done < <(find "$bin_dir" -maxdepth 1 -type f 2>/dev/null | sort)
|
||||
done < "$COMPONENTS_FILE"
|
||||
log_success "LFS 校验通过:未发现指针文件"
|
||||
|
||||
# 打包各个组件
|
||||
log_info "开始打包组件..."
|
||||
|
||||
@@ -234,7 +264,19 @@ while IFS= read -r component; do
|
||||
|
||||
# 进入组件目录
|
||||
cd "$component_path"
|
||||
|
||||
|
||||
# 组件内二次防御:若包脚本缺失 LFS 校验,这里再次阻断
|
||||
if [[ -d bin ]]; then
|
||||
for f in bin/*; do
|
||||
[[ -f "$f" ]] || continue
|
||||
if head -n1 "$f" 2>/dev/null | grep -q '^version https://git-lfs.github.com/spec/v1$'; then
|
||||
log_error "组件 $component 含 LFS 指针文件: $f"
|
||||
log_error "请执行: git lfs fetch --all && git lfs checkout"
|
||||
cd "$CURRENT_DIR"; rm -rf "$TEMP_DIR"; exit 1
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# 检查组件是否有 package.sh
|
||||
if [[ ! -f "package.sh" ]]; then
|
||||
log_error "$component 缺少 package.sh 文件"
|
||||
|
||||
@@ -67,7 +67,8 @@ RUN chmod +x /usr/local/bin/start-ftp-supervised.sh
|
||||
COPY vsftpd.conf /etc/vsftpd/vsftpd.conf
|
||||
|
||||
COPY dns-monitor.sh /usr/local/bin/dns-monitor.sh
|
||||
RUN chmod +x /usr/local/bin/dns-monitor.sh
|
||||
COPY dns-publish.sh /usr/local/bin/dns-publish.sh
|
||||
RUN chmod +x /usr/local/bin/dns-monitor.sh /usr/local/bin/dns-publish.sh
|
||||
|
||||
USER root
|
||||
|
||||
|
||||
@@ -66,6 +66,17 @@ ${FTP_BASE_PATH}/
|
||||
|
||||
/private/argus/etc/
|
||||
└── ${DOMAIN} # 容器IP记录文件
|
||||
|
||||
## DNS 同步到 FTP share(运行期)
|
||||
|
||||
- 运行期最新的 DNS 列表由 bind/master 写入挂载点 `/private/argus/etc/dns.conf`。
|
||||
- FTP 容器内置 `dns-publish`(Supervised):每 10s 比较并将该文件原子同步为 `${FTP_BASE_PATH}/share/dns.conf`,供客户端下载安装脚本直接读取。
|
||||
- 同步特性:
|
||||
- 原子更新:写入 `${DST}.tmp` 后 `mv -f` 覆盖,避免读到半写文件。
|
||||
- 权限:0644;属主 `${ARGUS_BUILD_UID}:${ARGUS_BUILD_GID}`。
|
||||
- 可观测:日志 `/var/log/supervisor/dns-publish.log`。
|
||||
|
||||
> 注:构建/发布阶段可能也会将静态 `config/dns.conf` 拷贝到 share;当 FTP 容器运行后,dns-publish 会用运行期最新文件覆盖该静态文件。
|
||||
```
|
||||
|
||||
## vsftpd 配置说明
|
||||
@@ -156,4 +167,4 @@ curl -fsS 'ftp://ftpuser:ZGClab1234!@177.177.70.200/setup.sh' -o setup.sh
|
||||
# root用户直接执行,非root用户需要使用sudo
|
||||
chmod +x setup.sh
|
||||
bash setup.sh --server {$域名} --user ftpuser --password 'ZGClab1234!'
|
||||
```
|
||||
```
|
||||
|
||||
40
src/metric/ftp/build/dns-publish.sh
Normal file
40
src/metric/ftp/build/dns-publish.sh
Normal file
@@ -0,0 +1,40 @@
|
||||
#!/bin/bash
|
||||
set -uo pipefail
|
||||
|
||||
# Publish latest /private/argus/etc/dns.conf to ${FTP_BASE_PATH}/share/dns.conf
|
||||
|
||||
SRC="/private/argus/etc/dns.conf"
|
||||
FTP_BASE_PATH="${FTP_BASE_PATH:-/private/argus/ftp}"
|
||||
DST_DIR="${FTP_BASE_PATH}/share"
|
||||
DST="${DST_DIR}/dns.conf"
|
||||
UID_VAL="${ARGUS_BUILD_UID:-2133}"
|
||||
GID_VAL="${ARGUS_BUILD_GID:-2015}"
|
||||
INTERVAL="${DNS_PUBLISH_INTERVAL:-10}"
|
||||
|
||||
log() { echo "$(date '+%Y-%m-%d %H:%M:%S') [DNS-Publish] $*"; }
|
||||
|
||||
mkdir -p "$DST_DIR" 2>/dev/null || true
|
||||
|
||||
log "service start: SRC=$SRC DST=$DST interval=${INTERVAL}s"
|
||||
|
||||
while true; do
|
||||
if [[ -f "$SRC" ]]; then
|
||||
# Only sync when content differs
|
||||
if ! cmp -s "$SRC" "$DST" 2>/dev/null; then
|
||||
tmp="${DST}.tmp"
|
||||
if cp "$SRC" "$tmp" 2>/dev/null; then
|
||||
mv -f "$tmp" "$DST"
|
||||
chown "$UID_VAL":"$GID_VAL" "$DST" 2>/dev/null || true
|
||||
chmod 0644 "$DST" 2>/dev/null || true
|
||||
ts_src=$(date -r "$SRC" '+%Y-%m-%dT%H:%M:%S%z' 2>/dev/null || echo "?")
|
||||
log "synced dns.conf (src mtime=$ts_src) -> $DST"
|
||||
else
|
||||
log "ERROR: copy failed $SRC -> $tmp"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
log "waiting for source $SRC"
|
||||
fi
|
||||
sleep "$INTERVAL"
|
||||
done
|
||||
|
||||
@@ -28,6 +28,18 @@ stopwaitsecs=10
|
||||
killasgroup=true
|
||||
stopasgroup=true
|
||||
|
||||
[program:dns-publish]
|
||||
command=/usr/local/bin/dns-publish.sh
|
||||
user=root
|
||||
stdout_logfile=/var/log/supervisor/dns-publish.log
|
||||
stderr_logfile=/var/log/supervisor/dns-publish_error.log
|
||||
autorestart=true
|
||||
startretries=3
|
||||
startsecs=5
|
||||
stopwaitsecs=10
|
||||
killasgroup=true
|
||||
stopasgroup=true
|
||||
|
||||
[unix_http_server]
|
||||
file=/var/run/supervisor.sock
|
||||
chmod=0700
|
||||
|
||||
7
src/sys/tests/.gitignore
vendored
Normal file
7
src/sys/tests/.gitignore
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
|
||||
private/
|
||||
private-nodea/
|
||||
private-nodeb/
|
||||
tmp/
|
||||
|
||||
.env
|
||||
@@ -1,13 +1,17 @@
|
||||
# ARGUS 系统级端到端测试(Sys E2E)
|
||||
|
||||
本目录包含将 log 与 agent 两线验证合并后的系统级端到端测试。依赖 bind/master/es/kibana + 两个“日志节点”(每个节点容器内同时运行 Fluent Bit 与 argus-agent)。
|
||||
本目录包含将 log、metric 与 agent 三线验证合并后的系统级端到端测试。依赖 bind/master/es/kibana/metric(ftp+prometheus+grafana+alertmanager)/web-proxy/web-frontend + 两个“计算节点”(每个节点容器内同时运行 Fluent Bit 与 argus-agent)。
|
||||
|
||||
---
|
||||
|
||||
## 一、如何运行
|
||||
|
||||
- 前置条件
|
||||
- 已构建镜像:`argus-elasticsearch:latest`、`argus-kibana:latest`、`argus-bind9:latest`、`argus-master:latest`
|
||||
- 已构建镜像:
|
||||
- 基座:`argus-elasticsearch:latest`、`argus-kibana:latest`、`argus-bind9:latest`、`argus-master:latest`
|
||||
- 节点:`argus-sys-node:latest`
|
||||
- 指标:`argus-metric-ftp:latest`、`argus-metric-prometheus:latest`、`argus-metric-grafana:latest`、`argus-alertmanager:latest`
|
||||
- 前端与代理:`argus-web-frontend:latest`、`argus-web-proxy:latest`
|
||||
- 可用根目录命令构建:`./build/build_images.sh [--intranet]`
|
||||
- 主机具备 Docker 与 Docker Compose。
|
||||
|
||||
@@ -33,11 +37,12 @@
|
||||
- 一键执行
|
||||
- `cd src/sys/tests`
|
||||
- `./scripts/00_e2e_test.sh`(CPU-only)或 `./scripts/00_e2e_test.sh --enable-gpu`(启用 GPU 流程)
|
||||
- 可选:`--no-clean` 跳过清理,便于失败后现场排查
|
||||
|
||||
- 分步执行(推荐用于排查)
|
||||
- `./scripts/01_bootstrap.sh` 生成目录/拷贝 `update-dns.sh`/构建 agent 二进制/写 `.env`
|
||||
- `./scripts/02_up.sh` 启动 Compose 栈(工程名 `argus-sys`)
|
||||
- `./scripts/03_wait_ready.sh` 等待 ES/Kibana/Master/Fluent‑Bit/Bind 就绪(Kibana 必须返回 200 且 overall.level=available)
|
||||
- `./scripts/03_wait_ready.sh` 等待 ES/Kibana/Master/Fluent‑Bit/Bind/Prometheus/Grafana/Alertmanager/Web‑Proxy 就绪(Kibana 必须 200 且 overall.level=available;Web‑Proxy 8084/8085 要有 CORS 头)
|
||||
- `./scripts/04_verify_dns_routing.sh` 校验 bind 解析与节点内域名解析
|
||||
- `./scripts/05_agent_register.sh` 获取两个节点的 `node_id` 与初始 IP,检查本地 `node.json`
|
||||
- `./scripts/06_write_health_and_assert.sh` 写健康文件并断言 `nodes.json` 仅包含 2 个在线节点
|
||||
@@ -58,7 +63,7 @@
|
||||
## 二、测试部署架构(docker-compose)
|
||||
|
||||
- 网络
|
||||
- 自定义 bridge:`argus-sys-net`,子网 `172.31.0.0/16`
|
||||
- 自定义 bridge:`sysnet`(Compose 工程名为 `argus-sys` 时实际为 `argus-sys_sysnet`),子网 `172.31.0.0/16`
|
||||
- 固定地址:bind=`172.31.0.2`,master=`172.31.0.10`
|
||||
|
||||
- 服务与端口(宿主机映射端口由 `01_bootstrap.sh` 自动分配并写入 `.env`)
|
||||
@@ -66,9 +71,15 @@
|
||||
- `bind`(`argus-bind9:latest`):监听 53/tcp+udp;负责同步 `*.argus.com` 记录
|
||||
- `master`(`argus-master:latest`):对外 `${MASTER_PORT}→3000`;API `http://localhost:${MASTER_PORT}`
|
||||
- `es`(`argus-elasticsearch:latest`):`${ES_HTTP_PORT}→9200`;单节点,无安全
|
||||
- `kibana`(`argus-kibana:latest`):`${KIBANA_PORT}→5601`;通过 `ELASTICSEARCH_HOSTS=http://es:9200` 访问 ES
|
||||
- `node-a`(`ubuntu:22.04`):同时运行 Fluent Bit + argus-agent,`hostname=dev-yyrshare-nbnyx10-cp2f-pod-0`,`${NODE_A_PORT}→2020`
|
||||
- `node-b`(`ubuntu:22.04`):同时运行 Fluent Bit + argus-agent,`hostname=dev-yyrshare-uuuu10-ep2f-pod-0`,`${NODE_B_PORT}→2020`
|
||||
- `kibana`(`argus-kibana:latest`):`${KIBANA_PORT}→5601`
|
||||
- `node-a`(`argus-sys-node:latest`):同时运行 Fluent Bit + argus-agent,`hostname=dev-yyrshare-nbnyx10-cp2f-pod-0`,`${NODE_A_PORT}→2020`
|
||||
- `node-b`(`argus-sys-node:latest`):同时运行 Fluent Bit + argus-agent,`hostname=dev-yyrshare-uuuu10-ep2f-pod-0`,`${NODE_B_PORT}→2020`
|
||||
- `ftp`(`argus-metric-ftp:latest`):`${FTP_PORT}→21`/`${FTP_DATA_PORT}→20`/`${FTP_PASSIVE_HOST_RANGE}` 被动端口
|
||||
- `prometheus`(`argus-metric-prometheus:latest`):`${PROMETHEUS_PORT}→9090`
|
||||
- `grafana`(`argus-metric-grafana:latest`):`${GRAFANA_PORT}→3000`
|
||||
- `alertmanager`(`argus-alertmanager:latest`):`${ALERTMANAGER_PORT}→9093`
|
||||
- `web-frontend`(`argus-web-frontend:latest`):内部访问页面,使用 `web-proxy` 暴露的对外端口渲染超链
|
||||
- `web-proxy`(`argus-web-proxy:latest`):多端口转发 8080..8085(首页、Grafana、Prometheus、Kibana、Alertmanager、Master API)
|
||||
|
||||
- 卷与目录
|
||||
- 核心服务(bind/master/es/kibana)共享宿主 `./private` 挂载到容器 `/private`
|
||||
@@ -83,7 +94,7 @@
|
||||
|
||||
- 节点入口
|
||||
- `scripts/node_entrypoint.sh`:
|
||||
- 复制 `/assets/fluent-bit/*` 到容器 `/private`,后台启动 Fluent Bit(监听 2020)
|
||||
- 离线优先:将 `/assets/fluent-bit/packages` 与 `etc` 拷贝到 `/private`,执行 `/private/start-fluent-bit.sh` 安装/拉起 Fluent Bit(监听 2020)
|
||||
- 以运行用户(映射 UID/GID)前台启动 `argus-agent`
|
||||
- 节点环境变量:`MASTER_ENDPOINT=http://master.argus.com:3000`、`REPORT_INTERVAL_SECONDS=2`、`ES_HOST=es`、`ES_PORT=9200`、`CLUSTER=local`、`RACK=dev`
|
||||
|
||||
@@ -106,6 +117,10 @@
|
||||
- Master `/readyz` 成功
|
||||
- Fluent Bit 指标接口 `:2020/:2021` 可访问
|
||||
- bind `named-checkconf` 通过
|
||||
- Prometheus `/-/ready` 可用
|
||||
- Grafana `GET /api/health` 返回 200 且 `database=ok`
|
||||
- Alertmanager `GET /api/v2/status` 成功
|
||||
- Web‑Proxy:8080 首页 200;8083 首页 200/302;8084/8085 对来自 8080 的请求需返回 `Access-Control-Allow-Origin`(CORS)
|
||||
|
||||
- `04_verify_dns_routing.sh`
|
||||
- 目的:验证从 bind → 节点容器的解析链路
|
||||
@@ -142,6 +157,28 @@
|
||||
|
||||
---
|
||||
|
||||
## 注意事项(2025‑10‑29 更新)
|
||||
|
||||
- 宿主 inotify 限制导致 03 卡住(Fluent Bit in_tail EMFILE)
|
||||
- 现象:`03_wait_ready.sh` 一直等待 `:2020/:2021 /api/v2/metrics`;节点日志出现 `tail_fs_inotify.c errno=24 Too many open files`,Fluent Bit 启动失败。
|
||||
- 根因:宿主 `fs.inotify.max_user_instances` 上限过低(常见默认 128),被其他进程占满;并非容器内 `ulimit -n` 过低。
|
||||
- 处理:在宿主执行(临时):
|
||||
- `sudo sysctl -w fs.inotify.max_user_instances=1024 fs.inotify.max_user_watches=1048576`
|
||||
- 建议永久:写入 `/etc/sysctl.d/99-argus-inotify.conf` 后 `sudo sysctl --system`
|
||||
- 提示:节点入口里对 sysctl 的写操作不影响宿主;需在宿主调整。
|
||||
|
||||
- Metric 安装制品包含 Git LFS 指针导致 node‑exporter 启动失败
|
||||
- 现象:第 11 步在线安装后,日志显示 `Node Exporter 服务启动失败`;容器内 `/usr/local/bin/node-exporter` 头部是文本:`version https://git-lfs.github.com/spec/v1`。
|
||||
- 根因:发布到 FTP 的安装包在打包前未执行 `git lfs fetch/checkout`,将指针文件打入制品。
|
||||
- 处理:在仓库根目录执行 `git lfs fetch --all && git lfs checkout` 后,重跑 `src/metric/tests/scripts/02_publish_artifact.sh` 再重试 `11_metric_node_install.sh`。
|
||||
- 防呆:已在 `all-in-one-full/scripts/package_artifact.sh` 与组件 `plugins/*/package.sh` 增加 LFS 指针校验,发现即失败并提示修复。
|
||||
|
||||
建议:
|
||||
- 运行前检查宿主 inotify 值(≥1024/≥1048576)与宿主端口占用(8080..8085、9200/5601/9090/9093/2020/2021/32300 等)。
|
||||
- 如需排查失败,使用 `--no-clean` 保留现场,配合 `docker logs`、`curl` 与 `tmp/*.json` 进行定位。
|
||||
|
||||
---
|
||||
|
||||
如需更严格的断言(例如 Kibana 载入具体插件、ES 文档字段校验),可在 `07_*.sh` 中追加查询与校验逻辑。
|
||||
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user