Jenkins+Packer build docker image trouble in Google Container Engine

2017-04-28 10:47:41来源:https://smalltowntechblog.com/2017/04/27/jenkinspacker-build作者:Smalltown Tech Blog人点击



tl;dr

本篇只是简述採坑的过程,没有最终解法,只是提醒看到这篇的朋友,在标準解决方案出来之前,先不要尝试这个解决方案了。


目标:用 Jenkins + Packer 搭配 GKE 来建置 docker image
初衷

又到了每年一度的搬家盛事了(辛酸),今年,我们终于要从多灾多难的某 S 平台搬到好像很潮的 Google Cloud Platform (GCP) 了。当然,第一件事就是要试着在由 Google 帮你管理的 kubernetes cluster 的 Google Container Engine (GKE) 上建製之前已经完全容器化的系统。


马上就找到有篇文章就是 Google 推荐介绍在 k8s 上自动化 build image 的文章,「 Automated Image Builds with Jenkins, Packer, and Kubernetes 」,带着初次在 GCP 上飞高高的兴奋感,立马跟着实作!


目标
透过 Jenkins Master / Slave 模式建置 docker image
可以在 Jenkins Master 侦测到 git repo 变更时,透过 Jenkins – Kubernetes Plugin 即时启动一个新的 Jenkins Slave container 进行 build docker image 的作业
Jenkins slave 要能使用 packer build docker image
採坑1 – memory 不够,一直被 Jenkins slave 一直被 kill

官方文章有提供 Jenkins 的 k8s yaml spec 方便你直接用 kubect create -f jenkins.yaml 就能装好 Jenkins,但是他也在 k8s spec 里面指定了 memory resource 的限制。这会造成当你在按下 build now 的时候,jenkins 会因为 memory 因为超过 cgroup 的 limit 而被砍掉。但是实际上你看不到什么 error log,只会一直从 GCP load balancer 看到 500 error 或是 timed out。所以记得把官方的 1.5G memory 限制,调整到至少 2G 以上,被砍掉的机率才会降低。


採坑2 – 官方文章的 Jenkins slave image 没有 packer

Configuring Jenkins for Container Engine 中在介绍设定 Kubernetes Plugin 时,需要指定 Jenkins slave launch 起来的 container 需要使用的 image,官方这边是使用


gcr.io/cloud-solutions-images/jenkins-k8s-slave

但是,jenkins-k8s-slave image 并没有帮你装好 packer 在里头的,但这算是小事,只要自己重包一下就可以解决。


庆幸的是官方有提供 jenkins-k8s-slave 的 Dockerfile,他的 git repo 在这边,抓来改一改,把 packer 放进去,再 push 回 GCR ,再从 Jenkins 的设定换成自己的 image 就好


https://github.com/GoogleCloudPlatform/continuous-deployment-on-kubernetes.git
採坑3 – packer 找不到要上传到 image 的档案

在 Jenkins slave 中的 packer 要 upload 我们需要预放到 image 的档案时,会碰到 file not found 的错误


cp: cannot stat '/packer-files/upload123456789': No such file or directory
.... 中间略过 ....
ui error: Build 'docker' errored: Upload failed with non-zero exit status: 2

这个问题,主要是因为 packer 是用下 run_command 的方式去把要上传到 image 的 file ,透过 docker 的 volume mount 的方式挂载到目标 image 后,再透过从 container 中下 cp 指令去複製到你指定的位置。


但由于我们是透过 Jenkins slave 里面的 docker-cli,去连接到 Jenkins slave container host 上的 docker engine 进行 build 的动作,推测 packer 用 run_command 的方法,会造成 mount 要 build 的 file 到 host 上的目录,但是实际上我们是要把 packer 所在的 container 的 file mount 到目标 image,所以就会有一些权限以及 mount 来 mount 去,最后 mount 到迷路的问题。


但最好一点的解法,就是目前官方正在使用 go-dockerclient 去重写整个 packer 内的 communicator。


这边的详细讨论,可以看下面「快速结论」中所附上的 Github link ,里面有对应的讨论。


快速结论

想要让 packer build docker image 在 container 中,目前是无解的。请期待官方正式 merge 或是有没有人有兴趣帮忙 merge 这部分的 code 啰,github issue 在这边 WIP: Switch Docker Driver to use the API instead of CLI #4186


注意哦,这个问题只在使用 packer 的 docker provisioner 来 build image 时才会有问题喔!


最后结论

最后笔者只好选择放弃 GKE + Jenkins Master / Slave + Packer 这个解决方案了,为了快速验证能不能将整个系统搬到 GCP,先用暂时的方案,让原本在 S社 的 Jenkins ,从外部 (external) push docker image 到 GCR (Google Container Registry),而这中间碰到的问题以及暂时的解法,就在下一篇介绍给大家吧!


微信扫一扫

第七城市微信公众平台