Skip to content

Commit 1356047

Browse files
authored
README updates (#37)
* Improve README * Add mention of key envs for remote access * Skip releases if they don't have artifacts
1 parent c76e9e9 commit 1356047

File tree

3 files changed

+472
-235
lines changed

3 files changed

+472
-235
lines changed

DEVELOPMENT.md

Lines changed: 291 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,291 @@
1+
# Development Guide
2+
3+
This document covers development setup, configuration, and contributing to Hypeman.
4+
5+
## Prerequisites
6+
7+
**Go 1.25.4+**, **KVM**, **erofs-utils**, **dnsmasq**
8+
9+
```bash
10+
# Verify prerequisites
11+
mkfs.erofs --version
12+
dnsmasq --version
13+
```
14+
15+
**Install on Debian/Ubuntu:**
16+
```bash
17+
sudo apt-get install erofs-utils dnsmasq
18+
```
19+
20+
**KVM Access:** User must be in `kvm` group for VM access:
21+
```bash
22+
sudo usermod -aG kvm $USER
23+
# Log out and back in, or use: newgrp kvm
24+
```
25+
26+
**Network Capabilities:**
27+
28+
Before running or testing Hypeman, ensure IPv4 forwarding is enabled:
29+
30+
```bash
31+
# Enable IPv4 forwarding (temporary - until reboot)
32+
sudo sysctl -w net.ipv4.ip_forward=1
33+
34+
# Enable IPv4 forwarding (persistent across reboots)
35+
echo 'net.ipv4.ip_forward=1' | sudo tee -a /etc/sysctl.conf
36+
sudo sysctl -p
37+
```
38+
39+
**Why:** Required for routing traffic between VM network and external network.
40+
41+
The hypeman binary needs network administration capabilities to create bridges and TAP devices:
42+
```bash
43+
# After building, grant network capabilities
44+
sudo setcap 'cap_net_admin,cap_net_bind_service=+eip' /path/to/hypeman
45+
46+
# For development builds
47+
sudo setcap 'cap_net_admin,cap_net_bind_service=+eip' ./bin/hypeman
48+
49+
# Verify capabilities
50+
getcap ./bin/hypeman
51+
```
52+
53+
**Note:** The `i` (inheritable) flag allows child processes spawned by hypeman (like `ip` and `iptables` commands) to inherit capabilities via the ambient capability set.
54+
55+
**Note:** These capabilities must be reapplied after each rebuild. For production deployments, set capabilities on the installed binary. For local testing, this is handled automatically in `make test`.
56+
57+
**File Descriptor Limits:**
58+
59+
Caddy (used for ingress) requires a higher file descriptor limit than the default on some systems. If you see "Too many open files" errors, increase the limit:
60+
61+
```bash
62+
# Check current limit (also check with: sudo bash -c 'ulimit -n')
63+
ulimit -n
64+
65+
# Increase temporarily (current session)
66+
ulimit -n 65536
67+
68+
# For persistent changes, add to /etc/security/limits.conf:
69+
* soft nofile 65536
70+
* hard nofile 65536
71+
root soft nofile 65536
72+
root hard nofile 65536
73+
```
74+
75+
## Configuration
76+
77+
### Environment variables
78+
79+
Hypeman can be configured using the following environment variables:
80+
81+
| Variable | Description | Default |
82+
|----------|-------------|---------|
83+
| `PORT` | HTTP server port | `8080` |
84+
| `DATA_DIR` | Directory for storing VM images, volumes, and other data | `/var/lib/hypeman` |
85+
| `BRIDGE_NAME` | Name of the network bridge for VM networking | `vmbr0` |
86+
| `SUBNET_CIDR` | CIDR notation for the VM network subnet (gateway derived automatically) | `10.100.0.0/16` |
87+
| `UPLINK_INTERFACE` | Host network interface to use for VM internet access | _(auto-detect)_ |
88+
| `JWT_SECRET` | Secret key for JWT authentication (required for production) | _(empty)_ |
89+
| `DNS_SERVER` | DNS server IP address for VMs | `1.1.1.1` |
90+
| `MAX_CONCURRENT_BUILDS` | Maximum number of concurrent image builds | `1` |
91+
| `MAX_OVERLAY_SIZE` | Maximum size for overlay filesystem | `100GB` |
92+
| `ENV` | Deployment environment (filters telemetry, e.g. your name for dev) | `unset` |
93+
| `OTEL_ENABLED` | Enable OpenTelemetry traces/metrics | `false` |
94+
| `OTEL_ENDPOINT` | OTLP gRPC endpoint | `127.0.0.1:4317` |
95+
| `OTEL_SERVICE_INSTANCE_ID` | Instance ID for telemetry (differentiates multiple servers) | hostname |
96+
| `LOG_LEVEL` | Default log level (debug, info, warn, error) | `info` |
97+
| `LOG_LEVEL_<SUBSYSTEM>` | Per-subsystem log level (API, IMAGES, INSTANCES, NETWORK, VOLUMES, VMM, SYSTEM, EXEC, CADDY) | inherits default |
98+
| `CADDY_LISTEN_ADDRESS` | Address for Caddy ingress listeners | `0.0.0.0` |
99+
| `CADDY_ADMIN_ADDRESS` | Address for Caddy admin API | `127.0.0.1` |
100+
| `CADDY_ADMIN_PORT` | Port for Caddy admin API | `2019` |
101+
| `CADDY_STOP_ON_SHUTDOWN` | Stop Caddy when hypeman shuts down (set to `true` for dev) | `false` |
102+
| `ACME_EMAIL` | Email for ACME certificate registration (required for TLS ingresses) | _(empty)_ |
103+
| `ACME_DNS_PROVIDER` | DNS provider for ACME challenges: `cloudflare` | _(empty)_ |
104+
| `ACME_CA` | ACME CA URL (empty = Let's Encrypt production) | _(empty)_ |
105+
| `TLS_ALLOWED_DOMAINS` | Comma-separated allowed domains for TLS (e.g., `*.example.com,api.other.com`) | _(empty)_ |
106+
| `DNS_PROPAGATION_TIMEOUT` | Max time to wait for DNS propagation (e.g., `2m`) | _(empty)_ |
107+
| `DNS_RESOLVERS` | Comma-separated DNS resolvers for propagation checking | _(empty)_ |
108+
| `CLOUDFLARE_API_TOKEN` | Cloudflare API token (when using `cloudflare` provider) | _(empty)_ |
109+
110+
**Important: Subnet Configuration**
111+
112+
The default subnet `10.100.0.0/16` is chosen to avoid common conflicts. Hypeman will detect conflicts with existing routes on startup and fail with guidance.
113+
114+
If you need a different subnet, set `SUBNET_CIDR` in your environment. The gateway is automatically derived as the first IP in the subnet (e.g., `10.100.0.0/16``10.100.0.1`).
115+
116+
**Alternative subnets if needed:**
117+
- `172.30.0.0/16` - Private range between common Docker (172.17.x.x) and cloud provider (172.31.x.x) ranges
118+
- `10.200.0.0/16` - Another private range option
119+
120+
**Example:**
121+
```bash
122+
# In your .env file
123+
SUBNET_CIDR=172.30.0.0/16
124+
```
125+
126+
**Finding the uplink interface (`UPLINK_INTERFACE`)**
127+
128+
`UPLINK_INTERFACE` tells Hypeman which host interface to use for routing VM traffic to the outside world (for iptables MASQUERADE rules). On many hosts this is `eth0`, but laptops and more complex setups often use Wi‑Fi or other names.
129+
130+
**Quick way to discover it:**
131+
```bash
132+
# Ask the kernel which interface is used to reach the internet
133+
ip route get 1.1.1.1
134+
```
135+
Look for the `dev` field in the output, for example:
136+
```text
137+
1.1.1.1 via 192.168.12.1 dev wlp2s0 src 192.168.12.98
138+
```
139+
In this case, `wlp2s0` is the uplink interface, so you would set:
140+
```bash
141+
UPLINK_INTERFACE=wlp2s0
142+
```
143+
144+
You can also inspect all routes:
145+
```bash
146+
ip route show
147+
```
148+
Pick the interface used by the default route (usually the line starting with `default`). Avoid using local bridges like `docker0`, `br-...`, `virbr0`, or `vmbr0` as the uplink; those are typically internal virtual networks, not your actual internet-facing interface.
149+
150+
### TLS Ingress (HTTPS)
151+
152+
Hypeman uses Caddy with automatic ACME certificates for TLS termination. Certificates are issued via DNS-01 challenges (Cloudflare).
153+
154+
To enable TLS ingresses:
155+
156+
1. Configure ACME credentials in your `.env`:
157+
```bash
158+
# Required for any TLS ingress
159+
160+
161+
# For Cloudflare
162+
ACME_DNS_PROVIDER=cloudflare
163+
CLOUDFLARE_API_TOKEN=your-api-token
164+
```
165+
166+
2. Create an ingress with TLS enabled:
167+
```bash
168+
curl -X POST http://localhost:8080/v1/ingresses \
169+
-H "Content-Type: application/json" \
170+
-d '{
171+
"name": "my-https-app",
172+
"rules": [{
173+
"match": {"hostname": "app.example.com", "port": 443},
174+
"target": {"instance": "my-instance", "port": 8080},
175+
"tls": true,
176+
"redirect_http": true
177+
}]
178+
}'
179+
```
180+
181+
Certificates are stored in `$DATA_DIR/caddy/data/` and auto-renewed by Caddy.
182+
183+
### Setup
184+
185+
```bash
186+
cp .env.example .env
187+
# Edit .env and set JWT_SECRET and other configuration values
188+
```
189+
190+
### Data directory
191+
192+
Hypeman stores data in a configurable directory. Configure permissions for this directory.
193+
194+
```bash
195+
sudo mkdir /var/lib/hypeman
196+
sudo chown $USER:$USER /var/lib/hypeman
197+
```
198+
199+
### Dockerhub login
200+
201+
Requires Docker Hub authentication to avoid rate limits when running the tests:
202+
```bash
203+
docker login
204+
```
205+
206+
Docker itself isn't required to be installed. `~/.docker/config.json` is a standard used for handling registry authentication.
207+
208+
## Build
209+
210+
```bash
211+
make build
212+
```
213+
214+
## Running the Server
215+
216+
1. Generate a JWT token for testing (optional):
217+
```bash
218+
make gen-jwt
219+
```
220+
221+
2. Start the server with hot-reload for development:
222+
```bash
223+
make dev
224+
```
225+
The server will start on port 8080 (configurable via `PORT` environment variable).
226+
227+
### Local OpenTelemetry (optional)
228+
229+
To collect traces and metrics locally, run the Grafana LGTM stack (Loki, Grafana, Tempo, Mimir):
230+
231+
```bash
232+
# Start Grafana LGTM (UI at http://localhost:3000, login: admin/admin)
233+
# Note, if you are developing on a shared server, you can use the same LGTM stack as your peer(s)
234+
# You will be able to sort your metrics, traces, and logs using the ENV configuration (see below)
235+
docker run -d --name lgtm \
236+
-p 127.0.0.1:3000:3000 \
237+
-p 127.0.0.1:4317:4317 \
238+
-p 127.0.0.1:4318:4318 \
239+
-p 127.0.0.1:9090:9090 \
240+
-p 127.0.0.1:4040:4040 \
241+
grafana/otel-lgtm:latest
242+
243+
# If developing on a remote server, forward the port to your local machine:
244+
# ssh -L 3001:localhost:3000 your-server (then open http://localhost:3001)
245+
246+
# Enable OTel in .env (set ENV to your name to filter your telemetry)
247+
echo "OTEL_ENABLED=true" >> .env
248+
echo "ENV=yourname" >> .env
249+
250+
# Restart dev server
251+
make dev
252+
```
253+
254+
Open http://localhost:3000 to view traces (Tempo), metrics (Mimir), and logs (Loki) in Grafana.
255+
256+
**Import the Hypeman dashboard:**
257+
1. Go to Dashboards → New → Import
258+
2. Upload `dashboards/hypeman.json` or paste its contents
259+
3. Select the Prometheus datasource and click Import
260+
261+
Use the Environment/Instance dropdowns to filter by `deployment.environment` or `service.instance.id`.
262+
263+
## Testing
264+
265+
Network tests require elevated permissions to create bridges and TAP devices.
266+
267+
```bash
268+
make test
269+
```
270+
271+
The test command compiles test binaries, grants capabilities via `sudo setcap`, then runs tests as the current user (not root). You may be prompted for your sudo password during the capability grant step.
272+
273+
## Code Generation
274+
275+
After modifying `openapi.yaml`, regenerate the Go code:
276+
277+
```bash
278+
make oapi-generate
279+
```
280+
281+
After modifying dependency injection in `cmd/api/wire.go` or `lib/providers/providers.go`, regenerate wire code:
282+
283+
```bash
284+
make generate-wire
285+
```
286+
287+
Or generate everything at once:
288+
289+
```bash
290+
make generate-all
291+
```

0 commit comments

Comments
 (0)