1. Kubernetes 1.20.5 上用 helm 安装 jenkins 到底卡在哪
Kubernetes 1.20.5 上用 helm 安装 jenkins,说白了就是把官方 chart 拉下来,改几个 values 字段,再helm install一把。但真正动手你会发现,卡人的从来不是安装命令本身,而是 chart values 里镜像拉不动、Ingress 入口对不上、插件初始化卡死、初始密码找不到这几件事。这篇就按我实际在 kubeadm 1.20.5 集群上的落地顺序,把每一步的 values.yaml 片段和 kubectl 验证动作都摊开写,你照着改就能一次跑通。
先说清楚这套流程适合谁:已经有一个能kubectl get nodes正常返回的 1.20.5 集群,装好了 helm3,集群里有可用的 StorageClass(我用的是腾讯云 CBS 块存储),并且有一个 Ingress 控制器在跑(我用 traefik,纯 HTTP,证书交给云负载均衡)。如果你集群里没有默认 StorageClass,jenkins 的 PVC 会一直 Pending,这个后面排障章节会专门讲。
为什么单独拎 1.20.5 这个版本说?因为 1.20 之后 Kubernetes 弃用了不少老 API,而 jenkins chart 的某些老版本 Ingress 模板还在用extensions/v1beta1,直接 apply 会报no matches for kind "Ingress"。所以 values 里入口这块要么用控制器自己的 CRD(比如 traefik 的 IngressRoute),要么确认 chart 版本已经切到networking.k8s.io/v1。这是第一个大坑,先记住。
整篇的节奏是:先讲清楚 chart values 里哪些字段必须改,再给可复制的 values.yaml 片段和 helm 命令,然后用 kubectl 一步步验证 Pod、Service、Ingress 是否就绪,最后把 401、镜像拉取失败、插件下载超时、初始密码读不到这些真实报错逐个拆掉。你不需要一次全记住,跟着命令走,哪一步报错就翻到对应小节。
2. 装 jenkins 之前先把 TaoToken 的接入信息备好
在动 helm 之前,有一件前置的事值得先做:把模型服务的接入信息准备好。因为 jenkins 本身只是个调度壳,真正跑 CI/CD 的时候,你大概率会在 pipeline 里调用大模型做代码审查、生成 changelog、或者跑 Agent 任务。与其等 jenkins 装完再回头折腾,不如现在就把 Base URL、API Key、Model ID 这三件套拿到手,后面在 jenkins 的凭据管理里直接建一条就行。
我自己的做法是先在 TaoToken 上把 key 建好。打开 https://taotoken.net/api-keys ,新建一个 API Key,复制出来存好。这个 key 就是后面所有请求的凭证,别直接写进 values.yaml 或者 pipeline 脚本里明文,jenkins 有 Credentials 功能,用Secret text类型存进去,脚本里用withCredentials引用。
Base URL 这块要注意,接口地址是 https://taotoken.net/api ,不带任何多余路径。很多人在这一步会手滑加上/v1或者结尾斜杠,结果请求直接 404。Model ID 就按你实际要用的模型填,比如做代码补全和审查常用的那几个,具体在控制台能看到可用列表。如果你还没决定用哪个模型,可以先到 https://taotoken.net/models 看一眼,或者直接开一个对话窗口试一下返回是否正常,确认 key 和模型都对得上,再去配 jenkins。
为什么强调"先备好"?因为 jenkins 装完之后,你要在Manage Jenkins -> Credentials里加凭据,还要在Manage Jenkins -> System里配环境变量或者全局工具,如果这时候才发现 key 没建、模型名记错,就得来回切页面。提前把三件套写在便签上,装完 jenkins 五分钟就能配完。
另外提一句,如果你后面打算在 jenkins 里跑长期的编码 Agent 或者定时任务,可以顺手了解一下 Coding Plan 的额度情况,避免跑一半发现额度不够。这个不是必须,但提前规划比事后补要省心。总之这一节的目标就一个:让 Base URL、Key、Model ID 三样东西在你手边,随时能填。
3. 可复制的 values.yaml 片段与 helm install 命令
这一节是核心,直接给能抄的配置。先把 chart 拉下来:
helm repo add jenkins https://charts.jenkins.io helm repo update helm pull jenkins/jenkins tar zxvf jenkins-*.tgz cd jenkins然后改 values.yaml。下面是我实际用的片段,重点改了存储、镜像、入口和插件初始化四块。你可以直接对照着改自己那份:
# values.yaml 关键片段 controller: # 镜像:如果默认镜像拉不动,换成你能访问的仓库 image: "jenkins/jenkins" tag: "2.387.1-lts" imagePullPolicy: IfNotPresent # 资源限制,1.20.5 集群节点小的话别给太大 resources: requests: cpu: "500m" memory: "1Gi" limits: cpu: "2" memory: "4Gi" # 存储:用集群默认 StorageClass,腾讯云 CBS 会自动绑定 storageClass: "cbs" volumes: - name: jenkins-home persistentVolumeClaim: claimName: jenkins-pvc # 初始化插件:下载慢就注释掉,后面手动装 installPlugins: false # 服务类型,走 Ingress 的话用 ClusterIP 就够 serviceType: ClusterIP # 管理员账号,避免匿名登录 adminUser: "admin" adminPassword: "你的强密码" # 关闭匿名访问 jenkinsUriPrefix: "" persistence: enabled: true storageClass: "cbs" size: "20Gi" accessMode: "ReadWriteOnce" serviceAccount: create: true name: jenkins rbac: create: true几个字段解释一下。installPlugins: false是解决插件下载超时的关键,官方 chart 默认会在启动时拉一堆插件,国内网络环境下经常卡在Downloading plugin十几分钟甚至直接失败。先关掉,等 jenkins 起来后手动装,反而更快。storageClass一定要填你集群里真实存在的名字,用kubectl get sc确认,填错就是 PVC Pending。adminUser和adminPassword建议显式设置,不然默认会生成随机密码,还得去 secret 里翻。
如果你用 traefik 做入口,chart 自带的 Ingress 模板可能和 1.20.5 的 API 版本对不上,那就别用 chart 的 ingress,单独写一个 IngressRoute:
apiVersion: traefik.containo.us/v1alpha1 kind: IngressRoute metadata: namespace: kube-ops name: jenkins-http spec: entryPoints: - web routes: - match: Host(`jenkins.example.com`) kind: Rule services: - name: jenkins port: 8080注意services.name要和你 helm release 生成的服务名一致,通常是jenkins,端口是8080。如果你用的是 nginx-ingress,那就写标准 Ingress,apiVersion: networking.k8s.io/v1,pathType: Prefix,后端指向jenkins:8080。
配置改完,执行安装:
kubectl create ns kube-ops helm install -f values.yaml jenkins jenkins/jenkins -n kube-ops如果装到一半发现 values 改错了,别慌,helm upgrade就能覆盖:
helm upgrade -f values.yaml jenkins jenkins/jenkins -n kube-ops实在乱套了就删掉重来:
helm delete jenkins -n kube-ops kubectl delete pvc jenkins-pvc -n kube-ops helm install -f values.yaml jenkins jenkins/jenkins -n kube-ops注意删 PVC 会丢数据,只在初始化阶段这么干。生产环境别随手删。
4. 用 kubectl 验证 Pod、Service、Ingress 是否就绪
装完不是看 helm 输出就完事,得一步步确认资源真的起来了。先看 Pod:
kubectl get pods -n kube-ops -w正常会看到jenkins-0从Init到Running,READY 变成2/2(一个主容器一个 config-reload 边车)。如果一直Pending,多半是 PVC 没绑上,kubectl describe pod jenkins-0 -n kube-ops看 Events,会提示no persistent volumes available或者storageclass not found。如果一直Init:0/1,可能是初始化容器在等插件下载,这时候检查 values 里installPlugins是不是没关。
Pod 起来后看 Service:
kubectl get svc -n kube-ops应该有一个jenkins和一个jenkins-agent。jenkins的 ClusterIP 是给 Ingress 用的,jenkins-agent是给构建 Agent 用的。如果jenkins的 EXTERNAL-IP 一直是<none>,说明你用的是 ClusterIP,正常,走 Ingress 访问就行。
再看 Ingress 或 IngressRoute:
kubectl get ingressroute -n kube-ops kubectl describe ingressroute jenkins-http -n kube-ops确认Status里没有报错,路由规则指向的 service 和端口正确。如果是标准 Ingress:
kubectl get ingress -n kube-ops kubectl describe ingress jenkins -n kube-ops看Rules里的 host 和 path 是不是你配的,Backends是不是jenkins:8080。
最后验证端到端连通。先在集群内 curl 一下 service:
kubectl run curl-test --image=curlimages/curl -it --rm --restart=Never -n kube-ops -- curl -s -o /dev/null -w "%{http_code}" http://jenkins:8080/login返回200就说明 service 通了。然后从你本地浏览器访问http://jenkins.example.com(换成你配的域名),能看到 jenkins 登录页就说明 Ingress 也通了。
如果浏览器打不开但集群内 curl 通,问题在 Ingress 控制器或者 DNS。检查 traefik 的 Pod 日志:
kubectl logs -l app.kubernetes.io/name=traefik -n kube-system --tail=50看有没有404或者no matching route。常见原因是 IngressRoute 的 namespace 和 service 的 namespace 不一致,或者 host 写错了。
初始密码这块,chart 会存在 secret 里:
kubectl get secret jenkins -n kube-ops -o jsonpath="{.data.jenkins-admin-password}" | base64 --decode; echo如果你在 values 里显式设了adminPassword,那就直接用你设的那个,不用去 secret 里翻。这一步很多人踩坑,是因为照着老教程去kubectl logs里找密码,但新版 chart 根本不往日志里打密码了,只在 secret 里。
5. 真实报错逐个拆:401、镜像拉取失败、插件超时、密码读不到
这一节按报错原文来,你遇到哪个就翻哪个。
报错一:Error response from daemon: pull access denied或ImagePullBackOff
kubectl describe pod jenkins-0 -n kube-ops会看到Failed to pull image。原因是默认镜像仓库访问不了。解决办法是把 values 里的controller.image换成你能访问的镜像源,或者提前在节点上docker pull好。如果是私有仓库,还要在 values 里加imagePullSecrets:
controller: imagePullSecrets: - name: my-registry-secret报错二:401 Unauthorized或local proxy failed
这个通常出现在你配了模型服务之后,jenkins pipeline 里调接口返回 401。先检查三件套:Base URL 是不是https://taotoken.net/api,结尾有没有多加斜杠;API Key 是不是复制完整,有没有多余空格;Model ID 是不是控制台里真实存在的。用 curl 单独测一下:
curl -X POST https://taotoken.net/api/chat/completions \ -H "Authorization: Bearer 你的KEY" \ -H "Content-Type: application/json" \ -d '{"model":"你的模型ID","messages":[{"role":"user","content":"hi"}]}'如果这里就 401,说明 key 或地址有问题,跟 jenkins 无关。如果这里通、jenkins 里不通,检查 jenkins 凭据是不是绑错了,或者 pipeline 里withCredentials的变量名对不上。local proxy failed一般是 jenkins 所在节点出网有问题,检查节点能不能访问外网,或者有没有配 HTTP 代理把请求拦了。
报错三:reading choices或返回体解析失败
这个报错说明请求发出去了,但返回的 JSON 结构和你代码里解析的字段对不上。常见原因是模型返回了错误信息而不是正常结果,比如额度不足、模型名写错。先把原始返回打出来看:
curl -s https://taotoken.net/api/chat/completions \ -H "Authorization: Bearer 你的KEY" \ -H "Content-Type: application/json" \ -d '{"model":"你的模型ID","messages":[{"role":"user","content":"hi"}]}' | jq .看error字段写了什么。如果是model not found,去控制台核对模型 ID;如果是额度问题,检查账户余额或套餐。
报错四:插件下载超时,日志卡在Downloading plugin
这就是前面说的installPlugins: false要解决的问题。如果你已经装上了但卡住,直接helm upgrade把installPlugins改成 false,然后重启 Pod:
helm upgrade -f values.yaml jenkins jenkins/jenkins -n kube-ops kubectl rollout restart statefulset jenkins -n kube-ops起来之后进Manage Jenkins -> Plugins手动装。手动装也慢的话,可以配国内镜像源,在Manage Jenkins -> Plugins -> Advanced里把 Update Site 换成国内地址。
报错五:初始密码读不到,secret "jenkins" not found
先确认 release 名字和 namespace:
helm list -n kube-ops kubectl get secret -n kube-ops | grep jenkinssecret 名字通常是<release-name>,如果你 release 叫jenkins,那就是jenkins。如果 values 里设了adminPassword,secret 里存的是你设的值,直接用它登录。如果忘了设,用前面那条jsonpath命令读。读出来是乱码的话,检查base64 --decode有没有漏,或者用-o go-template方式:
kubectl get secret jenkins -n kube-ops -o go-template='{{index .data "jenkins-admin-password" | base64decode}}'报错六:OAuth 或匿名登录问题
有人第一次访问 jenkins 发现不用密码就进去了,这是因为默认配置允许匿名访问。进Manage Jenkins -> Security,把Allow anonymous read access取消,选Jenkins' own user database,保存后就会要求登录。如果你用 OAuth(比如 GitHub 登录),需要在Security Realm里选对应插件并配 Client ID/Secret,配完记得重启。
6. 后续在 jenkins 里接模型服务的入口
jenkins 跑起来只是第一步,真正让它干活是在 pipeline 里调模型。这里给一个最小可用的 pipeline 片段,把前面备好的三件套用上:
pipeline { agent any environment { TAOTOKEN_KEY = credentials('taotoken-api-key') } stages { stage('Call Model') { steps { sh ''' curl -s -X POST https://taotoken.net/api/chat/completions \ -H "Authorization: Bearer $TAOTOKEN_KEY" \ -H "Content-Type: application/json" \ -d '{"model":"你的模型ID","messages":[{"role":"user","content":"review this diff"}]}' ''' } } } }凭据taotoken-api-key在Manage Jenkins -> Credentials里建,类型选Secret text,值填你的 API Key。这样 key 不会出现在脚本明文里。
如果你后面要跑更重的 Agent 任务,比如自动改代码、跑多轮对话,可以看看 Coding Plan 的额度,避免单次调用超限。模型对话的调试入口在 https://taotoken.net/chat ,配 pipeline 之前先在那里确认模型返回正常,能省不少排查时间。接入文档在 https://taotoken.net/doc ,里面有各语言的调用示例,照着改就行。
最后说个我踩过的坑:jenkins 的 config-reload 边车有时候会缓存旧配置,改了 values 之后helm upgrade了但 Pod 没重启,导致新配置不生效。养成习惯,改完 values 后手动kubectl rollout restart statefulset jenkins -n kube-ops,再kubectl get pods -n kube-ops -w看着它重新起来,确认 READY 2/2 再访问。这一步多做一次,能省掉很多"明明改了怎么没用"的困惑。