Post

Install kubectl and kubecolor on Debian/Ubuntu via APT

Install kubectl and kubecolor on Debian/Ubuntu via APT

Managing Kubernetes clusters using kubectl is the day-to-day norm for DevOps engineers and system administrators. However, plain text output from kubectl can quickly become hard to read when parsing long lists of resources or troubleshooting issues.

In this guide, we will install kubectl and kubecolor (a wrapper that colorizes output for improved readability) on Debian/Ubuntu systems using native package management (apt / dpkg). We will also set up kctl as a convenient alias/symlink to kubecolor and configure tab auto-completion for all of them.


Why Kubecolor?

kubecolor is a drop-in replacement wrapper for kubectl that intercepts command output and adds colors in real-time.

  • Readability: Clearly highlights statuses like Running (green), Terminating (yellow), and CrashLoopBackOff (red).
  • Auto TTY Detection: Automatically disables color styling when output is piped to files, logs, or other scripts.
  • Paging Support: Seamlessly integrates with tools like less for scrollable outputs.

By symlinking kctl to kubecolor, you get a fast, colorized terminal command that keeps all standard kubectl arguments and autocompletions intact.


Option 1: Automated Idempotent Installer Script

Below is the complete shell script to automate the setup process. It validates your architecture (AMD64 or ARM64), downloads the GPG keys, registers the official Kubernetes APT repository, fetches the latest kubecolor release DEB package, verifies its SHA256 checksum, installs both packages natively via apt, and creates the kctl symlink.

Create a script file (e.g. install-kubectl-kctl.sh), paste the following content, and make it executable:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
#!/usr/bin/env bash
# install-kubectl-kctl.sh
# Idempotent installer/updater for kubectl, kubecolor, and kctl (symlink) on Debian/Ubuntu.

set -euo pipefail

TARGET_DIR="/usr/local/bin"
KUBECTL_BIN="/usr/bin/kubectl"
KUBECOLOR_BIN="/usr/bin/kubecolor"
KCTL_LINK="${TARGET_DIR}/kctl"
FORCE=false
DRY_RUN=false
KUBECTL_VERSION=""
KUBECOLOR_VERSION=""
SETUP_COMPLETION=false
TMP_DIR=""

log_info() { echo -e "\e[32m[INFO]\e[0m $*"; }
log_warn() { echo -e "\e[33m[WARN]\e[0m $*"; }
log_err()  { echo -e "\e[31m[ERROR]\e[0m $*" >&2; }

cleanup() {
  if [[ -n "${TMP_DIR:-}" && -d "$TMP_DIR" ]]; then
    rm -rf "$TMP_DIR"
  fi
}
trap cleanup EXIT

show_help() {
  cat << EOF
Usage: $(basename "$0") [options]

Install or update 'kubectl', 'kubecolor', and 'kctl' (symlink to kubecolor) on Debian/Ubuntu via APT.

Options:
  -v, --version VERSION       Install a specific kubectl version (e.g., v1.30.0) instead of latest stable.
  -k, --kubecolor-version VER Install a specific kubecolor version (e.g., v0.6.0) instead of latest stable.
  -f, --force                 Force installation/download even if already up-to-date.
  -c, --completion            Configure shell autocompletion for kubectl, kubecolor, and kctl in ~/.bashrc and ~/.zshrc.
  -d, --dry-run               Run preflight checks and version comparison, but do not download or install.
  -h, --help                  Show this help message.
EOF
}

while [[ $# -gt 0 ]]; do
  case "$1" in
    -v|--version) KUBECTL_VERSION="$2"; shift 2 ;;
    -k|--kubecolor-version) KUBECOLOR_VERSION="$2"; shift 2 ;;
    -f|--force) FORCE=true; shift ;;
    -c|--completion) SETUP_COMPLETION=true; shift ;;
    -d|--dry-run) DRY_RUN=true; shift ;;
    -h|--help) show_help; exit 0 ;;
    *) log_err "Unknown option: $1"; show_help; exit 1 ;;
  esac
done

preflight_checks() {
  log_info "Running preflight checks..."
  if [[ ! -f /etc/os-release ]] || ! grep -qEi 'debian|ubuntu' /etc/os-release; then
    log_err "This script targets Debian/Ubuntu distributions."
    exit 1
  fi

  for cmd in curl gpg grep cut sha256sum dpkg apt-get; do
    if ! command -v "$cmd" >/dev/null 2>&1; then
      log_err "Required command '$cmd' is not installed. Please install it first."
      exit 1
    fi
  done

  if [[ "$DRY_RUN" = "false" ]] && [[ $EUID -ne 0 ]]; then
    if ! command -v sudo >/dev/null 2>&1 || ! sudo -n true 2>/dev/null; then
      log_info "Sudo privileges required. You may be prompted for your password."
    fi
  fi
}

detect_arch() {
  local machine
  machine=$(uname -m)
  case "$machine" in
    x86_64)  ARCH="amd64" ;;
    aarch64|arm64) ARCH="arm64" ;;
    *) log_err "Unsupported architecture: $machine."; exit 1 ;;
  esac
  log_info "Detected architecture: $ARCH ($machine)"
}

resolve_versions() {
  log_info "Fetching latest stable kubectl version..."
  local latest_kubectl
  latest_kubectl=$(curl -sSL https://dl.k8s.io/release/stable.txt)
  TARGET_KUBECTL_VERSION="${KUBECTL_VERSION:-$latest_kubectl}"
  [[ ! "$TARGET_KUBECTL_VERSION" =~ ^v ]] && TARGET_KUBECTL_VERSION="v${TARGET_KUBECTL_VERSION}"
  log_info "Target kubectl version: $TARGET_KUBECTL_VERSION"

  if command -v kubectl >/dev/null 2>&1; then
    INSTALLED_KUBECTL_VERSION=$(kubectl version --client 2>/dev/null | grep -oE 'v[0-9]+\.[0-9]+\.[0-9]+' | head -n1 || true)
    log_info "Currently installed kubectl version: ${INSTALLED_KUBECTL_VERSION:-none}"
  else
    INSTALLED_KUBECTL_VERSION="none"
  fi

  log_info "Fetching latest stable kubecolor version..."
  local redirect_url
  redirect_url=$(curl -sSfL -o /dev/null -w "%{url_effective}" https://github.com/kubecolor/kubecolor/releases/latest || true)
  local latest_kubecolor="v0.6.0"
  [[ -n "$redirect_url" ]] && latest_kubecolor="${redirect_url##*/}"
  TARGET_KUBECOLOR_VERSION="${KUBECOLOR_VERSION:-$latest_kubecolor}"
  [[ ! "$TARGET_KUBECOLOR_VERSION" =~ ^v ]] && TARGET_KUBECOLOR_VERSION="v${TARGET_KUBECOLOR_VERSION}"
  log_info "Target kubecolor version: $TARGET_KUBECOLOR_VERSION"

  if command -v kubecolor >/dev/null 2>&1; then
    INSTALLED_KUBECOLOR_VERSION=$(kubecolor --kubecolor-version 2>/dev/null | grep -oE 'v[0-9]+\.[0-9]+\.[0-9]+' | head -n1 || true)
    log_info "Currently installed kubecolor version: ${INSTALLED_KUBECOLOR_VERSION:-none}"
  else
    INSTALLED_KUBECOLOR_VERSION="none"
  fi
}

install_kubectl() {
  if [[ "$INSTALLED_KUBECTL_VERSION" == "$TARGET_KUBECTL_VERSION" ]] && [[ "$FORCE" = "false" ]]; then
    log_info "kubectl is already at the target version ($TARGET_KUBECTL_VERSION). Skipping."
    return
  fi

  local version_xy
  version_xy=$(echo "$TARGET_KUBECTL_VERSION" | grep -oE '^v[0-9]+\.[0-9]+')

  if [[ "$DRY_RUN" = "true" ]]; then
    log_info "[DRY-RUN] Would setup Kubernetes APT repository for version $version_xy and install"
    return
  fi

  log_info "Setting up Kubernetes APT repository for version $version_xy..."
  if [[ $EUID -eq 0 ]]; then
    mkdir -p -m 755 /etc/apt/keyrings
    curl -fsSL "https://pkgs.k8s.io/core:/stable:/${version_xy}/deb/Release.key" | gpg --dearmor --yes -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
    chmod 644 /etc/apt/keyrings/kubernetes-apt-keyring.gpg
    echo "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/${version_xy}/deb/ /" > /etc/apt/sources.list.d/kubernetes.list
    apt-get update && apt-get install -y kubectl
  else
    sudo mkdir -p -m 755 /etc/apt/keyrings
    curl -fsSL "https://pkgs.k8s.io/core:/stable:/${version_xy}/deb/Release.key" | sudo gpg --dearmor --yes -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
    sudo chmod 644 /etc/apt/keyrings/kubernetes-apt-keyring.gpg
    echo "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/${version_xy}/deb/ /" | sudo tee /etc/apt/sources.list.d/kubernetes.list > /dev/null
    sudo apt-get update && sudo apt-get install -y kubectl
  fi
}

install_kubecolor() {
  if [[ "$INSTALLED_KUBECOLOR_VERSION" == "$TARGET_KUBECOLOR_VERSION" ]] && [[ "$FORCE" = "false" ]]; then
    log_info "kubecolor is already at the target version ($TARGET_KUBECOLOR_VERSION). Skipping."
    return
  fi

  if [[ "$DRY_RUN" = "true" ]]; then
    log_info "[DRY-RUN] Would download and install kubecolor deb package version $TARGET_KUBECOLOR_VERSION"
    return
  fi

  local kubecolor_no_v="${TARGET_KUBECOLOR_VERSION#v}"
  local deb_name="kubecolor_${kubecolor_no_v}_linux_${ARCH}.deb"

  log_info "Downloading kubecolor DEB package..."
  curl -L -sS -o "${TMP_DIR}/${deb_name}" "https://github.com/kubecolor/kubecolor/releases/download/${TARGET_KUBECOLOR_VERSION}/${deb_name}"
  curl -L -sS -o "${TMP_DIR}/checksums.txt" "https://github.com/kubecolor/kubecolor/releases/download/${TARGET_KUBECOLOR_VERSION}/checksums.txt"

  log_info "Verifying SHA256 checksum for kubecolor..."
  grep "$deb_name" "${TMP_DIR}/checksums.txt" > "${TMP_DIR}/kubecolor.sha256"
  if ! (cd "$TMP_DIR" && sha256sum --check --status kubecolor.sha256); then
    log_err "Checksum verification failed!"; exit 1
  fi

  log_info "Installing kubecolor DEB via APT..."
  if [[ $EUID -eq 0 ]]; then
    apt-get install -y "${TMP_DIR}/${deb_name}"
  else
    sudo apt-get install -y "${TMP_DIR}/${deb_name}"
  fi
}

create_symlink() {
  if [[ "$DRY_RUN" = "true" ]]; then
    log_info "[DRY-RUN] Would create symlink $KCTL_LINK -> $KUBECOLOR_BIN"
    return
  fi

  log_info "Ensuring 'kctl' symlink points to 'kubecolor'..."
  local link_dir=$(dirname "$KCTL_LINK")
  [[ ! -d "$link_dir" ]] && ( [[ $EUID -eq 0 ]] && mkdir -p "$link_dir" || sudo mkdir -p "$link_dir" )

  if [[ $EUID -eq 0 ]]; then
    ln -sf "$KUBECOLOR_BIN" "$KCTL_LINK"
  else
    sudo ln -sf "$KUBECOLOR_BIN" "$KCTL_LINK"
  fi
}

configure_completion() {
  if [[ "$SETUP_COMPLETION" = "false" ]]; then return; fi
  if [[ "$DRY_RUN" = "true" ]]; then return; fi

  local line="source <(kubectl completion \${SHELL##*/})"
  
  # Setup Bash completion
  if [[ -f "$HOME/.bashrc" ]] && ! grep -q "kubectl completion bash" "$HOME/.bashrc"; then
    cat << 'EOF' >> "$HOME/.bashrc"
if command -v kubectl >/dev/null 2>&1; then
  source <(kubectl completion bash)
  complete -o default -F __start_kubectl kubecolor 2>/dev/null || true
  complete -o default -F __start_kubectl kctl 2>/dev/null || true
fi
EOF
  fi

  # Setup Zsh completion
  if [[ -f "$HOME/.zshrc" ]] && ! grep -q "kubectl completion zsh" "$HOME/.zshrc"; then
    cat << 'EOF' >> "$HOME/.zshrc"
if command -v kubectl >/dev/null 2>&1; then
  source <(kubectl completion zsh)
  compdef __start_kubectl kubecolor 2>/dev/null || true
  compdef __start_kubectl kctl 2>/dev/null || true
fi
EOF
  fi
}

main() {
  preflight_checks
  detect_arch
  resolve_versions
  if [[ "$DRY_RUN" = "false" ]]; then TMP_DIR=$(mktemp -d); fi
  install_kubectl
  install_kubecolor
  create_symlink
  configure_completion
  log_info "Finished successfully."
}

main "$@"

To execute the script and configure tab completion automatically for your active shells, run:

1
bash install-kubectl-kctl.sh --completion

Option 2: Step-by-Step Manual Installation

If you prefer to perform the configuration steps manually, follow the process outlined below.

Step 1: Install kubectl via Official APT Repository

First, download the official signing key and register the repository for the Kubernetes package pool.

1
2
3
4
5
6
7
8
9
10
11
12
13
# Create the keyrings folder if it does not exist
sudo mkdir -p -m 755 /etc/apt/keyrings

# Download the key (e.g. for Kubernetes version 1.36)
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.36/deb/Release.key | sudo gpg --dearmor --yes -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
sudo chmod 644 /etc/apt/keyrings/kubernetes-apt-keyring.gpg

# Register the APT source repository
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.36/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list

# Update package lists and install kubectl
sudo apt-get update
sudo apt-get install -y kubectl

Step 2: Download and Install kubecolor DEB Package

Download the appropriate .deb package for your CPU architecture from the official GitHub Release page.

1
2
3
4
5
6
7
8
9
10
11
12
13
# Fetch latest version (e.g., v0.6.0)
VERSION="v0.6.0"
VERSION_NO_V="0.6.0"
ARCH=$(dpkg --print-architecture) # amd64 or arm64

# Download the DEB package
wget https://github.com/kubecolor/kubecolor/releases/download/${VERSION}/kubecolor_${VERSION_NO_V}_linux_${ARCH}.deb

# Install the package via apt (which manages standard system registration)
sudo apt-get install -y ./kubecolor_${VERSION_NO_V}_linux_${ARCH}.deb

# Clean up
rm kubecolor_${VERSION_NO_V}_linux_${ARCH}.deb

Create a symbolic link in /usr/local/bin pointing to /usr/bin/kubecolor. This provides a global, shorter alias without polluting /usr/bin.

1
sudo ln -sf /usr/bin/kubecolor /usr/local/bin/kctl

Configure Shell Autocompletion

kubecolor operates as a wrapper around the kubectl CLI. Therefore, you must configure the standard kubectl autocompletion and then instruct the shell to reuse that completion function (__start_kubectl) for kubecolor and kctl.

Bash Setup

Append the following lines to your ~/.bashrc file:

1
2
3
4
5
6
# Kubernetes and Kubecolor completion
if command -v kubectl >/dev/null 2>&1; then
  source <(kubectl completion bash)
  complete -o default -F __start_kubectl kubecolor 2>/dev/null || true
  complete -o default -F __start_kubectl kctl 2>/dev/null || true
fi

Then reload your configuration:

1
source ~/.bashrc

Zsh Setup

Append the following lines to your ~/.zshrc file:

1
2
3
4
5
6
# Kubernetes and Kubecolor completion
if command -v kubectl >/dev/null 2>&1; then
  source <(kubectl completion zsh)
  compdef __start_kubectl kubecolor 2>/dev/null || true
  compdef __start_kubectl kctl 2>/dev/null || true
fi

Then reload your configuration:

1
source ~/.zshrc

Now, try running kctl get p[TAB] and watch the resource name autocomplete while rendering in beautiful, colorized terminal styles!

This post is licensed under CC BY 4.0 by the author.