Last active
January 29, 2026 14:55
-
-
Save noizo/997adc0a18cb7280f6eeb325c0034e4f to your computer and use it in GitHub Desktop.
gk8 is a script to connect to gcloud and select a gke cluster context with a namespace
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Add to .zshrc | |
| # Run `source ~/.zshrc` | |
| # Run gk8 | |
| # Select project | |
| # Select cluster | |
| # Select namespace | |
| # Enjoy | |
| gk8() { | |
| emulate -L zsh | |
| setopt local_options pipefail | |
| # Requirements: | |
| # - gcloud (Google Cloud SDK) | |
| # - gke-gcloud-auth-plugin | |
| # - kubectl | |
| # - fzf | |
| # | |
| # Auth model: | |
| # - kubeconfig uses an exec plugin (`gke-gcloud-auth-plugin`) instead of static tokens. | |
| # - kubectl calls the plugin to mint short-lived access tokens. | |
| # - tokens auto-refresh as long as `gcloud auth list` shows an ACTIVE account. | |
| # - you only need `gcloud container clusters get-credentials` when the context is missing | |
| # (or if cluster endpoint/CA changes). Use `gk8 -r` to force a refresh. | |
| local -a req_cmds | |
| req_cmds=(fzf gcloud kubectl gke-gcloud-auth-plugin) | |
| local c | |
| for c in "${req_cmds[@]}"; do | |
| command -v "$c" >/dev/null 2>&1 || { | |
| echo "Missing required command: $c" >&2 | |
| echo "Install requirements (macOS/Homebrew example):" >&2 | |
| echo " brew install fzf kubectl google-cloud-sdk" >&2 | |
| echo " gcloud components install gke-gcloud-auth-plugin" >&2 | |
| return 1 | |
| } | |
| done | |
| export USE_GKE_GCLOUD_AUTH_PLUGIN=True | |
| local force_refresh=false | |
| local skip_namespace=false | |
| local kubeconfig="${KUBECONFIG:-$HOME/.kube/config}" | |
| while getopts ":rn" opt; do | |
| case ${opt} in | |
| r) force_refresh=true ;; | |
| n) skip_namespace=true ;; | |
| \?) echo "Usage: gk8 [-r] [-n]"; return 1 ;; | |
| esac | |
| done | |
| shift $((OPTIND - 1)) | |
| # --- Ensure gcloud is authenticated --- | |
| local acct | |
| acct="$(gcloud auth list --filter="status:ACTIVE" --format="value(account)" 2>/dev/null | head -n1)" | |
| [[ -z "$acct" ]] && { gcloud auth login || { echo "gcloud auth login failed" >&2; return 1; }; } | |
| # --- Pick project --- | |
| local proj_list project | |
| if [[ -n "${GKE_ALLOWED_PROJECTS:-}" ]]; then | |
| proj_list="$(printf "%s\n" ${=GKE_ALLOWED_PROJECTS})" | |
| else | |
| proj_list="$(gcloud projects list --format="value(projectId)" 2>/dev/null)" | |
| fi | |
| [[ -z "$proj_list" ]] && { echo "No GCP projects visible" >&2; return 1; } | |
| project="$(printf "%s\n" "$proj_list" | fzf --select-1 --exit-0 --no-multi --height=60% --border --prompt="GCP project> " || true)" | |
| [[ -z "$project" ]] && { echo "No project selected"; return 1; } | |
| # Clean project string of whitespace and carriage returns | |
| setopt extended_glob | |
| project="${project//$'\r'/}" | |
| project="${project##[[:space:]]#}" | |
| project="${project%%[[:space:]]#}" | |
| # --- Pick cluster in that project --- | |
| local cmd_out cmd_rc rows sel cluster location loc_flag | |
| cmd_out="$(gcloud container clusters list --project "$project" --format="value(name,location)" 2>&1)" | |
| cmd_rc=$? | |
| if [[ $cmd_rc -ne 0 ]]; then | |
| echo "gcloud container clusters list failed for project [$project] (rc=$cmd_rc):" >&2 | |
| printf "%s\n" "$cmd_out" >&2 | |
| return 1 | |
| fi | |
| rows="$cmd_out" | |
| [[ -z "$rows" ]] && { echo "No GKE clusters visible in project [$project]" >&2; return 1; } | |
| sel="$(printf "%s\n" "$rows" | fzf --select-1 --exit-0 --no-multi --height=60% --border --prompt="GKE cluster> " || true)" | |
| [[ -z "$sel" ]] && { echo "No cluster selected"; return 1; } | |
| cluster="${sel%%$'\t'*}" | |
| location="${sel#*$'\t'}" | |
| [[ "$location" == "$sel" ]] && { echo "Parse failed (expected tab-delimited name/location): [$sel]" >&2; return 1; } | |
| [[ -z "$cluster" || -z "$location" ]] && { echo "Parse failed: [$sel]" >&2; return 1; } | |
| if [[ "$location" == *-*-* ]]; then | |
| loc_flag="--zone=$location" | |
| else | |
| loc_flag="--region=$location" | |
| fi | |
| local ctx="gke_${project}_${location}_${cluster}" | |
| # --- Decide whether to run get-credentials --- | |
| local need_creds=false | |
| if ! kubectl config get-contexts -o name 2>/dev/null | grep -qx "$ctx"; then | |
| need_creds=true | |
| else | |
| local cfg | |
| cfg="$(kubectl config view --raw --minify --context "$ctx" -o json 2>/dev/null || true)" | |
| if [[ -z "$cfg" ]]; then | |
| need_creds=true | |
| else | |
| printf "%s" "$cfg" | grep -q '"auth-provider"' && need_creds=true | |
| printf "%s" "$cfg" | grep -q 'gke-gcloud-auth-plugin' || need_creds=true | |
| fi | |
| fi | |
| [[ "$force_refresh" == true ]] && need_creds=true | |
| if [[ "$need_creds" == true ]]; then | |
| KUBECONFIG="$kubeconfig" gcloud container clusters get-credentials \ | |
| "$cluster" --project "$project" $loc_flag >/dev/null \ | |
| || { echo "get-credentials failed" >&2; return 1; } | |
| fi | |
| kubectl config use-context "$ctx" >/dev/null 2>&1 || true | |
| echo "Context: $ctx KUBECONFIG: $kubeconfig" | |
| # --- Namespace picker --- | |
| if [[ "$skip_namespace" == false ]]; then | |
| local ns | |
| ns="$( | |
| kubectl get ns -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}' 2>/dev/null \ | |
| | fzf --select-1 --exit-0 --no-multi --height=60% --border --prompt="NS> " \ | |
| || true | |
| )" | |
| [[ -z "$ns" ]] && { echo "No namespace selected"; return 0; } | |
| kubectl config set-context --current --namespace="$ns" >/dev/null || return 1 | |
| echo "Namespace: $ns" | |
| else | |
| echo "Skipping namespace selection." | |
| fi | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment