git,Jenkins,docker持续集成

docker的dockerfile/docker compose完成后再加入jenkins就能完成持续集成了

Jenkins篇

Jenkins创建多分支流水线任务:

image

 配置: 代码仓库地址,登录凭证,Jenkinsfile,保存后会自动扫描分支,构建时选择要构建的分支

image

 重点时jenkinsfile如何完成拉取代码到部署的:

先看项目结构:

image

 dockerfile dockercompose 在docker篇已经讲了,下面看jenkinsfile

// =====================================================================
// Seata 示例项目 CI/CD 流水线:代码提交 -> 编译测试 -> 打包 -> 镜像 -> 部署
// 触发:Git push(webhook)+ pollSCM 轮询兜底
// =====================================================================
pipeline {
    agent any

    environment {
        // 镜像仓库地址(换成你的 Harbor / 阿里云 ACR)
        REGISTRY = 'harbor.example.com/seata-demo'
        // 镜像版本:git 短哈希 + 构建号,保证每次的IMAGE_TAG都不同,后面执行dockercompose时,
        //IMAGE_TAG变化的镜像才会重新运行为容器,也便于追溯与回滚
        IMAGE_TAG = "${env.GIT_COMMIT ? env.GIT_COMMIT.take(7) : 'local'}-${BUILD_NUMBER}"
        // 需要打成镜像的可运行模块(common-api 是公共 jar,不单独成镜像)
        SERVICES = 'order-service storage-service account-service notify-service ' +
                   'tcc-order-service tcc-storage-service tcc-account-service saga-service'
    }

    options {
        timestamps()                                    // 日志带时间戳
        buildDiscarder(logRotator(numToKeepStr: '10'))  // 只保留最近 10 次构建,省磁盘
        timeout(time: 30, unit: 'MINUTES')
    }


    stages {
        stage('1. 拉取代码') { //从代码仓库获取最新代码
            steps {
                checkout scm
            }
        }


        stage('2. 构建 Docker 镜像') {
            steps {
                script {
                    SERVICES.split().each { module -> // SERVICES里配置了所有要构建镜像的模块
                        def image = "${REGISTRY}/${module}:${IMAGE_TAG}"
                        echo "构建镜像:${image}"
                        sh "docker build --build-arg MODULE=${module} -t ${image} ." // docker build命令作用是用dickerfile生成镜像,没有-f参数就是在上下文目录下找dockerfile,最后的 .代表上下文目录
                    }
                }
            }
        }

        stage('3. 推送镜像到仓库') {
            steps {
                withCredentials([usernamePassword(credentialsId: 'harbor-account',
                                                  usernameVariable: 'HARBOR_USER',
                                                  passwordVariable: 'HARBOR_PASS')]) {
                    sh "docker login ${REGISTRY} -u ${HARBOR_USER} -p ${HARBOR_PASS}"
                }
                script {
                    SERVICES.split().each { module ->
                        sh "docker push ${REGISTRY}/${module}:${IMAGE_TAG}"
                    }
                }
            }
        }

        stage('4. 部署到服务器') {
            steps {
                script {
                    // 目标机需先手动 docker login 一次(或用 docker config 持久化凭据)
                    def deployCmd = """
                        ssh -o StrictHostKeyChecking=no deploy@prod-server '
                            cd ~/app
                            export REGISTRY="${REGISTRY}"
                            export IMAGE_TAG="${IMAGE_TAG}"
                            docker compose pull //从镜像仓库拉取镜像
                            docker compose up -d //执行dockercompose.yml文件,这里没有加--build参数,表示如果已经有镜像就不会再次打镜像,所以步骤2构建镜像里已经打了镜像,这里不会再打,dockercompose里的nacos,mysql等不变的服务也不会打镜像,这一步就完成了容器的启动
                        '
                    """
                    sshagent(['prod-server-ssh-key']) {
                        sh deployCmd
                    }
                }
            }
        }

        stage('5. 健康检查') {
            steps {
                sh 'sleep 15 && curl -f http://prod-server:8081/actuator/health || exit 1'
            }
        }
    }

    post {
        success { echo '发布成功' }
        failure { echo '发布失败,请查看控制台日志' }
        always  { cleanWs() }
    }
}

 

posted @ 2021-05-13 17:44  杨吃羊  阅读(78)  评论(0)    收藏  举报