After you use OpenTelemetry eBPF Instrumentation (OBI) to report trace data to Application Real-Time Monitoring Service (ARMS) in a non-intrusive manner, ARMS starts monitoring your applications. You can view application topology, call traces, abnormal transactions, slow transactions, SQL analysis, and other monitoring data. This topic describes how to use OBI to monitor applications and report data.
Prerequisites
If you encounter any issues while using OpenTelemetry eBPF, contact us through the DingTalk Q&A group (group number: 159215000379).
A Linux server (Elastic Compute Service (ECS) instance or on-premises environment) that meets the following requirements is prepared.
Requirement
Supported range
Kernel version
Linux 5.8 or later. RHEL-based distributions (with eBPF backport patches) support a minimum of Linux 4.18.
BTF
The kernel must expose BTF (BPF Type Format) information.
CPU architecture
amd64 (x86_64), arm64 (aarch64).
Permissions
Root permissions.
NoteAlibaba Cloud Linux 3 and Alibaba Cloud Linux 4 meet the preceding requirements by default.
To check whether your server meets the requirements, run the following commands:
# 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
Background information
OBI is an eBPF-based automatic instrumentation component for Kubernetes observability. It is deployed as a DaemonSet on cluster nodes and can automatically collect Metrics and Traces data from applications without modifying application code or injecting sidecars. OBI supports automatic detection of mainstream protocols such as HTTP, gRPC, SQL, Redis, Kafka, and others, and provides deep extraction of request and response bodies for GenAI scenarios (OpenAI, Anthropic, Qwen, MCP, Embedding, Rerank, and more). The collected telemetry data is exported through the OTLP protocol and can be seamlessly integrated with observability platforms such as ARMS, helping you achieve zero-intrusion, low-overhead, full-stack observability.
Application discovery matching methods
OBI discovers and matches processes to monitor through the discovery.instrument configuration section. The following matching methods are supported (all conditions use AND logic — all conditions must be met for a match):
YAML field | Type | Description | Example |
open_ports | Port number/range | Port numbers that the process listens on. Comma-separated values and ranges are supported. | 8080, 80,443, 8000-8999 |
exe_path | Glob pattern | Matches the full path of the process executable file. | */java, */nginx, *myapp* |
cmd_args | Glob pattern | Matches process command-line arguments (excluding the executable file name). | *petclinic*, *--config=prod* |
languages | Glob pattern | Automatically matches by programming language (go/java/python/ruby/nodejs/rust/dotnet/php/cpp). | java, {go,rust} |
target_pids | PID list | Directly specifies process PIDs. | [12345, 67890] |
container_name | Glob pattern | Matches OCI container names (applicable to Docker deployments). | my-container-* |
containers_only | Boolean | Matches only processes inside containers. | true |
name | String | The application name displayed in the ARMS console. | my-app |
namespace | String | Service namespace. | production |
exports | Signal list | Controls the exported signal types (metrics/traces/logs). An empty array disables all exports. | [metrics, traces] |
sampler | Sampling config | Samples Traces by ratio to reduce data volume. | name: traceidratio, arg: "0.5" |
Common scenario configuration examples
Scenario 1: Match by port number — Simplest method, applicable to any type of web application
discovery:
instrument:
- name: my-web-app
open_ports: 8080Scenario 2: Java application (exe_path + cmd_args) — Locates the process by the java executable and JAR name
discovery:
instrument:
- name: my-java-app
exe_path: "*/java"
cmd_args: "*petclinic*"Scenario 3: Automatic discovery by programming language — Automatically detects all processes of a specified language
discovery:
instrument:
- name: go-services
languages: go
- name: python-services
languages: "{python,nodejs}"Scenario 4: Match by executable file path — Applicable to self-compiled binaries
discovery:
instrument:
- name: my-binary
exe_path: "*/my-server"Scenario 5: Match by Docker container name — Applicable to Docker deployments on ECS
discovery:
instrument:
- name: my-container-app
container_name: "my-container-*"Scenario 6: Multiple port ranges — Monitors services within a range of ports
discovery:
instrument:
- name: microservices
open_ports: 8080-8090,9090Scenario 7: Specify PIDs for temporary debugging — Directly specifies process PIDs for monitoring
discovery:
instrument:
- name: debug-target
target_pids: [12345]Scenario 8: Container processes only + sampling — Monitors only container processes with 50% Traces sampling
discovery:
instrument:
- name: container-apps
containers_only: true
open_ports: 8080
sampler:
name: traceidratio
arg: "0.5"Scenario 9: Multiple applications + exclusion rules — Monitors multiple applications while excluding specific processes
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*}"Scenario 10: Control exported signals — Exports only Metrics without Traces
discovery:
instrument:
- name: high-qps-app
open_ports: 8080
exports: [metrics]Procedure
Procedure overview: Install and deploy (obtain endpoint information > download OBI > write the configuration file > deploy the service) > Verify monitoring data
Install and deploy
Two deployment methods are available: one-click script deployment (recommended) and manual step-by-step deployment.
Method 1: One-click script deployment (recommended)
All steps are combined into a single obi-setup.sh script that supports both interactive and non-interactive modes.
#!/bin/bash
# ============================================================================
# OBI one-click deployment script
# Combines environment checks, download, configuration generation, and service installation into a complete workflow.
#
# Usage:
# sudo bash obi-setup.sh install — Interactive installation (binary + systemd)
# sudo bash obi-setup.sh docker — Deploy using Docker
# sudo bash obi-setup.sh check — Run environment checks only
# sudo bash obi-setup.sh uninstall — Uninstall the OBI service
# sudo bash obi-setup.sh status — View running status and logs
#
# Non-interactive deployment (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 rules
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 "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 5.8, RHEL-based 4.18)"
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} (not supported)"; 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
}
# ========================= Single Application Configuration =========================
collect_one_app() {
local app_name match_type
local entry=""
prompt_input app_name "Application name (displayed in ARMS console)" "my-app"
echo ""
echo -e " ${BOLD}Select application matching method:${NC}"
echo -e " 1) Port number matching — open_ports, e.g. 8080 or 80,443 or 8000-8999"
echo -e " 2) Command line matching — exe_path + cmd_args, for java -jar scenarios"
echo -e " 3) Executable path matching — exe_path, for self-compiled binaries"
echo -e " 4) Language auto-discovery — languages, auto-detect go/java/python/nodejs etc."
echo -e " 5) Docker container name — container_name, for Docker on ECS"
echo -e " 6) PID specification — 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 (e.g. 8080, 80,443, 8000-8999)" "8080"
entry="${entry}
open_ports: ${ports}"
;;
2)
local exe_path cmd_args
prompt_input exe_path "Executable path glob (e.g. */java)" "*/java"
prompt_input cmd_args "Command line arguments glob (e.g. *petclinic*)"
entry="${entry}
exe_path: \"${exe_path}\"
cmd_args: \"${cmd_args}\""
;;
3)
local exe_path
prompt_input exe_path "Executable 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 " 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" "8080"
entry="${entry}
open_ports: ${ports}"
;;
esac
# Optional: container processes only
if [[ "${match_choice:-1}" != "5" ]]; then
if prompt_yesno "Match only container processes (containers_only)?"; then
entry="${entry}
containers_only: true"
fi
fi
# Optional: sampling
if prompt_yesno "Configure Traces sampling (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 "Sampling parameter (e.g. 0.5 for 50% sampling)" "1.0"
entry="${entry}
sampler:
name: ${sampler_name}
arg: \"${sampler_arg}\""
fi
APP_ENTRIES+=("$entry")
ok "Application added: ${app_name}"
}
# ========================= Collect Configuration =========================
collect_config() {
echo -e "${BOLD}========== Configuration ==========${NC}"
echo ""
info "Obtain the following information from the ARMS Integration Center page:"
info " ARMS console -> Integration Center -> OpenTelemetry card -> 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 "Application added: ${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 "Continue adding another application?"; then
break
fi
done
# Optional: exclusion rules
echo ""
if prompt_yesno "Configure exclusion rules (exclude_instrument)?"; then
echo -e " Enter the executable 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 "Exclusion rule added: ${exclude_val}"
fi
}
# ========================= Generate Configuration File =========================
generate_config() {
local endpoint_metrics="${OTLP_ENDPOINT}/v1/metrics"
# Build instrument section
local instrument_yaml=""
for entry in "${APP_ENTRIES[@]}"; do
instrument_yaml="${instrument_yaml}
${entry}"
done
# Build exclude section
local exclude_yaml=""
if [[ -n "$EXCLUDE_PATTERN" ]]; then
exclude_yaml="
exclude_instrument:
- exe_path: \"${EXCLUDE_PATTERN}\""
fi
cat > "${CONFIG_FILE}" <<YAML
# OBI Configuration File - Auto-generated by obi-setup.sh
# Generated at: $(date '+%Y-%m-%d %H:%M:%S')
log_level: WARN
# ========== Metrics Export ==========
otel_metrics_export:
endpoint: ${endpoint_metrics}
metrics:
features:
- application
- network
- stats_tcp_rtt
routes:
nmatched: low-cardinality
max_path_segment_cardinality: 500
# ========== eBPF Probe Configuration ==========
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
rerank:
enabled: true
buffer_sizes:
http: 262144
# ========== Traces Export ==========
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
# ========== Application Discovery Rules ==========
discovery:
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 for auto-start"
}
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 "OBI service failed to start. Error logs:"
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 "Container failed to start:"
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"
}
# ========================= Status Check =========================
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 using binary (managed by systemd)"
echo " docker Deploy using Docker"
echo " check Run environment checks only"
echo " status View running status and logs"
echo " uninstall Uninstall OBI"
echo ""
echo "Application matching types (APP_MATCH_TYPE):"
echo " port Port number matching (open_ports)"
echo " cmd Command line matching (exe_path + cmd_args)"
echo " exe Executable path matching (exe_path)"
echo " lang Language auto-discovery (languages)"
echo " container Docker container name matching (container_name)"
echo " pid PID specification (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 "$@"Step 1: Obtain endpoint information
Log on to the ARMS console. In the left-side navigation pane, click Integration Center. In the server-side applications section, click the OpenTelemetry card and obtain the following two values:
OTEL_EXPORTER_OTLP_ENDPOINT(for example,http://xxx:4318)OTEL_EXPORTER_OTLP_HEADERS(for example,Authentication=xxx)
Step 2: Download and prepare the script
chmod +x obi-setup.shStep 3: Interactive installation (binary + systemd)
sudo bash obi-setup.sh installThe script sequentially performs the following steps: environment check > collect endpoint/headers > select application matching method (6 scenarios supported) > support adding multiple applications > optionally configure exclusion rules/sampling/export control > automatically detect CPU architecture and download OBI > generate config.yaml > create a systemd service and start it.
Step 4: Docker deployment
sudo bash obi-setup.sh dockerStep 5: Non-interactive deployment (batch scenarios)
Pass parameters through environment variables to skip interactive prompts. The following matching types are supported:
# 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"
Step 6: Other commands
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 OBIMethod 2: Manual step-by-step deployment
If you need more fine-grained control over each step, follow these manual steps.
Step 1: Obtain endpoint information
Same as above. Obtain OTEL_EXPORTER_OTLP_ENDPOINT and OTEL_EXPORTER_OTLP_HEADERS from the ARMS console.
Step 2: Download 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 obiStep 3: Write the configuration file
Create a config.yaml file. Replace <OTLP_ENDPOINT> with the actual value and modify the discovery.instrument section based on your application (see the "Application discovery matching methods" section above for appropriate configurations):
log_level: WARN
otel_metrics_export:
endpoint: <OTLP_ENDPOINT>/v1/metrics
metrics:
features:
- application
- network
- stats_tcp_rtt
routes:
nmatched: 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
rerank:
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:
# Select the matching method based on your scenario. See the "Application discovery matching methods" section.
- name: my-app
open_ports: 8080Step 4: Deploy the service
Binary deployment (managed by systemd):
Create a systemd service file /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.targetStart the service:
sudo systemctl daemon-reload
sudo systemctl enable obi
sudo systemctl start obi
sudo systemctl status obi
Docker deployment:
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.yamlVerify monitoring data
Log on to the ARMS console. In the left-side navigation pane, click Application Monitoring. Find the application name you configured in the application list and click it to view monitoring details such as topology, traces, and anomalies.
Common O&M commands
Operation | systemd method | Docker method |
View status | sudo systemctl status obi | docker ps -f name=obi |
View logs | sudo journalctl -u obi -f | docker logs -f obi |
Restart | sudo systemctl restart obi | docker restart obi |
Stop | sudo systemctl stop obi | docker stop obi |
Uninstall | sudo bash obi-setup.sh uninstall | docker rm -f obi |