Todos los productos
Search
Centro de documentos

Application Real-Time Monitoring Service:Enable ECS observability with OBI

Última actualización: Sep 17, 2026

Cuando se utiliza OpenTelemetry eBPF Instrumentation (OBI) para enviar datos de trazas a Application Real-Time Monitoring Service (ARMS) de forma no intrusiva, ARMS comienza a monitorear las aplicaciones. Desde ahí es posible consultar la topología de la aplicación, las trazas de llamadas, las transacciones anómalas, las transacciones lentas, el análisis de SQL y otros datos de monitoreo. En este tema se describe cómo usar OBI para monitorear aplicaciones y reportar datos.

Requisitos previos

Nota

Si encuentra algún problema al usar OpenTelemetry eBPF, contáctenos mediante el grupo de preguntas y respuestas de DingTalk (número de grupo: 159215000379).

  • Prepare un servidor Linux (una instancia de Elastic Compute Service (ECS) o un entorno local) que cumpla con los siguientes requisitos.

    Requisito

    Rango compatible

    Versión del kernel

    Linux 5.8 o posterior. Las distribuciones basadas en RHEL (con parches backport de eBPF) admiten como mínimo Linux 4.18.

    BTF

    El kernel debe exponer la información de BTF (BPF Type Format).

    Arquitectura de CPU

    amd64 (x86_64), arm64 (aarch64).

    Permisos

    Permisos de root.

    Nota

    Alibaba Cloud Linux 3 y Alibaba Cloud Linux 4 cumplen de forma predeterminada con los requisitos anteriores.

    Para comprobar si su servidor cumple con los requisitos, ejecute los siguientes comandos:

    # Check the kernel version (must be >= 5.8, or >= 4.18 for RHEL-based distributions)
    uname -r
    
    # Check the CPU architecture (must be amd64 or arm64)
    uname -m
    
    # Check whether BTF is available (the file exists if supported)
    ls /sys/kernel/btf/vmlinux
    
    # Check whether you have root permissions
    whoami

Contexto

OBI es un componente de instrumentación automática basado en eBPF diseñado para la observability en Kubernetes. Se despliega como un DaemonSet en los nodos del clúster y recopila automáticamente datos de métricas y trazas de las aplicaciones, sin necesidad de modificar el código ni de inyectar sidecars. OBI detecta de forma automática protocolos principales como HTTP, gRPC, SQL, Redis y Kafka, entre otros. Además, extrae de manera profunda los cuerpos de solicitud y respuesta para escenarios de GenAI (OpenAI, Anthropic, Qwen, MCP, Embedding, Rerank y más). Los datos de telemetría recopilados se exportan mediante el protocolo OTLP y se integran sin problemas con plataformas de observability como ARMS. Esto le permite lograr una observability de pila completa, sin intrusiones y con baja sobrecarga.

Métodos de coincidencia para el descubrimiento de aplicaciones

OBI descubre y asocia los procesos que va a monitorear mediante la sección de configuración discovery.instrument. A continuación se muestran los métodos de coincidencia compatibles. Todas las condiciones utilizan lógica AND, por lo que deben cumplirse en su totalidad para que exista una coincidencia:

Campo YAML

Tipo

Descripción

Ejemplo

open_ports

Número o rango de puertos

Números de puerto en los que escucha el proceso. Admite valores separados por comas y rangos.

8080, 80,443, 8000-8999

exe_path

Patrón Glob

Coincide con la ruta completa del archivo ejecutable del proceso.

/java, /nginx, myapp

cmd_args

Patrón Glob

Coincide con los argumentos de línea de comandos del proceso (sin incluir el nombre del archivo ejecutable).

petclinic, --config=prod

languages

Patrón Glob

Coincide automáticamente según el lenguaje de programación (go/java/python/ruby/nodejs/rust/dotnet/php/cpp).

java, {go,rust}

target_pids

Lista de PID

Especifica directamente los PID de los procesos.

[12345, 67890]

container_name

Patrón Glob

Coincide con los nombres de contenedores OCI (aplicable a despliegues de Docker).

my-container-*

containers_only

Booleano

Coincide únicamente con los procesos que se ejecutan dentro de contenedores.

true

name

Cadena

Nombre de la aplicación que se muestra en la consola de ARMS.

my-app

namespace

Cadena

Espacio de nombres del servicio.

production

exports

Lista de señales

Controla los tipos de señales exportadas (metrics/traces/logs). Una matriz vacía deshabilita todas las exportaciones.

[metrics, traces]

sampler

Configuración de muestreo

Muestrea las trazas por proporción para reducir el volumen de datos.

name: traceidratio, arg: "0.5"

Ejemplos de configuración para escenarios comunes

Escenario 1: coincidencia por número de puerto. Este método es el más sencillo y funciona con cualquier tipo de aplicación web.

discovery:
  instrument:
    - name: my-web-app
      open_ports: 8080

Escenario 2: aplicación Java (exe_path + cmd_args). Localiza el proceso mediante el ejecutable de Java y el nombre del archivo JAR.

discovery:
  instrument:
    - name: my-java-app
      exe_path: "*/java"
      cmd_args: "*petclinic*"

Escenario 3: descubrimiento automático por lenguaje de programación. Detecta de forma automática todos los procesos del lenguaje especificado.

discovery:
  instrument:
    - name: go-services
      languages: go
    - name: python-services
      languages: "{python,nodejs}"

Escenario 4: coincidencia por ruta del archivo ejecutable. Recomendado cuando se trabaja con archivos binarios compilados manualmente.

discovery:
  instrument:
    - name: my-binary
      exe_path: "*/my-server"

Escenario 5: coincidencia por nombre de contenedor de Docker. Diseñado para despliegues de Docker en ECS.

discovery:
  instrument:
    - name: my-container-app
      container_name: "my-container-*"

Escenario 6: varios rangos de puertos. Monitorea los servicios que operan dentro de un rango de puertos determinado.

discovery:
  instrument:
    - name: microservices
      open_ports: 8080-8090,9090

Escenario 7: especificar PID para depuración temporal. Indica directamente los PID de los procesos que desea monitorear.

discovery:
  instrument:
    - name: debug-target
      target_pids: [12345]

Escenario 8: solo procesos de contenedor con muestreo. Monitorea exclusivamente los procesos de contenedor y aplica un muestreo de trazas del 50 %.

discovery:
  instrument:
    - name: container-apps
      containers_only: true
      open_ports: 8080
      sampler:
        name: traceidratio
        arg: "0.5"

Escenario 9: varias aplicaciones con reglas de exclusión. Monitorea múltiples aplicaciones y excluye procesos específicos.

discovery:
  instrument:
    - name: api-gateway
      open_ports: 80,443
    - name: backend-java
      exe_path: "*/java"
      cmd_args: "*backend*"
    - name: worker
      exe_path: "*/python*"
      cmd_args: "*celery*"
  exclude_instrument:
    - exe_path: "{obi,prometheus,otelcol*}"

Escenario 10: control de señales exportadas. Exporta únicamente métricas, sin incluir trazas.

discovery:
  instrument:
    - name: high-qps-app
      open_ports: 8080
      exports: [metrics]

Procedimiento

Descripción general del procedimiento: instalar y desplegar (obtener la información del endpoint > descargar OBI > redactar el archivo de configuración > desplegar el servicio) > comprobar los datos de monitoreo.

Instalar y desplegar

Existen dos métodos de despliegue: el despliegue con script de un solo clic (recomendado) y el despliegue manual paso a paso.

Método 1: despliegue con script de un solo clic (recomendado)

Todos los pasos se agrupan en un único script obi-setup.sh que admite modos interactivo y no interactivo.

#!/bin/bash
# ============================================================================
#  OBI (OpenTelemetry eBPF Instrumentation) one-click deployment script
#  Combines the complete flow of environment check, download, configuration generation, and service installation
#
#  Usage:
#    sudo bash obi-setup.sh install   — Interactive installation (binary + systemd)
#    sudo bash obi-setup.sh docker    — Deploy with Docker
#    sudo bash obi-setup.sh check     — Perform environment check only
#    sudo bash obi-setup.sh uninstall — Uninstall the OBI service
#    sudo bash obi-setup.sh status    — View the running status and logs
#
#  Non-interactive deployment (using environment variables):
#    export OTLP_ENDPOINT="http://xxx:4318"
#    export OTLP_HEADERS="Authentication=xxx"
#    export APP_NAME="my-app"
#    export APP_MATCH_TYPE="port"    # port|cmd|exe|lang|container|pid
#    export APP_MATCH_VALUE="8080"
#    sudo -E bash obi-setup.sh install
# ============================================================================

set -euo pipefail

# ========================= Global Variables =========================
VERSION="0.10.0"
SERVICE_NAME="obi"
INSTALL_DIR="/opt/obi"
CONFIG_FILE="${INSTALL_DIR}/config.yaml"
OBI_BINARY="${INSTALL_DIR}/obi"
DOCKER_IMAGE="registry.cn-hangzhou.aliyuncs.com/private-mesh/obi:${VERSION}"
OSS_BASE="https://arms-apm-cn-hangzhou-pre.oss-cn-hangzhou.aliyuncs.com/obi-agent/${VERSION}"

# Colors
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
CYAN='\033[0;36m'; BOLD='\033[1m'; NC='\033[0m'

# Application list (array)
declare -a APP_ENTRIES=()
# Exclusion pattern
EXCLUDE_PATTERN=""

# ========================= Utility Functions =========================
info()  { echo -e "${CYAN}[INFO]${NC} $*"; }
ok()    { echo -e "${GREEN}[OK]${NC} $*"; }
warn()  { echo -e "${YELLOW}[WARN]${NC} $*"; }
fail()  { echo -e "${RED}[FAIL]${NC} $*"; }
die()   { fail "$*"; exit 1; }

prompt_input() {
    local var_name="$1" prompt_msg="$2" default_val="${3:-}"
    local current_val="${!var_name:-}"
    if [[ -n "$current_val" ]]; then
        info "Using environment variable ${var_name}=${current_val}"
        return
    fi
    if [[ -n "$default_val" ]]; then
        read -rp "$(echo -e "${BOLD}${prompt_msg} [${default_val}]: ${NC}")" input
        eval "$var_name=\"${input:-$default_val}\""
    else
        while true; do
            read -rp "$(echo -e "${BOLD}${prompt_msg}: ${NC}")" input
            if [[ -n "$input" ]]; then
                eval "$var_name=\"$input\""
                return
            fi
            warn "This field is required"
        done
    fi
}

prompt_yesno() {
    local prompt_msg="$1" default="${2:-n}"
    local yn
    read -rp "$(echo -e "${BOLD}${prompt_msg} [y/N]: ${NC}")" yn
    case "${yn:-$default}" in
        [Yy]*) return 0 ;;
        *) return 1 ;;
    esac
}

# ========================= Environment Check =========================
check_root() {
    if [[ "$EUID" -ne 0 ]]; then
        die "Please run with root permissions: sudo bash $0 $*"
    fi
    ok "Root permissions"
}

check_env() {
    echo ""
    echo -e "${BOLD}========== Environment Check ==========${NC}"

    local kernel_ver major minor
    kernel_ver=$(uname -r)
    major=$(echo "$kernel_ver" | cut -d. -f1)
    minor=$(echo "$kernel_ver" | cut -d. -f2)

    local is_rhel=false
    if [[ -f /etc/redhat-release ]] || grep -qi 'rhel\|centos\|rocky\|alma\|anolis\|alinux' /etc/os-release 2>/dev/null; then
        is_rhel=true
    fi

    if [[ "$major" -gt 5 ]] || { [[ "$major" -eq 5 ]] && [[ "$minor" -ge 8 ]]; }; then
        ok "Kernel version: ${kernel_ver} (>= 5.8)"
    elif $is_rhel && { [[ "$major" -gt 4 ]] || { [[ "$major" -eq 4 ]] && [[ "$minor" -ge 18 ]]; }; }; then
        ok "Kernel version: ${kernel_ver} (RHEL-based, >= 4.18)"
    else
        fail "Kernel version: ${kernel_ver} (Minimum requirement: 5.8, or 4.18 for RHEL-based systems)"
        return 1
    fi

    local arch
    arch=$(uname -m)
    case "$arch" in
        x86_64|amd64) ok "CPU architecture: ${arch} (amd64)" ;;
        aarch64|arm64) ok "CPU architecture: ${arch} (arm64)" ;;
        *) fail "CPU architecture: ${arch} (unsupported)"; return 1 ;;
    esac

    if [[ -f /sys/kernel/btf/vmlinux ]]; then
        ok "BTF: Available"
    else
        fail "BTF: /sys/kernel/btf/vmlinux does not exist"
        return 1
    fi

    echo -e "${GREEN}========== Environment Check Passed ==========${NC}"
    echo ""
    return 0
}

detect_arch() {
    local arch
    arch=$(uname -m)
    case "$arch" in
        x86_64|amd64) echo "amd64" ;;
        aarch64|arm64) echo "arm64" ;;
        *) die "Unsupported CPU architecture: ${arch}" ;;
    esac
}

# ========================= Collect Single Application Configuration =========================
collect_one_app() {
    local app_name match_type
    local entry=""

    prompt_input app_name "Application name (display name in the Cloud Monitor 2.0 console)" "my-app"

    echo ""
    echo -e "  ${BOLD}Select application matching method:${NC}"
    echo -e "    1) Match by port number        — open_ports, such as 8080, 80,443, or 8000-8999"
    echo -e "    2) Match by command line        — exe_path + cmd_args, suitable for scenarios like java -jar"
    echo -e "    3) Match by executable file path — exe_path, suitable for self-compiled binaries"
    echo -e "    4) Auto-discover by programming language   — languages, auto-detects go, java, python, nodejs, etc."
    echo -e "    5) Match by Docker container name  — container_name, suitable for running Docker on ECS"
    echo -e "    6) Specify by PID           — target_pids, for temporary debugging"
    read -rp "$(echo -e "${BOLD}Select [1-6, default 1]: ${NC}")" match_choice

    entry="    - name: ${app_name}"

    case "${match_choice:-1}" in
        1)
            local ports
            prompt_input ports "Listening port number (e.g., 8080, 80,443, 8000-8999)" "8080"
            entry="${entry}
      open_ports: ${ports}"
            ;;
        2)
            local exe_path cmd_args
            prompt_input exe_path "Executable file path Glob (e.g., */java)" "*/java"
            prompt_input cmd_args "Command line argument Glob (e.g., *petclinic*)"
            entry="${entry}
      exe_path: \"${exe_path}\"
      cmd_args: \"${cmd_args}\""
            ;;
        3)
            local exe_path
            prompt_input exe_path "Executable file path Glob (e.g., */my-server, */nginx)"
            entry="${entry}
      exe_path: \"${exe_path}\""
            ;;
        4)
            local lang
            echo -e "    Supported languages: go, java, python, ruby, nodejs, rust, dotnet, php, cpp"
            echo -e "    For multiple languages, use braces: {go,rust} or {python,nodejs}"
            prompt_input lang "Programming language" "java"
            entry="${entry}
      languages: \"${lang}\""
            ;;
        5)
            local cname
            prompt_input cname "Docker container name Glob (e.g., my-container-*)"
            entry="${entry}
      container_name: \"${cname}\""
            ;;
        6)
            local pids
            prompt_input pids "PID list, comma-separated (e.g., 12345,67890)"
            local pid_array
            pid_array=$(echo "$pids" | tr ',' '\n' | sed 's/^[[:space:]]*//' | awk '{printf "      - %s\n", $0}')
            entry="${entry}
      target_pids:
${pid_array}"
            ;;
        *)
            local ports
            prompt_input ports "Listening port number" "8080"
            entry="${entry}
      open_ports: ${ports}"
            ;;
    esac

    # Optional: Container processes only
    if [[ "${match_choice:-1}" != "5" ]]; then
        if prompt_yesno "Match only processes inside containers (containers_only)?"; then
            entry="${entry}
      containers_only: true"
        fi
    fi

    # Optional: Sampling
    if prompt_yesno "Configure Traces sampling (to reduce data volume)?"; then
        echo -e "    Samplers: always_on, always_off, traceidratio, parentbased_traceidratio"
        local sampler_name sampler_arg
        prompt_input sampler_name "Sampler name" "traceidratio"
        prompt_input sampler_arg  "Sampler argument (e.g., 0.5 for 50% sampling)" "1.0"
        entry="${entry}
      sampler:
        name: ${sampler_name}
        arg: \"${sampler_arg}\""
    fi

    APP_ENTRIES+=("$entry")
    ok "Added application: ${app_name}"
}

# ========================= Collect Full Configuration =========================
collect_config() {
    echo -e "${BOLD}========== Configuration Information ==========${NC}"
    echo ""
    info "Please obtain the following information from the Cloud Monitor Integration Center:"
    info "  Cloud Monitor 2.0 console -> Integration Center -> OpenTelemetry card -> Click to get LicenseKey"
    echo ""

    prompt_input OTLP_ENDPOINT "OTEL_EXPORTER_OTLP_ENDPOINT (e.g., http://xxx:4318)"
    prompt_input OTLP_HEADERS  "OTEL_EXPORTER_OTLP_HEADERS  (e.g., Authentication=xxx)"

    echo ""
    echo -e "${BOLD}========== Application Configuration ==========${NC}"

    # Non-interactive mode: Build a single app from environment variables
    if [[ -n "${APP_MATCH_TYPE:-}" ]]; then
        local entry="    - name: ${APP_NAME:-my-app}"
        case "$APP_MATCH_TYPE" in
            port)
                entry="${entry}
      open_ports: ${APP_MATCH_VALUE:-8080}" ;;
            cmd)
                entry="${entry}
      exe_path: \"${APP_EXE_PATH:-*/java}\"
      cmd_args: \"${APP_CMD_ARGS}\"" ;;
            exe)
                entry="${entry}
      exe_path: \"${APP_MATCH_VALUE}\"" ;;
            lang)
                entry="${entry}
      languages: \"${APP_MATCH_VALUE}\"" ;;
            container)
                entry="${entry}
      container_name: \"${APP_MATCH_VALUE}\"" ;;
            pid)
                local pid_array
                pid_array=$(echo "${APP_MATCH_VALUE}" | tr ',' '\n' | sed 's/^[[:space:]]*//' | awk '{printf "      - %s\n", $0}')
                entry="${entry}
      target_pids:
${pid_array}" ;;
            *)
                die "Unknown APP_MATCH_TYPE: ${APP_MATCH_TYPE} (Supported: port|cmd|exe|lang|container|pid)" ;;
        esac
        APP_ENTRIES+=("$entry")
        ok "Added application: ${APP_NAME:-my-app} (${APP_MATCH_TYPE})"
        return
    fi

    # Interactive mode: Loop to add applications
    while true; do
        echo ""
        collect_one_app
        echo ""
        if ! prompt_yesno "Add another application?"; then
            break
        fi
    done

    # Optional: Exclusion rules
    echo ""
    if prompt_yesno "Configure exclusion rules (exclude_instrument)?"; then
        echo -e "    Enter the executable file path Glob to exclude"
        echo -e "    Example: {obi,prometheus,otelcol*,node_exporter}"
        local exclude_val
        prompt_input exclude_val "Exclusion path Glob"
        EXCLUDE_PATTERN="$exclude_val"
        ok "Added exclusion rule: ${exclude_val}"
    fi
}

# ========================= Generate Configuration File =========================
generate_config() {
    local endpoint_metrics="${OTLP_ENDPOINT}/v1/metrics"

    # Concatenate the instrument section
    local instrument_yaml=""
    for entry in "${APP_ENTRIES[@]}"; do
        instrument_yaml="${instrument_yaml}
${entry}"
    done

    # Concatenate the exclude section
    local exclude_yaml=""
    if [[ -n "$EXCLUDE_PATTERN" ]]; then
        exclude_yaml="
  exclude_instrument:
    - exe_path: \"${EXCLUDE_PATTERN}\""
    fi

    cat > "${CONFIG_FILE}" <<YAML
log_level: WARN

otel_metrics_export:
  endpoint: ${endpoint_metrics}

metrics:
  features:
    - application
    - network
    - stats_tcp_rtt

routes:
  unmatched: low-cardinality
  max_path_segment_cardinality: 500

ebpf:
  context_propagation: all
  track_request_headers: true
  payload_extraction:
    http:
      genai:
        openai:
          enabled: true
        anthropic:
          enabled: true
        jsonrpc:
          enabled: true
        mcp:
          enabled: true
        qwen:
          enabled: true
        rerank:
          enabled: true
        embedding:
          enabled: true
        gemini:
          enabled: true
  buffer_sizes:
    http: 262144

otel_traces_export:
  endpoint: ${OTLP_ENDPOINT}
  batch_timeout: 10s
  batch_max_size: 512
  queue_size: 4096
  backoff_initial_interval: 5s
  backoff_max_interval: 15s
  backoff_max_elapsed_time: 2m
  instrumentations:
    - http
    - grpc
    - sql
    - redis
    - kafka
    - mqtt
    - mongo
    - couchbase
    - memcached
    - genai

nodejs:
  enabled: true

discovery:
  min_process_age: 30s
  instrument:${instrument_yaml}${exclude_yaml}
YAML

    ok "Configuration file generated: ${CONFIG_FILE}"
}

# ========================= Download OBI =========================
download_obi() {
    local arch
    arch=$(detect_arch)
    local url="${OSS_BASE}/obi-linux-${arch}"

    info "Downloading OBI v${VERSION} (${arch})..."
    mkdir -p "${INSTALL_DIR}"

    if command -v wget &>/dev/null; then
        wget -q --show-progress "${url}" -O "${OBI_BINARY}"
    elif command -v curl &>/dev/null; then
        curl -fL --progress-bar "${url}" -o "${OBI_BINARY}"
    else
        die "Neither wget nor curl is available"
    fi

    chmod +x "${OBI_BINARY}"
    ok "OBI downloaded to ${OBI_BINARY}"
}

# ========================= Systemd Service =========================
install_systemd() {
    info "Creating systemd service..."

    cat > "/etc/systemd/system/${SERVICE_NAME}.service" <<EOF
[Unit]
Description=OBI eBPF Instrumentation Service
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=root
WorkingDirectory=${INSTALL_DIR}
Environment="OTEL_EBPF_CONFIG_PATH=${CONFIG_FILE}"
Environment="OTEL_EXPORTER_OTLP_HEADERS=${OTLP_HEADERS}"
ExecStart=${OBI_BINARY}
Restart=always
RestartSec=5
StandardOutput=journal
StandardError=journal
SyslogIdentifier=${SERVICE_NAME}

[Install]
WantedBy=multi-user.target
EOF

    systemctl daemon-reload
    systemctl enable "${SERVICE_NAME}" --quiet
    ok "Systemd service created and enabled on boot"
}

start_service() {
    info "Starting OBI service..."
    systemctl start "${SERVICE_NAME}"
    sleep 2

    if systemctl is-active --quiet "${SERVICE_NAME}"; then
        ok "OBI service started successfully!"
    else
        fail "Failed to start OBI service. The error log is as follows:"
        journalctl -u "${SERVICE_NAME}" -n 30 --no-pager
        exit 1
    fi
}

# ========================= Docker Deployment =========================
deploy_docker() {
    if ! command -v docker &>/dev/null; then
        die "Docker is not installed"
    fi

    collect_config
    mkdir -p "${INSTALL_DIR}"
    generate_config

    info "Pulling Docker image: ${DOCKER_IMAGE}"
    docker pull "${DOCKER_IMAGE}"

    if docker ps -a --format '{{.Names}}' | grep -q "^${SERVICE_NAME}$"; then
        warn "Removing existing container..."
        docker rm -f "${SERVICE_NAME}" >/dev/null 2>&1
    fi

    info "Starting OBI container..."
    docker run -d \
        --name "${SERVICE_NAME}" \
        --pid=host \
        --privileged \
        --restart=always \
        -v "${CONFIG_FILE}:/config/config.yaml:ro" \
        -e "OTEL_EXPORTER_OTLP_HEADERS=${OTLP_HEADERS}" \
        -e "OTEL_EXPORTER_OTLP_ENDPOINT=${OTLP_ENDPOINT}" \
        "${DOCKER_IMAGE}" \
        --config=/config/config.yaml

    sleep 2
    if docker ps --format '{{.Names}}' | grep -q "^${SERVICE_NAME}$"; then
        ok "OBI container started successfully!"
    else
        fail "Failed to start container:"
        docker logs "${SERVICE_NAME}" --tail 30
        exit 1
    fi

    echo ""
    echo -e "${BOLD}Docker Management Commands:${NC}"
    echo "  View logs:   docker logs -f ${SERVICE_NAME}"
    echo "  Stop container:   docker stop ${SERVICE_NAME}"
    echo "  Remove container:   docker rm -f ${SERVICE_NAME}"
    echo ""
}

# ========================= Uninstall =========================
uninstall() {
    echo -e "${BOLD}========== Uninstall OBI ==========${NC}"

    if systemctl is-active --quiet "${SERVICE_NAME}" 2>/dev/null; then
        systemctl stop "${SERVICE_NAME}"
    fi
    if [[ -f "/etc/systemd/system/${SERVICE_NAME}.service" ]]; then
        systemctl disable "${SERVICE_NAME}" --quiet 2>/dev/null || true
        rm -f "/etc/systemd/system/${SERVICE_NAME}.service"
        systemctl daemon-reload
        ok "Systemd service removed"
    fi

    if command -v docker &>/dev/null && docker ps -a --format '{{.Names}}' | grep -q "^${SERVICE_NAME}$"; then
        docker rm -f "${SERVICE_NAME}" >/dev/null 2>&1
        ok "Docker container removed"
    fi

    if [[ -d "${INSTALL_DIR}" ]]; then
        rm -rf "${INSTALL_DIR}"
        ok "Installation directory cleaned up"
    fi

    ok "OBI has been completely uninstalled"
}

# ========================= Show Status =========================
show_status() {
    echo -e "${BOLD}========== OBI Running Status ==========${NC}"

    if [[ -f "/etc/systemd/system/${SERVICE_NAME}.service" ]]; then
        echo -e "\n${CYAN}[Systemd Service]${NC}"
        systemctl status "${SERVICE_NAME}" --no-pager 2>/dev/null || true
        echo -e "\n${CYAN}[Recent Logs]${NC}"
        journalctl -u "${SERVICE_NAME}" -n 20 --no-pager 2>/dev/null || true
    fi

    if command -v docker &>/dev/null && docker ps -a --format '{{.Names}}' | grep -q "^${SERVICE_NAME}$"; then
        echo -e "\n${CYAN}[Docker Container]${NC}"
        docker ps -f "name=${SERVICE_NAME}"
        echo -e "\n${CYAN}[Recent Logs]${NC}"
        docker logs "${SERVICE_NAME}" --tail 20 2>&1 || true
    fi

    if [[ -f "${CONFIG_FILE}" ]]; then
        echo -e "\n${CYAN}[Configuration File: ${CONFIG_FILE}]${NC}"
        cat "${CONFIG_FILE}"
    fi
}

# ========================= Binary Installation Main Flow =========================
install_binary() {
    check_env || die "Environment check failed"
    collect_config
    download_obi
    generate_config
    install_systemd
    start_service

    echo ""
    echo -e "${GREEN}============================================${NC}"
    echo -e "${GREEN}  OBI deployment complete!${NC}"
    echo -e "${GREEN}============================================${NC}"
    echo ""
    echo -e "${BOLD}Installation directory:${NC}   ${INSTALL_DIR}"
    echo -e "${BOLD}Configuration file:${NC}   ${CONFIG_FILE}"
    echo ""
    echo -e "Common commands:"
    echo "  View status:   sudo systemctl status ${SERVICE_NAME}"
    echo "  View logs:   sudo journalctl -u ${SERVICE_NAME} -f"
    echo "  Restart service:   sudo systemctl restart ${SERVICE_NAME}"
    echo "  Uninstall:       sudo bash $0 uninstall"
    echo ""
}

# ========================= Entry Point =========================
print_usage() {
    echo ""
    echo -e "${BOLD}OBI One-Click Deployment Script v${VERSION}${NC}"
    echo ""
    echo "Usage: sudo bash $0 <command>"
    echo ""
    echo "Commands:"
    echo "  install    Install as a binary (managed by systemd)"
    echo "  docker     Deploy with Docker"
    echo "  check      Perform environment check only"
    echo "  status     View running status and logs"
    echo "  uninstall  Uninstall OBI"
    echo ""
    echo "Application matching methods (APP_MATCH_TYPE):"
    echo "  port       Match by port number (open_ports)"
    echo "  cmd        Match by command line (exe_path + cmd_args)"
    echo "  exe        Match by executable file path (exe_path)"
    echo "  lang       Auto-discover by programming language (languages)"
    echo "  container  Match by Docker container name (container_name)"
    echo "  pid        Specify by PID (target_pids)"
    echo ""
}

main() {
    local action="${1:-}"
    case "$action" in
        install)   check_root "$@"; install_binary ;;
        docker)    check_root "$@"; check_env || die "Environment check failed"; deploy_docker ;;
        check)     check_root "$@"; check_env ;;
        uninstall) check_root "$@"; uninstall ;;
        status)    check_root "$@"; show_status ;;
        *)         print_usage; exit 1 ;;
    esac
}

main "$@"

Paso 1: obtener la información del endpoint

Inicie sesión en la consola de ARMS. En el panel de navegación izquierdo, haga clic en Integration Center. En la sección de aplicaciones del lado del servidor, haga clic en la tarjeta OpenTelemetry y obtenga los dos valores siguientes:

  • OTEL_EXPORTER_OTLP_ENDPOINT (por ejemplo, http://xxx:4318)

  • OTEL_EXPORTER_OTLP_HEADERS (por ejemplo, Authentication=xxx)

Paso 2: descargar y preparar el script

chmod +x obi-setup.sh

Paso 3: instalación interactiva (archivo binario + systemd)

sudo bash obi-setup.sh install

El script ejecuta de forma secuencial los siguientes pasos: comprobación del entorno > recopilación del endpoint y los encabezados > selección del método de coincidencia de la aplicación (admite 6 escenarios) > incorporación de varias aplicaciones > configuración opcional de reglas de exclusión, muestreo y control de exportación > detección automática de la arquitectura de CPU y descarga de OBI > generación del archivo config.yaml > creación e inicio de un servicio de systemd.

Paso 4: despliegue con Docker

sudo bash obi-setup.sh docker

Paso 5: despliegue no interactivo (escenarios por lotes)

Pase los parámetros mediante variables de entorno para omitir las solicitudes interactivas. Se admiten los siguientes tipos de coincidencia:

# Match by port
export OTLP_ENDPOINT="http://xxx:4318"
export OTLP_HEADERS="Authentication=xxx"
export APP_NAME="my-app"
export APP_MATCH_TYPE="port"
export APP_MATCH_VALUE="8080"
sudo -E bash obi-setup.sh install

# Java application (exe_path + cmd_args)
export APP_MATCH_TYPE="cmd"
export APP_EXE_PATH="*/java"
export APP_CMD_ARGS="*petclinic*"

# Match by programming language
export APP_MATCH_TYPE="lang"
export APP_MATCH_VALUE="java"

# Match by executable file path
export APP_MATCH_TYPE="exe"
export APP_MATCH_VALUE="*/my-server"

# Match by Docker container name
export APP_MATCH_TYPE="container"
export APP_MATCH_VALUE="my-container-*"

# Match by PID
export APP_MATCH_TYPE="pid"
export APP_MATCH_VALUE="12345,67890"

Paso 6: otros comandos

sudo bash obi-setup.sh check      # Run environment checks only
sudo bash obi-setup.sh status     # View running status and logs
sudo bash obi-setup.sh uninstall  # Uninstall OBI

Método 2: despliegue manual paso a paso

Si necesita un control más detallado de cada paso, siga estas instrucciones manuales.

Paso 1: obtener la información del endpoint

Siga el mismo proceso que en el método anterior. Obtenga OTEL_EXPORTER_OTLP_ENDPOINT y OTEL_EXPORTER_OTLP_HEADERS desde la consola de ARMS.

Paso 2: descargar OBI

# amd64 architecture
wget https://arms-apm-cn-hangzhou-pre.oss-cn-hangzhou.aliyuncs.com/obi-agent/0.10.0/obi-linux-amd64 -O obi

# arm64 architecture
wget https://arms-apm-cn-hangzhou-pre.oss-cn-hangzhou.aliyuncs.com/obi-agent/0.10.0/obi-linux-arm64 -O obi

chmod +x obi

Paso 3: redactar el archivo de configuración

Cree un archivo config.yaml. Reemplace <OTLP_ENDPOINT> con el valor real y modifique la sección discovery.instrument según su aplicación. Consulte la sección "Métodos de coincidencia para el descubrimiento de aplicaciones" de este documento para ver las configuraciones adecuadas:

log_level: WARN

otel_metrics_export:
  endpoint: <OTLP_ENDPOINT>/v1/metrics

metrics:
  features:
    - application
    - network
    - stats_tcp_rtt

routes:
  unmatched: low-cardinality
  max_path_segment_cardinality: 500

ebpf:
  context_propagation: all
  track_request_headers: true
  payload_extraction:
    http:
      genai:
        openai:
          enabled: true
        anthropic:
          enabled: true
        jsonrpc:
          enabled: true
        mcp:
          enabled: true
        qwen:
          enabled: true
        rerank:
          enabled: true
        embedding:
          enabled: true
        gemini:
          enabled: true
  buffer_sizes:
    http: 262144

otel_traces_export:
  endpoint: <OTLP_ENDPOINT>
  instrumentations:
    - http
    - grpc
    - sql
    - redis
    - kafka
    - mqtt
    - mongo
    - couchbase
    - memcached
    - genai

nodejs:
  enabled: true

discovery:
  instrument: 
    - name: my-app
      open_ports: 8080

Paso 4: desplegar el servicio

Despliegue de archivo binario (administrado por systemd):

Cree un archivo de servicio de systemd en /etc/systemd/system/obi.service:

[Unit]
Description=OBI eBPF Instrumentation Service
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=root
WorkingDirectory=/path/to/obi-dir
Environment="OTEL_EBPF_CONFIG_PATH=config.yaml"
Environment="OTEL_EXPORTER_OTLP_HEADERS=<Replace with actual value>"
ExecStart=/path/to/obi-dir/obi
Restart=always
RestartSec=5
StandardOutput=journal
StandardError=journal
SyslogIdentifier=obi

[Install]
WantedBy=multi-user.target

Inicie el servicio:

sudo systemctl daemon-reload
sudo systemctl enable obi
sudo systemctl start obi
sudo systemctl status obi

Despliegue con Docker:

docker pull registry.cn-hangzhou.aliyuncs.com/private-mesh/obi:0.10.0

docker run -d \
  --name obi \
  --pid=host \
  --privileged \
  --restart=always \
  -v $(pwd)/config.yaml:/config/config.yaml:ro \
  -e OTEL_EXPORTER_OTLP_HEADERS="<Replace with actual value>" \
  -e OTEL_EXPORTER_OTLP_ENDPOINT="<Replace with actual value>" \
  registry.cn-hangzhou.aliyuncs.com/private-mesh/obi:0.10.0 \
  --config=/config/config.yaml

Comprobar los datos de monitoreo

Inicie sesión en la consola de ARMS. En el panel de navegación izquierdo, haga clic en Application Monitoring. Busque el nombre de la aplicación que configuró en la lista de aplicaciones y haga clic en él para consultar los detalles de monitoreo, como la topología, las trazas y las anomalías.

Comandos comunes de operación y mantenimiento

Operación

Método con systemd

Método con Docker

Consultar el estado

sudo systemctl status obi

docker ps -f name=obi

Consultar los registros

sudo journalctl -u obi -f

docker logs -f obi

Reiniciar

sudo systemctl restart obi

docker restart obi

Detener

sudo systemctl stop obi

docker stop obi

Desinstalar

sudo bash obi-setup.sh uninstall

docker rm -f obi