上传镜像(前端镜像构建就是基于nginx镜像,将静态文件拷贝到发布目录下面,同时构建完毕之后docker run一下,看看在本地是否可以跑起来)
- 需要将docker镜像仓库的用户认证信息,以用户名和密码类型的凭据在Jenkins中存储;
- docker仓库:registry.cn-beijing.aliyuncs.com/${buName}/${appName};
- 镜像标签: ${releaseVersion}-${nowDate} 即 版本号-日期;
- 步骤: 登录镜像仓库> 构建镜像 > 上传镜像 > 删除本地镜像(节省空间);
//上传制品(jar、war >> docker images )
stage("PushArtifact"){
steps{
script{
//env.artifactUrl = nexus.PushArtifacts(buildType)
//println(env.artifactUrl)
def buildTime = sh returnStdout: true, script: 'date +%Y%m%d%H%M%S'
buildTime = buildTime - "\n"
env.imageTag = "${env.releaseVersion}-${buildTime}"
env.imageName = "192.168.1.200:8088/${buName}/${appName}:${env.imageTag}"
// 自定义index.html
sh "echo ${appName}----${env.releaseVersion} >index.html"
sh """
## 登录镜像仓库
docker login -u admin -pHarbor12345 192.168.1.200:8088
## 构建镜像
docker build -t ${env.imageName} -f ./Dockerfile .
## 上传镜像
docker push ${env.imageName}
sleep 2
## 清除镜像
docker rmi ${env.imageName}
"""
}
}
}
这里面先说一下writeFile和readFile,readFile和writeFile都是简单的文本文件读写。当你拿到一个文件,不知道选择什么方式来读写,那么这个readFile和writeFile就是最原始的方法。但是,如果是json类型文件,那么我们可以用前面介绍插件的readJson来读取,读取得到是一个json 的对象,就可以直接调用json的方法。
pipeline {
agent { label 'master' }
stages {
stage('write') {
steps {
script {
def date = new Date()
def data = "Hello World\nSecond line\n" + date
writeFile(file: 'zorg.txt', text: data)
sh "ls -l"
}
}
}
stage('read') {
steps {
script {
def data = readFile(file: 'zorg.txt')
println(data)
}
}
}
}
}
stage("PushImage"){
steps{
script{
withCredentials([usernamePassword(credentialsId: '6ed6e3ef-fdca-493f-a8a4-613f70aca281', passwordVariable: 'password', usernameVariable: 'username')]) {
env.nowDate = sh returnStdout: true, script: 'date +%Y%m%d%H%M%S'
env.nowDate = env.nowDate - "\n"
env.releaseVersion = "${env.branchName}"
env.imageTag = "${releaseVersion}-${nowDate}"
env.dockerImage = "registry.cn-beijing.aliyuncs.com/${buName}/${appName}:${env.imageTag}"
sh """
docker login -u ${username} -p ${password} registry.cn-beijing.aliyuncs.com
docker build -t ${dockerImage} -f ./Dockerfile .
sleep 1
docker push ${dockerImage}
sleep 1
docker rmi ${dockerImage}
"""
}
}
}
}
更新生成版本文件
- 步骤: 拿到 env仓库中的default.yaml模板文件(这个模板文件都是通用的), 然后替换内容,更新到版本库。
- 更新对象:
-
- __APPNAME__(应用名称)对应Jenkins作业名称;
- __VERSION__ (发布版本) 对应版本分支中的版本号;
-
- __NAMESPACE__ (名称空间) 对应业务名称;
- __INAGENAME__(镜像名称)
k8s文件做成一个模板文件,最终保存的是这种效果,模板文件需要修改的地方命名为_NAME_
stage("ReleaseFile"){
steps {
script {
//拿到版本库文件 anyops-devops-service/release.yaml里面内容
response = gitlab.GetRepoFile(13,"default.yaml", "master")
//将文件里面内容写到本地
writeFile file: 'default.yaml', text: """${response}"""
sh """
## 替换APPNAME
sed -i 's#__APPNAME__#${appName}#g' default.yaml
sed -i 's#__VERSION__#${env.releaseVersion}#g' default.yaml
sed -i 's#__NAMESPACE__#${buName}#g' default.yaml
sed -i 's#__IMAGENAME__#${env.dockerImage}#g' default.yaml
"""
newYaml = sh returnStdout: true, script: 'cat default.yaml'
println(newYaml)
//更新gitlab文件内容
base64Content = newYaml.bytes.encodeBase64().toString()
// 会有并行问题,同时更新报错
try {
gitlab.UpdateRepoFile(13,"${appName}%2f${branchName}.yaml",base64Content, "master")
} catch(e){
gitlab.CreateRepoFile(13,"${appName}%2f${branchName}.yaml",base64Content, "master")
}
}
}
}
应用发布
- 创建名称空间,更新应用,查看REVISION历史。
// 发布
stage("Deploy"){
steps{
script{
// kubectl 更新应用
sh "kubectl apply -f ${env.releaseVersion}.yaml"
// 获取应用状态
5.times{
sh "sleep 2; kubectl -n ${buName} get pod | grep ${appName}"
}
}
}
}
回滚步骤(交互)
- 给用户提供两个选项 :yes执行回滚,no跳过;
- 使用kubectl rollout undo 默认回滚上个版本;
// rollout
stage("RollOut"){
input {
message "是否继续回滚"
ok "Yes"
submitter "zeyang,aa"
parameters {
choice(choices: ['yes', 'no'], name: 'opts')
// string(name: 'opts', defaultValue: 'no', description: 'yes/no')
}
}
steps{
script{
echo "opts ---> ${opts}"
if ("${opts}" == "yes"){
// 回滚命令
sh " kubectl rollout undo deployment/${appName} -n ${buName}"
}
}
}
}