基于k8s 平台 jenkins 部署及动态slave节点制作和配置

前期准备

  1. 一个已经部署好的k8s 平台
  2. 一个已经搭建好的harbor 私有仓库

jenkins 部署

 这里 使用主流的rbac 模式部署jenkins 也就是说们们需要创建:
   1. 一个jenkins 命名空间
   2. 一个nodeport  service 用来外部web访问
   3.一个 serviceaccount 用来 保障jenkins 服务器能 访问Jenkins 命名空间下的资源
   3. 一个 clusterRole   用来设置 jenkins 能访问 k8s 哪些资源以及具体权限
   4. 一个 clusterBinding  将 clusterRole 跟 serviceaccount绑定起来 决定这个sa 能访问的范围
   5. 一个 deployment 用来 真正启动jenkins 服务器
   具体jenkins.yaml 如下:
---
# 命名空间
apiVersion: v1
kind: Namespace
metadata:
  name: jenkins

---
#动态存储 pvc 因为我这里用nfs 来存放jenkins 数据,如果你不需要进行数据持久化可以不创建,
#需要的话可以参考我之前文章搭建一个nfs 环境。
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: jenkins-pvc
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 5G
---
# jenkins deployment 启动 jenkins 服务器
apiVersion: apps/v1
kind: Deployment
metadata:
  name: jenkins-master
  namespace: jenkins
spec:
  selector:
    matchLabels:
        app: jenkins-master
  template:
    metadata:
      labels:
        app: jenkins-master
      namespace: jenkins
    spec:
      securityContext:
        fsGroup: 1000
      containers:
      - name: jenkins-master
        image: kanq.k8s.com:7443/devops/jenkins:latest #这里用的是我自己搭建的私有仓库。
        imagePullPolicy: Always
        ports:
        - containerPort: 8080
          name: http
        - containerPort: 50000
          name: agent
        volumeMounts:
        - name: jenkins-master-vol
          mountPath: /var/jenkins_home
      volumes:
      - name: jenkins-master-vol
        persistentVolumeClaim:
          claimName: jenkins-pvc
      serviceAccount: "jenkins-master"

---
#  svc 用来支持外部访问,这里我将jenkins 的 8080 和 50000 都设成了nodeport 型因为我需要 在jenkisn 
# 上外挂 非k8s 集群的节点,还有 k8s 默认的nodeport 节点范围是3000-32767 所以如果想用32768及以上的端口
# 的话一定到将 api-server service-node-port-range 这个启动参数设为你需要的。然后重启api-server 服务
apiVersion: v1
kind: Service
metadata:
  name: jenkins-master
  namespace: jenkins
spec:
  type: NodePort
  ports:
    - port: 8080
      name: http
      targetPort: 8080
      nodePort: 38080
    - port: 50000
      name: agent
      nodePort: 50000
      targetPort: 50000
  selector:
    app: jenkins-master

---
# 使用默认的secert 创建的serviceaccout 给 jenkins pod 提供访问k8s 集群的ssl 认证
apiVersion: v1
kind: ServiceAccount
metadata:
  name: jenkins-master
  namespace: jenkins

---
# 创建一个角色 设置 访问k8s资源类型和权限范围
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: jenkins-master
  namespace: 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: ["secrets"]
  verbs: ["get"]

---
# 将serviceaccount 和 role 绑定 这样配置了这个serviceaccount的pod 就能根据这个role 来规范访问 
# 这个命名空间下的资源数据
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: jenkins-master
  namespace: jenkins

roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: jenkins-master
subjects:
- kind: ServiceAccount
  name: jenkins-master
  namespace: jenkins

kubectl apply -f jenkins.yaml  
正常执行完后 
[root@kanq template]# kubectl get pod -n jenkins
NAME                             READY   STATUS    RESTARTS   AGE
jenkins-master-5c65d6b7f-hx4f2   1/1     Running   0          5d17h
kubectl logs -f jenkins-master-5c65d6b7f-hx4f2 -n jenkins 
....

*************************************************************
*************************************************************
*************************************************************

Jenkins initial setup is required. An admin user has been created and a password generated.
Please use the following password ddto proceed to installation:

4aa4c650ddddee9d46f1b020e2142e2df369  #这个就是你网页登录 http://k8s节点ip:38080 后输入的token

This may also be found at: /var/jenkins_home/secrets/initialAdminPassword 

*************************************************************
*************************************************************
*************************************************************

动态slave 节点制作

 一般直接用 jenkins 自带的就行但是如果不能满足我们的需求 我们可以自己定制。比如我这里需要满足 centos8 版本而且需要里面 可以使用podman  kubectl  等。 
 这里顺便介绍了podman, 后面 docker 已经商业收费了,而且 k8s 也会跟docker 解耦。 再加上 docker 实现dind(容器中可以执行docker 命令比如说docker build docker push )这个在 以容器为jenkins 节点的场景下 非常有必要.。
 比较麻烦的是因为docker 有一个守护进程的原因,需要我们将宿主机的docker.sock 挂载到容器中,限制太大,如果k8s 使用二进制部署,使用containerd 作为容器运行时而不用docker 就会发现宿主机根本就没有docker.sock 咋挂, 额外再安装一个docker?
 如果用 podman 就没有这个顾虑了。因为podman 没有后台运行的 docker.sock 这个守护进程。我们只用对容器内部的podman 做些配置即可。

回归正题 下面是制作 slave 的dockerfile 文件:

#使用centos8 的基础镜像 可以根据 需求修改
#  如果只制作jenkins slave 的话 可以不安装podman 两个sed 命令可以不执行。kubectl 也可以不拷
# slave.jar 下载地址:
#获取agent.jar
#也叫slave.jar,实际jenkins中的remoting
#官网地址
#https://www.jenkins.io/zh/projects/remoting/
#jar包下载地址
#https://repo.jenkins-ci.org/public/org/jenkins-ci/main/remoting/
#获取jenkins-slave
#git地址
#https://github.com/jenkinsci/docker-inbound-agent/blob/master/jenkins-agent
FROM centos:centos8 
RUN mkdir -p /usr/share/jekins && \
    yum install -y java-1.8.0-openjdk podman && \
    sed -i 's/#mount_program/mount_program/g' /etc/containers/storage.conf && \
    sed -i 's/mountopt/#mountopt/g' /etc/containers/storage.conf && \
    chmod +777 /usr/local/bin/jenkins-slave
COPY slave.jar /usr/share/jenkins/slave.jar
COPY jenkins-slave /usr/local/bin/jenkins-slave
COPY kubectl /usr/bin/kubectl

USER root
WORKDIR /home/jenkins
ENTRYPOINT ["jenkins-slave"]
将 slave.tar 跟 jenkins-slave 放在跟Dockerfile 文件同级目录就可以了。
docker build -t centos:jenkins-slave . 

jenkins 配置动态节点

  1. 打开 jenkins 配置找到cloud(一般在 配置页面的最下面)
    在这里插入图片描述

  2. 添加云环境选 kubernetes
    在这里插入图片描述

  3. 配置 kubernetes
    在这里插入图片描述

    a. 设置云平台 信息 名称随便填, 地址 不知道的看下自己的master 节点/root/.kube/config 中的
    server 地址
    在这里插入图片描述

在这里插入图片描述
配置完后 点击连接测试
在这里插入图片描述
b. 配置 jenkins 相关配置 ,这里使用 svc 内部ip 和 端口

[root@kanq jenkins-slave]# kubectl get svc -n jenkins
NAME             TYPE       CLUSTER-IP     EXTERNAL-IP   PORT(S)                          AGE
jenkins-master   NodePort   10.68.185.27   <none>        8080:30180/TCP,50000:50000/TCP   5d19h
这里 10.68.185.27 就是内部clusterip 
端口 是下面的 portip  (port 是集群内部端口  ,nodePort 是宿主机暴露端口, tragetPort 是 容器里面端口 )
所以我们这儿用 集群内部端口 8080 和50000 
kubectl get svc jenkins-master -n jenkins -o  yaml
'''
spec:
  clusterIP: 10.68.185.27
  clusterIPs:
  - 10.68.185.27
  externalTrafficPolicy: Cluster
  ports:
  - name: http
    nodePort: 30180
    port: 8080
    protocol: TCP
    targetPort: 8080
  - name: agent
    nodePort: 50000
    port: 50000
    protocol: TCP
    targetPort: 50000
  selector:
    app: jenkins-master
  sessionAffinity: None
  type: NodePort


在这里插入图片描述
b. 配置pod
名字随便取,但是命名空间要跟jenkins 服务器统一,标签 就是你后面 流水线中配置的节点名称。
在这里插入图片描述
如果使用默认的slave节点 到上一步就直接保存退出就可以了。因为jenkins 这个框架下自带一个jnlp 容器 使用 jenkins/inbound-agent 镜像
如果你想替换默认 pod 的镜像 需要如下配置,名字一定要填jnlp ,工作目录随便, 运行命令和参数不用填
在这里插入图片描述
如果你想再添加一个pod内容器(这种情况在pipline 流水下常见) 点击添加容器 注意这里的工作目录所有的容器要保持一致,这是 pod 内容器共享目录
注: 运行命令,和命令参数填写一定要保证 执行后容器一直运行,不会直接退出(pod 特性,里面启动的容器执行完配置的命令后会自动退出,这里如果不填它会执行镜像本身配置的命令)。不然会出现pod notready 情况
这也是曾困扰了一天的问题。所以这里最简单的我直接用sleep 99999 保障 容器一直运行,
在这里插入图片描述在这里插入图片描述

主要的配置就上面那些 还有其他 挂载卷,环境变量等。 这里就不一一介绍了。
注:
1. 这里挂的卷,配的环境变量会挂在所有容器中。不能自定义哪几个容器用哪几个变量和卷
2. 还有 对于多容器的jenkins slave 配置 只用保证 名为jnlp 这个 容器中安装了jenkins slave 相关工具就可以了,其他容器不用安装,而且即使安装了你的容器名如果不是jnlp 相关参数也不会传给你这个pod ,从而导致 容器运行失败(如果你的容器启动命令也是java-slave)。

下面介绍一种 在pipline中 配置 pod 模板的方法。 比上面页面配置就自主多了,可以自定义容器挂载的卷和 环境变量。做到每个容器 对应自己的配置
下面是我编写的一个声明式的pipline,当代码提交通过webhook 触发后 执行这个pipline. 主要做的就是:

  1. 配置 云kubernetes 的pod 模板
  2. 默认的jnlp 容器(镜像自己制作的添加了git)中 下载代码,
  3. build 容器中编译代码(使用的docker.hub 上下的golang:v1.17)
  4. podman 容器(安装了podman)中build镜像,并push 到私有仓库,然后执行kubectl create 命令用这个镜像启动一个deployment ,不成功异常退出,成功后删除启动的deployment
  5. 根据运行情况,发送邮件给代码提交人
def webHookData = readJSON text: "${head_commit}"
String commitID= webHookData["id"][0..7]
String url=webHookData.url
//String head_commit_author_email = 
realJenkinsUrl=BUILD_URL.replaceAll("172.16.3.154:30180","113.57.110.41:15401")
pipeline{
    agent {
        kubernetes{
            yaml '''
                apiVersion: "v1"
                kind: "Pod"
                metadata:
                  name: "devops"
                spec:
                  containers:
                  #  如果 默认的jenkins/inbound-agent满足你的需求可以跟 上面页面那样不配置
                  - name: "jnlp"
                    image: "kanq.k8s.com:7443/devops/centos-slave-jnlp-git:latest"
                    imagePullPolicy: "IfNotPresent"
                    volumeMounts:
                    - mountPath: "/home/jenkins/agent"
                      name: "workspace-volume"
                      readOnly: false
                    workingDir: "/home/jenkins/agent"
                  # 编译用镜像,记住一定要保证容器一直运行
                  - name: "build"
                    args:
                    - "999999"
                    command:
                    - "sleep"
                    image: "kanq.k8s.com:7443/devops/golang:1.17"
                    imagePullPolicy: "IfNotPresent"
                    name: "build"
                    volumeMounts:
                    - mountPath: "/home/jenkins/agent"
                      name: "workspace-volume"
                      readOnly: false
                    workingDir: "/home/jenkins/agent"
                  # 用于镜像制作,推库 ,部署 验证。
                  - name: "podman"
                    args:
                    - "999999"
                    command:
                    - "sleep"
                    env:
                    - name: HarborU
                      valueFrom:
                        secretKeyRef:
                          name: harbor
                          key: username
                    - name: HarborP
                      valueFrom:
                        secretKeyRef:
                          name: harbor
                          key: password
                    image: "kanq.k8s.com:7443/devops/centos-slave-podman-kubectl:latest"
                    imagePullPolicy: "IfNotPresent"
                    securityContext:
                      privileged: true
                    volumeMounts:
                    - mountPath: "/etc/containers/certs.d/kanq.k8s.com/"
                      name: podman
                    - mountPath: "/home/"
                      name: k8sconfigmap
                    - mountPath: "/home/jenkins/agent"
                      name: "workspace-volume"
                      readOnly: false
                    workingDir: "/home/jenkins/agent"
                  activeDeadlineSeconds: 60000
                  volumes:
                  - emptyDir:
                      medium: ""
                    name: "workspace-volume"
                  - secret:
                      secretName: dockersecret
                    name: podman
                  - secret:
                      secretName: harbor
                    name: harbor
                  - configMap:
                      name: k8sconfig
                    name: k8sconfigmap
            '''
        }
    }
    stages {
        
        stage('git') {
            steps {
                container("jnlp"){
                    sh """ 
                        git clone git@e.coding.net:kanqtest/kanq/kanqtest.git
                        env
                    """
                }
            }
            
        }
        stage("compile"){
            
            steps {
                container("build"){
                    dir("$WORKSPACE/kanqtest"){
                        sh """
                            go build -a -o devops-go-sample cmd/main.go
                        """
                    }
                }
                
            }
        }
        stage("build"){
            steps {
                container("podman"){
                    dir("$WORKSPACE/kanqtest"){
                        sh '''
                            cp -r /etc/containers/certs.d/kanq.k8s.com /etc/containers/certs.d/kanq.k8s.com:7443
                            echo "172.16.3.154 kanq.k8s.com" >>/etc/hosts
                            echo $HarborP |podman login -u $HarborU --password-stdin kanq.k8s.com:7443
                            podman build -t kanq.k8s.com:7443/devops/busybox:go .
                            podman push kanq.k8s.com:7443/devops/busybox:go
                            kubectl create deployment devopstest --image="kanq.k8s.com:7443/devops/busybox:go" -n jenkins
                            sleep 6s
                            heal=$(kubectl get pod -n jenkins|grep devopstest|grep Running)
                       
                            if [[ "$heal" == "" ]];then
                                exit -1
                            fi
                            kubectl delete deployment devopstest -n jenkins
                        '''
                    }
                }
                
            }
        }
    }
    post{
      always{
          sh "echo $commitID"
          sh "echo $url"
          addShortText background: 'white', borderColor: 'white', color: 'DodgerBlue', link: "$url", text: "$commitID"
          mail bcc: '', body: """
          代码coding 地址:'${head_commit_url}'
          jenkins 地址: '${realJenkinsUrl}'
          """, cc: '', from: '2833732855@qq.com', replyTo: '', subject: "kanq devops success!!!!", to: "$head_commit_author_email"
      
      }
  }

}

  • 4
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值