
1. 动手之前的准备安装方式与kubeconfig配置文件解析每次聊到kubectl我都习惯先提醒一句别急着背命令先搞清楚你手里的这个客户端到底是怎么连上集群的。kubectl本质上是Kubernetes的官方命令行工具它做的事情可以用一句话概括——把你在终端里敲的指令翻译成对API Server的HTTP请求然后由API Server去调度集群里的各种资源。所以你会发现kubectl本身并不直接操作容器它只是一个面向Kubernetes API的客户端。作为运维或平台工程师我和kubectl打交道的频率高过绝大多数工具。从看Pod状态、查日志到发布应用、排查故障几乎每天都在用。这些年用下来最大的体会是kubectl的命令再多真正高频、核心的就那么几十条只要把底层逻辑和常用场景吃透完全可以覆盖日常工作。这篇文章就把我平时最常用的命令和踩过的坑整理出来顺便聊聊很多人关心的配置文件问题。1.1 安装kubectl别小看这一步安装kubectl本身不复杂但你会遇到第一个问题版本。kubectl和集群的版本不建议相差太大官方建议是允许kubectl版本比集群的minor version大一或小一。实际操作中我一般直接装跟集群相同或者更新一点点的版本避免出现API资源列表识别不了的情况。Linux下最常见的安装方式就是下载官方二进制并放到PATH里然后chmod加执行权限。macOS可以用brew install kubectl。如果本地装了Docker Desktop它自己会带一个kubectl但那个版本往往偏老我建议还是单独装一份避免混淆。装完后先验证一下版本观察kubectl version输出的Client Version和Server Version。如果Server Version那一栏显示Unable to connect那说明kubectl本身没问题问题出在连不上集群这就要去看kubeconfig配置文件了。1.2 kubeconfig配置文件kubectl连接集群的钥匙这也是为什么会有人在问“gitlab怎么设置kubectl配置文件”的根本原因——kubeconfig通常默认路径是~/.kube/config就是kubectl用来确定“连接哪个集群、用什么身份、切换哪个命名空间”的唯一依据。一个标准的kubeconfig文件由三块核心内容组成clusters集群信息。里面保存的是API Server的访问地址server字段和证书信息certificate-authority-data字段。users用户凭证。包括客户端证书、私钥或者token等身份凭据。contexts上下文。它把cluster和user组合到一起同时指定默认的namespace。你可以理解为“用哪个身份、连哪个集群、进哪个命名空间”的三元组。打个比方clusters是门牌号users是你手里的钥匙contexts则是“你拿着这把钥匙去开这个门牌号对应的门然后直接走进某个房间”的完整路线。kubectl实际工作时会读config文件里的current-context字段找到当前上下文再根据上下文里指定的cluster和user去建立连接。这里有个实际场景值得多说一句很多人会不小心把集群的admin证书塞进kubeconfig然后到处分发。从安全角度来说这是我不太建议的最小权限原则在任何地方都适用。给开发或CI/CD环境用的kubeconfig最好单独创建只读或限定命名空间的ServiceAccount然后把对应的token分发出去。1.3 多集群与KUBECONFIG环境变量一份配置走天下如果你手上同时有好几个集群比如一个测试环境、一个预发环境还有一个生产环境那靠kubectl config view来回翻context就会效率很低。我常用的配置方式是利用KUBECONFIG环境变量把多个config文件合并起来。做法是这样的export KUBECONFIG/root/.kube/config:/opt/k8s/test.conf:/opt/k8s/prod.conf kubectl config get-contextsget-contexts会把所有config文件里的context都列出来然后你可以用一句话完成切换kubectl config use-context prod切完上下文后再执行kubectl get pods它就会去连接生产集群。用这个方案你再也不用把好多个config文件来回覆盖到~/.kube/config里了。我现在是把所有context名称约定成“环境名-集群名”的格式比如test-cluster、prod-cluster一眼就能认出当前在哪个环境。还有一个小技巧为了避免在某台机器上误操作生产环境我习惯给生产环境的context单独配置一个特殊的KUBECONFIG变量并且只在需要操作生产时才export它。配合kubectl config current-context确认当前位置基本不会出现“明明想操作测试集群结果把生产环境搞挂”的悲剧。2. 日常使用频率最高的kubectl命令命令不用背太多但常用的这几个你得形成肌肉记忆。我把它们分成“查看类”“变更类”“运维类”三组这样记忆起来更有条理。2.1 查看类三件套get、describe、logskubectl get是最基础的查询命令负责以列表形式展示资源状态。平时我用得最多的对象是pod、node、deployment、service、event。kubectl get pods kubectl get pods -n kube-system kubectl get nodes -o wide kubectl get deploy,svc -l appnginx-o wide会多显示一些字段比如Pod所在的节点IP、Pod的IP排查网络问题时几乎必用。至于-n参数没什么好说的——不指定命名空间的话只看default命名空间很多资源你会“找不到”但其实它就在别的namespace里待着。kubectl describe适合看一个资源的详细信息比如事件、标签、状态变化过程。我很少对着get的输出猜问题因为get只显示当前状态不显示历史事件。真正排查Pod为什么起不来我会先describe一下kubectl describe pod nginx-xxxxx重点看Events这一段。常见的情况是镜像拉取失败ImagePullBackOff、健康检查失败Liveness probe failed、资源不足FailedScheduling等原因基本在Events里都写得明明白白。kubectl logs用来查看容器日志你要是看过Pod里多个容器的情况得用-c指定容器名kubectl logs -f pod-name -n namespace kubectl logs pod-name -c container-name --tail50-f是实时跟踪--tail是只显示最后多少行这两个参数组合起来用排查问题的时候效率很高。如果容器之前崩溃过想查上一次进程的日志记住加-p参数kubectl logs pod-name -p这个-p参数很多人容易漏导致查不到崩溃原因。2.2 变更类apply、edit、patch、delete再接着说变更操作。我以前习惯用kubectl create来创建资源但后来发现如果要做“有则更新无则创建”这种幂等操作kubectl apply才是正道。特别是持续集成环境里反复执行同一个YAML用apply完全不会报错。kubectl apply -f deployment.yaml kubectl apply -f ./manifests/线上临时改镜像版本我不太喜欢打开编辑器去edit直接用set命令最快kubectl set image deployment/nginx nginxnginx:1.25 -n default不过如果你还是习惯像vim那样改kubectl edit也行它会把当前资源的定义拉下来变成YAML保存后自动apply。注意一点edit是直接改live object如果资源和当前声明的配置有冲突保存时会因为冲突报错这时候可以用patch去做局部字段的修改。kubectl patch适合精准修改某个字段尤其是改一些嵌套很深、用set很难表达的参数。示例kubectl patch deployment nginx -p {spec:{replicas:3}}这段命令的意思是把nginx这个Deployment的副本数改成3。patch处理JSON格式注意引号转义习惯了也就不觉得麻烦。删除资源的命令看起来简单但坑不少。kubectl delete会先把资源标记为删除状态然后看资源是否有finalizer如果finalizer没处理完资源会一直处于Terminating状态。遇到Terminating的Pod卡住可以用强制删除kubectl delete pod xxx --force --grace-period0但这里要提醒一句强制删除Pod会导致Pod里正在处理的任务被硬生生掐断不到万不得已别乱用。2.3 手动运维exec、port-forward、cp进到容器内部去调试在Docker时代是docker exec在Kubernetes时代就是kubectl execkubectl exec -it pod-name -- /bin/sh kubectl exec -it pod-name -c sidecar-container -- /bin/sh-c指定容器这点在Pod里有多个容器时非常重要。我在Pod里查完问题之后通常先敲exit再退出而不是直接关闭终端否则偶尔会留下异常会话。端口转发是另一个高频命令。比如你本地想访问集群里的某个服务但服务没有对外的NodePort或LoadBalancer可以直接用port-forward把远端端口映射到本地kubectl port-forward svc/nginx-service 8080:80执行完这条访问本地的8080端口就等于访问集群里nginx-service的80端口。调试阶段特别好用但别把它当成生产环境的流量入口——port-forward走的是kubectl建立的隧道稳定性跟网络直接相关扛不住生产流量。文件拷贝我平时用得也很多比如把Pod里的日志拉出来或者把本地配置传进去kubectl cp pod-name:/var/log/app.log ./app.log kubectl cp ./config.yaml pod-name:/etc/app/config.yamlkubectl cp的路径规则跟scp很像但有个细节如果Pod里有多容器同样用-c指定容器否则容易拷错容器这事我踩过一次传文件传到sidecar里找了半天才发现。3. 把kubectl用出效率的进阶技巧命令本身不难真正拉开效率差距的是组合使用和输出处理。下面这几个技巧是我日常使用频率最高、最能节省时间的。3.1 自定义输出列只看你想看的信息kubectl get默认会有一列输出但有时候字段太多有时候字段又不够。没有捷径用-o custom-columns就好kubectl get pods -o custom-columnsNAME:.metadata.name,IP:.status.podIP,NODE:.spec.nodeName这个表达方式简洁地指定了要输出的列。开发环境中我常用这个组合来看所有Pod分布在哪些节点上一轮肉眼扫描就能发现问题。另一个极其强大但很多人没用起来的是JSONPath。配合-o jsonpath可以取出某个字段的值。比如要获取某个Deployment的副本数kubectl get deploy nginx -o jsonpath{.spec.replicas}再配合shell的循环你就可以写一些很小但很实用的自动化脚本。比如批量将所有不符合规则的Deployment副本数统一调整。这种能力在日常巡检时很有价值。如果要沉淀成表格或报告可以用-o wide或-o yaml导出完整定义再用yq或jq去解析比人眼盯着终端输出稳得多。我自己比较常用的习惯是先kubectl get xxx -o yaml xxx.yaml再用编辑器打开做信息提取或备份。3.2 标签选择器与字段选择器从全量中筛出目标集群里Pod一多kubectl get pods不带过滤条件输出几百行基本等于没查。我习惯用标签选择器-l来缩小范围kubectl get pods -l appnginx,envprod kubectl get pods -l tier in (frontend,backend)标签是Kubernetes里推荐的资源关联方式。平时创建Deployment、Service时我会提前约定好环境、应用、版本这组标签规范后续用标签做筛选就非常顺手。除了标签还可以用--field-selector按字段过滤。比如查看某个节点上的所有Podkubectl get pods --field-selector spec.nodeNamenode01或者查所有处于Failed阶段的Podkubectl get pods --field-selector status.phaseFailed标签选择器和字段选择器可以一起用我自己做故障演练时经常这样组合能很快圈定一台节点上的异常Pod范围然后逐一排查。3.3 命名空间批处理与上下文操作想要“一键查询所有命名空间里的某个资源”可以加上--all-namespaces简写是-Akubectl get pods -A kubectl get events -A --sort-by.lastTimestamp-A这个参数太重了要慎用但排查那种“全局范围找不到哪个命名空间的Pod在报错”时特别有效。配合--sort-by排序后最新发生的异常事件会排在最上面我一般先看Events再看报错时间点前后的Pod日志基本就能定位。如果你经常在某几个命名空间之间切换kubectl config set-context可以直接修改当前context的默认namespacekubectl config set-context --current --namespacedev这比每次敲命名空间省事多了。但小心这个设置是持久的下次在这个context里执行命令还是会落到dev命名空间里如果临时切到别的环境忘了改回来可能就把资源建错地方了。3.4 自动补全与别名终端效率翻倍kubectl的命令参数又多又长手敲很费劲。我强烈建议开启自动补全。以bash为例source (kubectl completion bash) echo source (kubectl completion bash) ~/.bashrczsh用户就换成kubectl completion zsh。补全之后敲kubectl get po再加两下Tab键namespace、资源名都会自动提示节省的时间相当可观。别名这件事我的建议是只给那些你自己确实高频使用的命令配别名不要贪多。我自己的几个常用别名供参考alias kkubectl alias kgpkubectl get pods alias kgdkubectl get deploy alias ksyskubectl -n kube-system alias kdesckubectl describe注意一点如果用了类似kubectx和kubens这类切换工具别名系统会跟它们有交互自己按照习惯调整即可。4. 生产环境排障从Pod事件到核心命令的串联使用命令单个拿出来都好理解难的是在出问题时把这些命令串成一条排障流水线。下面分享一下我的排查思路和几个高频问题的处理方案。4.1 一次Pod故障的排查路径假设现在有个Pod一直处于CrashLoopBackOff状态我会按下面的次序来排查第一步先get pods看看整体状态确认是哪个命名空间下的哪个Pod出了问题。kubectl get pods -A | grep CrashLoopBackOff第二步describe这个Pod重点看Events和Status里的信息。Events里如果有Back-off restarting failed container说明容器启动后不断退出如果看到Failed to pull image那基本是镜像仓库认证或镜像名写错的问题。第三步看日志。如果容器还在运行或者刚崩溃用kubectl logs调试失败原因kubectl logs -f pod-name --previous--previous参数能看到上一次容器退出前的日志这一步往往能直接看到业务报错。如果是应用启动时报配置错误就在这里暴露无遗。第四步如果日志没输出可能是健康检查失败导致容器被杀。手动进入容器看一眼进程情况kubectl exec -it pod-name -- /bin/sh进去后检查进程是否存在、监听端口是否正常。有时候应用起来比较慢而readinessProbe的超时时间设得太短也会导致Pod被反复重启。这种问题在describe里也能看到线索。第五步结合事件中的调度信息确认资源是否充足。如果Events里有FailedScheduling且提示Insufficient cpu或Insufficient memory那就是节点资源不足要么扩容节点要么调低资源请求。这套流程走完90%以上的Pod异常都能找到原因。剩下的那10%大多是集群层面的问题这时就需要去查节点状态、网络组件、存储卷之类的内容那是另一个话题了。4.2 常见报错速查问题现象与原因对照我把工作中高频见过的kubectl报错做了一个整理方便对照参考。报错信息常见原因排查方向Unable to connect to the server: dial tcp ... i/o timeout集群APIServer网络不通或安全组拦截检查本机到APIServer地址的连通性telnet或nc测试对应端口server returned 401 Unauthorizedkubeconfig里的token过期或证书不匹配重新生成ServiceAccount的token或更新config里的client-certificateserver returned 403 Forbidden当前用户的RBAC权限不足检查RoleBinding或ClusterRoleBinding确认用户是否有相应命名空间的权限No resources found命名空间写错或该命名空间下确实没有这个资源确认-n参数或改用-A全命名空间查看error: You must be logged in to the server未设置KUBECONFIG或config文件为空检查KUBECONFIG环境变量和~/.kube/config是否存在The connection to the server ... was refusedAPIServer端口拒绝连接或服务未监听在集群节点上检查kube-apiserver进程与443端口状态pod has unbound PersistentVolumeClaimsPVC未绑定PV检查StorageClass和PV状态确认动态供给是否正常Error from server: etcdserver: request timed out集群存储层出现性能问题或etcd不稳定检查etcd集群健康状态、磁盘IO和节点负载上面这些都是实际工作中比较高频遇到的。我的经验是报错本身不可怕关键是先判断是client端问题还是server端问题。凡是出现Unable to connect、Unauthorized先查client侧的网络和配置凡是出现FailedScheduling、ImagePullBackOff再去查集群内部。4.3 在GitLab CI/CD中设置kubectl配置文件的实操最后来回答一下很多人关心的“gitlab怎么设置kubectl配置文件”这个问题。实际上GitLab本身不会直接操作Kubernetes集群它需要在CI/CD的job里让kubectl具备访问集群的能力。最稳妥的办法是在GitLab项目的CI/CD Variables里保存KUBECONFIG的内容然后在job里写入指定路径。第一步把kubeconfig文件内容作为变量存到GitLab里。打开项目的Settings - CI/CD - Variables添加一个变量类型选择File变量名建议叫KUBECONFIG然后粘贴kubeconfig文件的内容。选File类型的好处是GitLab会在runner上把它生成一个临时文件并把文件路径传给CI这样比直接把内容写到代码仓库安全得多。第二步在.gitlab-ci.yml里用这个变量。示例配置deploy-job: stage: deploy before_script: - mkdir -p $HOME/.kube - cp $KUBECONFIG $HOME/.kube/config script: - kubectl get namespaces - kubectl apply -f manifests/第三步是安全性设置。如果你的runner是共享的我建议不要在Runner上长期保留任何kubeconfig文件。更好的做法是基于短期token来动态生成kubeconfig。具体思路是在job里先使用一个只拥有临时权限的token创建config然后执行完任务后立即删除。这部分逻辑可以写成一个脚本作为公共模板复用cat EOF $HOME/.kube/config apiVersion: v1 kind: Config clusters: - cluster: server: ${K8S_APISERVER} certificate-authority-data: ${K8S_CA_DATA} name: gitlab-cluster users: - name: gitlab-user user: token: ${K8S_TOKEN} contexts: - context: cluster: gitlab-cluster user: gitlab-user namespace: ${CI_ENVIRONMENT_NAME} name: gitlab-context current-context: gitlab-context EOF这里把APIServer地址、CA证书、token全部通过CI/CD变量注入安全性和灵活性都得到了保障。而且注意我将namespace设置为当前环境名这样同一份模板可以同时用在test、preview、production多个环境上互不干扰。这种做法的好处是显而易见的不用把集群管理员凭证长时间暴露在CI系统里每个环境仅用最小权限的token出现安全问题时回收凭证也很方便。从我接触过的项目来看很多团队早期图省事直接拿admin kubeconfig塞进GitLab后面权限一旦泄露整个集群都暴露在风险之中所以这个成本值得花。最后再分享一个实际工作里的细节CI里执行kubectl apply之后建议加一步检查部署状态而不是apply完就算结束。可以在job里循环等待Rollout完成kubectl rollout status deployment/my-service -n my-namespace --timeout2m这条命令会阻塞到Deployment滚动更新完成或超时。如果超时CI job会直接失败这比发布完才发现服务没起来要舒服得多。很多真实事故的核心根源就是发布脚本只做了apply没有做rollout status校验结果上线报错半天后才被监控发现。这个习惯我现在一直保留着也建议读到这里的各位写进团队模板里。