* Add mDNS resolution. * Update the website and documentation
7.4 KiB
Kubernetes port-forward manager with interactive terminal UI
kportal manages multiple Kubernetes port-forwards with an interactive terminal interface. It provides real-time status updates, automatic reconnection, hot-reload configuration, and mDNS hostname publishing.
✨ Features
- Interactive TUI - Terminal interface with keyboard navigation
- Live management - Add, edit, and delete port-forwards without restarting
- Auto-reconnect - Exponential backoff retry on connection failures
- Hot-reload - Configuration changes applied automatically
- Health monitoring - Multiple check methods with stale connection detection
- Multi-context - Support for multiple Kubernetes contexts and namespaces
- Pod restart handling - Automatic reconnection when pods restart
- Label selectors - Dynamic pod targeting using label selectors
- Port conflict detection - Validates port availability with PID information
- mDNS hostnames - Access forwards via
.localhostnames
📦 Installation
Homebrew (macOS/Linux)
brew install lukaszraczylo/brew-taps/kportal
Quick Install
curl -fsSL https://raw.githubusercontent.com/lukaszraczylo/kportal/main/install.sh | bash
Manual Download
Download binaries from the releases page.
Build from Source
git clone https://github.com/lukaszraczylo/kportal.git
cd kportal
make build && make install
🚀 Quick Start
Create .kportal.yaml:
contexts:
- name: production
namespaces:
- name: backend
forwards:
- resource: service/postgres
protocol: tcp
port: 5432
localPort: 5432
alias: prod-db
- resource: service/redis
protocol: tcp
port: 6379
localPort: 6379
Run:
kportal
Keyboard Controls
| Key | Action |
|---|---|
↑↓ / j/k |
Navigate |
Space / Enter |
Toggle forward |
a |
Add forward |
e |
Edit forward |
d |
Delete forward |
q |
Quit |
📖 Configuration
Basic Structure
contexts:
- name: <context-name>
namespaces:
- name: <namespace-name>
forwards:
- resource: <type>/<name>
protocol: tcp
port: <remote-port>
localPort: <local-port>
alias: <display-name> # optional
selector: <label-selector> # optional
Forward Options
| Field | Required | Description |
|---|---|---|
resource |
Yes | Resource type and name (e.g., service/postgres, pod/my-app) |
protocol |
Yes | Protocol (tcp) |
port |
Yes | Remote port |
localPort |
Yes | Local port |
alias |
No | Display name and mDNS hostname |
selector |
No | Label selector for pod resolution |
Resource Formats
| Format | Description |
|---|---|
service/name |
Service forwarding |
pod/name |
Direct pod by name |
pod/prefix |
Pod by prefix (matches prefix-*) |
pod + selector |
Pod by label selector |
deployment/name |
Deployment |
Health Check Configuration
healthCheck:
interval: "3s" # Check frequency
timeout: "2s" # Check timeout
method: "data-transfer" # tcp-dial or data-transfer
maxConnectionAge: "25m" # Reconnect before k8s timeout
maxIdleTime: "10m" # Detect idle connections
reliability:
tcpKeepalive: "30s"
dialTimeout: "30s"
retryOnStale: true
Health check methods:
tcp-dial- Fast TCP connection testdata-transfer- Verifies tunnel functionality by attempting data read
Connection age reconnection only triggers when the connection is also idle, preventing interruption of active transfers like database dumps.
mDNS Hostnames
Enable mDNS to access forwards via .local hostnames:
mdns:
enabled: true
contexts:
- name: production
namespaces:
- name: default
forwards:
- resource: service/postgres
port: 5432
localPort: 5432
alias: prod-db # Accessible via prod-db.local:5432
- Explicit
aliasbecomes<alias>.local - Without alias, hostname is generated from resource name (
service/redis→redis.local) - Works on macOS (Bonjour) and Linux (avahi-daemon)
Verify registration:
dns-sd -B _kportal._tcp local # macOS
avahi-browse -t _kportal._tcp # Linux
Usage
Interactive Mode
kportal
Verbose Mode
kportal -v
Validate Configuration
kportal --check
Custom Config File
kportal -c /path/to/config.yaml
Status Indicators
| Indicator | Description |
|---|---|
● Active |
Connection healthy |
○ Starting |
Initial connection (10s grace period) |
◐ Reconnecting |
Reconnecting after failure |
✗ Error |
Connection failed |
○ Disabled |
Manually disabled |
Advanced Features
Hot-Reload
Configuration changes are applied automatically. Manual reload:
kill -HUP $(pgrep kportal)
Port Conflict Detection
kportal validates port availability at startup and during hot-reload, showing which process is using conflicting ports.
Retry Strategy
Exponential backoff: 1s → 2s → 4s → 8s → 10s (max). Retries continue indefinitely until connection succeeds.
Migration from kftray
kportal --convert configs.json --convert-output .kportal.yaml
Signal Handling
Ctrl+C/SIGTERM- Graceful shutdownSIGHUP- Reload configuration
🐛 Troubleshooting
Port Already in Use
lsof -i :<port>
kill <pid>
Connection Refused
- Verify pod is running:
kubectl get pods -n <namespace> - Verify port is correct:
kubectl describe pod <pod> - Check service endpoints:
kubectl get endpoints <service>
Context Not Found
kubectl config get-contexts
🔧 Development
Prerequisites
- Go 1.23+
- Kubernetes cluster access
- kubectl configured
Build
make build # Build binary
make test # Run tests
make all # fmt, vet, staticcheck, test
make install # Install locally
Contributing
See CONTRIBUTING.md for guidelines.
License
MIT License - see LICENSE.
Acknowledgments
- Bubble Tea - Terminal UI framework
- Lipgloss - Terminal styling
- client-go - Kubernetes client
- kftray - Inspiration
