Skip to content

Commit e5ed50e

Browse files
committed
feat: docker compose
1 parent 569c57c commit e5ed50e

File tree

17 files changed

+1388
-1
lines changed

17 files changed

+1388
-1
lines changed

COMPOSE-README.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
### Install dependencies locally (for faster docker builds)
2+
3+
```
4+
nimble install -l
5+
```
6+
7+
### Build docker image (run this after any change in code / dependencies)
8+
9+
```
10+
docker build -t nim-libp2p/quic .
11+
```
12+
13+
### Start simulation
14+
15+
```
16+
TRANSPORT=QUIC NUM_LIBP2P_NODES=10 docker compose up
17+
```
18+
Environment variables you can use:
19+
- `TRANSPORT` can be `QUIC` or `TCP` (default `QUIC`)
20+
- `NUM_LIBP2P_NODES` number of libp2p nodes to start, default `10`
21+
- `CONNECTTO` indicates the number of nodes each node will connect to, default `10`
22+
- Optionally add the `-d` flag to run in the background (you can then see the logs with `docker logs container_name_here`)
23+
24+
### Stop simulation (if using -d flag)
25+
26+
```
27+
docker compose down -v
28+
```

Dockerfile

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Create the build image
2+
FROM nimlang/nim:2.2.6-ubuntu-regular AS build
3+
4+
WORKDIR /node
5+
COPY . .
6+
7+
RUN git config --global http.sslVerify false
8+
9+
RUN nim c \
10+
-d:chronicles_sinks=json \
11+
--threads:on \
12+
-d:metrics -d:libp2p_network_protocols_metrics -d:release \
13+
quic.nim
14+
15+
FROM debian:bookworm-slim
16+
17+
RUN apt-get update && \
18+
apt-get install -y --no-install-recommends \
19+
ca-certificates \
20+
libssl3 \
21+
iproute2 \
22+
ethtool \
23+
curl \
24+
procps \
25+
&& rm -rf /var/lib/apt/lists/* \
26+
&& apt-get clean
27+
28+
WORKDIR /node
29+
30+
COPY --from=build /node/quic /node/quic
31+
32+
COPY ./entrypoint.sh .
33+
34+
RUN chmod +x quic
35+
36+
EXPOSE 5000 8008
37+
38+
ENTRYPOINT ["./entrypoint.sh"]

docker-compose.yml

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
networks:
2+
monitor:
3+
4+
services:
5+
# observability ui
6+
grafana:
7+
container_name: grafana
8+
image: grafana/grafana:11.1.0
9+
environment:
10+
- GF_SECURITY_ADMIN_USER=admin
11+
- GF_SECURITY_ADMIN_PASSWORD=admin
12+
- GF_AUTH_ANONYMOUS_ENABLED=true
13+
- GF_AUTH_ANONYMOUS_ORG_ROLE=Admin
14+
env_file:
15+
- ./grafana/provisioning/grafana-plugins.env
16+
volumes:
17+
- ./grafana/provisioning:/etc/grafana/provisioning
18+
- ./grafana/dashboards:/var/lib/grafana/dashboards/:z
19+
ports:
20+
- "3000:3000" # browse on http://localhost:3000
21+
networks: [monitor]
22+
depends_on:
23+
- prometheus
24+
25+
prometheus:
26+
container_name: prometheus
27+
image: prom/prometheus:v2.55.1
28+
command: ["--config.file=/etc/prometheus/prometheus.yml"]
29+
volumes:
30+
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
31+
networks: [monitor]
32+
33+
cadvisor:
34+
image: gcr.io/cadvisor/cadvisor:latest
35+
container_name: cadvisor
36+
volumes:
37+
- /:/rootfs:ro
38+
- /var/run:/var/run:rw
39+
- /sys:/sys:ro
40+
- /var/lib/docker/:/var/lib/docker:ro
41+
networks:
42+
- monitor
43+
44+
redis:
45+
container_name: redis
46+
image: redis:7-alpine
47+
ports:
48+
- "6379:6379" # optional; intra-network works without publishing
49+
networks: [monitor]
50+
tmpfs:
51+
- /data
52+
healthcheck:
53+
test: ["CMD", "redis-cli", "ping"]
54+
interval: 5s
55+
timeout: 3s
56+
retries: 20
57+
start_period: 5s
58+
59+
quic:
60+
image: nim-libp2p/quic:latest
61+
networks: [monitor]
62+
deploy:
63+
replicas: ${NUM_LIBP2P_NODES:-10}
64+
command: []
65+
cap_add:
66+
- NET_ADMIN # REQUIRED for tc
67+
environment:
68+
NETEM: "delay 100ms 10ms distribution normal"
69+
NUM_LIBP2P_NODES: ${NUM_LIBP2P_NODES:-10}
70+
TRANSPORT: ${TRANSPORT:-QUIC}
71+
CONNECTTO: ${CONNECTTO:-10}
72+
ports:
73+
- target: 5000 # app
74+
published: 0
75+
protocol: udp
76+
- target: 8008 # prometheus
77+
published: 0
78+
protocol: tcp
79+
depends_on:
80+
redis:
81+
condition: service_healthy
82+
83+
loki:
84+
image: grafana/loki:3.0.0
85+
container_name: loki
86+
command: ["-config.file=/etc/loki/config.yml"]
87+
ports:
88+
- "3100:3100"
89+
networks: [monitor]
90+
user: "0:0" # root
91+
tmpfs:
92+
- /loki
93+
volumes:
94+
- ./loki-config.yml:/etc/loki/config.yml:ro
95+
96+
promtail:
97+
image: grafana/promtail:3.0.0
98+
container_name: promtail
99+
command: ["-config.file=/etc/promtail/config.yml"]
100+
networks: [monitor]
101+
depends_on:
102+
- loki
103+
volumes:
104+
- ./promtail-config.yml:/etc/promtail/config.yml:ro
105+
- /var/log:/var/log:ro
106+
- /var/lib/docker/containers:/var/lib/docker/containers:ro
107+
- /var/run/docker.sock:/var/run/docker.sock:ro

entrypoint.sh

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#!/bin/sh
2+
set -eu
3+
4+
if [ -n "${NETEM:-}" ]; then
5+
tc qdisc add dev eth0 root netem $NETEM
6+
fi
7+
8+
./quic

env.nim

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import strutils, os
2+
import chronos, metrics/chronos_httpserver, chronicles
3+
from nativesockets import getHostname
4+
5+
let
6+
prometheusPort* = Port(8008) #prometheus metrics
7+
myPort* = Port(5000) #libp2p port
8+
chunks* = parseInt(getEnv("FRAGMENTS", "1")) #No. of fragments for each message
9+
10+
proc getPeerDetails*(): Result[(string, int, string), string] =
11+
let
12+
hostname = getHostname()
13+
connectTo = parseInt(getEnv("CONNECTTO", "10"))
14+
address =
15+
if getEnv("TRANSPORT", "QUIC") == "QUIC":
16+
"/ip4/0.0.0.0/udp/" & $myPort & "/quic-v1"
17+
else:
18+
"/ip4/0.0.0.0/tcp/" & $myPort
19+
info "Host info ", address = address
20+
return ok((hostname, connectTo, address))
21+
22+
#Prometheus metrics
23+
proc startMetricsServer*(
24+
serverIp: IpAddress, serverPort: Port
25+
): Result[MetricsHttpServerRef, string] =
26+
info "Starting metrics HTTP server", serverIp = $serverIp, serverPort = $serverPort
27+
28+
let metricsServerRes = MetricsHttpServerRef.new($serverIp, serverPort)
29+
if metricsServerRes.isErr():
30+
return err("metrics HTTP server start failed: " & $metricsServerRes.error)
31+
32+
let server = metricsServerRes.value
33+
try:
34+
waitFor server.start()
35+
except CatchableError:
36+
return err("metrics HTTP server start failed: " & getCurrentExceptionMsg())
37+
38+
info "Metrics HTTP server started", serverIp = $serverIp, serverPort = $serverPort
39+
ok(metricsServerRes.value)

0 commit comments

Comments
 (0)