jenkins-自动化部署(二)

配置关联机器

安装插件

系统管理->插件管理->可选插件

搜索" Publish over SSH" 因为我装了所以搜索不出来,搜索出来 打勾 点击直接安装就好了

 

 

配置关联机器

就是jenkins访问部署服务的机器

系统管理-系统配置

 

 

配置密码

 

 

输入服务器密码 

 

测试

安装git

因为我使用git作为源代码工具 所以在服务器安装git

yum -y install git

安装maven

源码构建工具使用的maven 所以安装maven <<maven安装>>

变量配置

如果不配置,会出现shell执行mvn命令 报:jenkinsmvn: command not found

将安装maven配置的变量设置到jenkins 如:

 vi /etc/profile

 

 

 

 

 

 

 

安装jdk

参考《jdk-安装》

变量配置

设置ssh免密登录

1.设置免密

注:需要在jenkins账户下创建秘钥,切换失败则参考下面

参考:《linux-scp免密登录》

2.因为jenkins是默认用jenkins账户取执行ssh jenkins账户是没有权限的

su jenkins

如果切换失败还是root账户

vim /etc/passwd

jenkins:x:986:980:Jenkins Automation Server:/var/lib/jenkins:/bin/false

改为

jenkins:x:986:980:Jenkins Automation Server:/var/lib/jenkins:/bin/bash

 

 

 

 再次执行

[root@cicd ~]# su jenkins
bash-4.1$

结果命令提示符的用户名不是jenkins而变成了 bash-4.1$,原因是在安装jenkins时,jenkins只是创建了jenkins用户,并没有为其创建home目录。

使用root账户执行

vim ~/.bash_profile

 

在文件末尾加上

export PS1='[\u@\h \W]\$'

刷新配置

source ~/.bash_profile

验证是否成功

 

3.jenkins系统用户开通免密登陆

使用root账户输入

sudo visudo

在文件末尾加上

jenkins ALL=(ALL) NOPASSWD: ALL

重启jenkins

systemctl status jenkins
systemctl stop jenkins
systemctl start jenkins

任务管理例子

这是我们的每个tag对应一个环境,然后需要发布某个环境下服务切到环境下点一下就行了,因为我们多个需求并行开发 所以测试环境很多套,不同的环境发不同的分支互不影响:如bbc-preview1 就是第一套   pro就是生产

 

创建任务

 

 

 

 

2.构建设置

 

3.变量设置,脚本和git需要使用

 

 

 

 

 

 

4.设置源码地址和登录名密码信息

 5.设置构建步骤 使用shell

 

 

脚本编写案例1

编写jenkins服务shell脚本

#!/bin/bash
#目标服务器主目录
_DEPLOYER='deploy'
#程序的yml环境配置
_PROFILES='alitest'
#日志目录
_LOG_DIRECTORY="/home/$_DEPLOYER/logs"
#这里定义服务的配置多个服务空格隔开 如:SERVICE_CONFIG_TABLE='service-bridge;9910;1g service-bridge2;9910;1g'
SERVICE_CONFIG_TABLE='service-bridge;9908;1g'
#是否部署bridge的变量 不支持-的定义 所以改为_
service_bridge=$service_bridge
#读取上面hosts配置的变量
hosts=$hosts
#是否重新打包,写死,如果需要动态勾选在jenkens通过变量配置
repackage=true
#是否重新部署服务  写死 如果需要动态勾选在jenkens通过变量配置
restart=true
#写死,如果需要动态勾选 在上面配置  写死 如果需要动态勾选在jenkens通过变量配置
skipTest=true
TEST_ARGUMENT="";
#maven打包是否跳过Test
if $skipTest; then
    TEST_ARGUMENT="-Dmaven.test.skip=true"
fi

#是否需要重新打包 循环服务配置 进行逐个maven打包
if $repackage; then
    #支持多服务配置 空格隔开 所以 用for in
    for SERVICE_CONFIG in $SERVICE_CONFIG_TABLE; do
        #通过;分割 取第一个 取出服务名字
        SERVICE_NAME=$(echo $SERVICE_CONFIG | cut -f 1 -d ';' )
        #将service-** 替换为service_**
        isDeployParameterName=${SERVICE_NAME/-/_};
        #根据名字获得value
        isDeployParameterValue=${!isDeployParameterName}
        #根据是否勾选了部署来判断是否部署
        if  $isDeployParameterValue; then
            #maven 命令 clean 并重新打包到targer
            mvn  -s "/var/lib/jenkins/workspace/preview-ch-micro-services/settings.xml" clean package -pl "$SERVICE_NAME" -am -U $TEST_ARGUMENT
            if [ $? -gt 0 ]; then
                echo "编译错误"
                exit 1
            fi
        fi
    done
    echo "打包成功[$branch]...准备scp到目标服务器"
    for SERVICE_CONFIG in $SERVICE_CONFIG_TABLE; do
        SERVICE_NAME=$(echo $SERVICE_CONFIG | cut -f 1 -d ';' )
        #将service-** 替换为service_**
        isDeployParameterName=${SERVICE_NAME/-/_};
        #根据名字获得value
        isDeployParameterValue=${!isDeployParameterName}
        #根据是否勾选了部署来判断是否部署
        if  $isDeployParameterValue; then
            #获得指定服务的变量名字
            hostParameterName=$isDeployParameterName"_hosts";
            #将打包后的jar 推送到目标服务器的projects目录
            #我们host是文本变量通过回车换行,其实变量值是空格隔开 直接循环
            for host in ${!hostParameterName};do
                scp $SERVICE_NAME/target/*.jar root@$host:/home/$_DEPLOYER/projects
                #判断上一个命令是否执行成功
                if [ $? -eq 0 ]; then
                    echo "服务"$SERVICE_NAME"主机地址"$host"已最新包scp到服务器成功"
                else
                    echo "服务"$SERVICE_NAME"主机地址"$host"最新包scp到服务器失败"
                fi

            done

        fi
    done
fi
#是否发布  循环服务 执行脚本start_bash
if $restart; then
    #支持多服务配置 空格隔开 所以 用for in
    for SERVICE_CONFIG in $SERVICE_CONFIG_TABLE; do
        SERVICE_NAME=$(echo $SERVICE_CONFIG | cut -f 1 -d ';' )
        #将service-** 替换为service_**
        isDeployParameterName=${SERVICE_NAME/-/_};
        #根据名字获得value
        isDeployParameterValue=${!isDeployParameterName}
        #根据是否勾选了部署来判断是否部署
        if  $isDeployParameterValue; then
            #通过;分割取第三个 获取内存大小
            MEMORY_MAX=$(echo $SERVICE_CONFIG | cut -f 3 -d ';' )
            #通过;分割去第二个 获取端口号
            SERVICE_PORT=$(echo $SERVICE_CONFIG | cut -f 2 -d ';' )
            #获得指定服务的变量名字
            hostParameterName=$isDeployParameterName"_hosts";
            #我们host是文本变量通过回车换行,其实变量值是空格隔开 直接循环
            for host in ${!hostParameterName};do

                #1.在指定主机执行递归创建2个目录
                #2.将projects的打包的jar复制到workspace
                #3.调用远程服务器的start_bash脚本 执行服务发布
                ssh root@$host "mkdir -p /home/deploy/logs && mkdir -p /home/deploy/workspace/$SERVICE_NAME-$SERVICE_PORT && \
                cp /home/deploy/projects/$SERVICE_NAME.jar /home/deploy/workspace/$SERVICE_NAME-$SERVICE_PORT/app.jar && \
                bash /home/deploy/start_bash -s -- -t/home/$_DEPLOYER/workspace/$SERVICE_NAME-$SERVICE_PORT/app.jar\
                -a-Xmx$MEMORY_MAX\ -Xms$MEMORY_MAX\ -XX:+PrintGCDetails\ -XX:+HeapDumpOnOutOfMemoryError\ -Dspring.profiles.active=alitest\ -Dproject.name=service-bridge\ -Dcsp.sentinel.dashboard.server=192.168.20.4:9998 -f$_LOG_DIRECTORY/$SERVICE_NAME.log"
                #判断上一个命令是否执行成功
                if [ $? -eq 0 ]; then
                    echo "服务"$SERVICE_NAME"主机地址"$host"已经执行ssh脚本成功"
                else
                    echo "服务"$SERVICE_NAME"主机地址"$host"执行ssh脚本失败"
                fi
            done
        fi
    done
fi

有点多 好好读可以看得懂

编写部署端脚本

可以看到上面调用了start_bash 在指定目录创建

JVA_HOME=/usr/java/jdk1.8.0_191
JRE_HOME=/usr/java/jdk1.8.0_191/jre
CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib
PATH=$JAVA_HOME/bin:$PATH
export PATH JAVA_HOME CLASSPATH

_TARGET=""
_DIRECTORY=""
_NAME=""
_PORT=""
_LOG=
_LOG_FILE="/dev/null"
_STOP=
_PID=
_COMMAND=
_ARGUMENTS=""
#getopts会将 对应入参封装到OPTARG里面 比如a 则会获取到-a参数 只有参数的才会进while循环 比如没有-a 就不会走case a
while getopts "a:t:p:x:s:lf:kh" opt; do
  case $opt in
        a)
                #$OPTARG" 为脚本-a的参数
                _ARGUMENTS=" $OPTARG"
                ;;
        t)
                #OPTARG 为脚本的-t参数
                _TARGET="$OPTARG"
                _DIRECTORY=$(dirname $OPTARG)"/"
                _NAME=$(echo $(basename $OPTARG) | cut -f 1 -d '.')
                ;;
    p)
        _PORT=$OPTARG
        ;;
    l)
                _LOG=true
                ;;
        f)
                _LOG=true
                if [ ! "$OPTARG" = "" ]; then
                        _LOG_FILE=$OPTARG
                fi
                ;;
        s)
                _STOP=true
                ;;
        h)
                _HELP_FORMAT="%-4s %-80s\n"
                printf "$_HELP_FORMAT" "参数" "描述"
                printf "$_HELP_FORMAT" "-t" "jar包绝对地址, 如: '-t/home/deployer/test.jar'"
                printf "$_HELP_FORMAT" "-p" "jar包占用端口, 如: '-p7777'"
                printf "$_HELP_FORMAT" "-a" "自定义参数, 如: '-a-DenableSecurity=true\ -Dtoken=xxxx'"
                printf "$_HELP_FORMAT" "-l" "开启日志输出,不指定该参数则不输出日志. 日志默认输出到目标jar包相同目录下的同文件名.log"
                printf "$_HELP_FORMAT" "-f" "强制开启日志输出,指定参数为'-f/var/log/test.log',则输出到/var/log/test.log文件"
                printf "$_HELP_FORMAT" "-s" "强制关闭目标程序(不会启动目标文件),默认按端口,次之按文件"
                exit
                ;;
  esac
done

#根据PID获取端口
function getPidByPort {
        if [ -f "/usr/sbin/lsof" ]; then
                echo `/usr/sbin/lsof -i:"$1" | grep LISTEN | awk '{ print $2}'`
        else
                echo `/usr/bin/lsof -i:"$1" | grep LISTEN | awk '{ print $2}'`
        fi
}
#根据PI获取file
function getPidByFile {
       echo `ps aux | grep \\\\-jar | grep $1 | awk '{ print $2}'`
}
#获得PID
function getPid {
 if [ "$_PORT" == "" ]; then
                if [ ! "$_NAME" == "" ]; then
                        _PID=`getPidByFile "$_TARGET"`
                fi
        else
                _PID=`getPidByPort $_PORT`
        fi
}
#调用PID
getPid
echo $_PID
#多有有则杀掉PID
if [[ $_PID =~ ^[0-9]+$ ]]; then
        echo "kill process $_PID"
        kill $_PID;
        echo "sleep 5 seconds"
        sleep 5
        getPid
        if [[ $_PID =~ ^[0-9]+$ ]]; then
                kill -9 $_PID
                sleep 1
        fi
fi

if [ $_STOP ]; then
        getPid
        if [[ $_PID =~ ^[0-9]+$ ]]; then
                echo "无法关闭进程:$_PORT"
                exit;
        else
                echo "已经关闭指定程序进程"
        fi
#       exit;
fi

if [ "$_NAME" == "" ]; then
        echo "请指定需要启动的jar包的绝对地址,如: -t/home/test.jar"
        exit
fi

if [ $_LOG ]; then
        if [ "$_LOG_FILE" = "/dev/null" ]; then
                _LOG_FILE="$_DIRECTORY$_NAME.log"
        else
                mkdir -p "$(dirname $_LOG_FILE)"
        fi
fi

_COMMAND="nohup java -jar$_ARGUMENTS $_TARGET > $_LOG_FILE 2>&1 &"
echo "正在执行:$_COMMAND"
source /etc/profile
eval $_COMMAND

脚本编写案例2

以下是我部署canal的脚本

jenkins

_DEPLOYER='canalServer'

task='';
if $repackage; then
task="maven打包并推服务器"
fi
if $restart; then
task="${task} 重启服务"
fi
echo "执行任务项:${task}"
if $repackage; then
 mvn clean install -Dmaven.test.skip -Denv=release
 echo "打包成功[${branch}]...准备scp到目标服务器 ${hosts}"
 for host in $hosts
    do
    if [ $? -gt 0 ]; then
          echo "编译错误"
         exit 1
    fi
    scp /home/jenkins/workspace/canal-server/${SERVICE_NAME}/target/canal.deployer-1.1.4.tar.gz ${_DEPLOYER}@${host}:/home/${_DEPLOYER}/projects/canal.deployer-1.1.4.tar.gz
   echo 
 done 
fi
if $restart; then
   echo "准备部署服务器 ${hosts}"
    for host in $hosts
     do
      ssh ${_DEPLOYER}@${host} "bash /home/canalServer/deploy.sh -p/home/canalServer/projects/canal.deployer-1.1.4.tar.gz -t/home/canalServer/projects"
     echo 
    done 
fi


 

部署端

deploy.sh

#!/bin/bash
#getopts会将 对应入参封装到OPTARG里面 比如a 则会获取到-a参数 只有参数的才会进while循环 比如没有-a 就不会走case a
_tarFilePath=''
_tarTargetPath=''
while getopts "a:t:p:x:s:lf:kh" opt; do
  case $opt in
        p)
                #$OPTARG" 为脚本-a的参数
                _tarFilePath="$OPTARG"
                ;;
        t)
                #OPTARG 为脚本的-t参数
                _tarTargetPath="$OPTARG"
                ;;
  esac
done
echo  $_tarTargetPath
echo  $_tarFilePath

#根据程序目录查找pid  grep -v 为排除 避免找到grep进程 awk '{print}'为打印第二个参数 即进程id 注意此获取放到第一行 避免查询到其他进程
_pid=`ps auxww|grep $_tarTargetPath |grep -v grep|grep -v cronolog|grep -v bash|awk '{print $2}'`
#$pid长度大于0
if [ -n "$_pid" ];
then
{
        echo "-----------------kill掉原有进程 $_pid---------------"
        #指定用户kill调进程
        kill  $_pid
         _command= "${_tarTargetPath}/bin/stop.sh"
        eval $_command
}
fi
echo "-------------------------删除原有目录------------------"
#删除以前的执行执行程序
eval "rm -rf ${_tarTargetPath}/bin"
eval "rm -rf ${_tarTargetPath}/conf"
eval "rm -rf ${_tarTargetPath}/logs"
eval "rm -rf ${_tarTargetPath}/lib"
eval "rm -rf ${_tarTargetPath}/plugin"
echo "------------------------执行新的解压-------------------"
_command="tar -xvf ${_tarFilePath} -C ${_tarTargetPath}"
eval $_command
if [ $? -gt 0 ]; then
                echo "解压错误"
                exit 1
        fi
echo '-------开始执行启动命令----------------'
_command="${_tarTargetPath}/bin/startup.sh"
echo $_command
eval $_command

 

测试

 

 

ssh 调用脚本java相关命令报错问题处理

 

 

脚本前面加上 source /etc/profile

posted @ 2020-10-29 15:39  意犹未尽  阅读(430)  评论(0编辑  收藏  举报