jenkins 部署以及基本使用
1 下载最新war包
下载地址:https://www.jenkins.io/zh/download/
下载对应war包文件
2 安装jdk环境
jdk下载地址:https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html
tar -zxvf jdk-8u60-linux-x64.tar.gz
mv jdk1.8.0_60 /usr/local/jdk1.8
vim /etc/profile
export JAVA_HOME=/usr/local/jdk1.8
export CLASSPATH=$JAVA_HOME/lib/
export PATH=$JAVA_HOME/bin:$PATH
source /etc/profile
java -version
3 编写启动脚本
创建目录
mkdir -p /home/module/jenkins
把对应的war包拷贝到 上面的目录
touch jenkins.sh
内容如下
#!/bin/bash
#这里可替换为你自己的执行程序,其他代码无需更改
export JENKINS_HOME=/home/module/jenkins
APP_NAME="jenkins.war"
JAVA_OPTS="-Xms512m -Xmx512m"
HTTP_PORT="28888"
#使用说明,用来提示输入参数
usage() {
echo "Usage: sh demo.sh [start|stop|restart|status]"
exit 1
}
#检查程序是否在运行
is_exist() {
pid=$(ps -ef | grep $APP_NAME | grep -v grep | awk '{print $2}')
#如果不存在返回1,存在返回0
if [ -z "${pid}" ]; then
return 1
else
return 0
fi
}
#启动方法
start() {
is_exist
if [ $? -eq "0" ]; then
# java -jar ${APP_NAME}
echo "${APP_NAME} is already running. pid=${pid} ."
else
nohup java ${JAVA_OPTS} -jar ${JENKINS_HOME}/${APP_NAME} --ajp13Port=-1 --httpPort=${HTTP_PORT} >/dev/null 2>&1 &
fi
}
#停止方法
stop() {
is_exist
if [ $? -eq "0" ]; then
kill -9 $pid
else
echo "${APP_NAME} is not running"
fi
}
#输出运行状态
status() {
is_exist
if [ $? -eq "0" ]; then
echo "${APP_NAME} is running. Pid is ${pid}"
else
echo "${APP_NAME} is not running."
fi
}
#重启
restart() {
stop
start
}
#根据输入参数,选择执行对应方法,不输入则执行使用说明
case "$1" in
"start")
start
;;
"stop")
stop
;;
"status")
status
;;
"restart")
restart
;;
*)
usage
;;
esac
4 给脚本授权
chmod 777 jenkins.sh
5 启动、停止jenkins
# 启动
./jenkins.sh start
# 停止
./jenkins.sh stop
# 查看状态
./jenkins.sh status
# 重启
./jenkins.sh restart
6 开机自启设置
在/etc/rc.d/rc.local文件底部,添加内容:
# jenkins
/home/module/jenkins/jenkins.sh start
chmod 777 /etc/rc.d/rc.local
7 重启
reboot
8 基本使用
8.1 安装
访问:http://xxx:28888/
安装pipeline相关插件全部安装上,防止错误
点击安装即可,如果出现安装失败的情况,就重新安装就行。
8.1 webhook配置
修改配置:
全局安全配置=》登录用户可以做任何事 =》匿名用户具有可读权限 打勾
跨站请求伪造保护 =》 防止跨站点请求伪造 取消打勾
创建流水线
配置:用于gitlab 触发使用
8.2 添加凭证
点击左侧菜单凭证
添加凭证
9 流水线基本使用
maven项目build
// jenkins 服务部署使用
// 获取代码是master主干分支,如果需要修改分支语法:v1-test 对应分支名称
// git branch: 'v1-test',credentialsId: 'gogs-auth', url: "${REPOSITORY}"
pipeline {
agent any
environment {
// gitee仓库地址
REPOSITORY = "https://gitee.com/dcy421/dcy-fast-cloud.git"
// 路径前缀
PATH_PREFIX = "business-center/"
// 模块名称
MODULE = "auth-center"
// 脚本路径
SCRIPT_PATH = "/data/module/jenkins-scripts/junban-v2"
// 运行环境
RUN_ENV = "dev"
}
stages {
stage('获取代码') {
steps {
echo "start fetch code from git:${REPOSITORY}"
// 删除代码
deleteDir()
// 获取地址
git credentialsId: 'gogs-auth', url: "${REPOSITORY}"
}
}
stage('编译代码') {
steps {
echo "start compile"
// 编译模块和依赖的
sh "mvn -U -pl ${PATH_PREFIX}${MODULE} -am -DskipTests clean package "
}
}
stage('构建镜像') {
steps {
echo "start build image"
sh "${SCRIPT_PATH}/build-images.sh ${MODULE} ${SCRIPT_PATH} ${RUN_ENV} java"
}
}
stage('发布系统') {
agent any
steps {
echo "start deploy"
sh "${SCRIPT_PATH}/deploy.sh ${MODULE} ${SCRIPT_PATH} ${RUN_ENV} svc"
}
}
}
}
vue前端项目build
pipeline {
agent any
environment {
// gogs仓库地址
REPOSITORY = "https://gitee.com/dcy421/dcy-fast-cloud-vue.git"
// 模块名称
MODULE = "dcy-fast-cloud-vue"
// 脚本路径
SCRIPT_PATH = "/data/module/jenkins-scripts/junban-v2"
// 运行环境
RUN_ENV = "test"
}
stages {
stage('获取代码') {
steps {
echo "start fetch code from git:${REPOSITORY}"
// 删除代码
deleteDir()
// 获取地址
git branch: 'v1-test', credentialsId: 'gogs-auth', url: "${REPOSITORY}"
}
}
stage('编译代码') {
steps {
echo "start compile"
// 编译模块和依赖的
sh "sh build.sh"
}
}
stage('构建镜像') {
steps {
echo "start build image"
sh "${SCRIPT_PATH}/build-images.sh ${MODULE} ${SCRIPT_PATH} ${RUN_ENV} web"
}
}
stage('发布系统') {
agent any
steps {
echo "start deploy"
sh "${SCRIPT_PATH}/deploy.sh ${MODULE} ${SCRIPT_PATH} ${RUN_ENV} web"
}
}
}
}
build-images.sh
#!/bin/bash
# 模块名称
MODULE=$1
# 脚本路径
SCRIPT_PATH=$2
# 环境
ENV=$3
# 项目类型
TYPE=$4
# 获取短版本号
TIME=$(date "+%Y%m%d%H%M")
GIT_REVISION=$(git log -1 --pretty=format:"%h")
# harbor项目名称
project='dcy-fast-cloud-dev'
harborHost='harbor地址'
harborUserName='用户名'
harborPassword='密码'
if [ ${ENV} == 'test' ]; then
project='dcy-fast-cloud-test'
elif [ ${ENV} == 'prod' ]; then
# 暂时空着
project='dcy-fast-cloud-dev'
harborHost='harbor地址'
harborUserName='用户名'
harborPassword='密码'
fi
# 拼接镜像名称
IMAGE_NAME=${harborHost}/${project}/${MODULE}:${TIME}_${GIT_REVISION}
# 进入模块目录
cd ${PATH_PREFIX}${MODULE}
# 打包
if [ ${TYPE} == 'java' ]; then
docker build -t ${IMAGE_NAME} -f src/main/docker/Dockerfile .
else
docker build -t ${IMAGE_NAME} -f docker/Dockerfile .
fi
# 登录
docker login ${harborHost} -u ${harborUserName} -p ${harborPassword}
# pull镜像
docker push ${IMAGE_NAME}
# 退出
docker logout ${harborHost}
# 创建临时文件夹
mkdir -p ${SCRIPT_PATH}/${ENV}
# 写临时文件
echo "${IMAGE_NAME}" >${SCRIPT_PATH}/${ENV}/${MODULE}:IMAGE_NAME
deploy.sh
#!/bin/bash
# 模块名称
MODULE=$1
# 脚本路径
SCRIPT_PATH=$2
# 环境
ENV=$3
# 服务名称
SVC=$4
# 进入目录
cd ${SCRIPT_PATH}/${ENV}
# 拼接镜像名称
IMAGE_NAME=$(cat ${MODULE}:IMAGE_NAME)
# 打印镜像名称
echo "update image to:${IMAGE_NAME}"
# k8s命名空间名称
namespaces="dcy-dev"
# 定义请求参数
contentType="content-type: application/strategic-merge-patch+json"
# token
Authorization="Authorization:Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6ImZmTVV5dGUza0dsdzBjcUJMOGx3ekJLNktWZVl3XzlxWHduUkM4NXVZVXMifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJrdWJvYXJkLXVzZXItdG9rZW4tOGp6cHIiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoia3Vib2FyZC11c2VyIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiYzg5NjVmMDItNTNiZC00YmMxLWI3N2EtYTZhMjFkNDIwNjhlIiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50Omt1YmUtc3lzdGVtOmt1Ym9hcmQtdXNlciJ9.2QpWQbgXmrw9OTpPENP6hd3jI1AFvLoB61jvnBVt3aMvOPVueY-99YK3SzlphBabSJ-nSDM1AjEKlFGOhJp8iqe-W5MY4L_boHFDetIRmJJmgLCMS_IIz7rPjAbj8n3LmdSPPAMbcnK8m_ys2YN5LxJH9p3FlNVr87M7MY5lig_T2wObMMFdN0bdTjZcBzy-CDSBoOvKPlqM0n-vY1hrFjseIUD5PluXIE5HqmMh_vVHVuHMPkNyUvhFg76pXt0qoNRggmWA3Vg4oifgt1DyQYuEucJOTU4SxEsBLY-AGKGd8wGx6Xzz3kvxdWEP28cOkBo3iLoeMzUwIou3t6LcHQ"
# 定义k8sapi地址
k8sApiUrl="http://192.168.3.58:32567/k8s-api/apis/apps/v1/namespaces"
# 根据不同环境赋值不同的变量
if [ ${ENV} == 'dev' ]; then
namespaces="dcy-dev"
Authorization="Authorization:Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6ImZmTVV5dGUza0dsdzBjcUJMOGx3ekJLNktWZVl3XzlxWHduUkM4NXVZVXMifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJrdWJvYXJkLXVzZXItdG9rZW4tOGp6cHIiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoia3Vib2FyZC11c2VyIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiYzg5NjVmMDItNTNiZC00YmMxLWI3N2EtYTZhMjFkNDIwNjhlIiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50Omt1YmUtc3lzdGVtOmt1Ym9hcmQtdXNlciJ9.2QpWQbgXmrw9OTpPENP6hd3jI1AFvLoB61jvnBVt3aMvOPVueY-99YK3SzlphBabSJ-nSDM1AjEKlFGOhJp8iqe-W5MY4L_boHFDetIRmJJmgLCMS_IIz7rPjAbj8n3LmdSPPAMbcnK8m_ys2YN5LxJH9p3FlNVr87M7MY5lig_T2wObMMFdN0bdTjZcBzy-CDSBoOvKPlqM0n-vY1hrFjseIUD5PluXIE5HqmMh_vVHVuHMPkNyUvhFg76pXt0qoNRggmWA3Vg4oifgt1DyQYuEucJOTU4SxEsBLY-AGKGd8wGx6Xzz3kvxdWEP28cOkBo3iLoeMzUwIou3t6LcHQ"
k8sApiUrl="http://192.168.3.58:32567/k8s-api/apis/apps/v1/namespaces"
elif [ ${ENV} == 'test' ]; then
namespaces="dcy-test"
Authorization="Authorization:Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6ImZmTVV5dGUza0dsdzBjcUJMOGx3ekJLNktWZVl3XzlxWHduUkM4NXVZVXMifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJrdWJvYXJkLXVzZXItdG9rZW4tOGp6cHIiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoia3Vib2FyZC11c2VyIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiYzg5NjVmMDItNTNiZC00YmMxLWI3N2EtYTZhMjFkNDIwNjhlIiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50Omt1YmUtc3lzdGVtOmt1Ym9hcmQtdXNlciJ9.2QpWQbgXmrw9OTpPENP6hd3jI1AFvLoB61jvnBVt3aMvOPVueY-99YK3SzlphBabSJ-nSDM1AjEKlFGOhJp8iqe-W5MY4L_boHFDetIRmJJmgLCMS_IIz7rPjAbj8n3LmdSPPAMbcnK8m_ys2YN5LxJH9p3FlNVr87M7MY5lig_T2wObMMFdN0bdTjZcBzy-CDSBoOvKPlqM0n-vY1hrFjseIUD5PluXIE5HqmMh_vVHVuHMPkNyUvhFg76pXt0qoNRggmWA3Vg4oifgt1DyQYuEucJOTU4SxEsBLY-AGKGd8wGx6Xzz3kvxdWEP28cOkBo3iLoeMzUwIou3t6LcHQ"
k8sApiUrl="http://192.168.3.58:32567/k8s-api/apis/apps/v1/namespaces"
elif [ ${ENV} == 'prod' ]; then
namespaces="dcy-prod"
Authorization="Authorization:Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6ImZmTVV5dGUza0dsdzBjcUJMOGx3ekJLNktWZVl3XzlxWHduUkM4NXVZVXMifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJrdWJvYXJkLXVzZXItdG9rZW4tOGp6cHIiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoia3Vib2FyZC11c2VyIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiYzg5NjVmMDItNTNiZC00YmMxLWI3N2EtYTZhMjFkNDIwNjhlIiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50Omt1YmUtc3lzdGVtOmt1Ym9hcmQtdXNlciJ9.2QpWQbgXmrw9OTpPENP6hd3jI1AFvLoB61jvnBVt3aMvOPVueY-99YK3SzlphBabSJ-nSDM1AjEKlFGOhJp8iqe-W5MY4L_boHFDetIRmJJmgLCMS_IIz7rPjAbj8n3LmdSPPAMbcnK8m_ys2YN5LxJH9p3FlNVr87M7MY5lig_T2wObMMFdN0bdTjZcBzy-CDSBoOvKPlqM0n-vY1hrFjseIUD5PluXIE5HqmMh_vVHVuHMPkNyUvhFg76pXt0qoNRggmWA3Vg4oifgt1DyQYuEucJOTU4SxEsBLY-AGKGd8wGx6Xzz3kvxdWEP28cOkBo3iLoeMzUwIou3t6LcHQ"
k8sApiUrl="http://192.168.3.58:32567/k8s-api/apis/apps/v1/namespaces"
fi
curl -X PATCH \
-H "${contentType}" \
-H "${Authorization}" \
-d '{"spec":{"template":{"spec":{"containers":[{"name":"'${MODULE}'","image":"'${IMAGE_NAME}'"}]}}}}' \
"${k8sApiUrl}/${namespaces}/deployments/${SVC}-${MODULE}"
chmod -R 777 文件名
10 远程ssh
添加全局凭证
def getHost(){
def remote = [:]
remote.name = '名称'
remote.host = 'xxx.xxx.xxx.xxx'
remote.port = 22
withCredentials([usernamePassword(credentialsId: 'xxx.xxx.xxx.xxx:22-ssh', passwordVariable: 'password', usernameVariable: 'username')]) {
remote.user = "${username}"
remote.password = "${password}"
}
remote.allowAnyHosts = true
return remote
}
pipeline {
agent any
environment {
// 变量
REPOSITORY= "http://xxx.xxx.xxx.xxx:8888/xxx/xxxxx.git"
PATH_PREFIX = "business/admin-center/"
MODULE = "admin-center-provider"
SCRIPT_PATH = "/home/xxx/build-scripts"
}
stages {
stage('获取代码'){
steps {
echo "start fetch code from git:${REPOSITORY}"
// 删除代码
deleteDir()
// 获取地址
git credentialsId: 'gogs-auth', url: "${REPOSITORY}"
}
}
stage('编译+单元测试'){
steps {
echo "start compile"
// 编译模块和依赖的
sh "mvn -U -pl ${PATH_PREFIX}${MODULE} -am -DskipTests clean package"
}
}
stage('构建镜像'){
steps {
echo "start build image"
sh "${SCRIPT_PATH}/build-images.sh ${MODULE} ${PATH_PREFIX}"
}
}
stage('发布系统'){
steps {
echo "start deploy"
script{
def IMAGE_NAME = readFile("/home/xxx/build-scripts/IMAGE_NAME")
echo "${IMAGE_NAME}"
sshCommand remote: getHost(), command: """
docker rm -f admin-center-provider
docker login xxx.xxx.xxx.xxx:21880 -u pull -p Aa123456
docker run -d -p 8999:8999 -e NACOS_SERVER_ADDR="xxx.xxx.xxx.xxx:18848" --net=host --name admin-center-provider ${IMAGE_NAME}
docker logout xxx.xxx.xxx.xxx:21880
"""
}
}
}
}
}
#!/bin/bash
MODULE=$1
PATH_PREFIX=$2
TIME=`date "+%Y%m%d%H%M"`
GIT_REVISION=`git log -1 --pretty=format:"%h"`
IMAGE_NAME=xxx.xxx.xxx.xxx:21880/xxx/${MODULE}:${TIME}_${GIT_REVISION}
cd ${PATH_PREFIX}${MODULE}
# 打包
docker build -t ${IMAGE_NAME} -f Dockerfile .
# 登录
docker login xxx.xxx.xxx.xxx:21880 -u pull -p Aa123456
# pull镜像
docker push ${IMAGE_NAME}
# 退出
docker logout xxx.xxx.xxx.xxx:21880
#删除镜像
docker rmi ${IMAGE_NAME}
# 写临时文件
echo "${IMAGE_NAME}" > '/home/xxx/build-scripts/'IMAGE_NAME