Files
kportal/README.md
T

395 lines
9.4 KiB
Markdown

# 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
```bash
# 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
```bash
# 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:
```yaml
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
```yaml
- 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
```yaml
- resource: pod
selector: app=nginx,env=prod
port: 80
localPort: 8080
```
Dynamically selects pods matching the label selector.
#### Service
```yaml
- resource: service/postgres
port: 5432
localPort: 5432
```
Most stable option - forwards to service endpoints.
#### Using Aliases
Aliases provide cleaner, more readable log output:
```yaml
- 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:
```bash
# 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:**
```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:**
```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:
1. The port-forward connection breaks
2. kportal immediately attempts to re-resolve the resource
3. For prefix matches: finds the newest pod with that prefix
4. For selectors: re-queries pods with matching labels
5. Reconnects to the new pod
6. 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:
1. File change detected
2. New config loaded and validated
3. Changes diff'd against current state
4. New forwards started, removed forwards stopped
5. Unchanged forwards continue running
If validation fails, the previous configuration remains active.
## Development
### Build Commands
```bash
# 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](https://github.com/lukaszraczylo/semver-generator) 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.
```bash
# 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:
```bash
# 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:
1. **Config Parse Time**: Detects duplicate local ports in configuration
2. **Startup Time**: Checks if ports are available on the system
3. **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
```yaml
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
```yaml
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
```yaml
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