• 08 . Jenkins之SpringCloud微服务+Vue+Docker持续集成


    简介

    大致流程
    /*
    		1.开发人员每天把代码提交到Gitlab代码仓库
    		2.jenkins从gitlab中拉取项目源码,编译并打包成war包,然后构建Docker镜像,将镜像上传到Harbor私有仓库
    		3.jenkins发送ssh远程命令,让生产部署服务到Harbor私有仓库拉取镜像到本地,然后创建容器
    		4.最后,用户就可以访问到容器
    */
    

    SpringCloud微服务源码概述

    /*
    	项目架构: 前后端分离
    	后端技术栈: SpringBoot+SpringCloud+SpringDatajpa(Spring全家桶)
    */
    
    
    
    /*
    	微服务项目结构
    		tensquare_parent:   父工程,存放基础配置
    		tensquare_common:   通用工程
    		tensquare_eureka_server:  SpringCloud的Eureka注册中心
    		tensquare_zull:  SpringCloud的网关服务
    		tensquare:  基础权限认证中心,负责用户认证(使用jwt认证)
    		tenquare_guathering:  一个简单的业务模块,活动微服务相关逻辑
    */
    
    
    /*
    	数据库结构
    		tensquare_user:  用户认证数据库,存放用户账号数据,对应tensquare_admin_service微服务
    		tensquare_gathering:  活动微服务数据库,对应tensquare_gathering微服务
    */
    
    
    /*
    	微服务配置分析
    		tensquare_eureka
    		tensquare_zuul
    		tensquare_admin_service
    		tensquare_gathering
    */
    

    部署Docker

    安装必要系统工具和软件源
    # 安装一些必要的系统工具
    sudo yum install -y yum-utils device-mapper-persistent-data lvm2
    # 添加软件源信息
    # docker 官方源
    sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
    
    # 阿里云源
    sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
    
    安装并启动Docker-ce
    # 安装前可以先更新 yum 缓存:
    sudo yum makecache fast
    
    # CentOS7安装 Docker-ce
    yum -y install docker-ce        # CentOS 中安装
    apt-get install docker-ce       # Ubuntu 中安装
    pacman -S docker                # Arch 中安装
    emerge --ask docker             # Gentoo 中安装
    
    # 如果想安装特定版本的Docker-ce版本,先列出repo中可用版本,然后选择安装
    yum list docker-ce --showduplicates |sort -r
    Loading mirror speeds from cached hostfile
    Loaded plugins: fastestmirror
    Installed Packages
    docker-ce.x86_64            3:19.03.4-3.el7                    docker-ce-stable
    docker-ce.x86_64            3:19.03.4-3.el7                    @docker-ce-stable
    docker-ce.x86_64            3:19.03.3-3.el7                    docker-ce-stable
    docker-ce.x86_64            3:19.03.2-3.el7                    docker-ce-stable
    docker-ce.x86_64            3:19.03.1-3.el7                    docker-ce-stable
    
    yum install docker-ce-<VERSION STRING>
    # 选择安装 docker-ce-18.06.1.ce
    yum install docker-ce-18.06.1.ce -y
    
    # Docker镜像加速
    # 没有启动/etc/docker目录不存在,需要自己创建,docker启动也会自己创建
    # 为了期望我们的镜像下载快一点,应该定义一个镜像加速器,加速器在国内
    mkdir /etc/docker
    vim /etc/docker/daemon.json
    {
    "registry-mirrors": ["https://registry.docker-cn.com"]
    }
    
    # 或者使用阿里云的
    sudo mkdir -p /etc/docker
    sudo tee /etc/docker/daemon.json <<-'EOF'
    {
      "registry-mirrors": ["https://yj9iu9ne.mirror.aliyuncs.com"]
    }
    EOF
    sudo systemctl daemon-reload
    sudo systemctl restart docker
    
    # 启动Docker后台服务
    systemctl start docker && systemctl enable docker
    systemctl daemon-reload                 # 守护进程重启
    
    # 通过运行hello-world镜像,验证是否正确安装了docker,或者通过查看版本
    docker run hello-world
    docker version
    Client: Docker Engine - Community
    Version:           19.03.4
    API version:       1.40
    Go version:        go1.12.10
    Git commit:        9013bf583a
    Built:            Fri Oct 18 15:52:22 2019
    OS/Arch:           linux/amd64
    Experimental:      false
    
    docker使用

    docker使用请看我前面写的docker blog

    https://www.cnblogs.com/you-men/category/1789332.html

    使用dockerfile制作微服务镜像

    1.上传Eureka的微服务jar包到linux

    2.编写Dockerfile

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

    3.构建镜像

    docker build --build-arg JAR_FILE=tensquare_eureka_server-1.0-SNAPSHOT.jar -t eureka:v1 .
    

    4.查看镜像是否创建成功

    docker images
    

    5.创建容器

    docker run -i --name=eureka -p 10086:10086 eureka:v1
    

    部署配置Harbor

    安装docker-compose
    curl -L "https://github.com/docker/compose/releases/download/1.22.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
    
    # 对二进制文件应用可执行权限:
    sudo chmod +x /usr/local/bin/docker-compose
    # 测试是否安装成功
    docker-compose --version
    
    解压安装配置harbor
    # 解压
    tar xf harbor-offline-installer-v1.9.2.tgz 
    mkdir /opt/harbor
    mv harbor/*  /opt/harbor
    cd /opt/harbor
    
    # 配置
    vim harbor.yml
    hostname: 192.168.1.8
    port: 88
      
    # 安装
    ./install
    
    启动访问harbor
    # 启动
    docker-compose up -d 
    
    # 停止
    docker-compose stop 
    
    # 重新启动
    docker-compose restart
    
    
    # 访问harbor
    # IP:88
    # 默认账户密码: admin/Harbor12345
    

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

    创建用户

    给项目分配用户

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

    镜像上传Harbor

    1. 给镜像打标签

    docker tag nginx:latest 192.168.1.8/tensquare/nginx:v1
    

    2. 将Harbor地址加入到Docker信任列表

    vim /etc/docker/daemon.json 
    {
      "registry-mirrors": ["https://yj9iu9ne.mirror.aliyuncs.com"],
      "insecure-registries": ["192.168.1.8:88"]
    }
    

    3. 登录harbor推送镜像

     docker login -u wunai -p xxxxx 192.168.1.8:88
        
     docker push 192.168.1.8:88/tensquare/nginx:v1
    

    从Harbor下载镜像

    1.修改docker配置

    vim /etc/docker/daemon.json
    {
    "registry-mirrors": ["https://registry.docker-cn.com"],
    "insecure-registries": ["192.168.1.8:88"]
    }
    

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

     docker login -u wunai -p xxxxx 192.168.1.8:88
     docker pull 192.168.1.8:88/tensquare/nginx:v1
    

    从GitHub拉取代码

    创建GitLab后端项目

    创建前端项目

    上传代码就不演示了

    配置Jenkins后端拉取项目

    jenkinsfile2

    //git凭证ID
    def git_auth = "d04c1647-902a-4d18-b5df-36e5a69af120"
    //git的url地址
    def git_url = "git@192.168.1.4:youmen/tensquare_back.git"
    
    
    node {
       stage('拉取代码') {
            checkout([$class: 'GitSCM', branches: [[name: "*/${branch}"]], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]]])
       }
    }
    

    提交到SonarQube代码审查

    jenkinsfile2

    //git凭证ID
    def git_auth = "d04c1647-902a-4d18-b5df-36e5a69af120"
    //git的url地址
    def git_url = "git@192.168.1.4:youmen/tensquare_back.git"
    
    
    node {
       stage('拉取代码') {
            checkout([$class: 'GitSCM', branches: [[name: "*/${branch}"]], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]]])
       }
    
       stage('代码审查') {
            //定义当前Jenkins的SonarQubeScanner工具
            def scannerHome = tool 'sonar-scanner'
            //引用当前JenkinsSonarQube环境
            withSonarQubeEnv('sonarqube') {
                sh """
                    cd ${project_name}
             	    ${scannerHome}/bin/sonar-scanner
                """
            }
       	}
    }
    

    编译打包微服务工程

    //git凭证ID
    def git_auth = "d04c1647-902a-4d18-b5df-36e5a69af120"
    //git的url地址
    def git_url = "git@192.168.1.4:youmen/tensquare_back.git"
    
    
    node {
       stage('拉取代码') {
            checkout([$class: 'GitSCM', branches: [[name: "*/${branch}"]], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]]])
       }
    
       stage('代码审查') {
            //定义当前Jenkins的SonarQubeScanner工具
            def scannerHome = tool 'sonar-scanner'
            //引用当前JenkinsSonarQube环境
            withSonarQubeEnv('sonarqube') {
                sh """
                    cd ${project_name}
             	    ${scannerHome}/bin/sonar-scanner
                """
            }
       	}
    
       	stage('编译,安装公共子工程') {
       		sh "mvn -f tensquare_common clean install"
       	}
    
       	stage('编译,打包微服务工程') {
       		sh "mvn -f ${project_name} clean package"
       	}
    }
    

    使用Dockerfile生成镜像

    在每个微服务项目pom.xml加入dockerfile-maven-plugin插件
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
                <plugin>
                    <groupId>com.spotify</groupId>
                    <artifactId>dockerfile-maven-plugin</artifactId>
                    <version>1.3.6</version>
                    <configuration>
                        <repository>${project.artifactId}</repository>
                        <buildArgs>
                            <JAR_FILE>target/${project.build.finalName}.jar</JAR_FILE>
                        </buildArgs>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    
    每个微服务项目根目录建立dockerfile文件
    #FROM java:8
    FROM openjdk:8-jdk-alpine
    ARG JAR_FILE
    COPY ${JAR_FILE} app.jar
    EXPOSE 10086
    ENTRYPOINT ["java","-jar","/app.jar"]
    
    配置jenkinsfile
    //git凭证ID
    def git_auth = "d04c1647-902a-4d18-b5df-36e5a69af120"
    //git的url地址
    def git_url = "git@192.168.1.4:youmen/tensquare_back.git"
    
    
    node {
       stage('拉取代码') {
            checkout([$class: 'GitSCM', branches: [[name: "*/${branch}"]], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]]])
       }
    
       stage('代码审查') {
            //定义当前Jenkins的SonarQubeScanner工具
            def scannerHome = tool 'sonar-scanner'
            //引用当前JenkinsSonarQube环境
            withSonarQubeEnv('sonarqube') {
                sh """
                    cd ${project_name}
             	    ${scannerHome}/bin/sonar-scanner
                """
            }
       	}
    
       	stage('编译,安装公共子工程') {
       		sh "mvn -f tensquare_common clean install"
       	}
    
       	stage('编译,打包微服务工程') {
       		sh "mvn -f ${project_name} clean package dockerfile:build"
       	}
    }
    

    上传Harbor镜像仓库并拉取发布应用

    创建harbor凭证

    # 创建完成后再点进去将里面ID复制出来,然后放到Jenkinsfile里面
    1d961bbc-82a1-41a2-b146-52bcaffe44f7
    

    将harbor用户名和密码通过凭证和pipline转换达到隐藏用户名和密码的功能

    上传Harbor镜像
    //git凭证ID
    def git_auth = "d04c1647-902a-4d18-b5df-36e5a69af120"
    
    //git的url地址
    def git_url = "git@192.168.1.4:youmen/tensquare_back.git"
    
    // 镜像版本号
    def tag = "latest"
    
    // Harbor的url地址
    def harbor_url="192.168.1.8:88"
    
    // 镜像库项目名称
    def harbor_project = "tensquare"
    
    // Harbor的登陆凭证
    def harbor_auth = "1d961bbc-82a1-41a2-b146-52bcaffe44f7"
    
    node {
       stage('拉取代码') {
            checkout([$class: 'GitSCM', branches: [[name: "*/${branch}"]], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]]])
       }
    
       stage('代码审查') {
            //定义当前Jenkins的SonarQubeScanner工具
            def scannerHome = tool 'sonar-scanner'
            //引用当前JenkinsSonarQube环境
            withSonarQubeEnv('sonarqube') {
                sh """
                    cd ${project_name}
             	    ${scannerHome}/bin/sonar-scanner
                """
            }
       	}
    
       	stage('编译,安装公共子工程') {
       		sh "mvn -f tensquare_common clean install"
       	}
    
       	stage('编译,打包微服务工程,上传镜像') {
       		sh "mvn -f ${project_name} clean package dockerfile:build"
    
       		// 定义镜像名称
       		def imageName = "${project_name}:${tag}"
    
       		// 对镜像打标签
       		sh "docker tag ${imageName} ${harbor_url}/${harbor_project}/${imageName}"
    
    
            //把镜像推送到Harbor
            withCredentials([usernamePassword(credentialsId: "${harbor_auth}", passwordVariable: 'password', usernameVariable: 'username')]) {
    
                //登录到Harbor
                sh "docker login -u ${username} -p ${password} ${harbor_url}"
    
                //镜像上传
                sh "docker push ${harbor_url}/${harbor_project}/${imageName}"
    
                sh "echo 镜像上传成功"
            }
       	}
    }
    

    拉取镜像和发布应用

    安装Publish Over SSH插件

    做jenkins与生产部署服务器免密
    # [root@jenkins-2 ~]# ssh-copy-id 192.168.1.6
    

    配置微服务启动端口

    配置jenkinsfile
    //git凭证ID
    def git_auth = "d04c1647-902a-4d18-b5df-36e5a69af120"
    
    //git的url地址
    def git_url = "git@192.168.1.4:youmen/tensquare_back.git"
    
    // 镜像版本号
    def tag = "latest"
    
    // Harbor的url地址
    def harbor_url="192.168.1.8:88"
    
    // 镜像库项目名称
    def harbor_project = "tensquare"
    
    // Harbor的登陆凭证
    def harbor_auth = "1d961bbc-82a1-41a2-b146-52bcaffe44f7"
    
    node {
       stage('拉取代码') {
            checkout([$class: 'GitSCM', branches: [[name: "*/${branch}"]], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]]])
       }
    
       stage('代码审查') {
            //定义当前Jenkins的SonarQubeScanner工具
            def scannerHome = tool 'sonar-scanner'
            //引用当前JenkinsSonarQube环境
            withSonarQubeEnv('sonarqube') {
                sh """
                    cd ${project_name}
             	    ${scannerHome}/bin/sonar-scanner
                """
            }
       	}
    
       	stage('编译,安装公共子工程') {
       		sh "mvn -f tensquare_common clean install"
       	}
    
       	stage('编译,打包微服务工程,上传镜像') {
       		sh "mvn -f ${project_name} clean package dockerfile:build"
    
       		// 定义镜像名称
       		def imageName = "${project_name}:${tag}"
    
       		// 对镜像打标签
       		sh "docker tag ${imageName} ${harbor_url}/${harbor_project}/${imageName}"
    
    
            //把镜像推送到Harbor
            withCredentials([usernamePassword(credentialsId: "${harbor_auth}", passwordVariable: 'password', usernameVariable: 'username')]) {
    
                //登录到Harbor
                sh "docker login -u ${username} -p ${password} ${harbor_url}"
    
                //镜像上传
                sh "docker push ${harbor_url}/${harbor_project}/${imageName}"
    
                sh "echo 镜像上传成功"
            }
    
            // 部署应用
           	sshPublisher(publishers: [sshPublisherDesc(configName: 'master_server', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: "/opt/jenkins_shell/deploy.sh $harbor_url $harbor_project $project_name  $tag $port", execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
       	}
    }
    
    配置部署脚本
    [root@tomcat-6 ~]# cat /opt/jenkins_shell/deploy.sh 
    #! /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}:${tag}  | 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 eric -p Eric123456 $harbor_url
    
    # 下载镜像
    docker pull $imageName
    
    # 启动容器
    docker run -di -p $port:$port $imageName
    
    echo "容器启动成功"
    
    
    # 记得加+x权限
    

    访问查看

    部署测试所有微服务

    # src/main/resourcesapplication.yml 修改数据库地址
    
    [root@tomcat-6 ~]# docker ps
    CONTAINER ID        IMAGE                                                     COMMAND                CREATED             STATUS              PORTS                               NAMES
    120baa66789c        192.168.1.8:88/tensquare/tensquare_gathering:latest       "java -jar /app.jar"   3 minutes ago       Up 3 minutes        0.0.0.0:9002->9002/tcp              friendly_jones
    29bb1c3156c3        192.168.1.8:88/tensquare/tensquare_zuul:latest            "java -jar /app.jar"   8 minutes ago       Up 8 minutes        0.0.0.0:10020->10020/tcp            xenodochial_knuth
    76113fb1c859        192.168.1.8:88/tensquare/tensquare_eureka_server:latest   "java -jar /app.jar"   13 minutes ago      Up 13 minutes       0.0.0.0:8080->8080/tcp, 10086/tcp   peaceful_euler
    7a84a0f6e3eb        192.168.1.8:88/tensquare/tensquare_admin_service:latest   "java -jar /app.jar"   20 minutes ago      Up 20 minutes       0.0.0.0:9001->9001/tcp              sad_beaver
    

    部署前端静态网站

    安装配置nginx
    yum -y install nginx
    systemctl start nginx && systemctl enable nginx
    # 查看nginx软件版本
    nginx -v
    
    # 修改nginx端口
    
        server {
            listen       9090 default_server;
            listen       [::]:9090 default_server;
            server_name  _;
            root         /usr/share/nginx/html;
    
    # 重启服务使配置生效        
    systemctl restart nginx 
    
    # 验证服务状态
    [root@tomcat-6 ~]# curl -I localhost:9090
    HTTP/1.1 200 OK
    Server: nginx/1.16.1
    
    安装NodeJS插件

    配置全局工具Nodejs

    Jenkins配置Nginx服务器

    注意修改前端代码的里面地址为网关地址

    'use strict'
    module.exports = {
      NODE_ENV: '"production"',
      // BASE_API: '"http://192.168.207.131:7300/mock/5c0b42c85b4c7508d4dc568c/1024"'
      BASE_API: '"http://192.168.1.6:10020"' // 管理员网关
    }
    

    // gitlab凭证
    def git_auth = "181829c8-c8cd-4e85-aa93-89ad280a5e69"
    
    def git_url = "git@192.168.1.4:youmen/tensquare_front.git"
    
    
    
    node {
       stage('拉取代码') {
            checkout([$class: 'GitSCM', branch
    es: [[name: "*/${branch}"]], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]]])
       }
    
    
    	stage('打包,部署网站') {
    	// 使用NodeJS的npm进行打包
    		sh '''
    			npm install 
    			nmp run build
    		'''
    	}
    
    	// 项目部署
       	sshPublisher(publishers: [sshPublisherDesc(configName: 'master_server', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: '', execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '/usr/share/nginx/html', remoteDirectorySDF: false, removePrefix: 'dist', sourceFiles: 'dist/**')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
    }
    
    

  • 相关阅读:
    Java程序执行超时——Future接口介绍
    JENKINS 打包发布脚本
    获取servletContext springMvc获取servletContext
    14.19 InnoDB and MySQL Replication InnoDB 和MySQL 复制:
    14.18.1 The InnoDB Recovery Process InnoDB 恢复进程:
    perl 获取文件内容里第一个AAA和最后一个AAA
    14.18 InnoDB Backup and Recovery 备份和恢复:
    职业素养与职业声誉——北漂18年(62)
    Openstack组件实现原理 — Nova 体系结构
    Openstack组件实现原理 — Nova 体系结构
  • 原文地址:https://www.cnblogs.com/you-men/p/13768536.html
Copyright © 2020-2023  润新知