jenkins-cicd-on-kubernetes

Posted by     "李森" on Sunday, September 23, 2018

TOC

kubernetes ci/cd 开源实现有很多,传统的有霸主jenkins、后起之秀drone、Spinnaker、gitlab-ci以及jenkins-kubernetes衍生版jenkins X等; 不可否认后起之秀们有性能优势、云原生,但论产品的功能性、成熟度、生态跟jenkins比都不是一个级别产品,ci/cd 是企业devops的关键一环, jenkins在Pipeline加持下依然是当前不二之选。

  1. 先说下我这里的后端部署有 jar包和 war包,前端都是一样,大家可以根据自己的实际情况进行适当修改即可。
  2. 在代码库中增加一个Jenkinsfile 结合BlueOcean插件,采用webhook触发打包发布,dev、test环境会直接部署,master会有一个确认步骤,同意后才能进行发布。
  3. 此次部署有持久化存储需求,请自行解决,或参考我之前的ceph文档。

部署jenkins

git clone https://github.com/li-sen/jenkins-cicd-on-kubernetes.git
cd jenkins-cicd-on-kubernetes

1. 创建namespace
kubectl create -f 01ns.yaml

2. 创建ceph-key
kubectl create secret generic ceph-storageclass-secret --type="kubernetes.io/rbd" --from-literal=key='xxxxxxxxxxxxxBzNNWJVcfyCrhWDA==' --namespace=kube-ops

3. 创建sa
kubectl create -f 02jenkins-rbac.yaml

4. 创建statefulset
kubectl create -f 03jenkins-statefulset.yaml

5. 创建svc
kubectl create -f 04jenkins-svc.yaml

6. 安装jenkins
# 获取初始密码
kubectl exec -it jenkins-0 /bin/bash -n kube-ops
jenkins@jenkins-0:/$ cat /var/jenkins_home/secrets/initialAdminPassword
# 后续步骤跟传统安装一样,按推荐下一步就行(插件安装也按默认推荐),这里省略了。
  1. Jenkins URL需要设置为: http://jenkins.kube-ops.svc.cluster.local:8080/ 不然slave pod 无法连接master
  2. 插件的需另外安装Blue Ocean、kubernetes Gitlab相关插件 这里我就不截图了。

目录说明

由于前后端,采用不同的打包方式,部署的方式也不一样,所以采用不同的slave进行打包部署

  • fe 表示前端

  • java 表示后端

build slave镜像

# fe 前端
# fe前端打包前需要打包一个自定义nginx镜像:增加自定义配置,详细看Dockerfile。
cd fe/
docker build -t harbor.xxx.com/pub/nginx:v1 .
docker push harbor.xxx.com/pub/nginx:v1

docker build -t harbor.xxx.com/pub/jnlp-slave:fe .
docker push harbor.xxx.com/pub/jnlp-slave:fe 

# 基础镜像,改时区,deploy虽然已经挂载了宿主机的/etc/localtime,但java还是无法正确识别时区,只能打基础镜像。
cd java/jar/springboot
docker build -t harbor.xxx.com/pub/springboot .
docker push harbor.xxx.com/pub/springboot

cd java/war/tomcat
docker build -t harbor.xxx.com/pub/tomcat .
docker push harbor.xxx.com/pub/tomcat

# war 后端
cd java/war/jenkins-slave
docker build -t harbor.xxx.com/pub/jnlp-slave:java .
docker push harbor.xxx.com/pub/jnlp-slave:java

# jar 后端
cd java/jar/jenkins-slave
docker build -t harbor.xxx.com/pub/jnlp-slave:jar .
docker push harbor.xxx.com/pub/jnlp-slave:jar

根据实际情况选取前后端slave

集成k8s

安装完毕后,点击 Manage Jenkins —> Configure System —> (拖到最下方)Add a new cloud —> 选择 Kubernetes,然后填写 Kubernetes 和 Jenkins 配置信息。

新增kubernetes信息

新增kubernetes

# 相关参数我这里贴下:
https://kubernetes.default.svc.cluster.local
kube-ops
http://jenkins.kube-ops.svc.cluster.local:8080
点击连接测试

新增后端 pod 模板

新增pod模板1

# 相关参数我这里贴下:
jnlp-java
jnlp-java
kube-ops
jenkins-jnlp-java # 这个lable很重要,后面的Jenkinsfile 运行指定容器就用这个参数

harbor.xxx.com/pub/jnlp-slave:java
# 这个镜像,这个镜像是在官方的 jnlp 镜像基础上定制的,加入了 kubectl 等一些实用的工具,具体请看Dockerfile。
# 说明下最好是镜像拉取策略为 Always,因为有时候基础slave 镜像更新了 由于tag一样,如果策略为IfNotPresent,则会一直使用老的镜像。

jenkins中设置多个 pod 模板,譬如java、或者前端fe 不要改变container模板的名称,不然jenkins-slave无法连接master

新增pod模板2

说明:

# 相关参数我这里贴下:
/var/run/docker.sock
/var/run/docker.sock

/root/.kube
/home/jenkins/.kube

# /var/run/docker.sock 让slave pod 共享宿主机的 Docker, docker in docker 的方式
# /root/.kube 让slave pod中能够使用 kubectl 工具来访问我们的 Kubernetes 
#代理的空闲存活时间 这个参数可以选择480分钟,这样会一直有slave在线,会加速打包编译以及发布速度。

新增pod模板3

说明:

# 相关参数我这里贴下:
myregistrykey
jenkins

新增前端 pod 模板

新增pod模板4 新增pod模板5 新增pod模板6

说明: 前端slave pod和后端 参数基本一样这里就不赘述了。

测试

创建harbor secrets

kubectl create secret docker-registry myregistrykey --docker-server=harbor.xxx.com --docker-username=admin --docker-password=xxxx --docker-email="xxx@xxx.com" -n kube-ops

创建一个自由风格项目

新增项目 新增项目

# 相关参数我这里贴下:
docker info
kubectl get pods

点击构建 查看结果

至此jenkins与kubernetes的集成完成!下面来进行gitlab中项目进行整合

Jenkinsfile

将对应的Jenkinsfile上传到 相应git项目的 根目录

# Jenkinsfile 流程
拉代码---> 替换配置文件、编译打包---> 拷贝相关文件、打包成docker镜像并上传--->替换k8s相关资源模板文件--->创建k8s资源发布

一定要看懂Jenkinsfile 的内容,因为每个公司技术栈不一样,打包方式也不一样,需求也不一样,基本上都要根据自己的情况进行修改的,pipeline语法还是挺简单的。

新建相关资源

k8s 新建 ns

kubectl create ns master
kubectl create ns test
kubectl create ns dev

# 新建ns 相关资源
kubectl create secret docker-registry myregistrykey --docker-server=harbor.xxx.com --docker-username=admin --docker-password=xxxx --docker-email="xxx@xxx.com" -n master
kubectl create secret docker-registry myregistrykey --docker-server=harbor.xxx.com --docker-username=admin --docker-password=xxxx --docker-email="xxx@xxx.com" -n test
kubectl create secret docker-registry myregistrykey --docker-server=harbor.xxx.com --docker-username=admin --docker-password=xxxx --docker-email="xxx@xxx.com" -n dev

kubectl create secret generic ceph-storageclass-secret --type="kubernetes.io/rbd" --from-literal=key='xxxxxxxxxxxxxxxxxxxx/SiECTd0WfQ==' --namespace=master
kubectl create secret generic ceph-storageclass-secret --type="kubernetes.io/rbd" --from-literal=key='xxxxxxxxxxxxxxxxxxxx/SiECTd0WfQ==' --namespace=test
kubectl create secret generic ceph-storageclass-secret --type="kubernetes.io/rbd" --from-literal=key='xxxxxxxxxxxxxxxxxxxx/SiECTd0WfQ==' --namespace=dev

jenkins 账号新增

# jenkins中新增 harbor账号密码 
# 我这里将数据库的账号密码也放jenkins中了
# 目的是为了隐藏账号密码,Jenkinsfile直接通过jenkins变量引入

jenkins 账号

BlueOcean

打开BlueOcean,安装提示部署,默认会在有Jenkinsfile的项目分支中建立多分支项目。

Jenkinsfile中 对与master分支 也就是一般的生产环境所用的分支,在发布的时候会有一个 确认操作!否则会一直等待直到失效。

前端项目,nginx的配置文件我是通过configmap进行存储控制的,所以打包发布之前先确认对应的configmap建立好。

webhook

只要代码进行了修改,就自动触发cicd

在gitlab 设置webhook url

Settings——>Integrations

格式为:

http://xxxxx/project/[ProjectName]

示例:

http://88.88.88.88:40002/project/api-gateway

webhook触发多分支流水线会自动判断并触发对应的分支打包,比如项目master分支更新了,只会触发jenkins上项目对应的master,其他的分支不会 触发打包发布操作。

回滚

由于在 发布/更新 时候添加了 --record ,所以会有一个版本号的概念

kubectl apply -f deploy.yaml --record
kubectl set image deploy ${app_name} ${app_name}=${image_name} -n ${env.BRANCH_NAME} --record

# 查看master namespace deployment 记录
kubectl rollout history deployment -n master

# 回滚
kubectl rollout undo deployment xxxx --to-revision=2 -n master

后续有需求再来采用 helm方式进行发布 回滚,先满足功能需求再说。。。