9.4 KiB
kportal
A robust Kubernetes port-forwarding tool that manages multiple concurrent port-forwards across different contexts, namespaces, and resources with automatic reconnection and failure recovery.
Features
- Multi-Context Support: Forward ports from multiple Kubernetes contexts simultaneously
- Automatic Pod Restart Handling: Detects and reconnects to pods when they restart
- Label Selector Support: Dynamically target pods using label selectors
- Prefix Matching: Automatically find and reconnect to pods with name prefixes
- Hot-Reload: Configuration file changes are automatically detected and applied
- Resilient Connections: Infinite retry with exponential backoff (max 10s)
- Port Conflict Detection: Validates port availability before starting
- Multiple Ports Per Resource: Forward multiple ports from the same pod/service
Installation
# Install development tools (including semver-gen for version management)
make install-tools
# Build from source (version automatically generated from git history)
make build
# Install to user bin directory
make install
# Install system-wide (requires sudo)
sudo make install-system
# Or build manually
go build -o kportal ./cmd/kportal
Usage
Basic Usage
# Use default config file (.kportal.yaml)
./kportal
# Use custom config file
./kportal -c myconfig.yaml
# Enable verbose logging
./kportal -v
# Validate configuration without starting
./kportal --check
# Convert kftray JSON config to kportal YAML
./kportal --convert configs.json --convert-output .kportal.yaml
Configuration File
Create a .kportal.yaml file in your current directory:
contexts:
- name: production
namespaces:
- name: default
forwards:
# Pod with prefix matching (auto-handles restarts)
- resource: pod/my-app
protocol: tcp
port: 8080
localPort: 8080
alias: my-api # Optional: cleaner log output
# Service forwarding with alias
- resource: service/postgres
protocol: tcp
port: 5432
localPort: 5432
alias: prod-db
- name: monitoring
forwards:
# Pod with label selector
- resource: pod
selector: app=prometheus
protocol: tcp
port: 9090
localPort: 9090
alias: prometheus
- name: staging
namespaces:
- name: default
forwards:
# Multiple ports from same pod
- resource: pod/test-app
port: 8080
localPort: 8081
alias: test-http
- resource: pod/test-app
port: 9090
localPort: 9091
alias: test-metrics
Resource Types
Pod with Prefix Matching
- resource: pod/my-app # Matches my-app-xyz789, my-app-abc123, etc.
port: 8080
localPort: 8080
Automatically reconnects to new pods when they restart.
Pod with Label Selector
- resource: pod
selector: app=nginx,env=prod
port: 80
localPort: 8080
Dynamically selects pods matching the label selector.
Service
- resource: service/postgres
port: 5432
localPort: 5432
Most stable option - forwards to service endpoints.
Using Aliases
Aliases provide cleaner, more readable log output:
- resource: service/victoria-metrics-cluster-vmselect
port: 8481
localPort: 8481
alias: vmetrics # Shows "vmetrics:8481→8481" instead of full path
Without alias:
[home/monitoring/service/victoria-metrics-cluster-vmselect:8481] Forwarding...
With alias:
[vmetrics:8481] Forwarding vmetrics:8481→8481 → localhost:8481
Converting from kftray
kportal can automatically convert kftray JSON configurations to kportal YAML format:
# Convert kftray config
kportal --convert kftray-config.json --convert-output .kportal.yaml
# The converter will:
# 1. Read the kftray JSON format
# 2. Group forwards by context and namespace
# 3. Generate kportal YAML with all aliases preserved
# 4. Display a summary of the conversion
Example kftray JSON:
[
{
"service": "postgres",
"namespace": "default",
"local_port": 5432,
"remote_port": 5432,
"context": "production",
"workload_type": "service",
"protocol": "tcp",
"alias": "prod-db"
}
]
Converts to kportal YAML:
contexts:
- name: production
namespaces:
- name: default
forwards:
- resource: service/postgres
protocol: tcp
port: 5432
localPort: 5432
alias: prod-db
How It Works
Pod Restart Handling
When a pod restarts:
- The port-forward connection breaks
- kportal immediately attempts to re-resolve the resource
- For prefix matches: finds the newest pod with that prefix
- For selectors: re-queries pods with matching labels
- Reconnects to the new pod
- Logs the switch:
Switched to new pod: old-pod → new-pod
Retry Strategy
Backoff intervals: 1s → 2s → 4s → 8s → 10s (max)
- Connection failures trigger immediate resource re-resolution
- Retries continue indefinitely until successful
- Each forward has independent retry logic
Hot-Reload
The config file is watched for changes:
- File change detected
- New config loaded and validated
- Changes diff'd against current state
- New forwards started, removed forwards stopped
- Unchanged forwards continue running
If validation fails, the previous configuration remains active.
Development
Build Commands
# Build binary
make build
# Check current version (from semver-gen)
make version
# Run all checks (fmt, vet, staticcheck, test, build)
make all
# Run tests with race detection
make test
# Run code quality checks
make vet
make staticcheck
make fmt
# Install development tools (staticcheck, mockery, semver-gen)
make install-tools
# Generate test coverage report
make coverage
Semantic Versioning
This project uses semver-gen for automatic semantic version generation based on git commit messages.
Version Keywords:
- Patch (0.0.X):
fix,bugfix,hotfix,patch,docs,test,refactor - Minor (0.X.0):
feat,feature,add,enhance,update,improve - Major (X.0.0):
breaking,major,BREAKING CHANGE
The version is automatically calculated from your git history and embedded in the binary at build time.
# Check current version
make version
# Build with auto-generated version
make build
# Verify version in binary
./kportal --version
Configuration is managed in semver.yaml. To manually install semver-gen:
# Automatically installed via make install-tools
# Or install manually from https://github.com/lukaszraczylo/semver-generator
Project Structure
kportal/
├── cmd/kportal/ # CLI entry point
├── internal/
│ ├── config/ # Configuration parsing and validation
│ ├── forward/ # Port-forward workers and manager
│ ├── k8s/ # Kubernetes client, resolver, port-forward wrapper
│ └── retry/ # Exponential backoff logic
├── test/
│ ├── integration/ # Integration tests
│ ├── fixtures/ # Test configurations
│ └── helpers/ # Test utilities
├── .kportal.yaml # Example configuration
├── semver.yaml # Semantic version configuration
├── Makefile # Build automation
└── CLAUDE.md # Development guide
Signal Handling
CTRL+C/SIGTERM: Graceful shutdown (closes all forwards)SIGHUP: Reload configuration file
Port Conflict Detection
kportal validates ports at multiple stages:
- Config Parse Time: Detects duplicate local ports in configuration
- Startup Time: Checks if ports are available on the system
- Hot-Reload Time: Validates new ports before applying changes
Errors show which process is using conflicting ports (with PID).
Examples
Forward Multiple Services from Production
contexts:
- name: production
namespaces:
- name: default
forwards:
- resource: service/api
port: 8080
localPort: 8080
- resource: service/postgres
port: 5432
localPort: 5432
- resource: service/redis
port: 6379
localPort: 6379
Monitor Multiple Environments
contexts:
- name: production
namespaces:
- name: monitoring
forwards:
- resource: service/prometheus
port: 9090
localPort: 9090
- name: staging
namespaces:
- name: monitoring
forwards:
- resource: service/prometheus
port: 9090
localPort: 9091 # Different local port
Debug Specific Pods
contexts:
- name: production
namespaces:
- name: default
forwards:
# Forward app HTTP and debug ports
- resource: pod
selector: app=myapp,version=v2
port: 8080
localPort: 8080
- resource: pod
selector: app=myapp,version=v2
port: 6060 # pprof
localPort: 6060
License
MIT
Contributing
Contributions welcome! Please ensure:
- Code passes
make check(fmt, vet, staticcheck) - Tests pass with
make test - New features include tests