Add Docker support and fix CLI bootstrap flag

- Add comprehensive Docker setup with docker-compose.yml and Dockerfile
- Fix critical CLI bootstrap flag bug that prevented local development
- Add Docker environment variable support for node configuration
- Add Windows Docker setup documentation
- Enable local 4-node network development environment

Key changes:
- cmd/cli/main.go: Fix bootstrap peer override in createClient()
- cmd/node/main.go: Add Docker environment variable support
- docker-compose.yml: Multi-container orchestration setup
- WINDOWS_DOCKER_SETUP.md: Complete user guide
This commit is contained in:
KM-DB 2025-09-24 13:54:45 +03:00
parent 5d951daaf8
commit a539b6ff2d
8 changed files with 619 additions and 41 deletions

39
.dockerignore Normal file
View File

@ -0,0 +1,39 @@
# Build artifacts
bin/
data/
logs/
# Git
.git/
.gitignore
# Docker
Dockerfile*
docker-compose*.yml
.dockerignore
# Documentation
*.md
docs/
# IDE
.vscode/
.idea/
*.swp
*.swo
# OS
.DS_Store
Thumbs.db
# Temporary files
*.tmp
*.temp
*~
# Test files
*_test.go
e2e/
# Examples (optional - remove if you want to include them)
examples/

3
.gitignore vendored
View File

@ -73,3 +73,6 @@ data/bootstrap/rqlite/
.env.*
configs/
# PR documentation (temporary files)
PR_CHANGES.md

67
Dockerfile Normal file
View File

@ -0,0 +1,67 @@
# Multi-stage build for DeBros Network
# Stage 1: Build stage
FROM golang:1.23-alpine AS builder
# Install build dependencies
RUN apk add --no-cache git make gcc musl-dev wget tar
# Set working directory
WORKDIR /app
# Build RQLite from source for Alpine compatibility
RUN RQLITE_VERSION="8.43.0" && \
git clone --depth 1 --branch v${RQLITE_VERSION} https://github.com/rqlite/rqlite.git /tmp/rqlite && \
cd /tmp/rqlite && \
go build -o /usr/local/bin/rqlited ./cmd/rqlited && \
go build -o /usr/local/bin/rqlite ./cmd/rqlite && \
chmod +x /usr/local/bin/rqlited /usr/local/bin/rqlite && \
rm -rf /tmp/rqlite
# Copy go mod files first for better caching
COPY go.mod go.sum ./
RUN go mod download
# Copy source code
COPY . .
# Build only node and gateway executables (CLI is built separately on host)
RUN mkdir -p bin && \
go build -ldflags "-X 'main.version=0.50.1-beta' -X 'main.commit=unknown' -X 'main.date=2025-09-23T15:40:00Z'" -o bin/node ./cmd/node && \
go build -ldflags "-X 'main.version=0.50.1-beta' -X 'main.commit=unknown' -X 'main.date=2025-09-23T15:40:00Z' -X 'github.com/DeBrosOfficial/network/pkg/gateway.BuildVersion=0.50.1-beta' -X 'github.com/DeBrosOfficial/network/pkg/gateway.BuildCommit=unknown' -X 'github.com/DeBrosOfficial/network/pkg/gateway.BuildTime=2025-09-23T15:40:00Z'" -o bin/gateway ./cmd/gateway
# Stage 2: Runtime stage
FROM alpine:latest
# Install runtime dependencies
RUN apk add --no-cache ca-certificates tzdata wget
# Create non-root user
RUN addgroup -g 1001 -S debros && \
adduser -u 1001 -S debros -G debros
# Create necessary directories
RUN mkdir -p /app/bin /app/data /app/configs /app/logs && \
chown -R debros:debros /app
# Copy built executables from builder stage
COPY --from=builder /app/bin/ /app/bin/
# Copy RQLite binaries from builder stage
COPY --from=builder /usr/local/bin/rqlited /usr/local/bin/rqlited
COPY --from=builder /usr/local/bin/rqlite /usr/local/bin/rqlite
# Set working directory
WORKDIR /app
# Switch to non-root user
USER debros
# Expose ports
# 4001: LibP2P P2P communication
# 5001: RQLite HTTP API
# 6001: Gateway HTTP/WebSocket
# 7001: RQLite Raft consensus
EXPOSE 4001 5001 6001 7001
# Default command (can be overridden in docker-compose)
CMD ["./bin/node"]

250
WINDOWS_DOCKER_SETUP.md Normal file
View File

@ -0,0 +1,250 @@
# DeBros Network - Windows Docker Setup Guide
Simple step-by-step guide to run the DeBros Network locally on Windows using Docker.
## Prerequisites
**Docker Desktop for Windows** - Must be installed and running
**PowerShell** - Comes with Windows
**Git** - For cloning the repository
## Step 1: Clone and Build
```powershell
# Clone the repository
git clone https://github.com/DeBrosOfficial/network.git
cd network
# Build the CLI for local testing
go build -ldflags "-X 'main.version=0.50.1-beta'" -o bin/network-cli.exe cmd/cli/main.go
```
## Step 2: Start the Docker Network
```powershell
# Start all services (this will take 1-2 minutes)
docker-compose up -d
# Check that all containers are running
docker-compose ps
```
**Expected output:** 4 containers running:
- `debros-bootstrap` (Bootstrap Node)
- `debros-node-2` (Node 2)
- `debros-node-3` (Node 3)
- `debros-gateway` (HTTP Gateway)
## Step 3: Wait for Network Initialization
```powershell
# Wait for all services to start up
Start-Sleep -Seconds 30
# Verify bootstrap node is running
docker logs debros-bootstrap --tail 5
```
**Look for:** `"current_peers": 2` (means node-2 and node-3 connected)
## Step 4: Setup CLI Environment
```powershell
# Set these environment variables (required for every new terminal)
$env:DEBROS_GATEWAY_URL="http://localhost:6001"
$BOOTSTRAP_PEER="/ip4/127.0.0.1/tcp/4001/p2p/12D3KooWQX6jcPTVSsBuVuxdkbMbau3DAqZT4pc7UgGh2FvDxrKr"
```
## Step 5: Test the Network
### Basic Health Check
```powershell
# Check if network is healthy
.\bin\network-cli.exe health --bootstrap $BOOTSTRAP_PEER
```
**Expected:** `Status: 🟢 healthy`
### View Connected Peers
```powershell
# List connected peers
.\bin\network-cli.exe peers --bootstrap $BOOTSTRAP_PEER
```
**Expected:** 2 peers (your CLI + bootstrap node) - **This is normal!**
### Test Messaging (Requires Authentication)
```powershell
# Send a message (first time will prompt for wallet authentication)
.\bin\network-cli.exe pubsub publish test-topic "Hello DeBros Network!" --bootstrap $BOOTSTRAP_PEER
# Listen for messages (in another terminal)
.\bin\network-cli.exe pubsub subscribe test-topic 10s --bootstrap $BOOTSTRAP_PEER
```
### Test Database (Requires Authentication)
```powershell
# Query the database
.\bin\network-cli.exe query "SELECT * FROM namespaces" --bootstrap $BOOTSTRAP_PEER
```
## Network Architecture
Your local network consists of:
```
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ Bootstrap │◄──►│ Node-2 │◄──►│ Node-3 │
│ localhost:4001 │ │ localhost:4002 │ │ localhost:4003 │
│ localhost:5001 │ │ localhost:5002 │ │ localhost:5003 │
└─────────────────┘ └──────────────────┘ └─────────────────┘
┌─────────────────┐ ┌──────────────────┐
│ CLI Client │ │ Gateway │
│ (Your Terminal) │ │ localhost:6001 │
└─────────────────┘ └──────────────────┘
```
**Ports Used:**
- **4001-4003**: P2P communication between nodes
- **5001-5003**: Database HTTP API
- **6001**: Gateway HTTP API
- **7001-7003**: Database internal communication
## Daily Usage Commands
### Start Your Development Session
```powershell
# Start the network
docker-compose up -d
# Setup environment (run in every new terminal)
$env:DEBROS_GATEWAY_URL="http://localhost:6001"
$BOOTSTRAP_PEER="/ip4/127.0.0.1/tcp/4001/p2p/12D3KooWQX6jcPTVSsBuVuxdkbMbau3DAqZT4pc7UgGh2FvDxrKr"
# Quick health check
.\bin\network-cli.exe health --bootstrap $BOOTSTRAP_PEER
```
### Common CLI Commands
```powershell
# Network status
.\bin\network-cli.exe status --bootstrap $BOOTSTRAP_PEER
# Send message
.\bin\network-cli.exe pubsub publish my-topic "Hello Network!" --bootstrap $BOOTSTRAP_PEER
# Listen for messages
.\bin\network-cli.exe pubsub subscribe my-topic 15s --bootstrap $BOOTSTRAP_PEER
# Database query
.\bin\network-cli.exe query "SELECT datetime('now') as current_time" --bootstrap $BOOTSTRAP_PEER
# List all database tables
.\bin\network-cli.exe query "SELECT name FROM sqlite_master WHERE type='table'" --bootstrap $BOOTSTRAP_PEER
```
### End Your Development Session
```powershell
# Stop network (keeps all data)
docker-compose stop
# OR stop and remove all data (clean slate)
docker-compose down -v
```
## Troubleshooting
### Check Container Status
```powershell
# View all containers
docker-compose ps
# Check specific container logs
docker logs debros-bootstrap --tail 20
docker logs debros-gateway --tail 20
docker logs debros-node-2 --tail 20
```
### Common Issues and Solutions
**❌ "Connection refused" error**
```powershell
# Solution: Check containers are running and wait longer
docker-compose ps
Start-Sleep -Seconds 60
```
**❌ "Authentication failed"**
```powershell
# Solution: Check gateway is running
docker logs debros-gateway --tail 10
```
**❌ Only seeing 2 peers instead of 4**
```
✅ This is NORMAL! The CLI only sees itself + bootstrap node.
Node-2 and Node-3 are connected to bootstrap but not visible to CLI.
Your network is working correctly!
```
### Restart Services
```powershell
# Restart all services
docker-compose restart
# Restart specific service
docker-compose restart bootstrap-node
# Complete clean restart
docker-compose down -v
docker-compose up -d
```
### View Real-time Logs
```powershell
# Follow logs for all services
docker-compose logs -f
# Follow logs for specific service
docker-compose logs -f bootstrap-node
```
## Important Notes
### Authentication
- First CLI command will prompt you to connect your wallet
- You'll receive an API key for future commands
- API key is stored locally and reused automatically
### Network Isolation
- **Your Docker Network**: Completely isolated for development
- **Production Network**: Live DeBros Network (separate)
- **Default CLI**: Connects to production (without `--bootstrap` flag)
- **CLI with `--bootstrap`**: Connects to your local Docker network
### Data Persistence
- All data is stored in Docker volumes
- Survives container restarts
- Use `docker-compose down -v` to reset everything
## Quick Reference Card
```powershell
# Essential daily commands
docker-compose up -d # Start
$env:DEBROS_GATEWAY_URL="http://localhost:6001" # Setup
$BOOTSTRAP_PEER="/ip4/127.0.0.1/tcp/4001/p2p/12D3KooWQX6jcPTVSsBuVuxdkbMbau3DAqZT4pc7UgGh2FvDxrKr"
.\bin\network-cli.exe health --bootstrap $BOOTSTRAP_PEER # Test
docker-compose down # Stop
```
---
🎉 **Your local DeBros Network is ready for development and testing!**
The network is completely isolated from production and perfect for:
- Testing new features
- Learning the DeBros Network
- Developing applications
- Experimenting safely

View File

@ -414,6 +414,11 @@ func handlePeerID() {
func createClient() (client.NetworkClient, error) {
config := client.DefaultClientConfig("network-cli")
// Override bootstrap peers if specified via flag
if bootstrapPeer != "/ip4/127.0.0.1/tcp/4001" {
config.BootstrapPeers = []string{bootstrapPeer}
}
// Check for existing credentials using enhanced authentication
creds, err := auth.GetValidEnhancedCredentials()
if err != nil {

View File

@ -100,11 +100,15 @@ func parseGatewayConfig(logger *logging.ColoredLogger) *gateway.Config {
}
cfg.BootstrapPeers = bp
}
if v := strings.TrimSpace(os.Getenv("RQLITE_DSN")); v != "" {
cfg.RQLiteDSN = v
}
// 3) Flags (override env)
addr := flag.String("addr", "", "HTTP listen address (e.g., :6001)")
ns := flag.String("namespace", "", "Client namespace for scoping resources")
peers := flag.String("bootstrap-peers", "", "Comma-separated bootstrap peers for network client")
rqliteDSN := flag.String("rqlite-dsn", "", "RQLite database DSN (e.g., http://localhost:5001)")
// Do not call flag.Parse() elsewhere to avoid double-parsing
flag.Parse()
@ -126,6 +130,9 @@ func parseGatewayConfig(logger *logging.ColoredLogger) *gateway.Config {
}
cfg.BootstrapPeers = bp
}
if r := strings.TrimSpace(*rqliteDSN); r != "" {
cfg.RQLiteDSN = r
}
logger.ComponentInfo(logging.ComponentGeneral, "Loaded gateway configuration",
zap.String("addr", cfg.ListenAddr),

View File

@ -31,7 +31,7 @@ func setup_logger(component logging.Component) (logger *logging.ColoredLogger) {
}
// parse_and_return_network_flags it initializes all the network flags coming from the .yaml files
func parse_and_return_network_flags() (configPath *string, dataDir, nodeID *string, p2pPort, rqlHTTP, rqlRaft *int, rqlJoinAddr *string, advAddr *string, help *bool) {
func parse_and_return_network_flags() (configPath *string, dataDir, nodeID *string, p2pPort, rqlHTTP, rqlRaft *int, rqlJoinAddr *string, advAddr, httpAdvAddr, raftAdvAddr *string, help *bool) {
logger := setup_logger(logging.ComponentNode)
configPath = flag.String("config", "", "Path to config YAML file (overrides defaults)")
@ -42,45 +42,15 @@ func parse_and_return_network_flags() (configPath *string, dataDir, nodeID *stri
rqlRaft = flag.Int("rqlite-raft-port", 7001, "RQLite Raft port")
rqlJoinAddr = flag.String("rqlite-join-address", "", "RQLite address to join (e.g., /ip4/)")
advAddr = flag.String("adv-addr", "127.0.0.1", "Default Advertise address for rqlite and rafts")
httpAdvAddr = flag.String("http-adv-addr", "", "HTTP advertise address (overrides adv-addr for HTTP)")
raftAdvAddr = flag.String("raft-adv-addr", "", "Raft advertise address (overrides adv-addr for Raft)")
help = flag.Bool("help", false, "Show help")
flag.Parse()
logger.Info("Successfully parsed all flags and arguments.")
if *configPath != "" {
cfg, err := LoadConfigFromYAML(*configPath)
if err != nil {
logger.Error("Failed to load config from YAML", zap.Error(err))
os.Exit(1)
}
logger.ComponentInfo(logging.ComponentNode, "Configuration loaded from YAML file", zap.String("path", *configPath))
// Instead of returning flag values, return config values
// For ListenAddresses, extract port from multiaddr string if possible, else use default
var p2pPortVal int
if len(cfg.Node.ListenAddresses) > 0 {
// Try to parse port from multiaddr string
var port int
_, err := fmt.Sscanf(cfg.Node.ListenAddresses[0], "/ip4/0.0.0.0/tcp/%d", &port)
if err == nil {
p2pPortVal = port
} else {
p2pPortVal = 4001
}
} else {
p2pPortVal = 4001
}
return configPath,
&cfg.Node.DataDir,
&cfg.Node.ID,
&p2pPortVal,
&cfg.Database.RQLitePort,
&cfg.Database.RQLiteRaftPort,
&cfg.Database.RQLiteJoinAddress,
&cfg.Discovery.HttpAdvAddress,
help
}
// Always return the parsed command line flags
// Config file loading will be handled separately in main()
return
}
@ -180,9 +150,13 @@ func load_args_into_config(cfg *config.Config, p2pPort, rqlHTTP, rqlRaft *int, r
logger.ComponentInfo(logging.ComponentNode, "Setting RQLite join address", zap.String("address", *rqlJoinAddr))
}
if *advAddr != "" {
// Only override advertise addresses if they're not already set in config and advAddr is not the default
if *advAddr != "" && *advAddr != "127.0.0.1" {
cfg.Discovery.HttpAdvAddress = fmt.Sprintf("%s:%d", *advAddr, *rqlHTTP)
cfg.Discovery.RaftAdvAddress = fmt.Sprintf("%s:%d", *advAddr, *rqlRaft)
logger.ComponentInfo(logging.ComponentNode, "Overriding advertise addresses",
zap.String("http_adv_addr", cfg.Discovery.HttpAdvAddress),
zap.String("raft_adv_addr", cfg.Discovery.RaftAdvAddress))
}
if *dataDir != "" {
@ -190,21 +164,89 @@ func load_args_into_config(cfg *config.Config, p2pPort, rqlHTTP, rqlRaft *int, r
}
}
// load_args_into_config_from_yaml applies only explicit command line overrides when loading from YAML
func load_args_into_config_from_yaml(cfg *config.Config, p2pPort, rqlHTTP, rqlRaft *int, rqlJoinAddr, advAddr, httpAdvAddr, raftAdvAddr, dataDir *string) {
logger := setup_logger(logging.ComponentNode)
// Only override if explicitly set via command line (check if flag was actually provided)
if *dataDir != "" {
cfg.Node.DataDir = *dataDir
logger.ComponentInfo(logging.ComponentNode, "Overriding data directory from command line", zap.String("dataDir", *dataDir))
}
// Check environment variable for RQLite join address (Docker-specific)
if rqlJoinEnv := os.Getenv("RQLITE_JOIN_ADDRESS"); rqlJoinEnv != "" {
cfg.Database.RQLiteJoinAddress = rqlJoinEnv
logger.ComponentInfo(logging.ComponentNode, "Setting RQLite join address from environment", zap.String("address", rqlJoinEnv))
}
// Handle RQLite join address override from command line (takes precedence over env var)
if *rqlJoinAddr != "" {
cfg.Database.RQLiteJoinAddress = *rqlJoinAddr
logger.ComponentInfo(logging.ComponentNode, "Setting RQLite join address from command line", zap.String("address", *rqlJoinAddr))
}
// Check environment variables for advertise addresses (Docker-specific)
if httpAdvEnv := os.Getenv("HTTP_ADV_ADDRESS"); httpAdvEnv != "" {
cfg.Discovery.HttpAdvAddress = httpAdvEnv
logger.ComponentInfo(logging.ComponentNode, "Setting HTTP advertise address from environment", zap.String("http_adv_addr", httpAdvEnv))
}
if raftAdvEnv := os.Getenv("RAFT_ADV_ADDRESS"); raftAdvEnv != "" {
cfg.Discovery.RaftAdvAddress = raftAdvEnv
logger.ComponentInfo(logging.ComponentNode, "Setting Raft advertise address from environment", zap.String("raft_adv_addr", raftAdvEnv))
}
// Handle specific advertise address overrides from command line (takes precedence over env vars)
if *httpAdvAddr != "" {
cfg.Discovery.HttpAdvAddress = *httpAdvAddr
logger.ComponentInfo(logging.ComponentNode, "Overriding HTTP advertise address from command line", zap.String("http_adv_addr", *httpAdvAddr))
}
if *raftAdvAddr != "" {
cfg.Discovery.RaftAdvAddress = *raftAdvAddr
logger.ComponentInfo(logging.ComponentNode, "Overriding Raft advertise address from command line", zap.String("raft_adv_addr", *raftAdvAddr))
}
// Handle general advertise address (only if specific ones weren't set)
if *advAddr != "" && *advAddr != "127.0.0.1" && *httpAdvAddr == "" && *raftAdvAddr == "" && os.Getenv("HTTP_ADV_ADDRESS") == "" && os.Getenv("RAFT_ADV_ADDRESS") == "" {
cfg.Discovery.HttpAdvAddress = fmt.Sprintf("%s:%d", *advAddr, *rqlHTTP)
cfg.Discovery.RaftAdvAddress = fmt.Sprintf("%s:%d", *advAddr, *rqlRaft)
logger.ComponentInfo(logging.ComponentNode, "Overriding advertise addresses from adv-addr flag",
zap.String("http_adv_addr", cfg.Discovery.HttpAdvAddress),
zap.String("raft_adv_addr", cfg.Discovery.RaftAdvAddress))
}
logger.ComponentInfo(logging.ComponentNode, "YAML configuration loaded with overrides applied")
}
func main() {
logger := setup_logger(logging.ComponentNode)
_, dataDir, nodeID, p2pPort, rqlHTTP, rqlRaft, rqlJoinAddr, advAddr, help := parse_and_return_network_flags()
configPath, dataDir, nodeID, p2pPort, rqlHTTP, rqlRaft, rqlJoinAddr, advAddr, httpAdvAddr, raftAdvAddr, help := parse_and_return_network_flags()
check_if_should_open_help(help)
select_data_dir(dataDir, nodeID)
// Load Node Configuration
var cfg *config.Config
if *configPath != "" {
// Load config from YAML file
var err error
cfg, err = LoadConfigFromYAML(*configPath)
if err != nil {
logger.Error("Failed to load config from YAML", zap.Error(err))
os.Exit(1)
}
logger.ComponentInfo(logging.ComponentNode, "Configuration loaded from YAML file", zap.String("path", *configPath))
// Only apply command line overrides if they were explicitly set (not defaults)
load_args_into_config_from_yaml(cfg, p2pPort, rqlHTTP, rqlRaft, rqlJoinAddr, advAddr, httpAdvAddr, raftAdvAddr, dataDir)
} else {
cfg = config.DefaultConfig()
logger.ComponentInfo(logging.ComponentNode, "Default configuration loaded successfully")
// Apply command line argument overrides
load_args_into_config(cfg, p2pPort, rqlHTTP, rqlRaft, rqlJoinAddr, advAddr, dataDir)
}
logger.ComponentInfo(logging.ComponentNode, "Command line arguments applied to configuration")
// LibP2P uses configurable port (default 4001); RQLite uses 5001 (HTTP) and 7001 (Raft)

165
docker-compose.yml Normal file
View File

@ -0,0 +1,165 @@
# Docker Compose file for DeBros Network
services:
# Bootstrap Node - First node in the network
bootstrap-node:
build: .
container_name: debros-bootstrap
hostname: bootstrap-node
command: ["./bin/node", "--config", "/app/configs/bootstrap.docker.yaml"]
ports:
- "4001:4001" # LibP2P P2P
- "5001:5001" # RQLite HTTP API
- "7001:7001" # RQLite Raft
volumes:
- bootstrap_data:/app/data
- ./configs:/app/configs:ro
- bootstrap_logs:/app/logs
environment:
- NODE_ID=bootstrap
- P2P_PORT=4001
- RQLITE_PORT=5001
- RQLITE_RAFT_PORT=7001
- DATA_DIR=/app/data/bootstrap
- LOG_LEVEL=info
networks:
- debros-network
restart: unless-stopped
healthcheck:
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:5001/status", "||", "exit", "1"]
interval: 30s
timeout: 10s
retries: 3
start_period: 45s
# Second Node - Joins the bootstrap node
node-2:
build: .
container_name: debros-node-2
hostname: node-2
command: ["./bin/node", "--config", "/app/configs/node.docker.yaml"]
ports:
- "4002:4001" # LibP2P P2P (mapped to different host port)
- "5002:5001" # RQLite HTTP API
- "7002:7001" # RQLite Raft
volumes:
- node2_data:/app/data
- ./configs:/app/configs:ro
- node2_logs:/app/logs
environment:
- NODE_ID=node-2
- P2P_PORT=4001
- RQLITE_PORT=5001
- RQLITE_RAFT_PORT=7001
- RQLITE_JOIN_ADDRESS=bootstrap-node:7001
- BOOTSTRAP_PEERS=/ip4/172.20.0.2/tcp/4001/p2p/12D3KooWQX6jcPTVSsBuVuxdkbMbau3DAqZT4pc7UgGh2FvDxrKr
- DATA_DIR=/app/data/node2
- LOG_LEVEL=info
- HTTP_ADV_ADDRESS=node-2:5001
- RAFT_ADV_ADDRESS=node-2:7001
networks:
- debros-network
depends_on:
bootstrap-node:
condition: service_healthy
restart: unless-stopped
healthcheck:
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:5001/status", "||", "exit", "1"]
interval: 30s
timeout: 10s
retries: 3
start_period: 45s
# Third Node - Additional network participant
node-3:
build: .
container_name: debros-node-3
hostname: node-3
command: ["./bin/node", "--config", "/app/configs/node.docker.yaml"]
ports:
- "4003:4001" # LibP2P P2P
- "5003:5001" # RQLite HTTP API
- "7003:7001" # RQLite Raft
volumes:
- node3_data:/app/data
- ./configs:/app/configs:ro
- node3_logs:/app/logs
environment:
- NODE_ID=node-3
- P2P_PORT=4001
- RQLITE_PORT=5001
- RQLITE_RAFT_PORT=7001
- RQLITE_JOIN_ADDRESS=bootstrap-node:7001
- BOOTSTRAP_PEERS=/ip4/172.20.0.2/tcp/4001/p2p/12D3KooWQX6jcPTVSsBuVuxdkbMbau3DAqZT4pc7UgGh2FvDxrKr
- DATA_DIR=/app/data/node3
- LOG_LEVEL=info
- HTTP_ADV_ADDRESS=node-3:5001
- RAFT_ADV_ADDRESS=node-3:7001
networks:
- debros-network
depends_on:
bootstrap-node:
condition: service_healthy
restart: unless-stopped
healthcheck:
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:5001/status", "||", "exit", "1"]
interval: 30s
timeout: 10s
retries: 3
start_period: 45s
# HTTP Gateway - Provides REST API and WebSocket interface
gateway:
build: .
container_name: debros-gateway
hostname: gateway
command: ["./bin/gateway", "--addr", ":6001", "--namespace", "default", "--bootstrap-peers", "/ip4/bootstrap-node/tcp/4001/p2p/12D3KooWQX6jcPTVSsBuVuxdkbMbau3DAqZT4pc7UgGh2FvDxrKr"]
ports:
- "6001:6001" # Gateway HTTP/WebSocket
volumes:
- ./configs:/app/configs:ro
- gateway_logs:/app/logs
environment:
- GATEWAY_ADDR=:6001
- GATEWAY_NAMESPACE=default
- GATEWAY_BOOTSTRAP_PEERS=/ip4/bootstrap-node/tcp/4001/p2p/12D3KooWQX6jcPTVSsBuVuxdkbMbau3DAqZT4pc7UgGh2FvDxrKr
- RQLITE_NODES=http://bootstrap-node:5001
- RQLITE_DSN=http://bootstrap-node:5001
- LOG_LEVEL=info
networks:
- debros-network
depends_on:
bootstrap-node:
condition: service_healthy
node-2:
condition: service_healthy
restart: unless-stopped
healthcheck:
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:6001/health", "||", "exit", "1"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
networks:
debros-network:
driver: bridge
ipam:
config:
- subnet: 172.20.0.0/16
volumes:
bootstrap_data:
driver: local
bootstrap_logs:
driver: local
node2_data:
driver: local
node2_logs:
driver: local
node3_data:
driver: local
node3_logs:
driver: local
gateway_logs:
driver: local