README
ΒΆ
fwkeeper
Port forwarding made easy. A Kubernetes port forwarding tool that automatically maintains persistent port forwards to pods with automatic reconnection and failure recovery.
Features
- π Automatic Port Forwarding: Maintains persistent port forwards to Kubernetes pods
- π Automatic Reconnection: Automatically reconnects on pod restarts or connection failures
- βοΈ Easy Configuration: CUE-based configuration for simple pod forwarding setup
- π Structured Logging: Comprehensive logging with configurable levels and pretty-printing
- π Kubernetes Integration: Seamless integration with your Kubernetes cluster (local or in-cluster)
- π Multiple Forwards: Support for multiple simultaneous port forwards
Installation
Prerequisites
- Go 1.25.1 or later - Download Go
- Access to a Kubernetes cluster (local kubeconfig or in-cluster)
Verify Go is installed:
go version
Install
Install fwkeeper directly:
go install github.com/codozor/fwkeeper@latest
This installs the binary to $GOPATH/bin (typically ~/go/bin), which should already be in your PATH.
Verify installation:
fwkeeper --version
fwkeeper --help
If fwkeeper is not found, ensure $GOPATH/bin is in your PATH:
# Add to ~/.bashrc, ~/.zshrc, or ~/.bash_profile
export PATH="$HOME/go/bin:$PATH"
Build from Source (Development)
For development or building locally:
git clone https://github.com/codozor/fwkeeper.git
cd fwkeeper
go build -o fwkeeper ./
./fwkeeper run -c fwkeeper.cue
Quick Start
1. Create a Configuration File
Create a fwkeeper.cue file:
logs: {
level: "debug"
pretty: true
}
forwards: [
{
name: "postgres"
ports: ["5432"]
namespace: "default"
resource: "postgres-pod"
},
{
name: "api"
ports: ["8080:8080", "9000:9000"]
namespace: "api"
resource: "api-server-deployment-abc123"
}
]
2. Run fwkeeper
./fwkeeper run -c fwkeeper.cue
Or using the default fwkeeper.cue:
./fwkeeper run
3. Access Your Services
The port forwards are now active. Connect to your services:
# Connect to postgres
psql -h localhost -p 5432
# Connect to API
curl http://localhost:8080
Configuration
Configuration File Format (CUE)
fwkeeper uses CUE for configuration validation and schema enforcement.
Top-Level Structure
logs: { ... }
forwards: [ ... ]
Logs Configuration
logs: {
level: "debug" # "error", "warn", "info", "debug", "trace" (default: "info")
pretty: true # Pretty-print logs to console (default: false)
}
Port Forward Configuration
forwards: [
{
name: "service-name" # Unique identifier for this forward
ports: ["8080", "9000:3000"] # Local:remote port mappings
namespace: "default" # Kubernetes namespace
resource: "pod-name" # Pod, Service, Deployment, StatefulSet, or DaemonSet
},
# ... more forwards
]
Resource Reference Syntax:
"pod-name"- Direct pod reference"svc/service-name"or"service/service-name"- Kubernetes Service"dep/deployment-name"or"deployment/deployment-name"- Kubernetes Deployment"sts/statefulset-name"or"statefulset/statefulset-name"- Kubernetes StatefulSet"ds/daemonset-name"or"daemonset/daemonset-name"- Kubernetes DaemonSet
When using a Service, Deployment, StatefulSet, or DaemonSet, fwkeeper automatically finds and connects to the first running pod that matches the resource's selector.
Port Mapping Syntax:
"8080"- Forward local port 8080 to pod port 8080"8080:9000"- Forward local port 8080 to pod port 9000
Validation Rules:
- Port numbers must be between 1 and 65535
- Each forward must have a unique name
- Namespace and resource must be specified
- Local ports must be unique across all forwards
Environment Variables
# Override kubeconfig location
KUBECONFIG=/path/to/kubeconfig ./fwkeeper run
# Use default kubeconfig locations
# 1. $KUBECONFIG environment variable
# 2. ~/.kube/config
# 3. In-cluster config (if running inside Kubernetes)
Usage
Basic Commands
# Show help
./fwkeeper --help
# Run with default config (fwkeeper.cue)
./fwkeeper run
# Run with custom config file
./fwkeeper run -c /path/to/config.cue
# Show command help
./fwkeeper run --help
Exit and Shutdown
Press Ctrl+C to gracefully stop fwkeeper. It will:
- Cancel all active port forwards
- Close connections
- Print shutdown message
Configuration Hot-Reload
fwkeeper automatically detects changes to your configuration file and reloads without interrupting active port forwards (when possible).
Automatic Reload:
- fwkeeper watches your config file for changes
- When the file is saved, the configuration is automatically reloaded
- New forwards are started, removed forwards are stopped, modified forwards are restarted
Manual Reload: Send a SIGHUP signal to trigger manual reload:
# In another terminal, while fwkeeper is running
kill -HUP <pid>
# Or using pkill
pkill -HUP fwkeeper
Config Reload Behavior:
- Invalid config β Current configuration continues, error logged, reload skipped
- New forwards β Started automatically
- Removed forwards β Stopped gracefully
- Modified forwards β Restarted with new configuration
- Unchanged forwards β Continue running without interruption
Example:
- Start fwkeeper:
./fwkeeper run -c fwkeeper.cue - Edit
fwkeeper.cue(add, remove, or modify forwards) - Save the file
- fwkeeper detects the change and updates automatically
- View the logs to see what changed
Examples
Example 1: Database Access
Forward to a PostgreSQL database pod:
logs: {
level: "info"
pretty: true
}
forwards: [
{
name: "database"
ports: ["5432"]
namespace: "databases"
resource: "postgres-primary"
}
]
Then connect:
psql -h localhost -p 5432 -U myuser -d mydb
Example 2: Development Environment
Forward multiple services for local development:
logs: {
level: "debug"
pretty: true
}
forwards: [
{
name: "api-server"
ports: ["8000:8000"]
namespace: "development"
resource: "api-server"
},
{
name: "frontend"
ports: ["3000:3000"]
namespace: "development"
resource: "frontend"
},
{
name: "postgres"
ports: ["5432:5432"]
namespace: "databases"
resource: "postgres-dev"
},
{
name: "redis"
ports: ["6379:6379"]
namespace: "databases"
resource: "redis-dev"
}
]
Example 3: Multiple Ports on Same Pod
Forward multiple ports from a single pod:
forwards: [
{
name: "api-services"
ports: ["8000:8000", "9000:9000", "5000:5000"]
namespace: "api"
resource: "api-pod"
}
]
Example 4: Using Deployments and StatefulSets
Forward to pods managed by Deployments, StatefulSets, or DaemonSets:
logs: {
level: "info"
pretty: true
}
forwards: [
{
name: "api-deployment"
ports: ["8080:8080"]
namespace: "production"
resource: "dep/api-server" # Deployment: automatically finds a running pod
},
{
name: "postgres-statefulset"
ports: ["5432:5432"]
namespace: "databases"
resource: "sts/postgres-primary" # StatefulSet: automatically finds a running pod
},
{
name: "monitoring-daemonset"
ports: ["9090:9090"]
namespace: "monitoring"
resource: "ds/prometheus" # DaemonSet: automatically finds a running pod
}
]
The resource finder automatically locates the first running pod managed by the specified Deployment, StatefulSet, or DaemonSet. This is useful when you have multiple replicas and want to connect to any available pod.
Logging
Log Levels
- error: Only errors
- warn: Warnings and errors
- info: General information (default)
- debug: Detailed debugging information
- trace: Very detailed tracing information
Log Output
Logs are written to stderr. Each log entry includes:
- Timestamp (Unix milliseconds)
- Log level
- Message
- Error details (when applicable)
Pretty Printing
Enable pretty-printed logs for development:
logs: {
pretty: true
}
Output will include timestamps and color-coded levels for better readability.
Troubleshooting
"Pod not in running state"
The pod exists but isn't currently running. Check pod status:
kubectl get pods -n <namespace> <pod-name>
kubectl describe pod -n <namespace> <pod-name>
"Connection refused" or "Connection reset"
The pod restarted or the port-forward connection dropped. fwkeeper will automatically reconnect with exponential backoff (starting at 100ms, up to 30s). Check logs for details.
"Unable to connect to kubeconfig"
Verify your kubeconfig:
# Check KUBECONFIG env var
echo $KUBECONFIG
# Test cluster access
kubectl cluster-info
# Set correct kubeconfig
export KUBECONFIG=~/.kube/config
./fwkeeper run
Configuration Validation Errors
Verify your CUE configuration syntax and against the schema:
# Check for CUE syntax errors in your config file
# Ensure all fields match the required structure in schema.cue
Common issues:
- Missing required fields (name, ports, namespace, resource)
- Invalid port numbers (not 1-65535)
- Malformed port specifications (should be "port" or "local:remote")
Debug Logs
Enable debug logging to see detailed information:
logs: {
level: "debug"
pretty: true
}
Testing
Running Tests
Run all tests in the project:
go test ./...
Run tests with verbose output:
go test -v ./...
Run specific test package:
go test -v ./internal/config
Run specific test:
go test -v -run TestPortValidation ./internal/config
Test Coverage
Run tests with coverage:
go test -cover ./...
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.out
Test Status
Phase 1 (Completed):
- β Config loading and parsing (valid config, parsing errors)
- β Port validation (range: 1-65535, invalid ports, port conflicts)
- β Port conflict detection (duplicate local ports across forwards)
Phase 2 (Planned):
- Locator implementations (Pod, Service, Deployment, StatefulSet, DaemonSet)
- Forward name uniqueness validation
- Configuration hot-reload
Phase 3 (Planned):
- Runner lifecycle (startup, shutdown, error handling)
- Forwarder reconnection behavior
Development
Project Structure
fwkeeper/
βββ cmd/ # CLI command definitions
β βββ root.go # Root command
β βββ run.go # Run command
βββ internal/
β βββ app/ # Application orchestration
β β βββ runner.go # Main runner and lifecycle management
β βββ bootstrap/ # Dependency injection setup
β βββ config/ # Configuration loading and validation
β β βββ schema.cue # CUE schema definition
β βββ forwarder/ # Port forwarding logic
β β βββ forwarder.go # Individual pod port forwarder
β βββ kubernetes/ # Kubernetes client setup
β βββ locator/ # Pod discovery and location
β β βββ locator.go # Pod/service locator implementations
β βββ logger/ # Logging setup
βββ main.go # Application entry point
βββ go.mod # Go module definition
βββ go.sum # Dependency checksums
βββ fwkeeper.cue # Default configuration
βββ README.md # This file
Building
# Build the binary
go build -o fwkeeper ./
# Build with version info
go build -ldflags="-X main.version=v1.0.0" -o fwkeeper ./
Running Tests
# Run all tests
go test ./...
# Run with verbose output
go test -v ./...
# Run specific test
go test -run TestName ./path/to/package
Code Quality
# Format code
go fmt ./...
# Run static analysis
go vet ./...
# Run golangci-lint (if installed)
golangci-lint run ./...
Dependencies
Key dependencies:
- Cobra: CLI framework
- CUE: Configuration language
- Zerolog: Structured logging
- samber/do: Dependency injection
- client-go: Kubernetes client library
Architecture
Key Components
- Runner: Orchestrates port forwarders, manages context and graceful shutdown
- Forwarder: Implements individual pod port forwarding with automatic reconnection
- Config: CUE-based configuration parsing and validation
- Logger: Structured logging with zerolog
- Kubernetes Integration: Handles kubeconfig loading and client initialization
Port Forward Flow
- Read configuration from CUE file
- Load Kubernetes credentials
- For each forward:
- Locate the pod
- Verify pod is running
- Establish SPDY connection to pod
- Forward ports
- Reconnect on failure (exponential backoff: 100ms β 30s with jitter)
- Listen for interrupt signal (Ctrl+C)
- Gracefully shutdown all forwarders
License
This project is under MIT License
Support
For issues, questions, or contributions, please visit the repository.
Documentation
ΒΆ
There is no documentation for this package.