Skip to content
Thomas Mangin edited this page Feb 2, 2026 · 5 revisions

Docker Integration

Table of Contents

Overview

ExaBGP runs excellently in Docker containers, providing isolated, reproducible deployments. The official Docker image includes all necessary dependencies and follows container best practices.

Key Benefits:

  • Isolation: Separate BGP processes per container
  • Portability: Consistent deployment across environments
  • Scalability: Easy horizontal scaling with orchestration
  • Version Control: Pin specific ExaBGP versions
  • Resource Limits: Control CPU/memory per instance

ExaBGP does NOT manipulate the routing table (RIB/FIB) - it only speaks the BGP protocol. Route installation must be handled by external processes or network devices.

Official Docker Images

Docker Hub

# Pull latest version
docker pull exabgp/exabgp:latest

# Pull specific version
docker pull exabgp/exabgp:5.0.0

# Available tags
docker pull exabgp/exabgp:main      # Development version
docker pull exabgp/exabgp:4.2       # Maintenance 4.x branch

GitHub Container Registry

# Alternative source
docker pull ghcr.io/exa-networks/exabgp:latest

Image Details

  • Base: Python 3.13 slim-bookworm
  • Size: ~150MB
  • User: Non-root user exa
  • Init: Uses dumb-init for proper signal handling
  • Dependencies: iproute2 included

Quick Start

Simple Announcement

Create a configuration file exabgp.conf:

neighbor 192.168.1.1 {
    router-id 10.0.0.1;
    local-address 10.0.0.2;
    local-as 65000;
    peer-as 65001;

    static {
        route 203.0.113.1/32 next-hop self;
    }
}

Run ExaBGP:

docker run -d \
    --name exabgp \
    --network host \
    -v $(pwd)/exabgp.conf:/etc/exabgp/exabgp.conf:ro \
    exabgp/exabgp:latest \
    /etc/exabgp/exabgp.conf

With Health Check Script

Configuration with API process:

process health-check {
    run /usr/local/bin/health_check.py;
    encoder json;
}

neighbor 192.168.1.1 {
    router-id 10.0.0.1;
    local-address 10.0.0.2;
    local-as 65000;
    peer-as 65001;

    api {
        processes [ health-check ];
    }
}

Run with health check script:

docker run -d \
    --name exabgp \
    --network host \
    -v $(pwd)/exabgp.conf:/etc/exabgp/exabgp.conf:ro \
    -v $(pwd)/health_check.py:/usr/local/bin/health_check.py:ro \
    exabgp/exabgp:latest \
    /etc/exabgp/exabgp.conf

Building Custom Images

Basic Dockerfile

FROM exabgp/exabgp:latest

# Add custom health check scripts
COPY health_checks/ /opt/exabgp/health_checks/
RUN chmod +x /opt/exabgp/health_checks/*.py

# Add custom configuration
COPY exabgp.conf /etc/exabgp/exabgp.conf

# Install additional dependencies
USER root
RUN apt-get update && \
    apt-get install -y curl netcat-openbsd && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*

USER exa

ENTRYPOINT ["/usr/bin/dumb-init", "--", "exabgp"]
CMD ["/etc/exabgp/exabgp.conf"]

Build:

docker build -t myorg/exabgp-custom:1.0 .

Multi-Stage Build (From Source)

# syntax=docker/dockerfile:1.4
FROM python:3.13-bookworm AS builder

# Install uv for fast builds
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/

WORKDIR /build

# Copy ExaBGP source
COPY . /build/

# Build wheel
RUN uv build --wheel

# Install to /opt/exabgp
RUN pip install --target /opt/exabgp dist/*.whl

# Production image
FROM python:3.13-slim-bookworm

COPY --from=builder /opt/exabgp /opt/exabgp

ENV PYTHONPATH=/opt/exabgp
ENV PATH=/opt/exabgp/bin:$PATH

# Install runtime dependencies
RUN apt-get update && \
    apt-get install -y iproute2 dumb-init curl && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*

# Create ExaBGP user and directories
RUN useradd -r -u 1000 exa && \
    mkdir -p /etc/exabgp /run/exabgp /var/log/exabgp && \
    mkfifo /run/exabgp/exabgp.{in,out} && \
    chown -R exa:exa /etc/exabgp /run/exabgp /var/log/exabgp && \
    chmod 600 /run/exabgp/exabgp.{in,out}

# Environment configuration
RUN echo "[exabgp.daemon]" > /etc/exabgp/exabgp.env && \
    echo "user = 'exa'" >> /etc/exabgp/exabgp.env && \
    echo "[exabgp.log]" >> /etc/exabgp/exabgp.env && \
    echo "all = false" >> /etc/exabgp/exabgp.env && \
    echo "configuration = true" >> /etc/exabgp/exabgp.env

USER exa
WORKDIR /etc/exabgp

ENTRYPOINT ["/usr/bin/dumb-init", "--", "exabgp"]
CMD ["--help"]

Docker Compose Setup

Basic Setup

version: '3.8'

services:
  exabgp:
    image: exabgp/exabgp:latest
    container_name: exabgp
    network_mode: host
    restart: unless-stopped

    volumes:
      - ./config/exabgp.conf:/etc/exabgp/exabgp.conf:ro
      - ./scripts:/opt/scripts:ro
      - exabgp-logs:/var/log/exabgp

    environment:
      - EXABGP_LOG_LEVEL=INFO
      - EXABGP_API_ACK=true

    command: /etc/exabgp/exabgp.conf

    healthcheck:
      test: ["CMD", "pgrep", "-f", "exabgp"]
      interval: 30s
      timeout: 10s
      retries: 3

volumes:
  exabgp-logs:

High Availability Setup (Multiple Nodes)

version: '3.8'

services:
  # ExaBGP Node 1
  exabgp-node1:
    image: exabgp/exabgp:latest
    hostname: exabgp-node1
    network_mode: host
    restart: unless-stopped

    volumes:
      - ./config/node1.conf:/etc/exabgp/exabgp.conf:ro
      - ./scripts/health_check.py:/opt/scripts/health_check.py:ro
      - node1-logs:/var/log/exabgp

    environment:
      - NODE_ID=1
      - SERVICE_IP=203.0.113.1
      - PRIMARY_METRIC=100

    command: /etc/exabgp/exabgp.conf

  # ExaBGP Node 2
  exabgp-node2:
    image: exabgp/exabgp:latest
    hostname: exabgp-node2
    network_mode: host
    restart: unless-stopped

    volumes:
      - ./config/node2.conf:/etc/exabgp/exabgp.conf:ro
      - ./scripts/health_check.py:/opt/scripts/health_check.py:ro
      - node2-logs:/var/log/exabgp

    environment:
      - NODE_ID=2
      - SERVICE_IP=203.0.113.1
      - PRIMARY_METRIC=101

    command: /etc/exabgp/exabgp.conf

  # Web service (example application)
  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
    volumes:
      - ./html:/usr/share/nginx/html:ro
    depends_on:
      - exabgp-node1
      - exabgp-node2

volumes:
  node1-logs:
  node2-logs:

With Monitoring Stack

version: '3.8'

services:
  exabgp:
    image: exabgp/exabgp:latest
    network_mode: host
    restart: unless-stopped
    volumes:
      - ./config:/etc/exabgp:ro
      - ./scripts:/opt/scripts:ro
    command: /etc/exabgp/exabgp.conf
    labels:
      - "prometheus.scrape=true"
      - "prometheus.port=9576"

  # Prometheus exporter
  exabgp-exporter:
    image: lusis/exabgp_exporter:latest
    ports:
      - "9576:9576"
    environment:
      - EXABGP_HOST=localhost
      - EXABGP_PORT=5000
    depends_on:
      - exabgp

  # Prometheus
  prometheus:
    image: prom/prometheus:latest
    ports:
      - "9090:9090"
    volumes:
      - ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml:ro
      - prometheus-data:/prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'

  # Grafana
  grafana:
    image: grafana/grafana:latest
    ports:
      - "3000:3000"
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=admin
    volumes:
      - grafana-data:/var/lib/grafana
      - ./monitoring/dashboards:/etc/grafana/provisioning/dashboards:ro
    depends_on:
      - prometheus

volumes:
  prometheus-data:
  grafana-data:

Volume Management

Configuration Files

Mount configuration as read-only:

docker run -d \
    -v $(pwd)/exabgp.conf:/etc/exabgp/exabgp.conf:ro \
    exabgp/exabgp:latest

Scripts Directory

Mount scripts directory with execute permissions:

docker run -d \
    -v $(pwd)/scripts:/opt/scripts:ro \
    -v $(pwd)/exabgp.conf:/etc/exabgp/exabgp.conf:ro \
    exabgp/exabgp:latest

Ensure scripts are executable:

chmod +x scripts/*.py

Logs

Persist logs using named volume:

docker run -d \
    -v exabgp-logs:/var/log/exabgp \
    -v $(pwd)/exabgp.conf:/etc/exabgp/exabgp.conf:ro \
    exabgp/exabgp:latest

View logs:

docker exec exabgp tail -f /var/log/exabgp/exabgp.log

Named Pipes (FIFO)

For interactive control:

docker run -d \
    -v $(pwd)/run:/run/exabgp \
    -v $(pwd)/exabgp.conf:/etc/exabgp/exabgp.conf:ro \
    exabgp/exabgp:latest

Send commands:

echo "announce route 203.0.113.1/32 next-hop self" > run/exabgp.in

Multi-Container Patterns

Pattern 1: Sidecar Container

ExaBGP as sidecar to application:

services:
  app:
    image: myapp:latest
    network_mode: "service:exabgp"
    depends_on:
      - exabgp

  exabgp:
    image: exabgp/exabgp:latest
    hostname: app-bgp
    ports:
      - "179:179"  # BGP port
    volumes:
      - ./config/exabgp.conf:/etc/exabgp/exabgp.conf:ro
      - shared-scripts:/opt/scripts
    command: /etc/exabgp/exabgp.conf

volumes:
  shared-scripts:

Pattern 2: Shared Network Stack

Multiple containers sharing network:

services:
  exabgp:
    image: exabgp/exabgp:latest
    network_mode: host
    volumes:
      - ./exabgp.conf:/etc/exabgp/exabgp.conf:ro

  haproxy:
    image: haproxy:latest
    network_mode: host
    volumes:
      - ./haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro
    depends_on:
      - exabgp

Pattern 3: Service Discovery

services:
  exabgp:
    image: exabgp/exabgp:latest
    environment:
      - SERVICE_NAME=web
      - SERVICE_IP=203.0.113.1
      - CONSUL_ADDR=consul:8500
    volumes:
      - ./scripts/consul_discovery.py:/opt/scripts/discovery.py:ro
      - ./exabgp.conf:/etc/exabgp/exabgp.conf:ro

  consul:
    image: consul:latest
    ports:
      - "8500:8500"

Pattern 4: FlowSpec Controller

services:
  # FlowSpec controller
  flowspec-controller:
    image: myorg/flowspec-controller:latest
    environment:
      - EXABGP_HOST=exabgp
      - EXABGP_PORT=5000
    depends_on:
      - exabgp

  # ExaBGP FlowSpec announcer
  exabgp:
    image: exabgp/exabgp:latest
    network_mode: host
    volumes:
      - ./flowspec.conf:/etc/exabgp/exabgp.conf:ro
    command: /etc/exabgp/exabgp.conf

  # DDoS detection (example)
  fastnetmon:
    image: fastnetmon/fastnetmon:latest
    network_mode: host
    environment:
      - EXABGP_HOST=localhost
    depends_on:
      - exabgp

Kubernetes Deployment

See Kubernetes.md for comprehensive Kubernetes integration documentation.

Quick Example:

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: exabgp
  namespace: bgp
spec:
  selector:
    matchLabels:
      app: exabgp
  template:
    metadata:
      labels:
        app: exabgp
    spec:
      hostNetwork: true
      containers:
      - name: exabgp
        image: exabgp/exabgp:latest
        args: ["/etc/exabgp/exabgp.conf"]
        volumeMounts:
        - name: config
          mountPath: /etc/exabgp
          readOnly: true
      volumes:
      - name: config
        configMap:
          name: exabgp-config

Health Checks

Docker Health Check

Add to Dockerfile or docker-compose.yml:

HEALTHCHECK --interval=30s --timeout=10s --retries=3 \
  CMD pgrep -f exabgp || exit 1

BGP Session Check

More sophisticated health check:

#!/bin/bash
# health_check.sh

# Check if ExaBGP process is running
if ! pgrep -f "exabgp" > /dev/null; then
    echo "ExaBGP process not running"
    exit 1
fi

# Check if BGP session is established (requires netstat)
if ! netstat -tn | grep -q ":179.*ESTABLISHED"; then
    echo "No established BGP sessions"
    exit 1
fi

echo "ExaBGP healthy"
exit 0
healthcheck:
  test: ["/opt/scripts/health_check.sh"]
  interval: 30s
  timeout: 10s
  retries: 3
  start_period: 40s

Application Health Integration

Monitor application and announce via BGP:

#!/usr/bin/env python3
# app_health.py

import sys
import time
import requests

def check_app_health():
    try:
        response = requests.get('http://localhost:8080/health', timeout=2)
        return response.status_code == 200
    except:
        return False

# Announce route when healthy
while True:
    if check_app_health():
        sys.stdout.write('announce route 203.0.113.1/32 next-hop self\n')
    else:
        sys.stdout.write('withdraw route 203.0.113.1/32 next-hop self\n')

    sys.stdout.flush()
    time.sleep(10)

Networking

Host Network Mode

Recommended for BGP (needs direct access to network):

docker run -d --network host exabgp/exabgp:latest

Advantages:

  • Direct access to host network interfaces
  • BGP uses standard port 179
  • No NAT/port mapping complexity
  • Full routing table visibility

Considerations:

  • Less isolation
  • Containers share host network stack
  • Port conflicts possible

Bridge Network Mode

For development/testing only:

docker run -d \
    -p 179:179 \
    --network bridge \
    exabgp/exabgp:latest

Not recommended for production - BGP requires proper network access.

Custom Networks

# Create network
docker network create --driver bridge bgp-network

# Run ExaBGP
docker run -d \
    --network bgp-network \
    --name exabgp \
    exabgp/exabgp:latest

Macvlan (Advanced)

For multiple BGP speakers with unique IPs:

# Create macvlan network
docker network create -d macvlan \
    --subnet=192.168.1.0/24 \
    --gateway=192.168.1.1 \
    -o parent=eth0 \
    bgp-macvlan

# Run with unique IP
docker run -d \
    --network bgp-macvlan \
    --ip 192.168.1.10 \
    --name exabgp1 \
    exabgp/exabgp:latest

Troubleshooting

Container Won't Start

Check logs:

docker logs exabgp

Common issues:

  • Invalid configuration syntax
  • Missing configuration file
  • Port 179 already in use
  • Permission issues

BGP Session Not Establishing

Debug networking:

# Check if BGP port is accessible
docker exec exabgp netstat -tlnp | grep 179

# Test connectivity to peer
docker exec exabgp ping -c 3 192.168.1.1

# Check routing table (if host network)
docker exec exabgp ip route

# Verify BGP process
docker exec exabgp ps aux | grep exabgp

Configuration Errors

Validate configuration:

# Check configuration syntax
docker run --rm \
    -v $(pwd)/exabgp.conf:/etc/exabgp/exabgp.conf:ro \
    exabgp/exabgp:latest \
    --test /etc/exabgp/exabgp.conf

Script Not Executing

Check script permissions:

# Inside container
docker exec exabgp ls -la /opt/scripts/

# Should be executable (chmod +x)
chmod +x scripts/*.py

Logs Not Appearing

Enable verbose logging:

[exabgp.log]
all = true
destination = /var/log/exabgp/exabgp.log

Or use environment variable:

docker run -d \
    -e EXABGP_LOG_LEVEL=DEBUG \
    exabgp/exabgp:latest

Performance Issues

Monitor resources:

# Container stats
docker stats exabgp

# Set resource limits
docker run -d \
    --memory="512m" \
    --cpus="1.0" \
    exabgp/exabgp:latest

Production Best Practices

1. Use Specific Version Tags

# Good
image: exabgp/exabgp:5.0.0

# Avoid
image: exabgp/exabgp:latest

2. Read-Only Root Filesystem

services:
  exabgp:
    image: exabgp/exabgp:5.0.0
    read_only: true
    tmpfs:
      - /tmp
      - /run

3. Resource Limits

services:
  exabgp:
    image: exabgp/exabgp:5.0.0
    deploy:
      resources:
        limits:
          cpus: '1.0'
          memory: 512M
        reservations:
          cpus: '0.5'
          memory: 256M

4. Restart Policy

services:
  exabgp:
    image: exabgp/exabgp:5.0.0
    restart: unless-stopped

5. Logging Configuration

services:
  exabgp:
    image: exabgp/exabgp:5.0.0
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"

6. Security Hardening

services:
  exabgp:
    image: exabgp/exabgp:5.0.0
    security_opt:
      - no-new-privileges:true
    cap_drop:
      - ALL
    cap_add:
      - NET_ADMIN  # Only if needed
      - NET_RAW

7. Configuration as Code

# Store configs in git
git/
β”œβ”€β”€ docker-compose.yml
β”œβ”€β”€ config/
β”‚   β”œβ”€β”€ exabgp.conf
β”‚   └── exabgp.env
└── scripts/
    β”œβ”€β”€ health_check.py
    └── announce.py

8. Automated Testing

services:
  exabgp-test:
    image: exabgp/exabgp:5.0.0
    profiles: ["test"]
    command: --test /etc/exabgp/exabgp.conf
    volumes:
      - ./config:/etc/exabgp:ro

Run tests:

docker compose --profile test up exabgp-test

9. Monitoring

Expose metrics:

services:
  exabgp:
    image: exabgp/exabgp:5.0.0
    labels:
      - "prometheus.scrape=true"
      - "prometheus.port=9576"
      - "prometheus.path=/metrics"

10. Backup Configuration

# Backup script
#!/bin/bash
docker exec exabgp cat /etc/exabgp/exabgp.conf > backup/exabgp.conf.$(date +%Y%m%d)

Complete Production Example

Full production-ready docker-compose.yml:

version: '3.8'

services:
  exabgp:
    image: exabgp/exabgp:5.0.0
    container_name: exabgp-prod
    hostname: bgp-node1
    network_mode: host
    restart: unless-stopped

    volumes:
      - ./config/exabgp.conf:/etc/exabgp/exabgp.conf:ro
      - ./config/exabgp.env:/etc/exabgp/exabgp.env:ro
      - ./scripts:/opt/scripts:ro
      - exabgp-logs:/var/log/exabgp

    environment:
      - NODE_ID=1
      - CLUSTER=production
      - REGION=us-east-1

    healthcheck:
      test: ["CMD", "/opt/scripts/health_check.sh"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s

    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "5"
        labels: "service=exabgp"

    security_opt:
      - no-new-privileges:true

    deploy:
      resources:
        limits:
          cpus: '2.0'
          memory: 1G
        reservations:
          cpus: '0.5'
          memory: 256M

    labels:
      - "com.example.service=exabgp"
      - "com.example.environment=production"
      - "prometheus.scrape=true"
      - "prometheus.port=9576"

    command: /etc/exabgp/exabgp.conf

volumes:
  exabgp-logs:
    driver: local
    driver_opts:
      type: none
      o: bind
      device: /var/log/exabgp

See Also

References


πŸ‘» Ghost written by Claude (Anthropic AI)

Clone this wiki locally