Add this to your .bashrc
alias k8_tmp_curl='kubectl run tmp-curl -it --rm --restart=Never --image=fedora:latest -- sh -c "dnf install -y curl && bash"'
A small, portable pattern that pins every kubectl call in a project to one
known context, so dev/PoC tooling can never accidentally hit a production
cluster — even when your kubeconfig is full of prod contexts (e.g. Teleport).
If a Makefile runs bare kubectl apply ..., it targets whatever
kubectl config current-context happens to be. Sign into a prod cluster
(tsh kube login ...), forget to switch back, run make deploy, and you've
just deployed into production. Calling kubectl config use-context inside the
Makefile is worse: it silently mutates your global current context as a
side effect of an unrelated command.
Pin to a context with --context via one variable, and never mutate global
state. Make every target use $(KUBECTL) instead of bare kubectl.
# Pin every kubectl call to a known-safe context. Override on the CLI if needed:
# make deploy KUBE_CONTEXT=some-other-context
KUBE_CONTEXT ?= rancher-desktop
KUBECTL = kubectl --context $(KUBE_CONTEXT)
.PHONY: guard deploy clean
guard:
@kubectl config get-contexts $(KUBE_CONTEXT) >/dev/null 2>&1 || { \
echo "❌ kube-context '$(KUBE_CONTEXT)' not found."; \
echo " Available: kubectl config get-contexts -o name"; exit 1; }
@$(KUBECTL) cluster-info >/dev/null 2>&1 || { \
echo "❌ Cannot reach '$(KUBE_CONTEXT)'. Is the cluster up?"; exit 1; }
@echo "✅ Targeting context: $(KUBE_CONTEXT)"
deploy: guard
$(KUBECTL) apply -f manifests/
clean: guard
$(KUBECTL) delete -f manifests/ --ignore-not-found
That's the whole pattern. Three rules:
KUBECTL) carries --context; everything routes through it.kubectl config use-context — pinning with --context leaves
your interactive context untouched.guard runs first. Make destructive/apply targets depend on guard
(deploy: guard) so they refuse to run against the wrong or an unreachable
context.--context instead of use-context--context (this pattern) | kubectl config use-context | |
|---|---|---|
| Scope | Per command | Mutates global kubeconfig |
| Side effects | None | Changes your interactive shell's context too |
| Safe alongside Teleport prod work | Yes | No — yanks you off whatever you were on |
| Reverting | Nothing to revert | You must remember to switch back |
?= makes the default overridable without editing the file:
make deploy # uses rancher-desktop
make deploy KUBE_CONTEXT=kind-dev # one-off override
For a different default per machine, set it in the environment:
export KUBE_CONTEXT=my-local-cluster
Copy the snippet into each project's Makefile and change the KUBE_CONTEXT
default. To avoid duplication, keep it in a shared make/context-guard.mk and
include it:
# make/context-guard.mk
KUBE_CONTEXT ?= rancher-desktop
KUBECTL = kubectl --context $(KUBE_CONTEXT)
guard:
@kubectl config get-contexts $(KUBE_CONTEXT) >/dev/null 2>&1 || \
{ echo "❌ context '$(KUBE_CONTEXT)' not found"; exit 1; }
@$(KUBECTL) cluster-info >/dev/null 2>&1 || \
{ echo "❌ cannot reach '$(KUBE_CONTEXT)'"; exit 1; }
# project Makefile
include make/context-guard.mk
deploy: guard
$(KUBECTL) apply -f manifests/
Block known-prod patterns. Refuse to run if the context name looks like production, as a belt-and-suspenders check on top of pinning:
guard:
@echo "$(KUBE_CONTEXT)" | grep -qiE 'prd|prod|teleport' && \
{ echo "❌ refusing: '$(KUBE_CONTEXT)' looks like production"; exit 1; } || true
@$(KUBECTL) cluster-info >/dev/null 2>&1 || { echo "❌ cannot reach cluster"; exit 1; }
Same idea for Helm/Kustomize: helm --kube-context $(KUBE_CONTEXT) ...,
kubectl --context $(KUBE_CONTEXT) kustomize ....
Scripts, not Make: export KUBECONFIG to a project-local file, or pass
--context on every call — the principle is identical.