#!/usr/bin/env bash set -euo pipefail show_help() { cat <<'EOF' ARGUS Unified Build System - Image Build Tool Usage: $0 [OPTIONS] Options: --intranet Use intranet mirror for log/bind builds --master-offline Build master offline image (requires src/master/offline_wheels.tar.gz) --metric Build metric module images (ftp, prometheus, grafana, test nodes) --no-cache Build all images without using Docker layer cache --only LIST Comma-separated targets to build: core,master,metric,web,alert,sys,all -h, --help Show this help message Examples: $0 # Build with default sources $0 --intranet # Build with intranet mirror $0 --master-offline # Additionally build argus-master:offline $0 --metric # Additionally build metric module images $0 --intranet --master-offline --metric EOF } use_intranet=false build_core=true build_master=true build_master_offline=false build_metric=true build_web=true build_alert=true build_sys=true no_cache=false while [[ $# -gt 0 ]]; do case $1 in --intranet) use_intranet=true shift ;; --master) build_master=true shift ;; --master-offline) build_master=true build_master_offline=true shift ;; --metric) build_metric=true shift ;; --no-cache) no_cache=true shift ;; --only) if [[ -z ${2:-} ]]; then echo "--only requires a target list" >&2; exit 1 fi sel="$2"; shift 2 # reset all, then enable selected build_core=false; build_master=false; build_metric=false; build_web=false; build_alert=false; build_sys=false IFS=',' read -ra parts <<< "$sel" for p in "${parts[@]}"; do case "$p" in core) build_core=true ;; master) build_master=true ;; metric) build_metric=true ;; web) build_web=true ;; alert) build_alert=true ;; sys) build_sys=true ;; all) build_core=true; build_master=true; build_metric=true; build_web=true; build_alert=true; build_sys=true ;; *) echo "Unknown --only target: $p" >&2; exit 1 ;; esac done ;; -h|--help) show_help exit 0 ;; *) echo "Unknown option: $1" >&2 show_help exit 1 ;; esac done root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" . "$root/scripts/common/build_user.sh" declare -a build_args=() if [[ "$use_intranet" == true ]]; then build_args+=("--build-arg" "USE_INTRANET=true") fi cd "$root" load_build_user build_args+=("--build-arg" "ARGUS_BUILD_UID=${ARGUS_BUILD_UID}" "--build-arg" "ARGUS_BUILD_GID=${ARGUS_BUILD_GID}") if [[ "$no_cache" == true ]]; then build_args+=("--no-cache") fi master_root="$root/src/master" master_offline_tar="$master_root/offline_wheels.tar.gz" master_offline_dir="$master_root/offline_wheels" if [[ "$build_master_offline" == true ]]; then if [[ ! -f "$master_offline_tar" ]]; then echo "❌ offline wheels tar not found: $master_offline_tar" >&2 echo " 请提前准备好 offline_wheels.tar.gz 后再执行 --master-offline" >&2 exit 1 fi echo "📦 Preparing offline wheels for master (extracting $master_offline_tar)" rm -rf "$master_offline_dir" mkdir -p "$master_offline_dir" tar -xzf "$master_offline_tar" -C "$master_root" has_wheel=$(find "$master_offline_dir" -maxdepth 1 -type f -name '*.whl' -print -quit) if [[ -z "$has_wheel" ]]; then echo "❌ offline_wheels extraction failed或无 wheel: $master_offline_dir" >&2 exit 1 fi fi echo "=======================================" echo "ARGUS Unified Build System" echo "=======================================" if [[ "$use_intranet" == true ]]; then echo "🌐 Mode: Intranet (Using internal mirror: 10.68.64.1)" else echo "🌐 Mode: Public (Using default package sources)" fi echo "👤 Build user UID:GID -> ${ARGUS_BUILD_UID}:${ARGUS_BUILD_GID}" echo "📁 Build context: $root" echo "" build_image() { local image_name=$1 local dockerfile_path=$2 local tag=$3 local context="." shift 3 if [[ $# -gt 0 ]]; then context=$1 shift fi local extra_args=("$@") echo "🔄 Building $image_name image..." echo " Dockerfile: $dockerfile_path" echo " Tag: $tag" echo " Context: $context" if docker build "${build_args[@]}" "${extra_args[@]}" -f "$dockerfile_path" -t "$tag" "$context"; then echo "✅ $image_name image built successfully" return 0 else echo "❌ Failed to build $image_name image" return 1 fi } pull_base_image() { local image_ref=$1 local attempts=${2:-3} local delay=${3:-5} # If the image already exists locally, skip pulling. if docker image inspect "$image_ref" >/dev/null 2>&1; then echo " Local image present; skip pull: $image_ref" return 0 fi for ((i=1; i<=attempts; i++)); do echo " Pulling base image ($i/$attempts): $image_ref" if docker pull "$image_ref" >/dev/null; then echo " Base image ready: $image_ref" return 0 fi echo " Pull failed: $image_ref" if (( i < attempts )); then echo " Retrying in ${delay}s..." sleep "$delay" fi done echo "❌ Unable to pull base image after ${attempts} attempts: $image_ref" return 1 } images_built=() build_failed=false if [[ "$build_core" == true ]]; then if build_image "Elasticsearch" "src/log/elasticsearch/build/Dockerfile" "argus-elasticsearch:latest"; then images_built+=("argus-elasticsearch:latest") else build_failed=true fi echo "" if build_image "Kibana" "src/log/kibana/build/Dockerfile" "argus-kibana:latest"; then images_built+=("argus-kibana:latest") else build_failed=true fi echo "" if build_image "BIND9" "src/bind/build/Dockerfile" "argus-bind9:latest"; then images_built+=("argus-bind9:latest") else build_failed=true fi fi echo "" if [[ "$build_master" == true ]]; then echo "" echo "🔄 Building Master image..." pushd "$master_root" >/dev/null master_args=("--tag" "argus-master:latest") if [[ "$use_intranet" == true ]]; then master_args+=("--intranet") fi if [[ "$build_master_offline" == true ]]; then master_args+=("--offline") fi if [[ "$no_cache" == true ]]; then master_args+=("--no-cache") fi if ./scripts/build_images.sh "${master_args[@]}"; then if [[ "$build_master_offline" == true ]]; then images_built+=("argus-master:offline") else images_built+=("argus-master:latest") fi else build_failed=true fi popd >/dev/null fi if [[ "$build_metric" == true ]]; then echo "" echo "Building Metric module images..." metric_base_images=( "ubuntu:22.04" "ubuntu/prometheus:3-24.04_stable" "grafana/grafana:11.1.0" ) for base_image in "${metric_base_images[@]}"; do if ! pull_base_image "$base_image"; then build_failed=true fi done metric_builds=( "Metric FTP|src/metric/ftp/build/Dockerfile|argus-metric-ftp:latest|src/metric/ftp/build" "Metric Prometheus|src/metric/prometheus/build/Dockerfile|argus-metric-prometheus:latest|src/metric/prometheus/build" "Metric Grafana|src/metric/grafana/build/Dockerfile|argus-metric-grafana:latest|src/metric/grafana/build" ) for build_spec in "${metric_builds[@]}"; do IFS='|' read -r image_label dockerfile_path image_tag build_context <<< "$build_spec" if build_image "$image_label" "$dockerfile_path" "$image_tag" "$build_context"; then images_built+=("$image_tag") else build_failed=true fi echo "" done fi # ======================================= # Sys (system tests) node images # ======================================= if [[ "$build_sys" == true ]]; then echo "" echo "Building Sys node images..." sys_base_images=( "ubuntu:22.04" "nvidia/cuda:12.2.2-runtime-ubuntu22.04" ) for base_image in "${sys_base_images[@]}"; do if ! pull_base_image "$base_image"; then build_failed=true fi done sys_builds=( "Sys Node|src/sys/build/node/Dockerfile|argus-sys-node:latest|." "Sys Metric Test Node|src/sys/build/test-node/Dockerfile|argus-sys-metric-test-node:latest|." "Sys Metric Test GPU Node|src/sys/build/test-gpu-node/Dockerfile|argus-sys-metric-test-gpu-node:latest|." ) for build_spec in "${sys_builds[@]}"; do IFS='|' read -r image_label dockerfile_path image_tag build_context <<< "$build_spec" if build_image "$image_label" "$dockerfile_path" "$image_tag" "$build_context"; then images_built+=("$image_tag") else build_failed=true fi echo "" done fi # ======================================= # Web & Alert module images # ======================================= if [[ "$build_web" == true || "$build_alert" == true ]]; then echo "" echo "Building Web and Alert module images..." # Pre-pull commonly used base images for stability web_alert_base_images=( "node:20" "ubuntu:24.04" ) for base_image in "${web_alert_base_images[@]}"; do if ! pull_base_image "$base_image"; then build_failed=true fi done if [[ "$build_web" == true ]]; then web_builds=( "Web Frontend|src/web/build_tools/frontend/Dockerfile|argus-web-frontend:latest|." "Web Proxy|src/web/build_tools/proxy/Dockerfile|argus-web-proxy:latest|." ) for build_spec in "${web_builds[@]}"; do IFS='|' read -r image_label dockerfile_path image_tag build_context <<< "$build_spec" if build_image "$image_label" "$dockerfile_path" "$image_tag" "$build_context"; then images_built+=("$image_tag") else build_failed=true fi echo "" done fi if [[ "$build_alert" == true ]]; then alert_builds=( "Alertmanager|src/alert/alertmanager/build/Dockerfile|argus-alertmanager:latest|." ) for build_spec in "${alert_builds[@]}"; do IFS='|' read -r image_label dockerfile_path image_tag build_context <<< "$build_spec" if build_image "$image_label" "$dockerfile_path" "$image_tag" "$build_context"; then images_built+=("$image_tag") else build_failed=true fi echo "" done fi fi echo "=======================================" echo "📦 Build Summary" echo "=======================================" if [[ ${#images_built[@]} -gt 0 ]]; then echo "✅ Successfully built images:" for image in "${images_built[@]}"; do echo " • $image" done fi if [[ "$build_failed" == true ]]; then echo "" echo "❌ Some images failed to build. Please check the errors above." exit 1 fi if [[ "$use_intranet" == true ]]; then echo "" echo "🌐 Built with intranet mirror configuration" fi if [[ "$build_master_offline" == true ]]; then echo "" echo "🧳 Master offline wheels 已解压到 $master_offline_dir" fi echo "" echo "🚀 Next steps:" echo " ./build/save_images.sh --compress # 导出镜像" echo " cd src/master/tests && MASTER_IMAGE_TAG=argus-master:offline ./scripts/00_e2e_test.sh" echo ""