摘要
1、kubernetes与Jenkis架构
Jenkins Master 和 Jenkins Slave 以 Pod 形式运行在 Kubernetes 集群的 Node 上,Master是常驻服务,所有的配置数据都存储在一个 Volume 中,Slave 不是一直处于运行状态,它会按照需求动态的创建并自动删除。
2、工作原理
当 Jenkins Master 接受到 Build 请求时,会根据配置的 Label 动态创建一个运行在 Pod 中的 Jenkins Slave 并注册到 Master 上,当运行完 Job 后,这个 Slave 会被注销并且这个 Pod 也会自动删除,恢复到最初状态。
3、优势
相对于部署在虚拟机环境下的Jenkins一主多从架构,将Jenkins部署到K8S会带来以下好处:
服务高可用: 当 Jenkins Master 出现故障时,Kubernetes 会自动创建一个新的 Jenkins Master 容器,并且将 Volume 分配给新创建的容器,保证数据不丢失,从而达到集群服务高可用。
动态伸缩: 合理使用资源,每次运行 Job 时,会自动创建一个 Jenkins Slave,Job 完成后,Slave 自动注销并删除容器,资源自动释放,而且 Kubernetes 会根据每个资源的使用情况,动态分配 Slave 到空闲的节点上创建,降低出现因某节点资源利用率高,还排队等待在该节点的情况。
扩展性:当 Kubernetes 集群的资源严重不足而导致 Job 排队等待时,可以很容易的添加一个 Kubernetes Node 到集群中,从而实现扩展。
开始
Step 1:部署Jenkins
1、创建一个名为 jenkins 的 namespace:
kubectl create namespace jenkins
2、声明一个PVC对象,用做存储
kubectl apply -f https://www.kubebiz.com/raw/KubeBiz/jenkins/latest/PersistentVolumeClaim.yaml
3、以Deployment方式部署Jenkins master
kubectl apply -f https://www.kubebiz.com/raw/KubeBiz/jenkins/latest/Deployment.yaml
4、暴露服务
创建一个 NodePort 类型的服务:
kubectl apply -f https://www.kubebiz.com/raw/KubeBiz/jenkins/latest/NodePort.yaml
查看:
kubectl get svc -n jenkins
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
jenkins-export NodePort 10.100.145.138 <none> 8080:32080/TCP 24s
服务启动成功后,就可以通过 NodePort 访问 jenkins 服务了。
5、创建一个名为 jenkins2 的 ServiceAccount ,并且为其赋予特定的权限,之后在配置Jenkins-Slave
时会用到。
kubectl apply -f https://www.kubebiz.com/raw/orchome/jenkins/latest/rbac.yaml
Step 2:安装Kubernetes插件
1、前面我们已经获取到Jenkins的外网IP地址,我们直接在浏览器输入NodeIP:32080
,提示需要输入初始化密码,需要先获取jenkins pod名称:
# kubectl get pods -n jenkins
NAME READY STATUS RESTARTS AGE
jenkins-deployment-55f9896fbd-cv5kd 1/1 Running 0 2m19s
2、然后通过 kubectl exec 获取 jenkins 获取初始化密码
kubectl exec jenkins-deployment-55f9896fbd-cv5kd -n jenkins -- cat /var/jenkins_home/secrets/initialAdminPassword
返回密码:
035d0b616c9942fd9b1eeb8fcc8469b4
3、选择推荐安装,添加完管理员帐号admin,即可进入到 jenkins 主界面。
4、接下来安装jenkins依赖插件。
位置 Manage Jenkins -> Manage Plugins -> Available -> Kubernetes勾选安装即可。
kubernets插件,它能够动态的生成 Slave 的 Pod。
安装插件相对较慢,请耐心等待,并且由于是在线安装,集群需要开通外网。
Step 3:配置Jenkins
接下来将进入最重要的一个步骤,在Kubernetes插件安装完毕后,我们需要配置Jenkins和Kubernetes参数,使Jenkins连接到K8S集群,并能调用Kubernetes API 动态创建Jenkins Slave,执行构建任务。
点击进入 Manage Jenkins —> Manage nodes and clouds,
然后点击 Configure Clouds -> 选择 Kubernetes。
输入Kubernetes Apiserver
地址,以及服务证书key
。
Apiserver的位置在:
cat /etc/kubernetes/admin.conf
服务证书key是集群凭证中的certificate-authority-data
字段内容
cat /etc/kubernetes/admin.conf | grep certificate-authority-data
进行base64
解码
echo "LS0tLS1C....省略....CBDRVJUSUZJQ0FURS0tLS0tCg==" | base64 -d
填写集群Namespace、上传凭据、Jenkins地址
Namespace此处填写之前创建Namespace即可,此处为jenkins。凭证处,点击”Add“,凭证类型选择"Secret file",将Kubernetes集群详情页全部内容复制下来,保存为kubeconfig上传。
点击”连接测试“,如果出现 Connected to Kubernetes v1.2x.x
的提示信息证明 Jenkins 已经可以和 Kubernetes 系统正常通信了。
接下来,我们点击”添加Pod模板“,这个Pod模板即Jenkins-slave pod的模板。
- namespace,我们这里填 ”jenkins“
- 标签列表,这里我们填
jnlp-slave
,这个标签我们在后面创建Jobs会用到,非常重要。 - 用法,选择 ”尽可能使用这个节点“
- 镜像,填写”jenkins/jnlp-slave:latest-jdk11“,这个容器镜像是我们CI/CD的运行环境。
选择添加卷,主机路径和挂载路径都填写为”/var/run/docker.sock“,使得jenkins-slave可以使用宿主机的Docker,让我们可以在容器中进行镜像Build等操作。
点击最下方的Advanced,Service Account 输入jenkins2,这是我们之前创建的SA。
其他几个参数由于只是演示,我们都使用默认值,在实际使用的时候,请自行选择合理的参数。到这里我们的 Kubernetes Plugin 插件就算配置完成了。
Step 4:运行一个简单任务
Kubernetes 插件的配置工作完成了,接下来我们就来添加一个 Job 任务,看是否能够在 Slave Pod 中执行,任务执行完成后看 Pod 是否会被销毁。
1、在 Jenkins 首页点击create new jobs,创建一个测试的任务,输入任务名称,然后我们选择 Freestyle project 类型的任务,点击OK。
2、在任务配置页,最下面的 Label Expression 这里要填入jnlp-slave,就是前面我们配置的 Slave Pod 中的 Label,这两个地方必须保持一致
3、在任务配置页的 Build 区域,选择Execute shell,输入一个简单的测试命令,并点击保存。
4、构建,可以在这里看到已经new了一个job
5、完成后,点击查看Console output,查看任务运行情况。
到这里我们就完成了使用 Kubernetes 动态生成 Jenkins Slave 了。
Step 6、运行一个pipeline任务
pipeline介绍
Pipeline,简单来说,就是一套运行在 Jenkins 上的工作流(流水线)框架,将原来独立运行于单个或者多个节点的任务连接起来,实现单个任务难以完成的复杂流程编排和可视化的工作。Jenkins Pipeline 有几个核心概念:
Node:节点,一个 Node 就是一个 Jenkins 节点,是执行 Step 的具体运行环境,比如我们之前动态运行的 Jenkins Slave 就是一个 Node 节点。
Stage:阶段,一个 Pipeline 可以划分为若干个 Stage,每个 Stage 代表一组操作,比如:Build、Test、Deploy,Stage 是一个逻辑分组的概念,可以跨多个 Node。
Step:步骤,Step 是最基本的操作单元,可以是打印一句话,也可以是构建一个 Docker 镜像,由各类 Jenkins 插件提供,比如命令:sh ‘make’,就相当于我们平时 shell 终端中执行 make 命令一样。
创建pipeline任务
Pipeline 有两种创建方法,一是直接在 Jenkins 的 Web UI 界面中输入脚本,二是通过创建一个 Jenkinsfile 脚本文件放入项目源码库中,这里为了方便演示,我们使用在 Web UI 界面中输入脚本的方式来运行Pipeline。
1、 点击”new item“,输入Job名称,选择Pipeline,点击"OK"。
2、 在最下方的pipeline 脚本部分,输入以下脚本内容,并点击保存
node('jnlp-slave') {
stage('Clone') {
echo "1.Clone Stage"
}
stage('Test') {
echo "2.Test Stage"
}
stage('Build') {
echo "3.Build Stage"
}
stage('Deploy') {
echo "4. Deploy Stage"
}
}
上面的脚本内容中,我们给 node 添加了一个 jnlp-slave 标签,指定这个pipeline的4个stage,都运行在jenkins的slave节点中。
3、任务创建好之后,点击”立即构建“,我们可以通过kubectl命令发现UK8S集群中正启动一个新的pod用于构建任务。
bash-4.4# kubectl get po -n jenkins
NAME READY STATUS RESTARTS AGE
jnlp-0qn7x 0/1 ContainerCreating 0 1s
4、 回到 Jenkins 的 Web UI 界面中查看 本次构建历史的 Console Output,也可以类似如下的信息,表明构建成功
Started by user admin
[Pipeline] Start of Pipeline
[Pipeline] node
Agent jnlp-vjcdm is provisioned from template jnlp
---
apiVersion: "v1"
kind: "Pod"
metadata:
labels:
jenkins: "slave"
jenkins/label-digest: "bb74484d3d8cfdd5465f289d1fe175836bf9e531"
jenkins/label: "jnlp-slave"
name: "jnlp-vjcdm"
namespace: "jenkins"
spec:
containers:
- env:
- name: "JENKINS_SECRET"
value: "********"
- name: "JENKINS_AGENT_NAME"
value: "jnlp-vjcdm"
- name: "JENKINS_NAME"
value: "jnlp-vjcdm"
- name: "JENKINS_AGENT_WORKDIR"
value: "/home/jenkins/agent"
- name: "JENKINS_URL"
value: "http://192.168.40.147:8080/"
image: "jenkins/jnlp-slave:latest-jdk11"
imagePullPolicy: "IfNotPresent"
name: "jnlp"
resources:
limits: {}
requests: {}
tty: false
volumeMounts:
- mountPath: "/home/jenkins/agent"
name: "workspace-volume"
readOnly: false
workingDir: "/home/jenkins/agent"
hostNetwork: false
nodeSelector:
kubernetes.io/os: "linux"
restartPolicy: "Never"
serviceAccountName: "jenkins2"
volumes:
- emptyDir:
medium: ""
name: "workspace-volume"
Running on jnlp-vjcdm in /home/jenkins/agent/workspace/pipeline
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Clone)
[Pipeline] echo
1.Clone Stage
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (Test)
[Pipeline] echo
2.Test Stage
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (Build)
[Pipeline] echo
3.Build Stage
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (Deploy)
[Pipeline] echo
4. Deploy Stage
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS
step1第2步部署pvc的时候不用部署pv吗,第3步的部署deploy会报错:pod has unbound immediate PersistentVolumeClaims
你的kubernetes没有配置自动生成pv,你就自己创建吧。