K9s:安装、资源浏览、日志排查与插件
K9s 把 Kubernetes 资源列表、对象详情、事件和容器日志放进同一个终端界面。输入资源名称切换视图,选择对象后查看关联信息,适合连续观察一次部署或排查一个异常 Pod。它运行在操作者电脑上,通过 kubeconfig 连接 API Server。
终端界面怎样读取集群
一个 K9s 会话的目标由下面几层组成:
kubeconfig
└── context:集群地址 + 登录身份 + 默认 namespace
└── namespace:当前资源范围
└── resource:Pod、Deployment、Service、Event……
└── object:某个具体对象
├── 描述 / YAML:配置与状态
├── 日志:指定容器的标准输出
└── 操作:编辑、删除、exec 或插件命令资源列表通过 API 查询与 watch 更新;日志需要访问 pods/log 子资源,容器终端需要访问 pods/exec。读取 Pod 的权限可以与读取日志、进入容器或删除 Pod 分开授予。界面能显示一个快捷键,服务端仍可能拒绝对应请求。
K9s 擅长缩短反复输入 kubectl 命令的过程。批量处理、自动化检查适合保留为 kubectl 命令或脚本;长期变更则应修改原始清单、Chart 或 GitOps 仓库,防止下次发布覆盖手工修改。Pod 重建后,容器内临时改动也会丢失。
CPU、内存列还依赖集群提供的资源指标。没有 Metrics API 时,应先查看指标接口是否可用;空白或缺失值不能当作资源使用量为零。
安装并完成第一次查看
Linux 二进制与独立配置目录
操作环境为 Linux amd64、Bash、curl、tar、sha256sum 和可用的 kubectl。安装使用当前普通用户,不写入系统目录。实验集群可按 kind 主文建立,以下固定选择其 kind-tooling-dev context;不要替换为生产集群。
下面安装 K9s v0.50.18,下载名和 SHA-256 来自该版本官方发行资产。其他架构必须选择相应文件及摘要。macOS、Windows 的包管理器入口见官方安装说明。
set -euo pipefail
umask 077
lab_dir=$(mktemp -d /tmp/k9s-lab.XXXXXX)
cd "$lab_dir"
mkdir -p bin config/k9s data cache state
curl -q --fail --show-error --location --max-time 120 \
https://github.com/derailed/k9s/releases/download/v0.50.18/k9s_Linux_amd64.tar.gz \
-o k9s_Linux_amd64.tar.gz
printf '%s k9s_Linux_amd64.tar.gz\n' \
'0b697ed4aa80997f7de4deeed6f1fba73df191b28bf691b1f28d2f45fa2a9e9b' \
| sha256sum -c -
tar -xzf k9s_Linux_amd64.tar.gz k9s
install -m 0755 k9s bin/k9s
k9s_lab() {
K9S_CONFIG_DIR="$lab_dir/config/k9s" \
XDG_CONFIG_HOME="$lab_dir/config" \
XDG_DATA_HOME="$lab_dir/data" \
XDG_CACHE_HOME="$lab_dir/cache" \
XDG_STATE_HOME="$lab_dir/state" \
"$lab_dir/bin/k9s" "$@"
}
k9s_lab version
k9s_lab info摘要校验应显示 OK,版本输出应为 v0.50.18。下载或校验失败时停止,不解压来源未确认的文件。k9s info 列出实际配置和日志路径;这些路径应落在本次实验目录。版本与目录都确认后再连接集群。
以下各段在同一个 Bash 会话执行,保留 lab_dir 和函数。K9s 的配置目录规则支持 K9S_CONFIG_DIR 与 XDG 目录;独立设置可避免覆盖个人主题、快捷键和历史视图。
建立一个有持续日志的 Pod
以测试集群管理员身份创建专用 namespace。已有同名 namespace 时,create 会报错并停止;先确认它的归属,不直接复用或删除。
CTX=kind-tooling-dev
NS=k9s-lab
k() { kubectl --context "$CTX" "$@"; }
k cluster-info
k create namespace "$NS"
k -n "$NS" create deployment log-demo --image=busybox:1.37.0 \
-- sh -c 'while true; do echo k9s-log-ok; sleep 5; done'
k -n "$NS" rollout status deployment/log-demo --timeout=180s
k -n "$NS" logs deployment/log-demo --tail=3
k9s_lab --context "$CTX" --namespace "$NS" --readonly -c pod集群节点需要能拉取 BusyBox 镜像;离线 kind 环境按 kind 主文先导入镜像。rollout 应完成,日志出现 k9s-log-ok。最后一条命令进入全屏界面;此时 Shell 要等 K9s 退出才继续执行后面的命令。
先检查标题区 context 与 namespace,再找到 log-demo Pod。正常状态应为 Running、READY 1/1。这里的 --readonly 限制 K9s 界面操作,当前 kubeconfig 仍是管理员身份;后面会建立真正受 RBAC 限制的观察账号。
资源、过滤与日志按键
命令前的冒号表示进入 K9s 命令模式,输入后按 Enter。按键以官方命令页为基础;每个视图中的 ? 可查看当前版本、当前资源实际支持的动作。
| 输入或按键 | 操作 | 可以观察什么 |
|---|---|---|
| :pods、:deploy、:events | 切换资源视图 | Pod 状态、Deployment 副本数、事件原因 |
| /log-demo | 按名称过滤当前列表 | 缩小到实验对象 |
| :pods app=log-demo | 使用标签选择器 | 只查询目标应用 Pod |
| ↑ / ↓,Enter | 选择对象、进入下一层 | 多容器 Pod 可继续选择容器 |
| d | 描述选中对象 | conditions、挂载和事件等信息 |
| v | 查看 YAML | spec 与 status 的实际字段 |
| l | 打开日志 | 持续出现 k9s-log-ok |
| Esc | 返回上一层或退出输入 | 回到资源列表 |
| :ns、:ctx | 查看 namespace 或 context | 切换目标前核对名称 |
| :q | 退出 K9s | 回到原来的 Shell |
普通文本过滤只缩小界面中的结果;按 namespace 和标签查询能进一步缩小目标集合。大型集群优先从一个 namespace 开始,不必一开始就拉取全局资源。
多容器 Pod 需要先确认容器名。日志为空时还应区分进程尚未启动、应用没有写标准输出、选错容器,以及没有 pods/log 权限。对于重启的容器,在日志视图按 ? 找到 previous logs 操作;对应的命令行核对方式为:
k -n "$NS" logs deployment/log-demo -c busybox --tail=20实验容器持续运行,没有 previous 实例,不能要求它返回上一轮日志。真实 CrashLoopBackOff 可对具体 Pod 使用 kubectl logs POD -c CONTAINER --previous,再与终止原因和退出码一起判断。
从资源观察到配置与插件
用错误镜像观察 Deployment 的两组 Pod
先以 :q 退出 K9s,在原 Bash 会话修改实验 Deployment。这里故意使用不存在的镜像标签;保留旧副本才能观察滚动更新为何停住。
k -n "$NS" set image deployment/log-demo \
busybox=busybox:k9s-lab-image-does-not-exist
if k -n "$NS" rollout status deployment/log-demo --timeout=30s; then
printf '异常:错误镜像发布竟然完成,请核对镜像与对象\n' >&2
exit 1
fi
k -n "$NS" get pods -l app=log-demo
k9s_lab --context "$CTX" --namespace "$NS" --readonly -c pod新 Pod 通常先显示 ErrImagePull,随后进入 ImagePullBackOff;旧 Pod 仍可保持 Running。rollout 超时本身还不足以确定是镜像问题:在新 Pod 上按 d,确认 Event 中的镜像名称与拉取失败原因。此时进程没有启动,日志视图无法提供应用日志,反复进入 shell 也无助于定位。
Deployment 的 Pod 模板已经改变,所以控制器创建新的 ReplicaSet;新副本未就绪时,默认滚动更新策略可以保留旧副本。应同时看新旧 Pod,而不是只凭仍有一个 Running 判断发布成功。
退出 K9s,恢复镜像并重新观察:
k -n "$NS" set image deployment/log-demo busybox=busybox:1.37.0
k -n "$NS" rollout status deployment/log-demo --timeout=180s
k -n "$NS" get pods -l app=log-demo
k -n "$NS" logs deployment/log-demo --tail=3恢复后 rollout 完成,新启动的容器继续输出 k9s-log-ok。对于 GitOps 管理的工作负载,应在原仓库修复镜像字段,否则控制器可能重新写回错误版本。
调整刷新、字符与日志窗口
退出会话后,在实验目录创建 config/k9s/config.yaml(配置文件):
k9s:
refreshRate: 3
readOnly: true
portForwardAddress: localhost
ui:
noIcons: true
logger:
tail: 100
buffer: 1000
textWrap: truerefreshRate 控制界面刷新间隔;tail 控制进入日志视图时请求的尾部行数,buffer 限制本地日志缓冲行数,textWrap 影响长行显示。无图标模式适合没有配套字体的终端。portForwardAddress 将 K9s 创建的端口转发约束在本机地址;转发功能仍需要相应权限,当前只读实验不要求开启。
重新运行 k9s_lab info 核对文件位置,再启动会话。配置项和层级见官方配置说明。配置未生效时先查 K9s 日志中的解析错误,不要删除整个用户目录来碰运气。
用短期身份限制资源访问
下面的配置只用于已有 k9s-lab namespace。管理员创建观察账号,允许读取工作负载、事件和 Pod 日志,不授予 Secret、exec 或任何资源写权限。
保存为 observer.yaml(完整授权配置):
apiVersion: v1
kind: ServiceAccount
metadata:
name: observer
namespace: k9s-lab
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: observer
namespace: k9s-lab
rules:
- apiGroups: [""]
resources: [pods, pods/log, services, endpoints, events]
verbs: [get, list, watch]
- apiGroups: [apps]
resources: [deployments, replicasets, statefulsets, daemonsets]
verbs: [get, list, watch]
- apiGroups: [discovery.k8s.io]
resources: [endpointslices]
verbs: [get, list, watch]
- apiGroups: [events.k8s.io]
resources: [events]
verbs: [get, list, watch]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: observer
namespace: k9s-lab
subjects:
- kind: ServiceAccount
name: observer
namespace: k9s-lab
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: observer需要 jq 生成独立 kubeconfig。下面只保留集群连接信息,替换身份为短期 Token,不修改原始 kubeconfig,也不把凭证打印到终端。
k -n "$NS" apply -f observer.yaml
k -n "$NS" create token observer --duration=1h > observer.token
k config view --minify --flatten --raw -o json \
| jq --rawfile token observer.token --arg ns "$NS" '{
apiVersion: "v1", kind: "Config", clusters: .clusters,
users: [{name: "observer", user: {
token: ($token | rtrimstr("\n"))
}}],
contexts: [{name: "k9s-observer", context: {
cluster: .clusters[0].name, user: "observer", namespace: $ns
}}],
"current-context": "k9s-observer"
}' > observer.kubeconfig
chmod 600 observer.kubeconfig
rm -- observer.token
reader() {
kubectl --kubeconfig "$lab_dir/observer.kubeconfig" \
--context k9s-observer -n "$NS" "$@"
}
reader auth can-i get pods
if reader auth can-i delete pods; then
printf '异常:观察账号获得了删除权限\n' >&2
exit 1
fi
reader get pods
reader logs deployment/log-demo --tail=3
k9s_lab --kubeconfig "$lab_dir/observer.kubeconfig" \
--context k9s-observer --namespace "$NS" --readonly -c pod权限检查应分别返回 yes 和 no,随后资源列表与日志读取成功。认证超时、证书错误或连接失败都不是“删除被正确拒绝”,应先修复连接再判断权限。
该账号没有全局 namespace、Node 或 Metrics API 权限;部分视图报 Forbidden 符合授权范围,不必为消除提示增加 cluster-admin。令牌有效期由服务端最终决定,过期后需重新申请。ServiceAccount 适合这个隔离实验;团队成员日常登录宜使用可追踪到个人的身份系统。令牌签发和失效条件见 Kubernetes ServiceAccount 管理。
给选中的 Pod 添加标签查看插件
K9s 插件在本机执行命令,可以把当前对象名称、namespace 和 context 作为参数。退出 K9s 后,保存以下内容为 config/k9s/plugins.yaml(插件文件);Shift-B 作为实验快捷键,启动后用 ? 确认显示 Show pod labels 且没有与个人配置冲突。
plugins:
pod-labels:
shortCut: Shift-B
description: Show pod labels
scopes: [po]
dangerous: false
background: false
command: kubectl
args:
- --kubeconfig
- $KUBECONFIG
- --context
- $CONTEXT
- --namespace
- $NAMESPACE
- get
- pod
- $NAME
- --show-labels重新使用上面的 observer.kubeconfig 启动命令,在 Pod 视图选中 log-demo,触发插件后应看到该 Pod 的标签,包含 app=log-demo。配置按独立参数传给 kubectl,没有借助 sh -c 拼接对象名称。变量定义见官方插件文档;固定版本支持的字段见 v0.50.18 插件配置。
dangerous: false 只是对插件的声明,K9s 不会据此分析任意脚本是否真的无害。即使观察账号只能读取集群资源,插件仍具有本地用户的文件与网络权限。只安装能够解释每个参数和所需权限的插件;不可信的插件不能通过“先放到只读会话”变得安全。
故障定位、升级与清理
按最先失败的操作定位
| 现象 | 对照检查 | 后续处理 |
|---|---|---|
| K9s 启动即报配置错误 | k9s_lab info 给出的日志与配置文件 | 修正报错字段;用独立目录启动默认配置作对照 |
| 资源列表为空 | 当前 context、namespace、标签过滤;reader get pods | 清除过滤或选择正确范围 |
| 401 或凭证插件失败 | 用同一 kubeconfig 执行 kubectl get pods | 更新短期 Token,或修复对应登录插件 |
| 列表可看、日志 Forbidden | reader auth can-i get pods --subresource=log | 核对 pods/log 的 get 权限及 RoleBinding |
| 新 Pod 无日志且拉取失败 | 对该 Pod 按 d 查看镜像与 Event | 修正镜像、仓库凭据或节点访问路径 |
| 字符错乱、列宽异常 | 终端字体、TERM、窗口宽度与 noIcons | 先关闭图标,再验证终端编码与字体 |
| 大集群界面卡顿 | 缩到单 namespace;查看客户端日志的限流/请求错误 | 缩小查询和日志范围,再排查 API Server 负载 |
检查日志权限可直接执行:
reader auth can-i get pods --subresource=log若日志权限存在而日志仍失败,用同一身份访问具体 Pod 和容器,比较错误是 NotFound、BadRequest 还是 Forbidden。Pod 已替换、容器从未启动和授权拒绝分别需要不同处理。
实时日志窗口只覆盖当前可读取的日志,不承担持久化检索。故障跨越 Pod 删除或节点故障时,需要集中日志系统;保存诊断片段时先去除令牌、请求体和个人数据。
升级保持二进制与配置可分开回退
升级前保存 k9s version、k9s info 和自定义配置。新版本放入另一个目录,校验对应发行摘要;使用复制到临时位置的配置启动,不在生产会话中试探配置迁移。
用同一个实验 namespace 检查资源显示、标签过滤、日志、只读身份和插件。出现配置不兼容时,关闭新进程,改回旧二进制与旧配置目录。K9s 的本地回退不会还原已经提交到集群的资源变更;资源修改需要从原清单或 Release 历史恢复。
退出并只删除实验对象
以 :q 关闭 K9s,然后在原管理员 Bash 会话清理本次 namespace。这里会删除 log-demo、observer 及其授权;不要对共享业务 namespace 执行。
test "$CTX" = kind-tooling-dev
test "$NS" = k9s-lab
k delete namespace "$NS" --wait=true --timeout=120s
case "$lab_dir" in
/tmp/k9s-lab.*)
test -d "$lab_dir"
cd /
rm -r -- "$lab_dir"
;;
*)
printf '拒绝删除不符合实验路径的目录\n' >&2
exit 1
;;
esac
unset -f k9s_lab reader k
unset lab_dir CTX NS删除 namespace 后,实验账号和服务端授权一并移除;本地 Token 文件随临时目录清除。仅卸载 K9s 不会撤销其他 kubeconfig 中仍然有效的登录凭证。
