# HarborKV

HarborKV is a distributed, strongly consistent key-value store designed for service coordination, configuration data, and low-latency application state. Nodes form a cluster using the Raft consensus protocol, replicate data across configurable failure domains, and expose HTTP and gRPC APIs.

> HarborKV is suitable for metadata and coordination workloads. It is not intended for large objects, analytics, or high-volume event storage.

## Features

- Strongly consistent reads and writes
- Raft-based replication and automatic leader election
- Compare-and-swap transactions
- Time-to-live (TTL) support
- Prefix scans and watches
- Automatic snapshotting and log compaction
- TLS encryption and optional mutual TLS
- Token-based client authentication
- Prometheus-compatible metrics
- HTTP and gRPC client APIs
- Single-node mode for local development

## Installation

### Prebuilt binaries

Download a release for your platform, extract it, and place the binaries on your `PATH`:

```sh
tar -xzf harborkv_1.4.0_linux_amd64.tar.gz
sudo install harborkv harborctl /usr/local/bin/
```

Verify the installation:

```sh
harborkv version
harborctl version
```

### Docker

```sh
docker pull ghcr.io/harborkv/harborkv:1.4.0
```

### Build from source

Building requires Go 1.24 or later:

```sh
git clone https://github.com/harborkv/harborkv.git
cd harborkv
make build
```

The resulting binaries are written to `bin/`.

## Usage

### Start a local node

```sh
harborkv \
  --name node-1 \
  --data-dir ./data/node-1 \
  --client-addr 127.0.0.1:7400 \
  --peer-addr 127.0.0.1:7401 \
  --bootstrap
```

Check cluster health:

```sh
harborctl --endpoint http://127.0.0.1:7400 status
```

### Store and retrieve values

```sh
harborctl put /services/payments/url https://payments.internal
harborctl get /services/payments/url
harborctl delete /services/payments/url
```

Values can also be read from standard input:

```sh
printf '%s' '{"enabled":true}' | harborctl put /features/checkout --stdin
```

### Use TTLs

Store a value that expires after five minutes:

```sh
harborctl put /sessions/8c21 active --ttl 5m
```

### List keys by prefix

```sh
harborctl get /services/ --prefix
```

### Watch for changes

```sh
harborctl watch /services/ --prefix
```

### Conditional updates

Update a key only when its revision matches:

```sh
harborctl put /config/version v2 --if-revision 18
```

### HTTP API

```sh
curl -X PUT \
  -H 'Content-Type: application/json' \
  -d '{"value":"aGVsbG8="}' \
  http://127.0.0.1:7400/v1/kv/example

curl http://127.0.0.1:7400/v1/kv/example
```

API values are Base64-encoded so arbitrary binary data can be stored safely.

## Running a Cluster

Production clusters should contain an odd number of voting nodes. A three-node cluster tolerates one unavailable node; a five-node cluster tolerates two.

Start the initial node:

```sh
harborkv --config /etc/harborkv/node-1.yaml
```

Join additional nodes using an existing member as the seed:

```sh
harborkv --config /etc/harborkv/node-2.yaml --join https://10.0.1.11:7401
harborkv --config /etc/harborkv/node-3.yaml --join https://10.0.1.11:7401
```

Each node must have a unique name and a peer address reachable by every other cluster member. Do not place the data directory on a network filesystem.

## Configuration

HarborKV accepts command-line flags, environment variables, or a YAML configuration file. Command-line flags take precedence over environment variables, which take precedence over file values.

Example `/etc/harborkv/harborkv.yaml`:

```yaml
node:
  name: node-1
  data_dir: /var/lib/harborkv
  snapshot_interval: 10000
  max_entry_size: 1048576

network:
  client_addr: 0.0.0.0:7400
  advertise_client_addr: 10.0.1.11:7400
  peer_addr: 0.0.0.0:7401
  advertise_peer_addr: 10.0.1.11:7401
  metrics_addr: 127.0.0.1:9090

cluster:
  bootstrap: true
  election_timeout: 2s
  heartbeat_interval: 250ms

storage:
  sync: true
  cache_size: 256MiB
  compaction_retention: 24h

security:
  client_tls:
    cert_file: /etc/harborkv/tls/server.crt
    key_file: /etc/harborkv/tls/server.key
  peer_tls:
    cert_file: /etc/harborkv/tls/peer.crt
    key_file: /etc/harborkv/tls/peer.key
    ca_file: /etc/harborkv/tls/ca.crt
    require_client_cert: true
  auth:
    enabled: true
    token_file: /etc/harborkv/tokens.yaml

logging:
  level: info
  format: json
```

Common environment variables:

| Variable | Description | Default |
|---|---|---|
| `HARBORKV_NAME` | Unique node name | Hostname |
| `HARBORKV_DATA_DIR` | Persistent data directory | `./data` |
| `HARBORKV_CLIENT_ADDR` | Client API listen address | `127.0.0.1:7400` |
| `HARBORKV_PEER_ADDR` | Cluster peer listen address | `127.0.0.1:7401` |
| `HARBORKV_LOG_LEVEL` | `debug`, `info`, `warn`, or `error` | `info` |
| `HARBORKV_CONFIG` | Path to the YAML configuration file | None |

Durations accept units such as `ms`, `s`, `m`, and `h`. Sizes accept binary units such as `KiB`, `MiB`, and `GiB`.

## Operations

The health endpoint is available at `/healthz`, and Prometheus metrics are exposed at `/metrics` on the configured metrics address.

Before upgrading, create a snapshot:

```sh
harborctl snapshot save backup.snapshot
```

Restore snapshots only into an empty data directory:

```sh
harborctl snapshot restore backup.snapshot --data-dir ./restored-data
```

Upgrade one follower at a time and upgrade the leader last. Keep a majority of voting nodes available throughout the process.

## License

HarborKV is licensed under the Apache License 2.0.