暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Jenkins部署单体SpringBoot项目

BugProvider 2021-06-30
1805


本文目的:

Jenkins部署Springboot单体项目

  1. Jenkins具备发布和回滚版本两种模式部署

1.规划

本次规划节点如下:

IP部署组件作用
192.168.99.78Jenkins,Docker,Harbor构建服务器
192.168.99.224Docker部署服务器

正式环境可以Jenkins,Harbor,Docker分别在三个服务器中。

Let`s go

2.准备一个简单的Boot项目

我这里随意构建一个测试项目,端口是8083

@RestController
@SpringBootApplication
public class WebTestApplication {

    public static void main(String[] args) {
        SpringApplication.run(WebTestApplication.classargs);
    }

    @GetMapping("/hello")
    public String hello() {
        return "hello";
    }

}

GET访问hello接口返回hello字符串

curl http://localhost:8083/hello

hello

3.Dockerfile构建

这里我们用到了docker构建插件dockerfile-maven-plugin,这个插件作用在于辅助我们快速构建boot的docker镜像。

官网:https://github.com/spotify/dockerfile-maven

具体使用如下:

3.1添加dockerfile-maven-plugin

pom.xml中添加

<build>
    <plugins>
        <plugin>
            <groupId>com.spotify</groupId>
            <artifactId>dockerfile-maven-plugin</artifactId>
            <version>1.4.13</version>
            <configuration>
                <repository>${project.artifactId}</repository>
                <buildArgs>
                    <JAR_FILE>target/${project.build.finalName}.jar</JAR_FILE>
                </buildArgs>
            </configuration>
        </plugin>
    </plugins>
</build>

说明:

  • repository:  这里指定是项目的artifactId
  • buildArgs: 这是指定dockerfile中接收的构建参数列表
    • JAR_FILE:dockerfile里的参数名,这里我们指定是target/xx.jar,也就是mvn build之后的jar包

3.2在项目根目录下新增Dockerfile

如下:

FROM openjdk:8-jdk-alpine
ARG JAR_FILE
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]

说明:

  • 指定引用jdk8做基础镜像

  • 接收docker build的参数 JAR_FILE,也就是上面我们在pom.xml中JAR_FILE指定的target/xxx.jar

  • COPY xxx.jar 到镜像的根目录下 命名为 app.jar

    • docker exec -it containerID /bin/sh

      ls 

    • 具体是否拷贝成功,可以在镜像build之后,run起来,进入容器内部查看

  • 执行启动程序 java -jar app.jar 命令

注意: 同时这里构建的镜像启动后内部的端口就是8083,也就是boot程序application.yml中server.port的端口

3.3 提交到远程Git仓库

我提交到了最大的同性网站上:https://github.com/PittYao/bootJenkins.git

4.部署Harbor

官网:https://goharbor.io/

简介:

Harbor is an open source registry that secures artifacts with policies and role-based access control, ensures images are scanned and free from vulnerabilities, and signs images as trusted. Harbor, a CNCF Graduated project, delivers compliance, performance, and interoperability to help you consistently and securely manage artifacts across cloud native compute platforms like Kubernetes and Docker.

Harbor(港口,港湾)是一个用于存储和分发Docker镜像的企业级Registry服务器。除了Harbor这个私有镜像仓库之外,还有Docker官方提供的Registry。相对Registry,Harbor具有很 多优势:

  1. 提供分层传输机制,优化网络传输 Docker镜像是是分层的,而如果每次传输都使用全量文件(所以 用FTP的方式并不适合),显然不经济。必须提供识别分层传输的机制,以层的UUID为标识,确定 传输的对象。
  2. 提供WEB界面,优化用户体验 只用镜像的名字来进行上传下载显然很不方便,需要有一个用户界 面可以支持登陆、搜索功能,包括区分公有、私有镜像。
  3. 支持水平扩展集群 当有用户对镜像的上传下载操作集中在某服务器,需要对相应的访问压力作分 解。
  4. 良好的安全机制 企业中的开发团队有很多不同的职位,对于不同的职位人员,分配不同的权限, 具有更好的安全性。

一言以蔽之:Docker的私有仓库,类似Maven中的Nexus3。u know that

4.1Harbor安装

Harbor需要安装在192.168.99.78上面

  1. 先安装Docker并启动Docker(已完成)

  2. 先安装docker-compose

    sudo curl -L https://github.com/docker/compose/releases/download/1.21.2/dockercompose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose
    sudo chmod +x /usr/local/bin/docker-compose

  3. 给docker-compose添加执行权限

    sudo chmod +x /usr/local/bin/docker-compose

  4. 查看docker-compose是否安装成功

    docker-compose -version

  5. 下载Harbor的压缩包,我这是2.3.0 https://github.com/goharbor/harbor/releases

  6. 上传压缩包到linux,并解压

    tar -xzf harbor-offline-installer-v2.3.0.tgz
    mkdir /opt/harbor
    mv harbor/* /opt/harbor
    cd /opt/harbor

  7. 修改Harbor的配置

    vi harbor.yml

    修改hostname和port

    hostname: 192.168.99.78
    port: 85

  8. 安装Harbor

    ./prepare
    ./install.sh

  9. 启动Harbor

    docker-compose up -d 启动
    docker-compose stop 停止
    docker-compose restart 重新启动

  10. 访问Harbor http://192.168.99.78:85 默认账户密码:admin/Harbor12345

    image-20210630165109170

4.2 具体使用

在Harbor创建用户和项目

  1. 创建项目 Harbor的项目分为公开和私有的:公开项目:所有用户都可以访问,通常存放公共的镜像,默认有一个library公开项目。私有项目:只有授权用户才可以访问,通常存放项目本身的镜像。我们创建一个新的项目:webtest

  2. 给webtest项目分配用户 进入webtest项目->成员

    image-20210630174036769
    角色权限说明
    访客对于指定项目拥有只读权限
    开发人员对于指定项目拥有读写权限
    维护人员对于指定项目拥有读写权限,创建 Webhooks
    项目管理员除了读写权限,同时拥有用户管理/镜像扫描等管理权限

4.3把镜像上传到Harbor

  1. 给镜像打上标签

    docker tag webtest:latest 192.168.99.78:85/webtest/webtest:latest

  2. 推送镜像

    docker push 192.168.99.78:85/webtest/webtest:latest

    The push refers to repository [192.168.66.102:85/tensquare/eureka] Get https://192.168.66.102:85/v2/: http: server gave HTTP response to HTTPS client

    这时会出现以上报错,是因为Docker没有把Harbor加入信任列表中

  3. 把Harbor地址加入到Docker信任列表

    vi /etc/docker/daemon.json

    {
        "registry-mirrors": ["https://zydiol88.mirror.aliyuncs.com"],
        "insecure-registries": ["192.168.99.78:85"]
    }

    需要重启Docker

  4. 再次执行推送命令,会提示权限不足

    denied: requested access to the resource is denied

    需要先登录Harbor,再推送镜像

  5. 登录Harbor

    docker login -u 用户名 -p 密码 192.168.99.78:85

    WARNING! Using --password via the CLI is insecure. Use --password-stdin.
    WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
    Configure a credential helper to remove this warning. See
    https://docs.docker.com/engine/reference/commandline/login/#credentials-store
    Login Succeeded

    登录成功

4.4从Harbor下载镜像

需求:在192.168.99.224服务器完成从Harbor下载镜像

  1. 安装Docker,并启动Docker(已经完成)

  2. 修改Docker配置

    vi /etc/docker/daemon.json

{
    "registry-mirrors": ["https://zydiol88.mirror.aliyuncs.com"],
    "insecure-registries": ["192.168.99.78:85"]
}

重启docker

  1. 先登录,再从Harbor下载镜像

    docker login -u 用户名 -p 密码 192.168.99.78:85

    docker pull 192.168.99.78:85/webtest/webtest:latest

5.Jenkinsfile构建

5.1在项目根目录下新建Jenkinsfile

//git的凭证
def git_auth = "3c624c30-b117-47c8-9e3e-c9551498e3a5"
//git地址
def git_url = "https://github.com/PittYao/bootJenkins.git"
//项目名称
def project_name = "webtest"
//构建版本的名称
// def tag = "latest"
//程序的端口
def port = 8083

//Harbor私服地址
def harbor_url = "192.168.99.78:85"
//Harbor的项目名称
def harbor_project_name = "webtest"
//Harbor的凭证
def harbor_auth = "734a87d9-5119-4c4f-bcb3-27c9a25b2ab1"

node {
    script {
        if ( "${deploy}" == "发布" ) {
            stage('拉取代码') {
               checkout([$class'GitSCM', branches: [[name: '*/${branch}']],
               doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [],
               userRemoteConfigs: [[credentialsId: "${git_auth}", url:"${git_url}"]]])
           }

           stage('编译,构建镜像') {
               //定义镜像名称
               def imageName = "${project_name}:${tag}"
               //编译,构建本地镜像
               sh "mvn clean package -Dmaven.test.skip dockerfile:build -Ddockerfile.tag=${tag}"
               //给镜像打标签
               sh "docker tag ${imageName} ${harbor_url}/${harbor_project_name}/${imageName}"//登录Harbor,并上传镜像

               withCredentials([usernamePassword(credentialsId: "${harbor_auth}",
               passwordVariable: 'password', usernameVariable: 'username')]) {
                   //登录
                   sh "docker login -u ${username} -p ${password} ${harbor_url}"
                   //上传镜像
                   sh "docker push ${harbor_url}/${harbor_project_name}/${imageName}"
               }

               //删除本地镜像
               sh "docker rmi -f ${imageName}"
               sh "docker rmi -f ${harbor_url}/${harbor_project_name}/${imageName}"
           }

           stage('部署服务器执行脚本'){
               //=====以下为远程调用进行项目部署========
               sshPublisher(publishers:
                   [
                       sshPublisherDesc(configName: '192.168.99.224',
                       transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand:
                       "/opt/jenkins_shell/back_deploy.sh $harbor_url $harbor_project_name $project_name $tag $port",
                       execTimeout: 120000, flatten: false, makeEmptyDirs: false,
                       noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '',
                       remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')],
                       usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)
                   ]
               )
           }
        }
    }

    script {
        if ( "${deploy}" == "回滚" ) {
            stage('服务器执行回滚脚本'){
                //=====以下为远程调用进行项目部署========
                sshPublisher(publishers:
                    [
                        sshPublisherDesc(configName: '192.168.99.224',
                        transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand:
                        "/opt/jenkins_shell/back_deploy.sh $harbor_url $harbor_project_name $project_name $tag $port",
                        execTimeout: 120000, flatten: false, makeEmptyDirs: false,
                        noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '',
                        remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')],
                        usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)
                    ]
                )
            }
        }
    }

}

参数说明:

  • 上述一开始定义了一堆变量:

    • git_auth:Jenkins中项目git仓库的凭证id
    • git_url:git地址
    • project_name:  镜像的名称
    • port : 程序的端口
    • harbor_url:  Harbor私服地址
    • harbor_project_name : 推送到Harbor的项目名称
    • harbor_auth : Jenkins登录Harbor的凭证
    • ${branch}:git的拉取代码分支
    • ${tag}: docker的tag版本号,这里我们用时间做唯一标识
    • ${deploy}: 这次部署是,发布新版本,还是回滚到之前的版本
  • 凭证的添加:

    image-20210630175020694

    新增凭据,输入地址,账号,密码即可。

    复制id到Jenkinsfile,替换为自己的git_auth,harbor_auth

  • 具体说明,看注释即可

5.2上传部署脚本到服务器

  • 在最后都通过ssh执行了远端服务器来执行部署脚本,这个部署脚本的功能也就是从Harbor拉取指定镜像的tag并启动,脚本内容具体如下:

    #! /bin/sh
    #接收外部参数
    harbor_url=$1
    harbor_project_name=$2
    project_name=$3
    tag=$4
    port=$5

    imageName=$harbor_url/$harbor_project_name/$project_name:$tag

    echo "$imageName"

    #查询容器是否存在,存在则删除
    containerId=`docker ps -a | grep -w ${project_name} | awk '{print $1}'`
    if [ "$containerId" != "" ] ; then
      #停掉容器
      docker stop $containerId
      #删除容器
      docker rm $containerId

      echo "成功删除容器"
    fi

    #查询镜像是否存在,存在则删除
    imageId=`docker images | grep -w $project_name | awk '{print $3}'`

    if [ "$imageId" != "" ] ; then

      #删除镜像
      docker rmi -f $imageId

      echo "成功删除镜像"
    fi

    # 登录Harbor私服,修改为自己的账号密码
    docker login -u user -p password $harbor_url

    # 下载镜像
    docker pull $imageName

    # 启动容器
    docker run -di -p $port:$port $imageName

    echo "容器启动成功"

  • 将back_deploy.sh上传到192.168.99.224的/opt/jenkins_shell/下

    scp root@192.168.99.224:/opt/jenkins_shell/back_deploy.sh

    前提是开启ssh免密登录,具体操作参考前面一章即可。

  • 并对脚本添加可执行权限

    chmod +x /opt/jenkins_shell/back_deploy.sh

6.新建Jenkins项目

6.1安装时间插件

因为在构建中使用到了时间参数,所以安装该插件

插件管理中安装:Date Parameter Plugin

6.2新建流水线项目

6.2.1添加构建参数

注意: 这下面的名称都和Jenkinsfile中的变量名要保持一致

  • 添加分支参数

    image-20210630181214118
  • 添加部署类型参数

    image-20210630181249266
  • 添加发布版本tag参数

    image-20210630181300476

6.2.2添加git配置

image-20210630181536707

最后构建界面如图:

image-20210630181610700

7.测试

7.1测试发布新版本

点击构建

Jenkins:

Harbor下有新的tag镜像:

image-20210630181838619

192.168.99.224下拉取到构建的新镜像:

root@fanyao:~# docker images
REPOSITORY                                    TAG                 IMAGE ID       CREATED        SIZE
192.168.99.78:85/webtest/webtest              2021-06-30_140002   5c138ade04e5   4 hours ago    122MB

docker运行状态:

root@fanyao:~# docker ps
CONTAINER ID   IMAGE       COMMAND                       PORTS                                       NAMES

a2478184f4e7   192.168.99.78:85/webtest/webtest:2021-06-30_140002   "java -jar /app.jar"   0.0.0.0:8083->8083/tcp, :::8083->8083/tcp   pedantic_hertz

访问接口

curl http://192.168.99.224:8083/hello

hello

测试发布成功

7.2测试回滚

需要登录Harbor查看要回滚的tag版本号:

image-20210630182428499

在Jenkins的参数中选择回滚,并输入tag号:

image-20210630182537964

再次点构建即可。

总结

通过Dockerfile和Jenkinsfile和Harbor以及基础的脚本组合,即可对一个单体的Boot项目进行发版和回滚。只需根据自己配置的情况来构建单体项目,当然微服务项目也以此类推。


文章转载自BugProvider,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论