# Understanding the Architecture of the Easegress Agent: Sidecar Observability Deep Dive

> Explore the Easegress agent architecture. Learn how this Java sidecar enhances applications, exposes a local HTTP API for configuration, and pushes JMX metrics without using quotes or special characters.

- Repository: [easegress-io/easegress](https://github.com/easegress-io/easegress)
- Tags: architecture
- Published: 2026-03-01

---

**The Easegress Agent (EaseAgent) is a Java-based sidecar that instruments applications via bytecode enhancement, exposing a local HTTP API on port 9900 to receive configuration from the Easegress control plane and push JMX-based metrics, logs, and traces.**

The architecture of the Easegress agent forms the backbone of Easegress's service mesh observability capabilities. Implemented in the `easegress-io/easegress` repository, this sidecar component runs alongside service instances to provide metrics, logging, and distributed tracing without requiring modifications to application code.

## Core Components of the Easegress Agent Architecture

The Easegress Agent architecture consists of three logical parts that work together to form a complete control-plane to data-plane observability loop.

### Agent Process (Java Side-Car)

The **Agent Process** is the Java-based sidecar that runs within the same pod or host as the service instance. According to the source analysis, this component:

- **Instruments the application** using bytecode enhancement to capture metrics and traces without code changes
- **Exposes a minimal HTTP API** on `localhost:9900` with endpoints `/config` and `/agent-info`
- **Collects JMX-based metrics** from the Java application and pushes them to the configured reporter endpoint
- **Handles TLS configuration** for secure communication with the observability backend

The agent type is declared in the `ServiceInstanceSpec` via the `AgentType` field, which can be set to `EaseAgent`, `GoSDK`, or empty (`None`) as defined in [`pkg/object/meshcontroller/spec/spec.go`](https://github.com/easegress-io/easegress/blob/main/pkg/object/meshcontroller/spec/spec.go).

### Agent Client (jmxtool)

The **Agent Client** is a Go HTTP client implemented in [`pkg/util/jmxtool/agent_controller.go`](https://github.com/easegress-io/easegress/blob/main/pkg/util/jmxtool/agent_controller.go) that enables the mesh controller to communicate with the Java sidecar:

- **Serializes `AgentConfig`** structures containing service specifications, header whitelists, and reporter TLS settings
- **Issues HTTP `PUT` requests** to `http://host:port/config` to push configuration updates
- **Queries `GET /agent-info`** to retrieve the agent version and type (`EaseAgent` or `GoSDK`) for health checks and upgrade validation

The client handles the protocol translation between the Go-based control plane and the Java-based agent.

### Observability Manager

The **Observability Manager** resides in the mesh controller worker and orchestrates the agent lifecycle:

- **Creates the `AgentClient`** targeting `localhost:9900` as implemented in [`pkg/object/meshcontroller/worker/observability.go`](https://github.com/easegress-io/easegress/blob/main/pkg/object/meshcontroller/worker/observability.go)
- **Builds `AgentConfig`** from the current `ServiceSpec` and canary rules, including the comma-separated list of headers that must be forwarded
- **Periodically pushes updates** every 30 seconds via `worker.updateAgentConfig()` (lines 283-327 in [`pkg/object/meshcontroller/worker/worker.go`](https://github.com/easegress-io/easegress/blob/main/pkg/object/meshcontroller/worker/worker.go))
- **Retrieves health information** to monitor agent connectivity and version compatibility

## Control-Plane to Data-Plane Communication Flow

The architecture of the Easegress agent implements a complete configuration and telemetry loop between the control plane and the sidecar:

1. **Mesh Controller Worker** loads the `ServiceSpec` from [`pkg/object/meshcontroller/spec/spec.go`](https://github.com/easegress-io/easegress/blob/main/pkg/object/meshcontroller/spec/spec.go), including `AgentType`, sidecar image name, and canary headers.

2. **Worker initializes ObservabilityManager**, which creates an `AgentClient` configured to communicate with `localhost:9900`.

3. **ObservabilityManager builds AgentConfig** containing the full service definition, header whitelist (e.g., `x-demo-header,authorization`), and optional `AgentReporter` configuration with TLS credentials.

4. **AgentClient pushes configuration** via HTTP `PUT` to `/config`. The Java sidecar unmarshals the JSON, updates its internal JMX exporter, and begins pushing metrics to the configured reporter endpoint.

5. **EaseAgent streams telemetry** through its reporter (e.g., OpenTelemetry collector) back to the Easegress observability stack for display in the portal or external monitoring systems.

6. **Health monitoring** occurs when the control plane queries `GET /agent-info` to fetch agent type and version, enabling automatic upgrade checks and compatibility validation.

## Key Implementation Details

Several critical implementation details govern how the Easegress agent architecture handles configuration and security:

- **AgentType Declaration**: The `ServiceInstanceSpec` struct defines `AgentType` to distinguish between `EaseAgent`, `GoSDK`, or `None`, determining which instrumentation mechanism to activate.

- **TLS Credential Handling**: Reporter TLS certificates are stored base64-encoded in the mesh spec and decoded at runtime via `decodeBase64` before being passed to the agent configuration.

- **Configuration Refresh Cycle**: The worker invokes `updateAgentConfig()` every 30 seconds (as seen in [`worker.go`](https://github.com/easegress-io/easegress/blob/main/worker.go) lines 260-317), ensuring that changes to canary headers or mTLS settings propagate without requiring sidecar restarts.

- **Localhost Binding**: The agent HTTP API binds to `localhost:9900` by default, ensuring that only local processes (the mesh controller worker) can access the configuration endpoints.

## Code Example: Configuring the Agent

The following Go example demonstrates how the mesh controller creates a client and pushes configuration to the Easegress Agent, mirroring the logic found in `worker.updateAgentConfig()`:

```go
// Create a client that talks to the side-car running on the same host.
client := jmxtool.NewAgentClient("localhost", "9900")

// Build the AgentConfig – normally the Mesh controller fills these
// fields from the ServiceSpec.
cfg := &jmxtool.AgentConfig{
    Service: spec.Service{
        Name:          "my-service",
        RegisterTenant: "default",
        Sidecar: &spec.Sidecar{
            Address:      "10.1.2.3",
            IngressPort:  9900,
            EgressPort:   9901,
        },
    },
    Headers: "x-demo-header,authorization",
    Reporter: &jmxtool.AgentReporter{
        ReporterTLS: &jmxtool.AgentReporterTLS{
            Enable: true,
            CACert: "base64-ca",
            Cert:   "base64-cert",
            Key:    "base64-key",
        },
        AppendType:      "http",
        BootstrapServer: "http://observability:9090",
        Username:        "agent",
        Password:        "s3cr3t",
    },
}

// Push the configuration to the side-car.
if err := client.UpdateAgentConfig(cfg); err != nil {
    logger.Errorf("failed to update agent config: %v", err)
}

```

This implementation references the actual source in [`pkg/object/meshcontroller/worker/worker.go`](https://github.com/easegress-io/easegress/blob/main/pkg/object/meshcontroller/worker/worker.go) (lines 283-327), where the worker constructs the `AgentConfig` from the current service specification and canary rules before pushing updates every 30 seconds.

## Summary

The architecture of the Easegress agent implements a robust sidecar observability pattern through three integrated components:

- **Java-based Agent Process** runs alongside service instances, instrumenting applications via bytecode enhancement and exposing a local HTTP API on port 9900 for configuration and health checks.
- **Go-based Agent Client** (`jmxtool`) enables the mesh controller to serialize and push `AgentConfig` structures containing service specifications, header whitelists, and TLS reporter settings to the sidecar.
- **Observability Manager** orchestrates the control-plane loop, refreshing agent configuration every 30 seconds and retrieving health information without requiring sidecar restarts.

Together, these components form a complete telemetry pipeline that streams JMX-based metrics, logs, and traces from the data plane to the Easegress observability stack.

## Frequently Asked Questions

### What port does the Easegress Agent use for communication?

The Easegress Agent exposes its HTTP API on **port 9900** by default, binding to localhost. This port handles `PUT /config` requests for configuration updates and `GET /agent-info` requests for health and version checks. The `AgentClient` in [`pkg/util/jmxtool/agent_controller.go`](https://github.com/easegress-io/easegress/blob/main/pkg/util/jmxtool/agent_controller.go) targets this port when communicating with the sidecar.

### How does the Easegress Agent instrument applications?

The agent uses **bytecode enhancement** to instrument Java applications without requiring code changes. As a Java sidecar, it attaches to the application process and modifies bytecode at runtime to capture metrics, logs, and traces. This approach allows the `EaseAgent` type (specified in the `ServiceInstanceSpec.AgentType` field) to collect JMX-based metrics transparently from the running service.

### What is the refresh interval for agent configuration updates?

The mesh controller worker pushes configuration updates to the Easegress Agent every **30 seconds**. This refresh cycle, implemented in [`pkg/object/meshcontroller/worker/worker.go`](https://github.com/easegress-io/easegress/blob/main/pkg/object/meshcontroller/worker/worker.go) (lines 260-317), ensures that changes to canary headers, mTLS settings, or service specifications propagate to the sidecar without requiring a restart. The `updateAgentConfig()` function handles this periodic synchronization.

### How are TLS credentials handled in the Easegress Agent architecture?

TLS credentials for the agent's reporter are stored **base64-encoded** in the mesh specification and decoded at runtime before being passed to the agent configuration. The `AgentReporter` structure in the `AgentConfig` includes `AgentReporterTLS` fields for `CACert`, `Cert`, and `Key`, all handled as base64 strings in [`pkg/object/meshcontroller/spec/spec.go`](https://github.com/easegress-io/easegress/blob/main/pkg/object/meshcontroller/spec/spec.go). This ensures secure transmission of certificate data from the control plane to the sidecar's observability reporter.