基于jenkins的CICD(一)
原文: 基于jenkins的CICD
参考:https://www.jenkins.io/doc/book/installing/kubernetes/
参考:https://github.com/jenkinsci/docker-inbound-agent
namespace.yml
apiVersion: v1
kind: Namespace
metadata:
name: kube-ops
pv.yml
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: opspvc
namespace: jenkins
spec:
accessModes:
- ReadWriteMany
storageClassName: nfs-client
resources:
requests:
storage: 20Gi
rbac.yaml
定义了一个clusterrole,允许创建deployment,service和pod。进入容器,查看容器日志以及secret的权限
- resources: ["pods/exec"] 可以进入容器以及拷贝权限。这种资源类型叫subresource
- resources: ["pods/log"] 可以查看容器的日志
apiVersion: v1
kind: ServiceAccount
metadata:
name: jenkins2
namespace: jenkins
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: jenkins2
rules:
- apiGroups: ["extensions", "apps"]
resources: ["deployments"]
verbs: ["create", "delete", "get", "list", "watch", "patch", "update"]
- apiGroups: [""]
resources: ["services"]
verbs: ["create", "delete", "get", "list", "watch", "patch", "update"]
- apiGroups: [""]
resources: ["pods"]
verbs: ["create","delete","get","list","patch","update","watch"]
- apiGroups: [""]
resources: ["pods/exec"]
verbs: ["create","delete","get","list","patch","update","watch"]
- apiGroups: [""]
resources: ["pods/log"]
verbs: ["get","list","watch"]
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: jenkins2
namespace: jenkins
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: jenkins2
subjects:
- kind: ServiceAccount
name: jenkins2
namespace: jenkinss
deployment.yml
使用的镜像是官方的jenkins镜像:jenkins/jenkins:lts, 如果需要给镜像里面打包插件或者设置环境变量的话可以参考 https://github.com/jenkinsci/docker ,pvc挂载到/var/jenkins_home目录下面
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: jenkins2
namespace: jenkins
spec:
selector:
matchLabels:
app: jenkins2
template:
metadata:
labels:
app: jenkins2
spec:
terminationGracePeriodSeconds: 10
serviceAccount: jenkins2
containers:
- name: jenkins
image: jenkins/jenkins:lts
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
name: web
protocol: TCP
- containerPort: 50000
name: agent
protocol: TCP
resources:
limits:
cpu: 1000m
memory: 1Gi
requests:
cpu: 500m
memory: 512Mi
livenessProbe:
httpGet:
path: /login
port: 8080
initialDelaySeconds: 60
timeoutSeconds: 5
failureThreshold: 12
readinessProbe:
httpGet:
path: /login
port: 8080
initialDelaySeconds: 60
timeoutSeconds: 5
failureThreshold: 12
volumeMounts:
- name: jenkinshome
subPath: jenkins2
mountPath: /var/jenkins_home
securityContext:
fsGroup: 1000
volumes:
- name: jenkinshome
persistentVolumeClaim:
claimName: opspvc
service.yml
web端需要暴露8080端口
---
apiVersion: v1
kind: Service
metadata:
name: jenkins2
namespace: jenkins
labels:
app: jenkins2
spec:
selector:
app: jenkins2
type: NodePort
ports:
- name: web
port: 8080
targetPort: web
nodePort: 30004
- name: agent
port: 50000
targetPort: agent
一、创建资源
正常情况下不会有什么问题,如果有,那就看日志
kubectl create -f xxx.yaml
二、访问测试
[root@master jenkins]# kubectl -n jenkins exec -it jenkins2-5d577cc67d-4g5nh -- cat /var/jenkins_home/secrets/initialAdminPassword
7e0afde2bc7d46f08d048f41218f4189

安装推荐插件

三、k8s部署jenkins的优势
我们知道持续构建与发布是我们日常工作中必不可少的一个步骤,目前大多公司都采用 Jenkins 集群来搭建符合需求的 CI/CD 流程,然而传统的 Jenkins Slave 一主多从方式会存在一些痛点,比如:
- 主 Master 发生单点故障时,整个流程都不可用了
- 每个 Slave 的配置环境不一样,来完成不同语言的编译打包等操作,但是这些差异化的配置导致管理起来非常不方便,维护起来也是比较费劲
- 资源分配不均衡,有的 Slave 要运行的 job 出现排队等待,而有的 Slave 处于空闲状态
- 资源有浪费,每台 Slave 可能是物理机或者虚拟机,当 Slave 处于空闲状态时,也不会完全释放掉资源。
正因为上面的这些种种痛点,我们渴望一种更高效更可靠的方式来完成这个 CI/CD 流程,而 Docker 虚拟化容器技术能很好的解决这个痛点,又特别是在 Kubernetes 集群环境下面能够更好来解决上面的问题,下图是基于 Kubernetes 搭建 Jenkins 集群的简单示意图:

从图上可以看到 Jenkins Master 和 Jenkins Slave 以 Pod 形式运行在 Kubernetes 集群的 Node 上,Master 运行在其中一个节点,并且将其配置数据存储到一个 Volume 上去,Slave 运行在各个节点上,并且它不是一直处于运行状态,它会按照需求动态的创建并自动删除。
这种方式的工作流程大致为:当 Jenkins Master 接受到 Build 请求时,会根据配置的 Label 动态创建一个运行在 Pod 中的 Jenkins Slave 并注册到 Master 上,当运行完 Job 后,这个 Slave 会被注销并且这个 Pod 也会自动删除,恢复到最初状态。
那么我们使用这种方式带来了哪些好处呢?
- 服务高可用,当 Jenkins Master 出现故障时,Kubernetes 会自动创建一个新的 Jenkins Master 容器,并且将 Volume 分配给新创建的容器,保证数据不丢失,从而达到集群服务高可用。
- 动态伸缩,合理使用资源,每次运行 Job 时,会自动创建一个 Jenkins Slave,Job 完成后,Slave 自动注销并删除容器,资源自动释放,而且 Kubernetes 会根据每个资源的使用情况,动态分配 Slave 到空闲的节点上创建,降低出现因某节点资源利用率高,还排队等待在该节点的情况。
- 扩展性好,当 Kubernetes 集群的资源严重不足而导致 Job 排队等待时,可以很容易的添加一个 Kubernetes Node 到集群中,从而实现扩展。
四、配置
配置jenkins,让jenkins可以自动创建slave的pod,去完成CI构建工作
4.1、安装kubernetes插件
首页 --> manage jenkins --> 插件管理 --> 可选插件 --> kubernetes

4.2、configure a cloud
也就是jenkins对接kubernetes,自动创建slave,传统情况下是添加node节点
首页 --> manage jenkins --> 节点管理 --> cloud configure --> Add a new cloud --> kubernetes

4.3、Kubernetes Cloud details
填写kubernetes的访问地址,命名空间,jenkins地址等信息


4.4、配置pod模板(Pod Templates)
其实就是配置 Jenkins Slave 运行的 Pod 模板
填写Pod名称,命名空间,pod标签,pod容器名字,容器镜像,工作目录,挂载docker.sock,挂载.kube目录
官方的镜像是jenkins/jnlp-slave,但是今天使用的阳明大佬制作的镜像,跑通了再换官方的镜像


挂载docker.sock文件到容器里面

service account

其他默认,保存
五、创建一个freestyle job测试

描述信息随便写下

填写项目运行的节点标签

添加构建步骤,选择执行shell命令

echo "测试 Kubernetes 动态生成 jenkins slave"
echo "==============docker in docker==========="
docker info
echo "=============kubectl============="
kubectl get pods

保存,并点击立即构建
此时在后台可以看到k8s枣jenkins分区下面创建了一个jnlp开头的pod,随后又删除了。这是因为编译构建结束了,pod就终止了,如果想pod多停留一会儿需要修改上面配置的pod模版信息,如下

然后查看构建的日志信息
