基于Kubernetes pod完成分布式构建及build、push image
需要在jenkins上部署kubernetes插件
对于处于集群外部的Jenkins
添加云节点
kubernetes地址kubeapi.magedu.com,为k8s集群的对外访问地址,以次来进行访问集群
在jenkins上对此地址进行解析
vim /etc/hosts
172.29.6.1 kubeapi.magedu.com
获取集群的证书,把证书粘贴到配置中
cd /etc/kubernetes/pki
cat ca.crt
将Service Account的Token保存为Jenkins上的认证凭据
创建新凭据
确保pod能解析jenkins.magedu.com:50000
(没有DNS服务器,需要给每个pod加上host记录)
查看coredns服务
kubectl get cm -n kube-system
coredns
把该文件原有配置取出来,做修改
kubectl get cm coredns -o yaml -n kube-system
vim configmap-coredns.yaml
kubectl apply -f configmap-coredns.yaml
添加pod模板
配置声明式示例
pipeline {
agent {
kubernetes {
inheritFrom 'kube-agent'
}
}
stages {
stage('Testing...') {
steps {
sh '''
java -version
echo ${NODE_NAME}
'''
}
}
}
}
立即构建
构建复杂的环境(在节点管理中的pod template之上,在添加pod模板)
添加容器
添加卷,做持久化保存(创建的任何一个pod下载的maven的缓存都放在卷上,任何pod只要基于该模板创建的,都能加载共享的内容)
在k8s上查看pvc
kubectl get pvc -n jenkins
pvc-maven-cache Bound
基于kubernetes完成构建功能(其中构建、测试、代码质量扫描指定在maven容器中运行)
pipeline {
agent {
kubernetes {
inheritFrom 'kube-maven'
}
}
parameters {
booleanParam(name:'pushImage', defaultValue: 'true', description: 'Push Image to Harbor?')
}
tools {
maven 'maven-3.8.7'
}
triggers {
GenericTrigger(
genericVariables: [
[key: 'ref', value: '$.ref']
],
token: 'fClZ0e/kTcqL2ARh7YqxW/3ndOCZA2SqfKnRTLat',
causeString: 'Triggered on $ref',
printContributedVariables: true,
printPostContent: true
)
}
environment {
codeRepo="http://gitlab.mengfanchao.com/root/spring-boot-helloWorld.git"
harborServer='harbor.meng.org'
projectName='spring-boot-helloworld'
imageUrl="${harborServer}/ikubernetes/${projectName}"
imageTag='latest'
}
stages {
stage('Source') {
steps {
git branch: 'main', credentialsId: 'gitlab-root-credential', url: "${codeRepo}"
}
}
stage('Build') {
steps {
container('maven') {
sh 'mvn -B -DskipTests clean package'
}
}
}
stage('Test') {
steps {
container('maven') {
sh 'mvn test'
}
}
}
stage("SonarQube Analysis") {
steps {
container('maven') {
withSonarQubeEnv('SonarQube-Server') {
sh 'mvn sonar:sonar'
}
}
}
}
stage("Quality Gate") {
steps {
timeout(time: 30, unit: 'MINUTES') {
waitForQualityGate abortPipeline: true
}
}
}
}
post {
always {
mail to: '1153454651@qq.com',
subject: "Status of pipeline: ${currentBuild.fullDisplayName}",
body: "${env.BUILD_URL} has result ${currentBuild.result}"
}
}
}
立即构建
镜像build和push
节点管理--云节点--kubernetes集群--添加pod模板,定义成先继承上面添加的maven,在添加dind
父级的pod模板名称,就相当于继承
添加容器
添加卷host path volume 把宿主机的某个路径与容器的某个路径建立关联关系
修改之前的流水线,添加上具有docker镜像build和docker镜像push的功能
pipeline {
agent {
kubernetes {
inheritFrom 'maven-and-docker' #不在使用maven模板,使用maven-and-docker模板
}
}
triggers {
GenericTrigger(
genericVariables: [
[key: 'ref', value: '$.ref']
],
token: 'fClZ0e/kTcqL2ARh7YqxW/3ndOCZA2SqfKnRTLat',
causeString: 'Triggered on $ref',
printContributedVariables: true,
printPostContent: true
)
}
environment {
codeRepo="http://gitlab.mengfanchao.com/root/spring-boot-helloWorld.git"
harborServer='harbor.meng.org'
projectName='spring-boot-helloworld'
imageUrl="${harborServer}/ikubernetes/${projectName}"
imageTag="${BUILD_ID}"
}
stages {
stage('Source') {
steps {
git branch: 'main', credentialsId: 'gitlab-root-credential', url: "${codeRepo}"
}
}
stage('Build') {
steps {
container('maven') {
sh 'mvn -B -DskipTests clean package'
}
}
}
stage('Test') {
steps {
container('maven') {
sh 'mvn test'
}
}
}
stage("SonarQube Analysis") {
steps {
container('maven') {
withSonarQubeEnv('SonarQube-Server') {
sh 'mvn sonar:sonar'
}
}
}
}
stage("Quality Gate") {
steps {
timeout(time: 30, unit: 'MINUTES') {
waitForQualityGate abortPipeline: true
}
}
}
stage('Build Image') {
steps {
container('dind') {
sh 'docker image build -t ${imageUrl}:${imageTag} .'
}
}
}
stage('Push Image') {
steps {
withCredentials([usernamePassword(credentialsId: 'harbor-user-credential', passwordVariable: 'harborUserPassword', usernameVariable: 'harborUserName')]) {
container('dind') {
sh ''' #当在一个内部需要运行多条shell命令的时候,可以三引号,不必每一步写shell
echo ${harborUserPassword} | docker login -u ${harborUserName} --password-stdin ${harborServer}
docker image push ${imageUrl}:${imageTag}
docker image tag ${imageUrl}:${imageTag} ${imageUrl}:latest
docker image push ${imageUrl}:latest
'''
}
}
}
}
}
post {
always {
mail to: '1153454651@qq.com',
subject: "Status of pipeline: ${currentBuild.fullDisplayName}",
body: "${env.BUILD_URL} has result ${currentBuild.result}"
}
}
}
此时需要注意的是,需要在整个k8s的节点上对域名进行解析
cat /etc/hosts
172.29.9.200 hub.magedu.com
另外还要确保整个k8s的节点不去强验证harbor的证书
cat /etc/docker/daemon.json
[root@ubuntu2004 ~]#cat /etc/docker/daemon.json
{
"registry-mirrors": [
"https://registry.docker-cn.com"
],
"exec-opts": ["native.cgroupdriver=systemd"],
"insecure-registries": ["hub.magedu.com"]
}
可登录测试是否完成以上两步
docker login hub.magedu.com
Username:magedu
Password:
显示Login Succeeded,表示每个节点对接hub.magedu.com成功
无误后进行触发
在Pod Agent中制作和推送Docker Image的另一种方法
Docker Pipline插件提供了一个名为docker的全局变量,以docker变量作为入口,可以调用该插件的所有功能。
build(image):基于当前工作目录下的Dockerfile构建Image,其name和tag则由“image”指定;
push():推送构建好的Image对象;
push('tag'):将构建好的Image对象上的tag替换为此处指定的tag,并完成push;
pipeline {
agent {
kubernetes {
inheritFrom 'maven-and-docker' #不在使用maven模板,使用maven-and-docker模板
}
}
triggers {
GenericTrigger(
genericVariables: [
[key: 'ref', value: '$.ref']
],
token: 'fClZ0e/kTcqL2ARh7YqxW/3ndOCZA2SqfKnRTLat',
causeString: 'Triggered on $ref',
printContributedVariables: true,
printPostContent: true
)
}
environment {
codeRepo="http://gitlab.mengfanchao.com/root/spring-boot-helloWorld.git"
registry='harbor.meng.org'
registryCredential='harbor-user-credential'
projectName='spring-boot-helloworld'
imageUrl="${registry}/ikubernetes/${projectName}"
imageTag="${BUILD_ID}"
}
stages {
stage('Source') {
steps {
git branch: 'main', credentialsId: 'gitlab-root-credential', url: "${codeRepo}"
}
}
stage('Build') {
steps {
container('maven') {
sh 'mvn -B -DskipTests clean package'
}
}
}
stage('Test') {
steps {
container('maven') {
sh 'mvn test'
}
}
}
stage("SonarQube Analysis") {
steps {
container('maven') {
withSonarQubeEnv('SonarQube-Server') {
sh 'mvn sonar:sonar'
}
}
}
}
stage("Quality Gate") {
steps {
timeout(time: 30, unit: 'MINUTES') {
waitForQualityGate abortPipeline: true
}
}
}
stage('Build Image') {
steps {
container('dind') {
script {
dockerImage = docker.build("${imageUrl}:${imageTag}")
}
}
}
}
stage('Push Image') {
steps {
container('dind') {
script {
docker.withRegistry(registryUrl, registryCredential) {
dockerImage.push()
dockerImage.push('latest')
}
}
}
}
}
}
post {
always {
mail to: '1153454651@qq.com',
subject: "Status of pipeline: ${currentBuild.fullDisplayName}",
body: "${env.BUILD_URL} has result ${currentBuild.result}"
}
}
}