Opservant can be deployed as a Docker container, a systemd service on a Linux host, or a Kubernetes DaemonSet. Choose the method that best fits your infrastructure.

Prerequisites

Before deploying, ensure you have:

  • An agent registration token generated from the S4E dashboard under Settings > Agents > Add Agent.
  • The S4E platform URL (e.g., https://platform.s4e.io or your on-premises endpoint).
  • Outbound HTTPS (port 443) access from the host to the platform URL.

1. Docker

Quick start

docker run -d \
  --name opservant \
  --restart unless-stopped \
  --network host \
  -e S4E_API_URL=https://platform.s4e.io \
  -e S4E_AGENT_TOKEN=<registration-token> \
  -e S4E_AGENT_ID=<agent-id> \
  -v opservant-data:/var/lib/opservant \
  s4e/opservant:latest

Note

Using --network host gives the agent visibility into the host's network stack, which is required for accurate network discovery. If host networking is not an option, ensure the container can reach target subnets through Docker network configuration.

Docker Compose

version: "3.9"
services:
  opservant:
    image: s4e/opservant:latest
    container_name: opservant
    restart: unless-stopped
    network_mode: host
    environment:
      S4E_API_URL: https://platform.s4e.io
      S4E_AGENT_TOKEN: ${S4E_AGENT_TOKEN}
      S4E_AGENT_ID: ${S4E_AGENT_ID}
      S4E_LOG_LEVEL: INFO
    volumes:
      - opservant-data:/var/lib/opservant
      - /etc/opservant/config.yaml:/etc/opservant/config.yaml:ro

volumes:
  opservant-data:

The named volume opservant-data persists agent state (registration certificates, local task queue, SQLite database) across container restarts and upgrades.


2. systemd

Installation

Download the latest release archive and extract it:

curl -LO https://releases.s4e.io/opservant/latest/opservant-linux-amd64.tar.gz
tar -xzf opservant-linux-amd64.tar.gz -C /opt/opservant
chmod +x /opt/opservant/bin/opservant

Create the configuration directory and place your config file:

mkdir -p /etc/opservant
cp /opt/opservant/examples/config.yaml /etc/opservant/config.yaml

Edit /etc/opservant/config.yaml to set your platform URL, agent token, and agent ID (see the configuration reference below).

Unit file

Create /etc/systemd/system/opservant.service:

[Unit]
Description=Opservant S4E Agent
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
ExecStart=/opt/opservant/bin/opservant --config /etc/opservant/config.yaml
Restart=on-failure
RestartSec=10
User=opservant
Group=opservant
LimitNOFILE=65536
Environment=S4E_LOG_LEVEL=INFO

[Install]
WantedBy=multi-user.target

Service management

sudo systemctl daemon-reload
sudo systemctl enable opservant
sudo systemctl start opservant
sudo systemctl status opservant
journalctl -u opservant -f

Tip

Create a dedicated opservant system user with no login shell (useradd -r -s /usr/sbin/nologin opservant) to follow the principle of least privilege.


3. Kubernetes DaemonSet

The DaemonSet ensures one Opservant pod runs on every selected node, which is ideal for scanning each node's local network segment.

Manifest

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: opservant
  namespace: s4e-agents
  labels:
    app: opservant
spec:
  selector:
    matchLabels:
      app: opservant
  template:
    metadata:
      labels:
        app: opservant
    spec:
      hostNetwork: true
      dnsPolicy: ClusterFirstWithHostNet
      serviceAccountName: opservant
      nodeSelector:
        s4e.io/scan-agent: "true"
      tolerations:
        - key: node-role.kubernetes.io/master
          effect: NoSchedule
      containers:
        - name: opservant
          image: s4e/opservant:latest
          env:
            - name: S4E_API_URL
              value: "https://platform.s4e.io"
            - name: S4E_AGENT_TOKEN
              valueFrom:
                secretKeyRef:
                  name: opservant-credentials
                  key: token
            - name: S4E_AGENT_ID
              valueFrom:
                fieldRef:
                  fieldPath: spec.nodeName
          resources:
            requests:
              cpu: 100m
              memory: 128Mi
            limits:
              cpu: 500m
              memory: 512Mi
          volumeMounts:
            - name: state
              mountPath: /var/lib/opservant
          livenessProbe:
            httpGet:
              path: /healthz
              port: 9191
            initialDelaySeconds: 15
            periodSeconds: 30
          readinessProbe:
            httpGet:
              path: /readyz
              port: 9191
            initialDelaySeconds: 5
            periodSeconds: 10
      volumes:
        - name: state
          emptyDir: {}

RBAC

The agent pod requires a ServiceAccount with minimal permissions. It does not need access to the Kubernetes API - the ServiceAccount exists solely to pull image secrets and mount volumes.

apiVersion: v1
kind: ServiceAccount
metadata:
  name: opservant
  namespace: s4e-agents

Warning

Do not grant the Opservant ServiceAccount cluster-admin or broad RBAC roles. The agent operates at the network level and does not interact with the Kubernetes control plane.

Node selector

Label target nodes to control where the DaemonSet schedules pods:

kubectl label node worker-01 s4e.io/scan-agent=true

Configuration File

The primary configuration file is located at /etc/opservant/config.yaml. Command-line flags and environment variables override values in this file.

platform:
  api_url: https://platform.s4e.io
  agent_id: agent-eu-west-01
  token: <registration-token>

agent:
  heartbeat_interval: 30s
  task_concurrency: 4
  scratch_dir: /tmp/opservant

logging:
  level: INFO
  output: stdout
  file: /var/log/opservant/agent.log

proxy:
  https: ""

Environment Variable Reference

Variable Description Default
S4E_API_URL Platform API endpoint required
S4E_AGENT_TOKEN One-time registration token required
S4E_AGENT_ID Unique agent identifier hostname
S4E_LOG_LEVEL Log verbosity (DEBUG, INFO, WARNING, ERROR, CRITICAL) INFO
S4E_HEARTBEAT_INTERVAL Heartbeat frequency in seconds 30
S4E_TASK_CONCURRENCY Max parallel executor tasks 4
S4E_SCRATCH_DIR Temporary working directory for executors /tmp/opservant
S4E_PROXY_HTTPS HTTPS proxy URL for outbound connections none
S4E_TLS_CA_CERT Path to custom CA certificate bundle system default

Health Check Endpoint

The agent exposes a local HTTP health endpoint on port 9191 (configurable via S4E_HEALTH_PORT).

Path Purpose
/healthz Returns 200 OK when the agent process is alive
/readyz Returns 200 OK when the agent is registered and the WebSocket channel is connected
/metrics Prometheus-compatible metrics (task counts, executor durations, heartbeat status)
curl -s http://localhost:9191/healthz
# {"status": "ok", "uptime": "4h12m", "version": "1.6.2"}

Upgrading the Agent

Docker

Pull the new image and recreate the container. The persistent volume retains agent state.

docker pull s4e/opservant:latest
docker stop opservant && docker rm opservant
# Re-run the docker run command or docker compose up -d

systemd

Replace the binary and restart the service:

curl -LO https://releases.s4e.io/opservant/latest/opservant-linux-amd64.tar.gz
tar -xzf opservant-linux-amd64.tar.gz -C /opt/opservant
sudo systemctl restart opservant

Kubernetes

Update the image tag in the DaemonSet manifest and apply:

kubectl set image daemonset/opservant opservant=s4e/opservant:1.7.0 -n s4e-agents

Tip

Enable the auto-update feature in the agent configuration (agent.auto_update: true) to let the platform push verified updates to agents without manual intervention.