GitLab CI/CD 自动化部署-springBoot-demo示例

23 篇文章 0 订阅
16 篇文章 0 订阅

CI/CD 的核心概念是持续集成、持续交付和持续部署

  • CI 持续集成(Continuous Integration)
  • CD 持续交付(Continuous Delivery)
  • CD 持续部署(Continuous Deployment)

GitLab 是一个用于仓库管理系统的开源项目,使用Git作为代码管理工具,并在此基础上搭建起来的Web服务。安装方法是参考GitLab在GitHub上的Wiki页面。
GitLab 是支持CI/CD的,当前项目使用的gitlab管理的代码,故自己尝试一下 jar的CI/CD。

参考

主要参考:GitLab CI/CD 自动化部署入门 ,手把手教你搭建 —— 从安装 Linux 到 GitLab 自动化部署(非常详细)
Gitlab CI 配置文件 .gitlab-ci.yaml 详解(上)
GitLab Runner的安装与使用
部署-gitlab克隆地址踩坑
Gitlab 安装gitlab-runner踩坑记录
什么是 CI/CD ?

操作

Linux服务器是使用的 公司内网测试服务 centos 7
gitlab的server端是由同事前不久部署的,版本 14.0.5
在这里插入图片描述
下载gitlab-runner,版本15.1.0

 wget https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-amd64
 ll

部署、授权、增加用户、安装、运行

cp gitlab-runner-linux-amd64 /usr/local/bin/gitlab-runner
 # 分配运行权限
 chmod +x /usr/local/bin/gitlab-runner
 ll /usr/local/bin/
 # 获取版本
 gitlab-runner -v
 # 创建用户
 useradd --comment 'GitLab Runner' --create-home gitlab-runner --shell /bin/bash
 # 安装 指定工作目录
 gitlab-runner install --user=gitlab-runner --working-directory=/home/gitlab-runner
 # 运行 
 gitlab-runner start
 # 注册 runner
gitlab-runner register
####
# 输入 gitlab 的访问地址
http://192.168.x.x:x
# 输入 runner token,把开 http://192.168.x.x:x/admin/runners 页面查看
xxxxxxx
# runner 描述,随便填
构建 runner-001 项目
# runner tag
runner-001
# 输入(选择) shell
shell
####

注册完成后,在页面 http://192.168.x.x:x/admin/runners 中查看
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

创建测试项目

结构如下
在这里插入图片描述

gitlab-ci.yml

# gitlab 持续CI配置

## 用于docker镜像
#image: ruby:2.1

## 用于docker服务
#services:
#  - postgres

## 定义在每个job之前运行的命令
before_script:
  - echo "----> start"

## 定义在每个job之后运行的命令
after_script:
  - echo "----> end"

## 定义构建变量-全局
variables:
  MVN_ECHO_1: "开始mvn编译打包"
  RUN_DIR_1: /home/gitlab-runner/server
  JAR_NAME_1: runner-spring-demo-1.0-SNAPSHOT.jar
## 定义构建阶段, 默认是(build、test、deploy),可以自定义名称 无限量(不能用 gitlab-ci的保留字)
stages:
  - build
  - deploy
cache: # 缓存-全局,job内有就覆盖全局的
  untracked: true # 缓存git中没有被跟踪的文件
  # $CI_JOB_NAME 缓存每个job、$CI_COMMIT_REF_NAME 缓存每个分支、
  # $CI_JOB_NAME/$CI_COMMIT_REF_NAME 缓存每个job且每个分支、$CI_JOB_STAGE/$CI_COMMIT_REF_NAME 缓存每个分支且每个stage
  #key: "$CI_JOB_NAME"
  paths: # 缓存 target 目录,mvn会清理。如果是前端项目 就可以缓存 依赖目录 如 node_modules 可以减少打包时间
    - target/
# 单独job,名字唯一-拉取项目
build:
  #cache: # job级别缓存,内容和全局配置一样
  #variables: [] # job级别变量,内容和全局配置一样,[] 是关闭全局变量
  #before_script: # job级别 job之前运行的命令,内容和全局配置一样
  #before_script: # job级别 job之后运行的命令,内容和全局配置一样
  #allow_failure: true # 设置一个job失败的之后并不影响后续的CI组件 默认false
  # 定义何时开始job。可以是on_success(前面stages的所有工作成功时才执行 默认),on_failure(前面stages中任意一个jobs失败后执行),
  # always(无论前面stages中jobs状态如何都执行)或者manual(手动执行)
  #when: on_success
  stage: build # 阶段名称 对应,stages
  tags: # runner 标签(注册runner时设置的,可在 admin->runner中查看)
    - runner_001
  script: # 脚本(执行的命令行)
    - cd ${CI_PROJECT_DIR} # 拉取项目的根目录
    - pwd
    - echo ${MVN_ECHO_1}
    - mvn clean validate  package -Dmaven.test.skip=true
  only: # 定义一列git分支,并为其创建job
    - master # 拉取分支
  #except: # 定义一列git分支,不创建job,和only对应
  artifacts: # 把 dist 的内容传递给下一个阶
    paths:
      - target/
      - archive/
deploy:
  stage: deploy
  tags:
    - runner_001
  script:
    - echo "开始部署>>jar"
    - mkdir -p ${RUN_DIR_1} # 创建目录,如果存在 不报错
    - /bin/cp -rf ${CI_PROJECT_DIR}/target/${JAR_NAME_1} ${RUN_DIR_1}/${JAR_NAME_1} # 使用系统原生cp强制覆盖 避免交互提示
    - /bin/cp -rf ${CI_PROJECT_DIR}/archive/start_server.sh ${RUN_DIR_1}/start_server.sh # 复制 启动脚本
    - cd ${RUN_DIR_1} # 跳转到 服务目录
    - chmod +x ${RUN_DIR_1}/start_server.sh # 授权运行权限
    - sh ${RUN_DIR_1}/start_server.sh restart # 重启
    - ps -ef | grep ${JAR_NAME_1} # 查看运行状态
    - tail ${RUN_DIR_1}/logs/runner-demo.log # 查看服务运行日志,可以看指定时间日志 info.`date +"%Y-%m-%d"`.0.log

start_server.sh

#!/bin/bash

#jar包路径
APP_PATH="/home/gitlab-runner/server/"
JAR_FILE_PATH="${APP_PATH}runner-spring-demo-1.0-SNAPSHOT.jar"
#环境变量 如果没有可空,dev test prod
# ACTIVE="-Dspring.profiles.active=test"
ACTIVE=""
#web项目检查,是否启动 此路径需要自己创建直接返回 ok,不填写则经过默认时间后认为服务启动
WEB_CHECK_URL=""
#console path 数据输出路径,即项目print的内容以及日志sdpt的内容会输出到此文件 /dev/null 为 消失,其他具体文件为输出到指定文件
CONSOLE_PATH="${APP_PATH}hup.out"
#预计项目多久启动
WEB_START_TIME=10

#jvm配置 值依次如下
#元空间初始大小
#元空间最大
#新生代初始空间
#堆栈初始大小
#堆栈最大空间
#垃圾回收器
#启动模式 使用server
#设置时区
#配置文件路径 -Dspring.config.location=${APP_PATH}etc/
JAVA_OPTS="-XX:MetaspaceSize=256M
-XX:MaxMetaspaceSize=512M
-Xms256M
-Xmx4G
-XX:+UseG1GC
-Xss512k
-server
-Duser.timezone=GMT+08
"

#检查服务是否在运行
is_running(){
  pid=$(ps -ef |grep ${JAR_FILE_PATH}|grep -v grep|awk '{print $2}')
  #如果不存在返回1,存在返回0
  if [ -z "${pid}" ]; then
    return 1
  else
    return 0
  fi
}

#运行服务,如果服务运行中则进行提示
start_service(){
  echo `date +"%Y-%m-%d %H:%M:%S"` "开始启动服务..."
  is_running
  if [ $? -eq "0" ]; then
    echo `date +"%Y-%m-%d %H:%M:%S"` "${JAR_FILE_PATH} 已经在运行,线程id ${pid}"
  else
    #启动jar包,并且将输出扔入黑洞(即不保留输出)
    nohup java $JAVA_OPTS -jar $ACTIVE $JAR_FILE_PATH > $CONSOLE_PATH 2>&1 &
    if [ -n "$WEB_CHECK_URL" ]; then
      i=1
      start_ok=0
      while [ $start_ok -eq 0 ]
      do
          if [ $WEB_START_TIME -lt $i ]; then
            start_ok=1
            break
          fi
          back=$(curl -s ${WEB_CHECK_URL})
          if [ "$back" == "ok" ]; then
            start_ok=2
            break
          fi
          let i++
          sleep 1
      done
      if [ $start_ok -eq 2 ]; then
        echo "服务已启动"
      else
        echo `date +"%Y-%m-%d %H:%M:%S"` "服务未在规定时间内正确运行(${WEB_START_TIME}),请检查日志"
      fi
    else
      echo `date +"%Y-%m-%d %H:%M:%S"` "等待${WEB_START_TIME}秒..."
      sleep $WEB_START_TIME
      echo `date +"%Y-%m-%d %H:%M:%S"` "服务已启动"
    fi
  fi
}

stop_service(){
  echo `date +"%Y-%m-%d %H:%M:%S"` "即将关闭程序..."
  is_running
  if [ $? -eq "1" ]; then
    echo "${JAR_FILE_PATH} 未运行,无需停止"
  else
    echo `date +"%Y-%m-%d %H:%M:%S"` "杀死进程(kill不带-9) ${pid}"
    kill $pid
    echo `date +"%Y-%m-%d %H:%M:%S"` "程序已关闭"
  fi
}

status(){
  is_running
  if [ $? -eq "0" ]; then
    echo "${JAR_FILE_PATH} 运行中,线程id ${pid}"
  else
    echo "${JAR_FILE_PATH} 未运行"
  fi
}

#重启服务
restart_service(){
  echo `date +"%Y-%m-%d %H:%M:%S"` "等待1秒,在执行停止..."
  sleep 1
  stop_service
  echo `date +"%Y-%m-%d %H:%M:%S"` "等待10秒,在执行重启..."
  sleep 10
  start_service
  echo `date +"%Y-%m-%d %H:%M:%S"` "服务重启结束..."
}

case "$1" in
  "start")
    echo `date +"%Y-%m-%d %H:%M:%S"` "开始执行服务启动..."
    start_service
    ;;
  "stop")
    echo `date +"%Y-%m-%d %H:%M:%S"` "开始执行服务停止..."
    stop_service
    ;;
  "restart")
    echo `date +"%Y-%m-%d %H:%M:%S"` "开始执行服务重启..."
    restart_service
    ;;
  "status")
    status
    ;;
  *)
    echo "命令为 start|stop|restart|status"
    exit 0
    ;;
esac

pom

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>cn.zy.demo.runner</groupId>
    <artifactId>runner-spring-demo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <!--基于Springboot-->
    <parent>
        <artifactId>spring-boot-starter-parent</artifactId>
        <groupId>org.springframework.boot</groupId>
        <version>2.3.1.RELEASE</version>
        <relativePath/>
    </parent>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <skipTests>true</skipTests>

        <spring-boot.version>2.3.1.RELEASE</spring-boot.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>
    <build>
        <finalName>${project.artifactId}-${project.version}</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <executions>
                    <execution>
                        <id>default-jar</id>
                        <phase>package</phase>
                        <goals>
                            <goal>jar</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-deploy-plugin</artifactId>
                <configuration>
                    <skip>true</skip>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

yml

server:
  port: 9980
  version: 2022072001
  servlet:
    context-path: /runner-demo/
spring:
  jackson:
    time-zone: GMT+8
    date-format: yyyy-MM-dd HH:mm:ss
logging:
  file:
    name: ./logs/runner-demo.log
  pattern:
    console: '%clr(%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}'

java

启动类
import cn.zy.demo.runner.util.EnvUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * 启动类
 *
 * @author z.y.l
 * @version v1.0
 * @date 2022/7/20
 */
@SpringBootApplication
public class RunnerSpringDemoApplication {
    private static final Logger log = LoggerFactory.getLogger(RunnerSpringDemoApplication.class);
    public static void main(String[] args) {
        SpringApplication.run(RunnerSpringDemoApplication.class,args);
        String port = EnvUtil.getStr("server.port"),
                path = EnvUtil.getStr("server.servlet.context-path");
        log.info("http://127.0.0.1:{}{}",port,path);
    }
}
工具类
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

import javax.validation.constraints.NotNull;

/**
 * EnvUtil 类说明:
 *
 * @author z.y.l
 * @version v1.0
 * @date 2022/7/20
 */
@Component
public class EnvUtil implements EnvironmentAware {
    private static Environment env;
    @Override
    public void setEnvironment(@NotNull Environment environment) {
        env = environment;
    }
    public static String getStr(String key){
        return env.getProperty(key);
    }
}
测试接口
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Date;
import java.util.Map;
import java.util.TreeMap;

/**
 * RootController 类说明:
 *
 * @author z.y.l
 * @version v1.0
 * @date 2022/7/20
 */
@RestController
@RequestMapping("/")
public class RootController {
    private static final Logger logger = LoggerFactory.getLogger(RootController.class);
    private static final Date RUN_TIME = new Date();
    @Value("${server.version}")
    private String version;
    @RequestMapping
    public Map<String, Object> index(){
        Map<String, Object> map  = new TreeMap<>();
        map.put("now-time", new Date());
        map.put("run-time", RUN_TIME);
        map.put("version", version);
        logger.info("请求,{}",map);
        return map;
    }
}

测试CI CD

提交代码,登录 页面 http://192.168.x.x:x/admin/jobs,就可以看到触发的自动job。
可以看到定义的两个阶段job串行执行了,status 状态大概是:等待、执行中、已失败、已跳过等。点击 status状态,就可以看到日志了
在这里插入图片描述

大概分为几个运行阶段

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

mvn编译的日志

在这里插入图片描述

第二个job

在这里插入图片描述
在这里插入图片描述在这里插入图片描述

部署的日志

在这里插入图片描述

失败的情况

在这里插入图片描述

跳过的没有日志

因为依赖的上个job执行失败,就会跳过,也和yml中的配置有关系
在这里插入图片描述

提交项目,自动构建,查看发现失败

构建失败的原因是gitlab的克隆路径不对,因为gitlab是公司同事维护的,并且是在docker部署。联系同事一起解决问题
在这里插入图片描述
在这里插入图片描述
修复后
在这里插入图片描述
在这里插入图片描述

问题-部署失败-git版本低问题

报错

Running with gitlab-runner 15.1.0 (76984217)
  on 构建 runner001 项目 xymGSfhp
Preparing the "shell" executor
00:00
Using Shell executor...
Preparing environment
00:00
Running on localhost.localdomain...
Getting source from Git repository
00:01
Fetching changes with git depth set to 50...
重新初始化现存的 Git 版本库于 /home/gitlab-runner/builds/xymGSfhp/0/****/runner-spring-demo/.git/
fatal: git fetch-pack: expected shallow list
fatal: The remote end hung up unexpectedly
ERROR: Job failed: exit status 1

解决方式

# git版本太低 要升级
git --version
#git version 1.8.3.1
#安装源
yum install http://opensource.wandisco.com/centos/7/git/x86_64/wandisco-git-release-7-2.noarch.rpm
#安装git
#yum install git
#更新git
yum update git
#...
git --version
#git version 2.31.1

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

END

这只是后端的部署,前端部署 在cp文件到nginx下面就可以了,命令更少点。这只是个人的操作记录,请根据实际情况自行判断。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值