实现持续集成和部署的工具很多,此篇博客主要介绍如何利用GitAction来完成构建和在k8s集群下安装和使用jenkins来完成job运行。利用GitHub的action来完成构建有如下优势:

低成本:GitHub目前为项目提供免费的构建流水线,可满足日常构建需求。
免运维:无需自己构建流水线,GitHub提供小量构建请求。
易构建:GitHub action非常容易构建,另外提供了一系列内建的action,社区还有大量可复用的action。
易集成:无需配置GitHub webHook即可完成与PR联动。

接下来就看看如何在github上创建action来完成持续构建,如下图所示,在创建workflow时,可以选择已有的模版,也可以完全自定义,这里选择go模版,因为源代码是用go语言编写,右边是具体的workflows中的yml文件定义,可以看到文件中定义了在push代码和提交pr时会触发该job,job中定义了三个step,

step1:checkout代码

step2:setup构建环境(即安装go build的环境)

step3:执行go build命令完成构建。

完成配置后,在github上提交commit或者pr,可以看到触发了action,如下图所示

点击进入action,还可以看到每个步骤的执行日志信息,如下图所示

上面只是演示了简单的构建过程,更多关于github action的语法定义可以参考官网资料。接下来看看如何在k8s集群中使用jenkins完成构建。下图是在k8s集群下通过jenkins完成job执行的过程图

下面通过实际例子演示来看看如何在k8s上安装和配置jenkins,完成job执行。

k8s上安装jenkins,如果要安装jenkins只需如下yaml文件,创建StatefulSet和Service即可,Service类型是NodePort,这样可以在外网访问创建在集群上的jenkins。

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: jenkins
spec:
  selector:
    matchLabels:
      name: jenkins
  serviceName: jenkins
  replicas: 1
  template:
    metadata:
      name: jenkins
      labels:
        name: jenkins
    spec:
      terminationGracePeriodSeconds: 10
      serviceAccountName: jenkins
      containers:
        - name: jenkins
          image: jenkins/jenkins:lts-alpine
          ports:
            - containerPort: 8080
            - containerPort: 50000
---
apiVersion: v1
kind: Service
metadata:
  name: jenkins
spec:
  selector:
    name: jenkins
  ports:
    - name: http
      port: 80
      targetPort: 8080
      protocol: TCP
    - name: agent
      port: 50000
      protocol: TCP
  type: NodePort

除了安装jenkins的直接yaml文件外,还需要定义个SA,以及给SA设置role和roleBinding,创建SA在后续配置jenkins时会用到,具体的yaml文件内容如下所示

---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: jenkins

---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: jenkins
rules:
- 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: ["events"]
  verbs: ["watch"]
- apiGroups: [""]
  resources: ["secrets"]
  verbs: ["get"]

---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: jenkins
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: jenkins
subjects:
- kind: ServiceAccount
  name: jenkins

 通过kubectl create -f xx.yaml文件完成安装后,即可通过节点IP+servicePort在外网访问jenkins。首次访问需要输入登录密码,登陆的密码可以通过查询jenkin的pod日志获取 (kubectl logs jenkinspod)。

登陆成功后,首先需要安装jenkins的插件,这里选择安装插件后不重启服务,因为重启后,安装的插件会消失,又需要重新安装。

插件安装完成后,配置Cloud Provider

菜单Manage Jenkins->Manage Node and Cloud->Configure Cloud

  • Add a new cloud:Kubernetes
  • Kubernetes URL:https://kubernetes.default
  • Kubernetes Namespace:填写安装jenkins时的namespace
  • Credentials:Add->Jenkins->Kind:Kubernetes Service Account,之前为jenkins创建了service account和分配了权限,所以这里选择Kubernetes Service Account

配置完成后,点击Test Connnection,如果连接成功,说明安装、插件安装、配置都正确。可以看到下图连接成功

接着配置PodTemplate配置,添加PodTemplate

  • name:jnlp-slave
  • Label:jnlp-slave
  • Add Container

               Name:jnlp
               Image:jenkins/inbound-agent
              Argumentes to pass the command:${computer.jnlpmac}${computer.name}。

完成配置后,创建一个freestyle的project,这里输入的Label是jnlp-slave,主要不要有空格,输入后下面应该会显示macth到了一个cloud node的信息才行。另外,job的build步骤配置简单的echo test命令即可。

完成job配置后,运行job,可以看到启动了jenkins-slave,实际此时在k8s集群上新启动了一个pod,pod中拉取的image就是podTemplate中配置的image,这个pod启动起来就是为了执行job中的构建命令。

实际实验室,jenkins-slave在启动后总是被kill掉,查看了下pod日志,显示JNLP4-connect refused。这里使用的集群是aws上的eks集群,具体什么原因导致JNLP4-connect连接失败,没有继续调查,但这不影响对jenkins的理解。

可以看到真正执行job的是jenkins-slave,上面的配置中构建命令只是简单的echo test。在实际项目中构建命令肯定是真正的对应用进行打包,例如go的应用,应该执行go build命令。那么在配置podTemplate时,需要提前制备jenkins-slave的image,即包含go build环境的镜像,否则启动的slave pod无法执行go build命令。如果是java或者其他技术栈应用,道理相同,即需要制备构建所需的环境镜像。

另外,如果在构建过程中需要执行docker命令,即在启动的pod中需要从源代码中生成镜像文件,就需要实现docker in docker。关于docker in docker有两种解决方案:

方案一:在启动的容器中是没有docker.socket的,而如果想执行docker命令,需要用到docker.socket.所以可以吧host的docker.socket mount到容器内。

方案二:引入Kaniko,Kaniko是google提供了解决docker in docker问题的一个工具,Kaniko运行用户在container或者Kubernetes cluster上通过Dockerfile构建image,并将生成的镜像推送到镜像仓库。Kaniko底层不依赖Docker daemon,Kaniko自己编写了executer,这个executer负责将Dockerfile构建成镜像。关于Kaniko的详细信息可查看官网资料

另外,实际项目中除了安装jenkins外,还需要创建PVC,保证jenkins master pod出错时,新的kubernetes pod可以mount同样的工作目录,保证配置不丢失。

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐