Todos os produtos
Search
Central de documentação

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

Última atualização: Sep 18, 2026

Ao usar o OpenTelemetry eBPF Instrumentation (OBI) para enviar dados de rastreamento ao Application Real-Time Monitoring Service (ARMS) de forma não intrusiva, o ARMS inicia o monitoramento das suas aplicações. Visualize a topologia da aplicação, traces de chamadas, transações anômalas, transações lentas, análise de SQL e outros dados de monitoramento. Este tópico descreve como utilizar o OBI para monitorar aplicações e reportar dados.

Pré-requisitos

Nota

Caso encontre problemas ao usar o OpenTelemetry eBPF, entre em contato conosco pelo grupo de perguntas e respostas do DingTalk (número do grupo: 159215000379).

  • Prepare um servidor Linux (instância do Elastic Compute Service (ECS) ou ambiente on-premises) que atenda aos seguintes requisitos.

    Requisito

    Intervalo suportado

    Versão do kernel

    Linux 5.8 ou superior. Distribuições baseadas em RHEL (com patches de backport para eBPF) exigem no mínimo o Linux 4.18.

    BTF

    O kernel deve expor informações BTF (BPF Type Format).

    Arquitetura da CPU

    amd64 (x86_64), arm64 (aarch64).

    Permissões

    Permissões de root.

    Nota

    O Alibaba Cloud Linux 3 e o Alibaba Cloud Linux 4 atendem aos requisitos acima por padrão.

    Para verificar se o seu servidor atende aos requisitos, execute os comandos a seguir:

    # 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

Informações gerais

O OBI é um componente de instrumentação automática baseado em eBPF para observabilidade no Kubernetes. Implantado como DaemonSet nos nós do cluster, ele coleta automaticamente dados de métricas e traces das aplicações sem modificar o código ou injetar sidecars. O OBI detecta automaticamente os principais protocolos, como HTTP, gRPC, SQL, Redis e Kafka, além de extrair profundamente corpos de requisição e resposta para cenários de GenAI (OpenAI, Anthropic, Qwen, MCP, Embedding, Rerank, entre outros). Os dados de telemetria coletados são exportados via protocolo OTLP e integram-se perfeitamente a plataformas de observabilidade como o ARMS, permitindo alcançar observabilidade full-stack com zero intrusão e baixa sobrecarga.

Métodos de correspondência para descoberta de aplicações

O OBI descobre e associa processos para monitoramento por meio da seção de configuração discovery.instrument. Há suporte aos seguintes métodos de correspondência (todas as condições usam lógica AND — todos os critérios devem ser atendidos para haver correspondência):

Campo YAML

Tipo

Descrição

Exemplo

open_ports

Número/faixa de porta

Portas nas quais o processo escuta. Aceita valores separados por vírgula e intervalos.

8080, 80,443, 8000-8999

exe_path

Padrão Glob

Corresponde ao caminho completo do arquivo executável do processo.

/java, /nginx, myapp

cmd_args

Padrão Glob

Corresponde aos argumentos de linha de comando do processo (excluindo o nome do executável).

petclinic, --config=prod

languages

Padrão Glob

Correspondência automática por linguagem de programação (go/java/python/ruby/nodejs/rust/dotnet/php/cpp).

java, {go,rust}

target_pids

Lista de PIDs

Especifica diretamente os PIDs dos processos.

[12345, 67890]

container_name

Padrão Glob

Corresponde a nomes de contêineres OCI (aplicável a implantações Docker).

my-container-*

containers_only

Booleano

Corresponde apenas a processos dentro de contêineres.

true

name

String

Nome da aplicação exibido no console do ARMS.

my-app

namespace

String

Namespace do serviço.

production

exports

Lista de sinais

Controla os tipos de sinais exportados (metrics/traces/logs). Um array vazio desativa todas as exportações.

[metrics, traces]

sampler

Configuração de amostragem

Amostra traces por proporção para reduzir o volume de dados.

name: traceidratio, arg: "0.5"

Exemplos de configuração para cenários comuns

Cenário 1: Correspondência por número de porta — Método mais simples, aplicável a qualquer tipo de aplicação web

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

Cenário 2: Aplicação Java (exe_path + cmd_args) — Localiza o processo pelo executável java e pelo nome do JAR

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

Cenário 3: Descoberta automática por linguagem de programação — Detecta automaticamente todos os processos de uma linguagem especificada

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

Cenário 4: Correspondência por caminho do arquivo executável — Adequado para binários compilados localmente

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

Cenário 5: Correspondência por nome de contêiner Docker — Indicada para implantações Docker no ECS

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

Cenário 6: Múltiplas faixas de portas — Monitora serviços em um intervalo de portas

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

Cenário 7: Especificar PIDs para depuração temporária — Define PIDs de processos específicos para monitoramento direto

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

Cenário 8: Apenas processos em contêineres + amostragem — Monitora exclusivamente processos em contêineres com amostragem de traces de 50%

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

Cenário 9: Múltiplas aplicações + regras de exclusão — Monitora várias aplicações enquanto exclui processos 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*}"

Cenário 10: Controle de sinais exportados — Exporta apenas métricas, sem traces

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

Procedimento

Visão geral do procedimento: Instalar e implantar (obter informações do endpoint > baixar o OBI > escrever o arquivo de configuração > implantar o serviço) > Verificar dados de monitoramento

Instalação e implantação

Há dois métodos de implantação disponíveis: implantação via script com um clique (recomendado) e implantação manual passo a passo.

Método 1: Implantação via script com um clique (recomendado)

Todas as etapas estão reunidas em um único script obi-setup.sh compatível com modos interativo e não interativo.

#!/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 "$@"

Etapa 1: Obter informações do endpoint

Faça login no console do ARMS. No painel de navegação à esquerda, clique em Integration Center. Na seção de aplicações server-side, clique no cartão OpenTelemetry e obtenha os dois valores a seguir:

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

  • OTEL_EXPORTER_OTLP_HEADERS (por exemplo, Authentication=xxx)

Etapa 2: Baixar e preparar o script

chmod +x obi-setup.sh

Etapa 3: Instalação interativa (binário + systemd)

sudo bash obi-setup.sh install

O script executa sequencialmente as etapas a seguir: verificação de ambiente > coleta de endpoint/headers > seleção do método de correspondência da aplicação (6 cenários suportados) > adição de múltiplas aplicações > configuração opcional de regras de exclusão/amostragem/controle de exportação > detecção automática da arquitetura da CPU e download do OBI > geração do config.yaml > criação e inicialização de um serviço systemd.

Etapa 4: Implantação com Docker

sudo bash obi-setup.sh docker

Etapa 5: Implantação não interativa (cenários em lote)

Defina parâmetros por variáveis de ambiente para ignorar os prompts interativos. Há suporte aos seguintes tipos de correspondência:

# 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"

Etapa 6: Outros 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: Implantação manual passo a passo

Para obter controle mais granular sobre cada etapa, siga estes passos manuais.

Etapa 1: Obter informações do endpoint

Conforme descrito acima. Obtenha OTEL_EXPORTER_OTLP_ENDPOINT e OTEL_EXPORTER_OTLP_HEADERS no console do ARMS.

Etapa 2: Baixar o 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

Etapa 3: Escrever o arquivo de configuração

Crie um arquivo config.yaml. Substitua <OTLP_ENDPOINT> pelo valor real e modifique a seção discovery.instrument conforme sua aplicação (consulte a seção "Métodos de correspondência para descoberta de aplicações" acima para configurações adequadas):

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

Etapa 4: Implantar o serviço

Implantação de binário (gerenciado pelo systemd):

Crie um arquivo de serviço systemd em /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 o serviço:

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

Implantação com 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

Verificar dados de monitoramento

Faça login no console do ARMS. No painel de navegação à esquerda, clique em Application Monitoring. Localize o nome da aplicação configurada na lista de aplicações e clique nele para visualizar detalhes de monitoramento, como topologia, traces e anomalias.

Comandos comuns de O&M

Operação

Método systemd

Método Docker

Visualizar status

sudo systemctl status obi

docker ps -f name=obi

Visualizar logs

sudo journalctl -u obi -f

docker logs -f obi

Reiniciar

sudo systemctl restart obi

docker restart obi

Parar

sudo systemctl stop obi

docker stop obi

Desinstalar

sudo bash obi-setup.sh uninstall

docker rm -f obi