# kubectl expose: Usage, Options & Common CI Errors

> kubectl expose creates a Service for a Deployment or pod. Service types, target-port mapping, and the no-selector-match error yielding no endpoints.

Source: https://latchkey.dev/learn/command-reference/kubectl-expose  
Updated: 2026-06-25

Generate a Service in front of a workload in one command.

kubectl expose creates a Service that load-balances to the pods of a workload, deriving the selector from the target. It is a quick imperative way to make a Deployment reachable in a preview or test cluster.

## What it does

kubectl expose deploy/web --port=80 --target-port=8080 creates a Service whose selector matches the Deployment's pod labels, mapping the Service port to the container's target-port. --type sets ClusterIP (default), NodePort, or LoadBalancer. It is the imperative twin of writing a Service manifest.

## Common usage

```Terminal
kubectl expose deploy/web --port=80 --target-port=8080
kubectl expose deploy/web --type=LoadBalancer --port=80
kubectl expose pod/my-pod --port=6379 --name=redis
kubectl expose deploy/web --port=80 --dry-run=client -o yaml
```

## Common errors in CI

The silent failure is a Service with no endpoints: if the workload has no labels (or expose picks a selector that matches nothing), the Service exists but kubectl get endpoints svc/web is empty, and every request hits a connection refused. Verify endpoints after exposing. "error: couldn't find port via --port flag" means the source has no obvious port to copy - pass --port explicitly. And a target-port mismatch (Service points at 80 but the container listens on 8080) gives connection failures even with healthy pods.

## Using this in CI

A runner has no kubeconfig, no cached context, and no interactive auth. Every kubectl invocation in CI needs the context supplied explicitly, and most confusing CI failures here are the command running against the wrong cluster or no cluster at all.

```Terminal
# never rely on the ambient context on a runner
kubectl --context "$KUBE_CONTEXT" -n "$NAMESPACE" get pods

# confirm what you are actually connected to before mutating anything
kubectl config current-context
kubectl cluster-info

# fail fast instead of hanging on an unreachable API server
kubectl --request-timeout=30s get nodes
```

> Always set `--request-timeout` in CI. Without it an unreachable API server hangs until the job times out, which turns a thirty-second failure into a twenty-minute one.

## FAQ

### kubectl expose: Usage, Options & Common CI Errors?

kubectl expose creates a Service that load-balances to the pods of a workload, deriving the selector from the target. It is a quick imperative way to make a Deployment reachable in a preview or test cluster.

### What it does?

kubectl expose deploy/web --port=80 --target-port=8080 creates a Service whose selector matches the Deployment's pod labels, mapping the Service port to the container's target-port. --type sets ClusterIP (default), NodePort, or LoadBalancer. It is the imperative twin of writing a Service manifest.

### Common errors in CI?

The silent failure is a Service with no endpoints: if the workload has no labels (or expose picks a selector that matches nothing), the Service exists but kubectl get endpoints svc/web is empty, and every request hits a connection refused. Verify endpoints after exposing.

---

Latchkey runs CI/CD that repairs its own failures. Agent entry points: https://latchkey.dev/agent.txt, https://latchkey.dev/openapi.json, https://latchkey.dev/llms.txt
