A terminal utility with a better UX for kubectl port-forward
Project description
kpf - A better way to port-forward with kubectl
This is a Python utility that (attempts to) dramatically improve the experience of port-forwarding with kubectl.
It is essentially a wrapper around kubectl port-forward that adds an interactive service selection with automatic reconnect when the pods are restarted or your network connection is interrupted (computer goes to sleep, etc).
You may also be interested in https://github.com/jessegoodier/kdebug, a utility for launching ephemeral debug containers in Kubernetes pods with interactive shell access, backup capabilities, and a colorful TUI for pod selection.
Demo
Demo of the TUI and the reconnect when a pod is restarted:
Features
- 🔄 Automatic Restart: Monitors endpoint changes and restarts port-forward automatically
- 🛡️ Network Watchdog: Detects zombie connections after laptop sleep/wake and auto-recovers
- 🎯 Interactive Selection: Choose services with a colorful, intuitive interface
- 🌈 Color-coded Status: Green for services with endpoints, red for those without
- 🔍 Multi-resource Support: Services, pods, deployments, etc.
- 🔐 Smart Port Handling: Automatically detects privileged port issues (< 1024) and suggests alternatives
Installation
Note: The oh-my-zsh kubectl plugin will conflict with this kpf command. You must unalias kpf before using this tool.
echo "unalias kpf 2>/dev/null" >> ~/.zshrc
Homebrew (Recommended)
Other methods do no automatically install command completions.
brew tap jessegoodier/kpf
brew install kpf
Or install directly:
brew install jessegoodier/kpf/kpf
Using pipx
pipx install kpf
Using uv
If you have uv installed, you can install kpf with:
uv tool install kpf
from source:
uv tool install .
Usage
Interactive Mode (Recommended)
Warm Tip: You can use the interactive mode to find the service you want, and it will output the command to connect to that service directly next time.
Note: You might think that "warm tip" is something that AI wrote, but that's not the case. It really is just a little bit cooler than a hot tip.
Visual explanation of the features:
Check which endpoints are up on entire cluster (can be slow):
Select services interactively:
Interactive selection in current namespace:
kpf
Interactive selection in specific namespace:
kpf -n production
Interactive selection with namespace prompt:
kpf -p
Show all services across all namespaces:
kpf --all
Include pods and deployments with ports defined:
kpf --all-ports
Combine a few options (interactive mode, all services, and endpoint status checking, debug mode):
kpf -pAdl
Check Mode
Add endpoint status checking to service selection (slower but shows endpoint health):
# Interactive selection with endpoint status
kpf --check
# Show all services with endpoint status
kpf --all --check
# Include pods and deployments with status
kpf --all-ports --check
Legacy Mode
Direct port-forward (maintain expected behavior):
# Traditional kubectl port-forward syntax
kpf svc/frontend 8080:8080 -n production
kpf pod/my-pod 3000:3000
Command Options
Example usage:
kpf # Interactive mode
kpf svc/frontend 8080:8080 -n production # Direct port-forward (maintain expected behavior)
kpf -n production # Interactive selection in specific namespace
kpf --all (or -A) # Show all services across all namespaces
kpf --all-ports (or -l) # Show all services with their ports
kpf --check -n production # Interactive selection with endpoint status
kpf --prompt-namespace (or -p) # Interactive namespace selection
kpf -z # Listen on 0.0.0.0 (all interfaces)
Examples
Interactive Service Selection
Fast mode (without endpoint checking):
$ kpf -n kube-system
Services in namespace: kube-system
# Type Name Ports
1 SERVICE kube-dns 53, 9153
2 SERVICE metrics-server 443
3 SERVICE kubernetes-dashboard 443
Select a service [1]: 1
Local port (press Enter for 53): 5353
With endpoint status checking:
$ kpf --check -n kube-system
Services in namespace: kube-system
# Type Name Ports Status
1 SERVICE kube-dns 53, 9153 ✓
2 SERVICE metrics-server 443 ✓
3 SERVICE kubernetes-dashboard 443 ✗
✓ = Has endpoints ✗ = No endpoints
Select a service [1]: 1
Local port (press Enter for 53): 5353
Cross-Namespace Discovery
$ kpf --all
Services across all namespaces
# Namespace Type Name Ports Status
1 default SERVICE kubernetes 443 ✓
2 kube-system SERVICE kube-dns 53, 9153 ✓
3 production SERVICE frontend 80, 443 ✓
4 production SERVICE backend 8080 ✗
Smart Low Port Handling
When you try to use privileged ports (< 1024), kpf will detect the permission issue and offer to use a higher port automatically:
$ kpf -n monitoring svc/grafana 80:80
Error: Port 80 requires elevated privileges (root/sudo)
Low ports (< 1024) require administrator permissions on most systems
Suggested alternative: Use port 1080 instead?
This would forward: localhost:1080 -> service:80
Use suggested port? [Y/n]: y
Updated port mapping to 1080:80
Direct command: kpf svc/grafana 1080:80 -n monitoring
http://localhost:1080
🚀 port-forward started 🚀
This feature prevents confusing "port already in use" errors when the real issue is insufficient permissions.
How It Works
- Port-Forward Thread: Runs kubectl port-forward in a separate thread
- Endpoint Watcher: Monitors endpoint changes using
kubectl get ep -w - Network Watchdog: Checks both K8s API connectivity and local port health every 5 seconds to detect zombie connections (e.g., after laptop sleep/wake). This catches cases where the API is reachable but the port-forward tunnel is dead.
- Automatic Restart: When endpoints change or connectivity is lost, gracefully restarts the port-forward
- Service Discovery: Uses kubectl to discover services and their endpoint status
Requirements
- kubectl configured with cluster access
Configuration
kpf can be configured via ~/.config/kpf/kpf.json (follows XDG Base Directory Specification).
All settings are optional with sensible defaults:
{
"autoSelectFreePort": true,
"showDirectCommand": true,
"showDirectCommandIncludeContext": true,
"directCommandMultiLine": true,
"autoReconnect": true,
"reconnectAttempts": 30,
"reconnectDelaySeconds": 5,
"captureUsageDetails": false,
"usageDetailFolder": "${HOME}/.config/kpf/usage-details",
"networkWatchdogEnabled": true,
"networkWatchdogInterval": 5,
"networkWatchdogFailureThreshold": 2
}
Configuration Options
| Option | Type | Default | Description |
|---|---|---|---|
autoSelectFreePort |
boolean | true |
When requested port is busy, automatically try next ports (9091, 9092, etc.) |
showDirectCommand |
boolean | true |
Show the direct kpf command for future use |
showDirectCommandIncludeContext |
boolean | true |
Include kubectl context in the command display |
directCommandMultiLine |
boolean | true |
Format direct command across multiple lines for readability |
autoReconnect |
boolean | true |
Automatically reconnect when connection drops |
reconnectAttempts |
integer | 30 |
Number of reconnection attempts before giving up |
reconnectDelaySeconds |
integer | 5 |
Delay in seconds between reconnection attempts |
captureUsageDetails |
boolean | false |
Capture usage details locally for debugging (not sent anywhere) |
usageDetailFolder |
string | ${HOME}/.config/kpf/usage-details |
Where to store usage detail logs |
networkWatchdogEnabled |
boolean | true |
Monitor K8s API connectivity to detect zombie connections |
networkWatchdogInterval |
integer | 5 |
Seconds between connectivity checks |
networkWatchdogFailureThreshold |
integer | 2 |
Consecutive failures before triggering restart |
Notes:
- All settings are optional - kpf will use defaults if the config file doesn't exist
- Environment variables like
${HOME}are expanded automatically - The config file location respects the
XDG_CONFIG_HOMEenvironment variable - Invalid JSON or unknown keys will show warnings but won't prevent kpf from running
- CLI arguments override config file values when provided
Example: Minimal Configuration
If you only want to change specific settings:
{
"showDirectCommand": false,
"reconnectAttempts": 10
}
Development
Setup Development Environment
# Clone the repository
git clone https://github.com/jessegoodier/kpf.git
cd kpf
# Install with development dependencies
uv venv
uv pip install -e ".[dev]"
source .venv/bin/activate
Code Quality Tools
# Format and lint code
uvx ruff check . --fix
uvx ruff format .
# Sort imports
uvx isort .
# Run tests
uv run pytest
Contributing
- Fork the repository
- Create a feature branch
- Make your changes
- Run tests and linting
- Submit a pull request
Shell Completion
Shell completions can be generated using the --completions flag.
Homebrew
If you installed via Homebrew (and the formula is updated), completions should be installed automatically. You may need to follow Homebrew's shell completion instructions to ensure it's loaded.
Manual Installation
Bash
# User-local installation (recommended)
kpf --completions bash > ~/.local/share/bash-completion/completions/kpf
# Or system-wide
kpf --completions bash | sudo tee /etc/bash_completion.d/kpf > /dev/null
Zsh
# Add to a directory in your fpath
kpf --completions zsh > /usr/share/zsh/site-functions/_kpf
# Or for oh-my-zsh users
kpf --completions zsh > ~/.oh-my-zsh/completions/_kpf
Then reload your shell: exec $SHELL
License
MIT License - see LICENSE file for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file kpf-0.9.1.tar.gz.
File metadata
- Download URL: kpf-0.9.1.tar.gz
- Upload date:
- Size: 41.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.0 {"installer":{"name":"uv","version":"0.10.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1f1b80310c3565f48a1b2a98961553284791e5720e4f749d5b8c70cce41e467c
|
|
| MD5 |
f5866e0904c850fe70a41d2cb669cc7d
|
|
| BLAKE2b-256 |
e7f9c6f84bc7bcc52d1a00c2a4d75db6bb9379ece7323022ba7624782e39248b
|
File details
Details for the file kpf-0.9.1-py3-none-any.whl.
File metadata
- Download URL: kpf-0.9.1-py3-none-any.whl
- Upload date:
- Size: 47.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.0 {"installer":{"name":"uv","version":"0.10.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5365b10d7dfcc2666c5d7a998df93a2621c2a28e188207d19f9d4091e614fa83
|
|
| MD5 |
7bd1426317ab6d0940da845662741cea
|
|
| BLAKE2b-256 |
347518b505513e68f098b9c44c5585d388d1037725f3112590053fef4f89d5c0
|