一、Jenkins + K8S + Gitlab构建RLEASE打包发布更新流水线到K8S集群

1.1 Jenkins + K8S + Gitlab构建RLEASE打包发布更新流水线到K8S集群

获取运行中deploy的yaml -> 上传到gitlab -> 更新Container Image (打包jar包 -> 创建新的Image -> 上传Image到Docker Hub) -> 上传到gitlab (yaml) -> 将新的yaml apply 到集群中

1.2 配置Prod-Release流水线构建镜像

1.2.1 Release测试流水线

  • 代码 -> 编译 -> 单测 -> 打包 -> 扫描 -> 接口测试 -> 镜像 -> 发布 -> 生成版本文件 -> 邮件通知

Alt Image Text

1.2.2 Docker in Docker配置

你可以在K8S 集群中 Run K8S Pod as Agent

- name: dockersock
   hostPath: 
    path: /var/run/docker.sock
- name: dockercmd
   hostPath: 
    path: /usr/local/bin/docker

1.2.3 创建一个凭据存储registry仓库的账号和密码

ID: docker-registry-admin

Alt Image Text

1.2.4 添加Dockerfile到 项目中demo-maven-service

Dockerfile

FROM  openjdk:8-alpine
MAINTAINER devops

ADD target/*.jar /app.jar

## 执行命令
ENTRYPOINT ["java","-jar","/app.jar"]

1.2.5 创建BuildImage pipeline

stage("BuildImages"){
                steps{
                    script{
                        env.serviceName = "${JOB_NAME}".split("_")[0]

                        withCredentials([usernamePassword(credentialsId: 'docker-registry-admin', passwordVariable: 'password', usernameVariable: 'username')]) {

                           env.dockerImage = "nyjxi/${serviceName}:${branchName}"
                           sh """
                               docker login -u ${username} -p ${password} 
                               docker build -t nyjxi/${serviceName}:${branchName} .
                               sleep 1
                               docker push nyjxi/${serviceName}:${branchName}
                               sleep 1
                               #docker rmi nyjxi/devopstest/${serviceName}:${branchName}
                            """
                        }
                    }
                }
            }

1.2.6 Pipeline Name: demo-java-service_UAT

  • https://github.com/Chao-Xi/JenkinslibTest/blob/master/src/org/devops/gitlab.groovy
  • https://github.com/Chao-Xi/JenkinslibTest/blob/master/src/org/devops/kubernetes.groovy
#!groovy
@Library('jenkinslib@master') _

def k8s = new org.devops.kubernetes()
def gitlab = new org.devops.gitlab()
def build = new org.devops.buildtools()

pipeline {
    agent { node { label "vagrant-agent" }}
    parameters {
        string(name: 'srcUrl', defaultValue: 'http://192.168.33.1:30088/root/demo-maven-service.git', description: '') 
        choice(name: 'versionName', choices: '1.0\n1.1\n1.2\n1.3', description: 'Please chose your versionName')
        choice(name: 'branchName', choices: 'master\nstage\ndev', description: 'Please chose your branch')
        choice(name: 'buildType', choices: 'mvn', description: 'build tool')
        choice(name: 'buildShell', choices: 'clean package -DskipTest\n--version', description: 'build tool')

    }
    stages{
        stage('Checkout') {
            steps {
                script {
                    checkout([$class: 'GitSCM', branches: [[name: "${branchName}"]], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: 'gitlab-admin-user', url: "${srcUrl}"]]])
                } 
            }
        }

        stage('Build') {
            steps {
                script {
                    build.Build(buildType,buildShell)
                } 
            }
        }

        // 构建镜像
           stage("BuildImages"){
                steps{
                    script{
                        env.serviceName = "${JOB_NAME}".split("_")[0]

                        withCredentials([usernamePassword(credentialsId: 'docker-registry-admin', passwordVariable: 'password', usernameVariable: 'username')]) {

                           env.dockerImage = "nyjxi/${serviceName}:${branchName}"
                           sh """
                               docker login -u ${username} -p ${password} 
                               docker build -t nyjxi/${serviceName}:${branchName} .
                               sleep 1
                               docker push nyjxi/${serviceName}:${branchName}
                               sleep 1
                               #docker rmi nyjxi/devopstest/${serviceName}:${branchName}
                            """
                        }
                    }
                }
            }

        //连入部署集群
        stage("GetDeployment"){
            agent { node { label "master" }}
            steps{
                script{
                    response = k8s.GetDeployment("demo-prod","demoapp")
                    response = response.content

                    //文件转换
                    base64Content = response.bytes.encodeBase64().toString()

                    //上传文件
                    // gitlab.CreateRepoFile(3,"demo-prod%2f${versionName}-prod.yaml",base64Content)

                }  
            }
        }

    }
}

连入K8S部署集群

 stage("GetDeployment"){
     agent { node { label "master" }}
    ....

Console Output

...
[Pipeline] withCredentials
Masking supported pattern matches of $username or $password
[Pipeline] {
[Pipeline] sh
+ docker login -u **** -p ****
WARNING! Using --password via the CLI is insecure. Use --password-stdin.
WARNING! Your password will be stored unencrypted in /home/vagrant/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded
+ docker build -t ****/demo-java-service:master .
Sending build context to Docker daemon  150.5kB
...
Successfully built 478beebd8a2f
Successfully tagged ****/demo-java-service:master
+ sleep 1
+ docker push ****/demo-java-service:master
The push refers to repository [docker.io/****/demo-java-service]
30c0b2f82718: Preparing
ceaf9e1ebef5: Preparing
9b9b7f3d56a0: Preparing
f1b5933fe4b5: Preparing
9b9b7f3d56a0: Mounted from library/openjdk
f1b5933fe4b5: Mounted from library/openjdk
ceaf9e1ebef5: Mounted from library/openjdk
30c0b2f82718: Pushed
master: digest: sha256:e5e037dfcb67f85dce10ebd98d8cd8278e6b8378f26a4980dafe4a795e532b8b size: 1155
+ sleep 1
[Pipeline] }
...

Image被push到 dockerhub中

Alt Image Text

1.3 获取Gitlab Release发布文件(k8s-yaml文件)

1.3.1 gitlab API获取文件内容

def GetRepoFile(projectId,filePath){
    apiUrl = "projects/${projectId}/repository/files/${filePath}/raw?ref=master"
    response = HttpReq('GET',apiUrl,'')
    return response.content
}

1.3.2 Pipeline调用gitlab API获取 部署文件

stage('Deploy') {
            steps {
                    script{
                        //下载版本库文件 
                        // releaseVersion = "${branchName}".split("-")[-1]
                        releaseVersion = "${versionName}"
                        response = gitlab.GetRepoFile(3,"demo-prod%2f${releaseVersion}-prod.yaml")
                    }
                } 
            }
  • projectId: 3
  • filePath: demo-prod%2f${releaseVersion}-prod.yaml

  • demo-info-test/-/blob/master/demo-prod/1.0-prod.yaml

Alt Image Text

完整Pipeline

#!groovy
@Library('jenkinslib@master') _

def k8s = new org.devops.kubernetes()
def gitlab = new org.devops.gitlab()
def build = new org.devops.buildtools()

pipeline {
    agent { node { label "vagrant-agent" }}
    parameters {
        string(name: 'srcUrl', defaultValue: 'http://192.168.33.1:30088/root/demo-maven-service.git', description: '') 
        choice(name: 'versionName', choices: '1.0\n1.1\n1.2\n1.3', description: 'Please chose your versionName')
        choice(name: 'branchName', choices: 'master\nstage\ndev', description: 'Please chose your branch')
        choice(name: 'buildType', choices: 'mvn', description: 'build tool')
        choice(name: 'buildShell', choices: 'clean package -DskipTest\n--version', description: 'build tool')

    }
    stages{
        stage('Checkout') {
            steps {
                script {
                    checkout([$class: 'GitSCM', branches: [[name: "${branchName}"]], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: 'gitlab-admin-user', url: "${srcUrl}"]]])
                } 
            }
        }

      stage('Deploy') {
            steps {
                    script{
                        //下载版本库文件 
                        // releaseVersion = "${branchName}".split("-")[-1]
                        releaseVersion = "${versionName}"
                        response = gitlab.GetRepoFile(3,"demo-prod%2f${releaseVersion}-prod.yaml")
                    }
                } 
            }
    }

Console Output

...
Masking supported pattern matches of $gitlabToken
[Pipeline] {
[Pipeline] httpRequest
HttpMethod: GET
URL: http://192.168.33.1:30088/api/v4/projects/3/repository/files/demo-prod%2f1.0-prod.yaml/raw?ref=master
Content-Type: application/json
PRIVATE-TOKEN: *****
Sending request to url: http://192.168.33.1:30088/api/v4/projects/3/repository/files/demo-prod%2f1.0-prod.yaml/raw?ref=master
Response Code: HTTP/1.1 200 OK
Response: 
apiVersion: apps/v1
kind: Deployment
metadata:
...

1.4 更新release流水线yaml(镜像)发布文件

1.4.1 gitlab API更新文件内容

//更新文件内容
def UpdateRepoFile(projectId,filePath,fileContent){
    apiUrl = "projects/${projectId}/repository/files/${filePath}"
    reqBody = """{"branch": "master","encoding":"base64", "content": "${fileContent}", "commit_message": "update a new file"}"""
    response = HttpReq('PUT',apiUrl,reqBody)
    println(response)

}

1.4.2 在pipeline中更新dockerImage并上传覆盖gitlab原有文件

stage('Pre-deploy') {
            steps {
                    script{
                        //下载版本库文件 
                        // releaseVersion = "${branchName}".split("-")[-1]
                        releaseVersion = "${versionName}"
                        response = gitlab.GetRepoFile(3,"demo-prod%2f${releaseVersion}-prod.yaml")

                        //获取文件中内容(镜像)
                        fileData = readYaml text: """${response}"""
                        println(fileData["spec"]["template"]["spec"]["containers"][0]["image"])
                        println(fileData["metadata"]["resourceVersion"])

                        // 更新新的镜像
                        dockerImage = "nyjxi/demo-java-service:master"
                        OldImage = fileData["spec"]["template"]["spec"]["containers"][0]["image"]
                        response = response.replace(OldImage,dockerImage)
                        println(response)

                        //更新gitlab文件内容
                        base64Content = response.bytes.encodeBase64().toString()
                        gitlab.UpdateRepoFile(3,"demo-prod%2f${releaseVersion}-prod.yaml",base64Content)
                    }
                } 
            }

Console output

....
spec:
      containers:
      - image: nyjxi/demo-java-service:master
        imagePullPolicy: IfNotPresent
        name: demoapp
        ports:
        - containerPort: 8080
 ...
 [Pipeline] withCredentials
Masking supported pattern matches of $gitlabToken
[Pipeline] {
[Pipeline] httpRequest
HttpMethod: PUT
URL: http://192.168.33.1:30088/api/v4/projects/3/repository/files/demo-prod%2f1.0-prod.yaml
Content-Type: application/json
PRIVATE-TOKEN: *****
Sending request to url: http://192.168.33.1:30088/api/v4/projects/3/repository/files/demo-prod%2f1.0-prod.yaml
Response Code: HTTP/1.1 200 OK
Response: 
{"file_path":"demo-prod/1.0-prod.yaml","branch":"master"}
Success code from [100‥399]
[Pipeline] }
[Pipeline] // withCredentials
[Pipeline] echo
Status: 200
[Pipeline] }

Alt Image Text

1.5 配置Prod-Release流水线应用发布

1.5.1 Kubernetes API更新Deployment

def UpdateDeployment(nameSpace,deployName,deplyBody){
    apiUrl = "namespaces/${nameSpace}/deployments/${deployName}"
    response = HttpReq('PUT',apiUrl,deplyBody)
    println(response)
}

1.5.2 Pipeline调用API更新Deployment

stage('Pre-deploy') {
            steps {
                    script{
                        //下载版本库文件 
                        // releaseVersion = "${branchName}".split("-")[-1]
                        releaseVersion = "${versionName}"
                        response = gitlab.GetRepoFile(3,"demo-prod%2f${releaseVersion}-prod.yaml")

                        //获取文件中内容(镜像)
                        fileData = readYaml text: """${response}"""
                        println(fileData["spec"]["template"]["spec"]["containers"][0]["image"])
                        println(fileData["metadata"]["resourceVersion"])

                        // 更新新的镜像
                        dockerImage = "nyjxi/demo-java-service:master"
                        oldImage = fileData["spec"]["template"]["spec"]["containers"][0]["image"]
                        oldVersion = fileData["metadata"]["resourceVersion"]
                        response = response.replace(oldImage,dockerImage)
                        response = response.replace(oldVersion,"")
                        println(response)

                        //更新gitlab文件内容
                        base64Content = response.bytes.encodeBase64().toString()
                        gitlab.UpdateRepoFile(3,"demo-prod%2f${releaseVersion}-prod.yaml",base64Content)
                    }
                } 
            }

        stage('Deploy-deploy') {
            agent { node { label "master" }}
            steps {
                script{
                   k8s.UpdateDeployment("demo-prod","demoapp",response)      
                }
            }
        }

Console output

...
Running on Jenkins in /var/lib/jenkins/workspace/k8s-gitlab-updatefile
[Pipeline] {
[Pipeline] script
[Pipeline] {
[Pipeline] withCredentials
Masking supported pattern matches of $kubernetestoken
[Pipeline] {
[Pipeline] httpRequest
HttpMethod: PUT
URL: https://kubernetes.docker.internal:6443/apis/apps/v1/namespaces/demo-prod/deployments/demoapp
Authorization: *****
Content-Type: application/yaml
Accept: application/yaml
Sending request to url: https://kubernetes.docker.internal:6443/apis/apps/v1/namespaces/demo-prod/deployments/demoapp
Response Code: HTTP/1.1 200 OK
Response: 
apiVersion: apps/v1
kind: Deployment
...
$ kubectl get pod -n demo-prod
NAME                       READY   STATUS              RESTARTS   AGE
demoapp-564f789c47-fzkbd   1/1     Running             0          6d18h
demoapp-766654c58c-x5vgx   0/1     ContainerCreating   0          2s
...

$ kubectl logs demoapp-766654c58c-x5vgx -n demo-prod
Hello World!

1.6 完整Prod-Release应用发布流水线

  • gitlab.groovy: https://github.com/Chao-Xi/JenkinslibTest/blob/master/src/org/devops/gitlab.groovy
  • kubernetes.groovy: https://github.com/Chao-Xi/JenkinslibTest/blob/master/src/org/devops/kubernetes.groovy

1.6.1 完整Pipeline

  • 获取运行中deploy的yaml -> 上传到gitlab -> 更新Container Image -> 上传到gitlab (yaml) -> 将新的yaml apply 到集群中

k8s-gitlab-fullpip

#!groovy
@Library('jenkinslib@master') _

def k8s = new org.devops.kubernetes()
def gitlab = new org.devops.gitlab()
def build = new org.devops.buildtools()

pipeline {
    agent { node { label "vagrant-agent" }}
    parameters {
        string(name: 'srcUrl', defaultValue: 'http://192.168.33.1:30088/root/demo-maven-service.git', description: '') 
        choice(name: 'versionName', choices: '1.0\n1.1\n1.2\n1.3', description: 'Please chose your versionName')
        choice(name: 'branchName', choices: 'master\nstage\ndev', description: 'Please chose your branch')
        choice(name: 'buildType', choices: 'mvn', description: 'build tool')
        choice(name: 'buildShell', choices: 'clean package -DskipTest\n--version', description: 'build tool')

    }
    stages{
        stage('Checkout') {
            steps {
                script {
                    checkout([$class: 'GitSCM', branches: [[name: "${branchName}"]], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: 'gitlab-admin-user', url: "${srcUrl}"]]])
                } 
            }
        }

        stage('Build') {
            steps {
                script {
                    build.Build(buildType,buildShell)
                } 
            }
        }

        // 构建镜像
           stage("BuildImages"){
                steps{
                    script{
                        env.serviceName = "${JOB_NAME}".split("_")[0]

                        withCredentials([usernamePassword(credentialsId: 'docker-registry-admin', passwordVariable: 'password', usernameVariable: 'username')]) {

                           env.dockerImage = "nyjxi/${serviceName}:${branchName}"
                           sh """
                               docker login -u ${username} -p ${password} 
                               docker build -t nyjxi/${serviceName}:${branchName} .
                               sleep 1
                               docker push nyjxi/${serviceName}:${branchName}
                               sleep 1
                               #docker rmi nyjxi/devopstest/${serviceName}:${branchName}
                            """
                        }
                    }
                }
            }

        stage("GetDeployment"){
            agent { node { label "master" }}
            steps{
                script{
                    response = k8s.GetDeployment("demo-prod","demoapp")
                    response = response.content

                    //文件转换
                    base64Content = response.bytes.encodeBase64().toString()

                    //上传文件
                    gitlab.CreateRepoFile(3,"demo-prod%2f${versionName}-prod.yaml",base64Content)

                }  
            }
        }

        stage('Pre-deploy') {
            steps {
                    script{
                        //下载版本库文件 
                        // releaseVersion = "${branchName}".split("-")[-1]
                        releaseVersion = "${versionName}"
                        response = gitlab.GetRepoFile(3,"demo-prod%2f${releaseVersion}-prod.yaml")

                        //获取文件中内容(镜像)
                        fileData = readYaml text: """${response}"""
                        println(fileData["spec"]["template"]["spec"]["containers"][0]["image"])
                        println(fileData["metadata"]["resourceVersion"])

                        // 更新新的镜像
                        dockerImage = "nyjxi/demo-java-service:master"
                        oldImage = fileData["spec"]["template"]["spec"]["containers"][0]["image"]
                        oldVersion = fileData["metadata"]["resourceVersion"]
                        response = response.replace(oldImage,dockerImage)
                        response = response.replace(oldVersion,"")
                        println(response)

                        //更新gitlab文件内容
                        base64Content = response.bytes.encodeBase64().toString()
                        gitlab.UpdateRepoFile(3,"demo-prod%2f${releaseVersion}-prod.yaml",base64Content)
                    }
                } 
            }

        stage('Deploy-deploy') {
            agent { node { label "master" }}
            steps {
                script{
                   k8s.UpdateDeployment("demo-prod","demoapp",response)      
                }
            }
        }
    }
}

Alt Image Text

Alt Image Text

$ kubectl get pod -n demo-prod 
NAME                       READY   STATUS             RESTARTS   AGE
demoapp-766654c58c-28t4v   0/1     CrashLoopBackOff   12         36m

$ kubectl logs demoapp-766654c58c-28t4v -n demo-prod 
Hello World!

二、版本晋级及发布流水线

2.1 版本晋级及发布流水线

  • https://github.com/Chao-Xi/JenkinslibTest/blob/master/src/org/devops/gitlab.groovy
  • https://github.com/Chao-Xi/JenkinslibTest/blob/master/src/org/devops/kubernetes.groovy

2.2 配置版本晋级流水线

晋级/版本更新流水线

  • 选择晋级策略 -> 根据版本文件晋级 -> 生成新版本文件

2.2.1 晋级流水线

demo-java-service_Update

#!groovy
@Library('jenkinslib@master') _

def k8s = new org.devops.kubernetes()
def gitlab = new org.devops.gitlab()

// String updateType = "${env.updateType}"
// String releaseVersion = "${env.releaseVersion}"

pipeline{
    agent { node { label "master" }}

    parameters {
        choice(name: 'releaseVersion', choices: '1.0\n1.1\n1.2\n1.3', description: 'Please chose your versionName')
        choice(name: 'updateType', choices: 'UAT -> STAGE\nSTAGE -> PROD', description: 'Please chose your updateType')
    }

    stages{
        stage("UAT->STAGE"){
            when {
                environment name: 'updateType', value: 'UAT -> STAGE' 
            }

            steps {
                script{
                    println("UAT -> STAGE")

                   //获取UAT文件中的images
                    response = gitlab.GetRepoFile(3,"demo-uat%2f${releaseVersion}-uat.yaml")
                    fileData = readYaml text: """${response}"""
                    uatImage = fileData["spec"]["template"]["spec"]["containers"][0]["image"]
                    println("UAT IMAGES --> ${uatImage}")

                   //获取最新STAG环境的deployment
                    stagResponse = k8s.GetDeployment("demo-stage","demoapp")
                    stagResponse = stagResponse.content

                    //获取镜像和version
                    stagfileData = readYaml text: """${stagResponse}"""
                    stagOldImage = stagfileData["spec"]["template"]["spec"]["containers"][0]["image"]
                    stagOldVersion = stagfileData["metadata"]["resourceVersion"]

                    //更新镜像和version
                    println("STAG OLD IMAGES --> ${stagOldImage}")
                    stagResponse = stagResponse.replace(stagOldImage,uatImage)
                    stagResponse = stagResponse.replace(stagOldVersion,"")

                    //生成最新的STAGE版本文件
                    //文件转换
                    base64Content = stagResponse.bytes.encodeBase64().toString()
                    //上传文件
                    try {
                        gitlab.CreateRepoFile(3,"demo-stage%2f${releaseVersion}-stage.yaml",base64Content)
                    } catch(e){
                        gitlab.UpdateRepoFile(3,"demo-stage%2f${releaseVersion}-stage.yaml",base64Content)
                    }

                }
            }
        }

    stage("STAG->PROD"){
            when {
                environment name: 'updateType', value: 'STAGE -> PROD' 
            }

            steps {
                script{
                    println("STAGE -> PROD")

                   //获取STAG文件中的images
                    response = gitlab.GetRepoFile(3,"demo-stage%2f${releaseVersion}-stage.yaml")
                    fileData = readYaml text: """${response}"""
                    stagImage = fileData["spec"]["template"]["spec"]["containers"][0]["image"]
                    println("STAGE IMAGES --> ${stagImage}")

                   //获取最新PROD环境的deployment
                    prodResponse = k8s.GetDeployment("demo-prod","demoapp")
                    prodResponse = prodResponse.content

                    //获取镜像和version
                    prodfileData = readYaml text: """${prodResponse}"""
                    prodOldImage = prodfileData["spec"]["template"]["spec"]["containers"][0]["image"]
                    prodOldVersion = prodfileData["metadata"]["resourceVersion"]

                    //更新镜像和version
                    println("PROD OLD IMAGES --> ${prodOldImage}")
                    prodResponse = prodResponse.replace(prodOldImage,stagImage)
                    prodResponse = prodResponse.replace(prodOldVersion,"")

                    //生成最新的PROD版本文件
                    //文件转换
                    base64Content = prodResponse.bytes.encodeBase64().toString()
                    //上传文件
                    try {
                        gitlab.CreateRepoFile(3,"demo-prod%2f${releaseVersion}-prod.yaml",base64Content)
                    } catch(e){
                        gitlab.UpdateRepoFile(3,"demo-prod%2f${releaseVersion}-prod.yaml",base64Content)
                    }

                }
            }
        }
    }
}

2.2.2 调用在kubernetes.groovy定义API方法

//获取Deployment
def GetDeployment(nameSpace,deployName){
    apiUrl = "namespaces/${nameSpace}/deployments/${deployName}"
    response = HttpReq('GET',apiUrl,'')
    return response
}

2.2.3 调用在gitlab.groovy定义API方法

//更新文件内容
def UpdateRepoFile(projectId,filePath,fileContent){
    apiUrl = "projects/${projectId}/repository/files/${filePath}"
    reqBody = """{"branch": "master","encoding":"base64", "content": "${fileContent}", "commit_message": "update a new file"}"""
    response = HttpReq('PUT',apiUrl,reqBody)
    println(response)

}

//获取文件内容
def GetRepoFile(projectId,filePath){
    apiUrl = "projects/${projectId}/repository/files/${filePath}/raw?ref=master"
    response = HttpReq('GET',apiUrl,'')
    return response.content
}

//创建仓库文件
def CreateRepoFile(projectId,filePath,fileContent){
    apiUrl = "projects/${projectId}/repository/files/${filePath}"
    reqBody = """{"branch": "master","encoding":"base64", "content": "${fileContent}", "commit_message": "create a new file"}"""
    response = HttpReq('POST',apiUrl,reqBody)
    println(response)
}

Alt Image Text

Alt Image Text

Console Output: UAT -> STAGE

STAG OLD IMAGES --> bitnami/java-example:0.0.1
[Pipeline] withCredentials
Masking supported pattern matches of $gitlabToken
[Pipeline] {
[Pipeline] httpRequest
HttpMethod: POST
URL: http://192.168.33.1:30088/api/v4/projects/3/repository/files/demo-stage%2f1.0-stage.yaml
Content-Type: application/json
PRIVATE-TOKEN: *****
Sending request to url: http://192.168.33.1:30088/api/v4/projects/3/repository/files/demo-stage%2f1.0-stage.yaml
Response Code: HTTP/1.1 201 Created
Response: 
{"file_path":"demo-stage/1.0-stage.yaml","branch":"master"}
Success code from [100‥399]
[Pipeline] }
[Pipeline] // withCredentials
[Pipeline] echo
Status: 201
[Pipeline] }
[Pipeline] // script
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (STAG->PROD)
Stage "STAG->PROD" skipped due to when conditional
[Pipeline] }

Console Output: STAGE -> PROD

Stage "UAT->STAGE" skipped due to when conditional
[Pipeline] }
...
HttpMethod: POST
URL: http://192.168.33.1:30088/api/v4/projects/3/repository/files/demo-prod%2f1.0-prod.yaml
Content-Type: application/json
PRIVATE-TOKEN: *****
Sending request to url: http://192.168.33.1:30088/api/v4/projects/3/repository/files/demo-prod%2f1.0-prod.yaml
Response Code: HTTP/1.1 400 Bad Request
Response: 
{"message":"A file with this name already exists"}
[Pipeline] }
[Pipeline] // withCredentials
[Pipeline] withCredentials
Masking supported pattern matches of $gitlabToken
[Pipeline] {
[Pipeline] httpRequest
HttpMethod: PUT
URL: http://192.168.33.1:30088/api/v4/projects/3/repository/files/demo-prod%2f1.0-prod.yaml
Content-Type: application/json
PRIVATE-TOKEN: *****
Sending request to url: http://192.168.33.1:30088/api/v4/projects/3/repository/files/demo-prod%2f1.0-prod.yaml
Response Code: HTTP/1.1 200 OK
Response: 
{"file_path":"demo-prod/1.0-prod.yaml","branch":"master"}
Success code from [100‥399]
[Pipeline] }
[Pipeline] // withCredentials
[Pipeline] echo
Status: 200

Alt Image Text

Alt Image Text

2.3 配置应用发布流水线

2.3.1 发布流水线到不同的环境(Uat, Stage, Prod)

STAG/PROD发布流水线

  • 选择版本号 -> 获取版本文件 -> 发布应用

demo-java-service_Deploy

#!groovy

@Library('jenkinslib@master') _

// String stackName = "${env.stackName}"
// String releaseVersion = "${env.releaseVersion}"

def gitlab = new org.devops.gitlab()
def k8s = new org.devops.kubernetes()

pipeline{
   agent { node { label "master" }}

   parameters {
        choice(name: 'stackName', choices: '\nUAT\nSTAGE\nPROD', description: 'Please chose your stackName')
        choice(name: 'releaseVersion', choices: '1.0\n1.1\n1.2\n1.3', description: 'Please chose your versionName')
    }

   stages{

       stage("Deploy"){
            steps{
                script{

                    //获取版本文件
                    stack = "${stackName}".toLowerCase()
                    response = gitlab.GetRepoFile(3,"demo-${stack}%2f${releaseVersion}-${stack}.yaml")
                    //发布应用
                    k8s.UpdateDeployment("demo-${stack}","demoapp",response)

                }  
           }
       }
   }
}

2.3.2 调用在kubernetes.groovy定义API方法

//更新Deployment
def UpdateDeployment(nameSpace,deployName,deplyBody){
    apiUrl = "namespaces/${nameSpace}/deployments/${deployName}"
    response = HttpReq('PUT',apiUrl,deplyBody)
    println(response)
}

Alt Image Text

Console Output

[Pipeline] httpRequest
HttpMethod: PUT
URL: https://kubernetes.docker.internal:6443/apis/apps/v1/namespaces/demo-stage/deployments/demoapp
Authorization: *****
Content-Type: application/yaml
Accept: application/yaml
Sending request to url: https://kubernetes.docker.internal:6443/apis/apps/v1/namespaces/demo-stage/deployments/demoapp
Response Code: HTTP/1.1 200 OK
...
Success code from [100‥399]
[Pipeline] }
[Pipeline] // withCredentials
[Pipeline] echo
Status: 200
$ kubectl get pod -n demo-stage
NAME                       READY   STATUS        RESTARTS   AGE
demoapp-678d789d86-z6dkm   0/1     Terminating   0          3h22m
demoapp-7d548887f4-tm25g   0/1     Completed     1          6s

$ kubectl logs demoapp-7d548887f4-tm25g -n demo-stage
Hello World!