Development Workflow
Welcome to the Mermin contributor guide! This document will help you set up your development environment, build the project, run tests, and contribute effectively to Mermin.
Prerequisites
Ensure you have the following installed:
Stable Rust Toolchain:
rustup toolchain install stableNightly Rust Toolchain:
rustup toolchain install nightly --component rust-srcbpf-linker:
cargo install bpf-linker(use--no-default-featureson macOS — optionally specify your llvm version with--features llvm-21)(if cross-compiling) rustup target:
rustup target add ${ARCH}-unknown-linux-musl(if cross-compiling) LLVM: (e.g.)
brew install llvm(on macOS)(if cross-compiling) C toolchain: (e.g.)
brew install filosottile/musl-cross/musl-cross(on macOS)
Build and Run Locally
Mermin supports multiple local development workflows depending on your needs:
Bare Metal (Native)
Low
Fast (seconds)
Rapid eBPF/userspace development, packet parsing logic
Dockerized Build
Medium
Medium (minutes)
Cross-platform development (macOS), CI/CD environment parity
Kubernetes (kind)
High
Slow (minutes)
Testing K8s metadata enrichment, Helm charts, full deployment scenarios
Choosing your workflow:
Bare Metal (Native): Requires Linux, but provides instant feedback. Run
cargo buildand execute the binary directly withsudo. Ideal for iterating on eBPF programs, packet parsing, and core flow logic. Cannot test Kubernetes metadata enrichment without a cluster.Dockerized Build: Use a Docker container for building to match the CI/CD environment. Useful on macOS or when you need a consistent, reproducible build environment. Slightly slower than native builds but works anywhere Docker runs.
Kubernetes (kind): Full integration testing environment. Deploy to a local Kubernetes cluster for testing Kubernetes metadata enrichment, Helm chart configurations, and complete deployment scenarios. Highest setup complexity and slowest iteration cycle, but essential for validating end-to-end functionality.
1. Build the mermin agent
mermin agentThe build script automatically compiles the eBPF program and embeds it into the final binary.
Pull Pre-built Images
You may optionally pull the existing image for testing purposes instead of building locally. Check the latest releases to find the most recent version tag.
2. Configuration Files
Mermin supports configuration in both HCL and YAML formats. A comprehensive example configuration file is provided at charts/mermin/config/examples/config.hcl, which includes:
Stdout exporter enabled: Flow data printed to console for easy debugging
OTLP exporter configured: With placeholders for authentication and TLS settings
Kubernetes metadata enrichment: Default Pod, Service, Deployment associations and selectors
Interface discovery: Defaults for automatic detection and attachment to network interfaces
Flow filtering: Configurable filters for source, destination, network, and flow attributes
Parser options: Tunnel protocol detection (VXLAN, Geneve, WireGuard) and protocol parsing flags
Logging: Set to
infolevel by default
For local development, create a minimal configuration in the local/ directory. Here's a simple starter config that enables stdout output:
The comprehensive example at charts/mermin/config/examples/config.hcl can be used as a reference for more advanced configuration options.
Converting between HCL and YAML:
Mermin also supports YAML configuration. You can convert between formats using the fmtconvert tool:
3. Run the agent
Running the eBPF agent requires elevated privileges. Use the --config flag to specify your configuration file.
Note: You can run without a configuration file, but the default settings disable stdout and OTLP exporting, so you won't see any flow trace output. For local development, it's recommended to use atleast a configuration file with stdout exporting enabled (see the minimal config example above).
Using HCL:
Using YAML:
If you prefer YAML format, you can convert your HCL config on-the-fly:
The
sudo -Ecommand runs the program as root while preserving the user's environment variables, which is necessary forcargoto find the correct binary.
4. Generate Traffic
Once the program is running, open a new terminal and generate some network activity to see the logs.
If you experience unexpected results, try to run
cargo cleanbefore each build to avoid stale artifacts.
Testing and Linting
Run unit tests
Run the following commands to run the unit tests for the main application.
Run the following command to run the unit tests for the eBPF program only:
Format your code
Run Clippy for lints
"hack" hints
Generate metrics description for the app-metrics docs with
jqDownload Grafana dashboard JSON from a local Grafana instance
Using a Dockerized Build Environment
To ensure a consistent and reproducible build environment that matches the CI/CD pipeline, you can use Docker. This is especially helpful on platforms like macOS.
1. Build the containerized environment
2. Run commands inside the container
This mounts your local repository into the container at /app.
Inside the container's shell, you can now run any of the cargo build or test commands mentioned above.
Testing on local Kind K8s cluster
You can create a local cluster, build the Mermin image, and deploy it with a single command sequence:
Alternative deployment options:
Optionally install metrics-server to get metrics if it has not been installed yet
Optionally install Prometheus/Grafana to get Mermin metrics: Not intended for a production usage, Grafana auth is disabled (insecure).
Iterating on Code Changes
When making changes to the Mermin code, you can quickly rebuild and reload the image into kind without redeploying the entire Helm chart:
This workflow is much faster than a full helm upgrade when you're only changing the application code.
Note: For this workflow to work, your
values.yamlmust configure the image to use the local build. The example atdocs/deployment/examples/local/values.yamlalready includes these settings.
Required image configuration:
Note: The repository includes a
Makefilewith convenience targets (make k8s-get,make k8s-diff) for some of these commands.
Verifying the Deployment
Check that the
merminpods are running on each node. You should see one pod per worker node.View the logs from any of the Mermin pods to see network flow data.
To generate some network traffic, try pinging between pods in your cluster.
Cleanup
To remove Mermin from your cluster, uninstall the Helm chart. To tear down the entire cluster, use kind delete.
Cross-Compiling
To build a Linux binary from a different OS (like macOS), you can cross-compile. The following command builds for a specified architecture (e.g., aarch64 or x86_64).
The final binary will be located at target/${ARCH}-unknown-linux-musl/release/mermin and can be copied to a Linux server to be executed.
Setting Up rust-analyzer on macOS
Since Mermin is a Linux eBPF project, rust-analyzer needs to be configured to check code for the Linux target instead of macOS. Without this configuration, you'll encounter proc-macro errors and type mismatches in Cursor/VS Code.
Configure VS Code/Cursor settings
Create or update .vscode/settings.json in the project root with the following configuration (adjust ARCH to match your system):
Note: Replace
aarch64withx86_64throughout the configuration if you're on an Intel Mac.
Next Steps
Once you have your development environment set up, you may want to explore:
Debugging Network Traffic - Learn how to use Wireshark for live packet capture
Debugging eBPF Programs - Deep dive into eBPF program inspection and optimization
Deployment Documentation - Understand production deployment scenarios
Getting Help
If you encounter issues during development:
Check the Troubleshooting Guide
Ask questions in GitHub Discussions
Report bugs via GitHub Issues
Last updated