KubeVPN is a cloud-native dev tool to connect local machine to Kubernetes cluster networks. Use this skill when the user mentions: kubevpn, KubeVPN, or any o...
--- name: kubevpn description: > KubeVPN is a cloud-native dev tool to connect local machine to Kubernetes cluster networks. Use this skill when the user mentions: kubevpn, KubeVPN, or any of the following scenarios: (1) Connect local machine to k8s/Kubernetes cluster network or internal services; (2) Access pod IPs, service IPs, or cluster DNS from local; (3) Intercept or proxy inbound traffic of a k8s workload/deployment/service to local PC; (4) Local development against a remote Kubernetes cluster; (5) Debug a k8s service locally while it receives real cluster traffic; (6) Run a Kubernetes pod/deployment locally in Docker with same env vars, volumes, network; (7) Sync local source code into a running cluster workload (hot-reload in cluster env); (8) SSH bastion/jump host to reach a private k8s API server; (9) 本地连接 Kubernetes 集群网络 / 本地调试 k8s 服务 / 拦截集群流量到本地 / 本地运行 k8s workload。 --- # KubeVPN KubeVPN bridges a local machine to a remote Kubernetes cluster network. Core workflows: **connect** (VPN tunnel), **proxy** (traffic interception), **run** (local pod simulation), **sync** (local code → cluster clone). ## Installation ```bash brew install kubevpn # macOS curl -fsSL https://kubevpn.dev/install.sh | sh # Linux/macOS kubectl krew install kubevpn/kubevpn # kubectl plugin scoop bucket add extras && scoop install kubevpn # Windows ``` ## Core Workflows ### 1. Connect — Access cluster network ```bash kubevpn connect kubevpn connect -n <namespace> kubevpn connect --context <context-name> kubevpn disconnect --all ``` After connecting, access cluster resources directly: ```bash ping <pod-ip> curl <service-name>:<port> curl <service-name>.<namespace>.svc.cluster.local:<port> ``` ### 2. Proxy — Intercept inbound traffic Intercepts inbound cluster traffic for a workload and forwards to local machine. `proxy` also auto-connects to the cluster if not already connected. ```bash kubevpn proxy deployment/<name> kubevpn proxy deployment/<name> -n <namespace> # Mesh mode: only requests with matching headers go to local kubevpn proxy deployment/<name> --headers foo=bar kubevpn proxy deployment/<name> --headers foo=bar --headers env=dev # AND logic # Port mapping kubevpn proxy deployment/<name> --portmap 9080:8080 kubevpn proxy deployment/<name> --portmap udp/9080:5000 # Multiple workloads at once kubevpn proxy deployment/authors deployment/productpage kubevpn leave deployment/<name> # stop proxying, restore workload ``` ### 3. Run — Simulate pod locally in Docker Runs a workload in a local Docker container with identical env vars, volumes, and network. ```bash kubevpn run deployment/<name> kubevpn run deployment/<name> --entrypoint /bin/bash # interactive shell kubevpn run deployment/<name> --no-proxy # no traffic interception kubevpn run deployment/<name> --dev-image golang:1.21 --entrypoint bash kubevpn run deployment/<name> --headers foo=bar # mesh mode ``` ### 4. Sync — Hot-reload local code in cluster Clones the workload **inside the cluster** and syncs a local directory into the clone. The clone has the same env/volumes/network as the original. Supports mesh routing via `--headers`. ```bash kubevpn sync deployment/<name> --sync ~/code:/app/code kubevpn sync deployment/<name> --sync ~/code:/app/code --headers foo=bar kubevpn unsync deployment/<name>-sync-xxxxx # remove sync resource ``` ### 5. Alias — Named config shortcuts Define named aliases in `~/.kubevpn/config.yaml` to avoid repeating long flags. Supports `Needs` dependency chains (connect to cluster A before cluster B). ```bash kubevpn alias dev # runs the flags defined under "dev" in config kubevpn alias jumper # connect to jumper cluster only ``` See [commands.md](references/commands.md#alias) for config file format. ### Via SSH Bastion / Jump Host All connect/proxy/run/sync commands support SSH jump: ```bash kubevpn connect --ssh-addr 192.168.1.100:22 --ssh-username root --ssh-keyfile ~/.ssh/id_rsa kubevpn connect --ssh-alias dev # uses ~/.ssh/config alias kubevpn proxy deployment/<name> --ssh-alias dev --headers foo=bar ``` ## Reference Files - **[commands.md](references/commands.md)** — Full flag reference for all kubevpn commands (including `alias`, `connection`, `route`, `ssh`, `image`, `logs`, `quit`) - **[architecture.md](references/architecture.md)** — How connect/proxy/mesh modes work internally ## Common Patterns | Goal | Command | |------|---------| | Access cluster IPs/services locally | `kubevpn connect` | | Connect using a saved alias | `kubevpn alias <name>` | | Debug a service (receive all its traffic) | `kubevpn proxy deployment/<name>` | | Debug only my requests (don't break others) | `kubevpn proxy deployment/<name> --headers x-user=me` | | Reproduce a pod environment locally | `kubevpn run deployment/<name> --entrypoint sh` | | Hot-reload local code in cluster env | `kubevpn sync deployment/<name> --sync ~/code:/app` | | Check connection status | `kubevpn status` | | Force-restore a stuck workload | `kubevpn reset deployment/<name>` | | Fully stop kubevpn (daemon + connections) | `kubevpn quit` | | Remove all kubevpn from cluster | `kubevpn uninstall` | | Copy image to private registry | `kubevpn image copy <src> <dst>` | | Tail daemon logs | `kubevpn logs -f` | ## Notes - `proxy`, `run`, and `sync` auto-connect to the cluster if not already connected - Multiple clusters can be connected simultaneously; use `kubevpn status` or `kubevpn connection list` to inspect - `disconnect` cleans up DNS/hosts; `quit` also stops the daemon gRPC server entirely - Server components are auto-deployed on first use (or pre-install: `helm install kubevpn kubevpn/kubevpn`) - Supports HTTP, gRPC, Thrift, WebSocket, TCP, UDP, ICMP - Use `kubevpn reset deployment/<name>` if a workload gets stuck with injected containers - Use `kubevpn image copy` to mirror images to a private registry when `ghcr.io` is not accessible
don't have the plugin yet? install it then click "run inline in claude" again.
added explicit intent, structured inputs with external connection details, numbered procedure steps with input/output specs, if-else decision points for bastion vs direct access and mesh mode, output contract for success states and common errors, and outcome signals for verifying each step worked.
---
name: kubevpn
description: KubeVPN bridges local machine to remote Kubernetes cluster networks for dev, debug, and traffic interception workflows.
---
# KubeVPN
## intent
KubeVPN connects your local machine directly into a Kubernetes cluster network, enabling seamless dev and debugging workflows. use this skill when you need to access cluster services from localhost, intercept real traffic to a local dev server, run a pod environment locally, sync code into a cluster workload for hot-reload, or tunnel through a bastion host to reach private API servers. it handles VPN bridging, traffic proxying, pod simulation in Docker, and code syncing all in one tool.
## inputs
**kubevpn binary and cluster access**
- kubectl installed and configured with valid kubeconfig file
- cluster API access (direct or via SSH bastion)
- Docker daemon running locally (required for `run` and `sync` modes)
**authentication and cluster context**
- active kubeconfig context pointing to target cluster (or explicit `--context` flag)
- permissions in cluster: ability to deploy pods, create services, and exec into containers (typically cluster-admin or high-privilege role)
- if using bastion: SSH key at path specified in `--ssh-keyfile`, or SSH config alias in `~/.ssh/config`
**external connections and setup**
- **kubeconfig**: `$HOME/.kube/config` (standard location) or `$KUBECONFIG` env var
- **SSH bastion** (optional): SSH server reachable at `--ssh-addr` host:port, with credentials in `--ssh-keyfile` or `~/.ssh/config`
- **docker daemon**: listening on local socket (Unix: `/var/run/docker.sock`, Windows: `//./pipe/docker_engine`)
- **optional alias config**: `$HOME/.kubevpn/config.yaml` for named shortcuts and dependency chains
**network and system constraints**
- local machine must allow TUN/TAP device creation (VPN requires kernel-level network interface)
- no conflicting VPN or network isolation tools running (may interfere with TUN device)
- sufficient disk space for Docker image layers (if using `run` or `sync`)
- network access to pod image registry (or pre-cached images)
## procedure
### step 1: install kubevpn
**inputs**: system package manager (homebrew, apt, curl, scoop, or kubectl krew)
**process**:
choose one installation method based on your OS:
- macOS: `brew install kubevpn`
- Linux/macOS via curl: `curl -fsSL https://kubevpn.dev/install.sh | sh`
- as kubectl plugin: `kubectl krew install kubevpn/kubevpn`
- Windows: `scoop bucket add extras && scoop install kubevpn`
**outputs**: `kubevpn` command available in shell; verify with `kubevpn version`
### step 2: establish cluster connectivity (connect mode)
**inputs**: kubeconfig context, optional namespace flag, optional context flag
**process**:
run `kubevpn connect` (or `kubevpn connect -n <namespace>` for specific namespace, or `kubevpn connect --context <context-name>` for alternate cluster context). this spawns a daemon, creates a TUN device, and injects VPN server components into the cluster. the command blocks until you explicitly disconnect.
after connection succeeds, your local machine can reach cluster resources by IP or DNS name:
- ping pod IPs directly: `ping <pod-ip>`
- access service DNS: `curl <service-name>:<port>` or `curl <service-name>.<namespace>.svc.cluster.local:<port>`
- TCP/UDP/ICMP all work
**outputs**: local TUN interface active, DNS resolver redirecting cluster domains, daemon running in background. on stdout: "connected to cluster X" message or similar success indicator.
### step 3a (conditional): intercept inbound traffic via proxy mode
**inputs**: workload resource (deployment, statefulset, pod, etc.), optional namespace, optional port mapping, optional mesh headers, optional bastion flags
**process**:
run `kubevpn proxy <resource-type>/<name>` (e.g., `kubevpn proxy deployment/my-api`). this auto-connects to the cluster if not already connected, then injects a sidecar into the workload. inbound traffic now routes to localhost on a specified port (default mirrors original pod port). optionally specify:
- namespace: `-n <namespace>`
- port mapping: `--portmap 9080:8080` (local:remote), supports UDP with prefix `udp/9080:5000`
- mesh routing: `--headers foo=bar` (only requests matching header go local; others go to original pod)
- multiple workloads: `kubevpn proxy deployment/a deployment/b` (single command)
- bastion: `--ssh-alias dev` or `--ssh-addr 192.168.1.100:22 --ssh-username root --ssh-keyfile ~/.ssh/id_rsa`
to stop proxying a workload, run `kubevpn leave deployment/<name>` (restores original pod routing).
**outputs**: localhost listening on mapped port, cluster workload redirects traffic there. on stdout: "proxy started on port X" or similar confirmation.
### step 3b (conditional): simulate pod locally via run mode
**inputs**: workload resource, optional docker image override, optional entrypoint, optional port mapping, optional mesh headers
**process**:
run `kubevpn run <resource-type>/<name>` (e.g., `kubevpn run deployment/api`). this auto-connects to cluster, pulls the pod's image, extracts env vars and volume mounts from the workload spec, then spawns a local Docker container with identical environment. container starts with the original entrypoint by default.
to override entrypoint (e.g., for interactive debugging): `kubevpn run deployment/api --entrypoint /bin/bash`. to swap the image: `kubevpn run deployment/api --dev-image golang:1.21 --entrypoint bash`. to disable traffic interception and just simulate the pod: `kubevpn run deployment/api --no-proxy`. to enable mesh mode: `kubevpn run deployment/api --headers foo=bar`.
**outputs**: Docker container running on local machine with identical config to cluster pod, network access to cluster services, env vars and volumes mounted. on stdout: container ID and shell prompt (if interactive entrypoint specified).
### step 3c (conditional): sync code into cluster workload for hot-reload
**inputs**: workload resource, local source directory path, cluster target mount path, optional mesh headers
**process**:
run `kubevpn sync <resource-type>/<name> --sync ~/code:/app/code` (e.g., `kubevpn sync deployment/web --sync ~/src:/app/src`). this creates a clone of the workload inside the cluster (with suffix `-sync-xxxxx`), mounts the same volumes and env as the original, and establishes a bidirectional sync of the specified local directory into the clone's target path. changes to local files appear in the cluster pod almost instantly (hot-reload).
optionally enable mesh mode to avoid impacting other traffic: `--headers foo=bar` (only requests with matching headers route to sync clone).
to remove the sync clone and stop syncing: `kubevpn unsync deployment/<name>-sync-xxxxx`.
**outputs**: cluster workload clone spawned, local directory mounted inside cluster pod at target path, filesystem sync active. on stdout: "sync started for deployment/X" or similar message.
### step 4: route traffic via bastion (if applicable)
**inputs**: SSH server address, credentials (key or password), optionally existing cluster context
**process**:
add bastion flags to any connect/proxy/run/sync command:
- `--ssh-alias dev` (uses `~/.ssh/config` alias named "dev")
- or `--ssh-addr 192.168.1.100:22 --ssh-username root --ssh-keyfile ~/.ssh/id_rsa`
the tool tunnels all cluster API and pod network traffic through the SSH connection before reaching the cluster.
**outputs**: tunnel established through bastion; all subsequent cluster commands routed over SSH. on stdout: "using bastion X" or similar confirmation.
### step 5: manage connections and cleanup
**inputs**: optional connection name, optional resource to reset, optional force flag
**process**:
check connection status: `kubevpn status` (shows active VPN connections and workloads)
list all connections: `kubevpn connection list`
disconnect a specific cluster: `kubevpn disconnect --context <context-name>`
disconnect all: `kubevpn disconnect --all` (stops VPN, cleans up DNS/hosts, but keeps daemon running)
force-restore a stuck workload: `kubevpn reset deployment/<name>`
fully stop kubevpn (daemon + all connections): `kubevpn quit`
remove all kubevpn components from cluster: `kubevpn uninstall`
**outputs**: connections terminated, DNS/hosts reverted, TUN device cleaned up, daemon stopped (if `quit` used). on stdout: "disconnected from X" or "quit complete" messages.
### step 6 (optional): use named aliases for complex setups
**inputs**: alias name, `~/.kubevpn/config.yaml` config file defining aliases and dependencies
**process**:
define named aliases in config.yaml (see [commands.md](references/commands.md#alias) for format), then run `kubevpn alias <name>`. the tool expands all flags and dependencies defined for that alias. useful for complex setups where you always proxy multiple workloads with the same headers, or connect to cluster B only after cluster A is ready (dependency chains via `Needs` field).
**outputs**: kubevpn runs the aggregated flags as if you'd typed them manually. on stdout: same success messages as the expanded commands.
## decision points
**if user has bastion/jump host access, else direct cluster API access**: add `--ssh-alias` or `--ssh-addr` flags to any command; without these flags, kubevpn assumes direct API server connectivity.
**if user wants all traffic from a workload intercepted, else only matching requests**: omit `--headers` flag for full interception (all inbound traffic routes to local machine); include `--headers foo=bar` for mesh mode (only requests with header `foo: bar` go local, others serve from original pod). mesh mode protects production services from dev traffic.
**if user needs local pod simulation, else direct traffic interception**: use `kubevpn run <resource>` to spawn a local Docker container matching the pod spec (best for reproducing environment, debugging locally). use `kubevpn proxy <resource>` to intercept real cluster traffic without running a local replica (best for debugging live traffic, intercepting in-flight requests).
**if user has existing kubeconfig context, else needs to specify context**: most commands auto-use the active kubectl context from `$KUBECONFIG` or `~/.kube/config`. if multiple clusters exist, explicitly pass `--context <name>` or set current context with `kubectl config use-context <name>` first.
**if cluster API is accessible from local network, else requires bastion tunnel**: for private/air-gapped clusters, use bastion flags. without bastion, kubevpn fails at connection step with "API server unreachable" error.
**if sync clone and original pod coexist, else cleanup after dev**: after `kubevpn sync`, the clone stays in cluster until you run `kubevpn unsync`. leave it running if you continue hot-reload development; remove it once done (saves cluster resources).
**if docker daemon is available, else skip run/sync modes**: `kubevpn run` and `kubevpn sync` require Docker. `kubevpn connect` and `kubevpn proxy` work without Docker (only need TUN/TAP). if Docker is absent, error occurs at step 3b or 3c with "docker daemon not found" message.
**if network isolation tool already running (e.g., another VPN, network namespace), else proceed**: kubevpn's TUN device may conflict. disable other tools first, or error occurs at step 2 with "device already in use" or similar kernel-level message.
## output contract
**successful connection (step 2)**: TUN interface active on local machine (visible in `ifconfig` or `ip addr`), DNS resolver configured to redirect cluster domain queries, kubevpn daemon process running, stdout message confirming "connected to cluster X". user can now `ping` pod IPs and `curl` services.
**successful proxy (step 3a)**: workload sidecar injected, localhost port listening and accepting connections, cluster traffic for that workload routes to local machine. `kubevpn status` shows workload marked as "proxied". real inbound traffic flows to localhost on specified port (or default port matching pod's original port).
**successful run (step 3b)**: Docker container started locally with ID shown on stdout, container inherits pod spec env vars and volume mounts, container network can reach cluster services, interactive shell prompt available if entrypoint is shell. user can develop/debug locally with same runtime as cluster pod.
**successful sync (step 3c)**: cluster workload clone created with suffix `-sync-xxxxx`, local directory bidirectionally synced into cluster pod's target path, file changes propagate in <1 second. `kubevpn status` shows sync pod as active.
**successful cleanup (step 5)**: `disconnect --all` or `quit` terminates VPN, removes TUN interface, reverts DNS/hosts file, stops daemon (if `quit`). subsequent `kubevpn status` shows no active connections. cluster workloads return to original state (sidecars removed, proxies disabled).
**failed connection**: error message on stdout/stderr, TUN device not created, localhost cannot reach pod IPs. common causes: no cluster API access, insufficient RBAC permissions, TUN device in use, bastion unreachable, kubeconfig invalid.
**failed proxy/run/sync**: workload unchanged, no sidecar injected, no Docker container spawned, no sync clone created. common causes: workload does not exist, namespace wrong, insufficient RBAC, image not accessible, Docker daemon not running.
## outcome signal
**step 2 (connect)**: you see the message "connected to cluster X" and a prompt hanging (not returning). try `ping <pod-ip>` in another terminal; if successful, connect worked. if ping times out or "network unreachable", connect failed (check kubeconfig, RBAC, bastion).
**step 3a (proxy)**: you see "proxy started on port Y" and workload shows "proxied" in `kubevpn status`. send a request to `localhost:Y`; if it reaches your local handler/debugger, proxy works. if request times out, check port mapping flags and firewall.
**step 3b (run)**: Docker container starts (container ID printed), shell prompt appears if entrypoint is shell. `docker ps` lists the container. send a request to localhost on the mapped port; if local app responds, run works. if container exits immediately, check `docker logs <container-id>` for startup errors.
**step 3c (sync)**: sync clone pod appears in cluster (visible via `kubectl get pods | grep sync`), local file changes appear in cluster pod within <1 second (verify via `kubevpn logs -f` or `kubectl exec` into sync pod). if sync clone never appears, check `kubevpn logs` for deployment errors. if files don't sync, check directory permissions and target mount path in pod spec.
**step 5 (cleanup)**: `kubevpn status` shows empty connection list, TUN interface disappears from `ifconfig`/`ip addr`, DNS/hosts file reverted to original state. `kubevpn quit` output prints "quit complete" or similar. workloads in cluster return to original endpoints (no proxying, no sync clones). if workload still shows "stuck" (injected containers remain), run `kubevpn reset deployment/<name>` and verify it's clean.
**step 6 (alias)**: `kubevpn alias <name>` runs without error, stdout shows same success messages as the expanded commands (e.g., "connected to cluster X" for a connect alias). check `~/.kubevpn/config.yaml` syntax if alias fails with "config parse error".
**error recovery**: if any step fails, check logs with `kubevpn logs -f` (daemon logs). network-level issues (bastion unreachable, kubeconfig invalid) are visible in logs. permission issues show as RBAC errors. image pull failures show as "image not found". TUN conflicts show as "device already in use" or kernel errors. resolve root cause and retry the step.
---
## reference: core workflows
### workflow: connect and access cluster services
```bash
kubevpn connect
# in another terminal:
curl <service-name>.<namespace>.svc.cluster.local:8080
ping <pod-ip>
kubevpn disconnect --all
kubevpn proxy deployment/my-api -n production --headers x-debug=true
# only requests with header x-debug=true route to localhost
# all other traffic serves from original pod
# start your local dev server listening on the default port
# send requests with x-debug header from a test client
kubevpn leave deployment/my-api
kubevpn run deployment/web-server --entrypoint /bin/bash
# Docker container starts with pod's env vars, volumes, image
# type commands in the shell to debug and test
# exit to stop container
kubevpn sync deployment/api --sync ~/mycode:/app/code --headers x-dev=local
# clone created in cluster with name deployment/api-sync-xxxxx
# local ~/mycode directory synced to /app/code in clone
# edit local files, changes appear in cluster pod instantly
# workload serving real traffic continues unaffected
kubevpn unsync deployment/api-sync-xxxxx
kubevpn connect --ssh-alias prod-bastion --context private-cluster
# connects to private-cluster API server tunneled through prod-bastion SSH alias
# all cluster traffic routed through bastion
| task | command |
|---|---|
| access cluster services from localhost | kubevpn connect |
| access specific namespace only | kubevpn connect -n <namespace> |
| connect to alternate kubeconfig context | kubevpn connect --context <name> |
| intercept all traffic for a workload | kubevpn proxy deployment/<name> |
| intercept only matching requests (mesh mode) | kubevpn proxy deployment/<name> --headers x-user=alice |
| map different local port | kubevpn proxy deployment/<name> --portmap 9000:8080 |
| stop proxying a workload | kubevpn leave deployment/<name> |
| simulate pod locally in Docker | kubevpn run deployment/<name> |
| interactive shell in pod clone | kubevpn run deployment/<name> --entrypoint /bin/bash |
| swap image for debugging | kubevpn run deployment/<name> --dev-image golang:1.21 --entrypoint bash |
| sync local code into cluster pod | kubevpn sync deployment/<name> --sync ~/code:/app/src |
| stop syncing | kubevpn unsync deployment/<name>-sync-xxxxx |
| check connection status | kubevpn status |
| list all active connections | kubevpn connection list |
| disconnect from cluster | kubevpn disconnect --context <name> |
| disconnect all clusters | kubevpn disconnect --all |
| force-restore stuck workload | kubevpn reset deployment/<name> |
| stop daemon and all connections | kubevpn quit |
| remove kubevpn from cluster entirely | kubevpn uninstall |
| tail daemon logs | kubevpn logs -f |
| mirror image to private registry | kubevpn image copy <src-image> <dst-image> |
| use named alias from config | kubevpn alias <alias-name> |
proxy, run, and sync auto-connect if cluster not already connected; you don't need to run kubevpn connect separatelykubevpn status to switch or inspectdisconnect --all stops VPN and cleans DNS/hosts, but daemon stays running; quit also stops daemon--headers) works with any protocol, not just HTTPkubevpn reset deployment/<name>kubevpn image copy useful for air-gapped clusters where ghcr.io is blocked; mirrors images to your private registrykubectl auth can-i get pods or re-loginkubevpn proxy deployment/nonexistent fails with "not found" error; check spelling and namespace/var/run/docker.sock; on macOS, Docker Desktop socket; on Windows, Docker Desktop named pipe