介绍:本文介绍使用docker命令启动jenkins,并搭建服务自动部署流水线
1. docker启动jenkins.
我的服务器上安装的是jdk17,所以我指定了镜像版本,启动的时候必须指定配置-e JAVA_OPTS="-Djenkins.update.center=https://mirrors.huaweicloud.com/jenkins/update-center.json" ,主要是为了启动完成,安装插件的时候速度快一些,默认的是https://updates.jenkins-zh.cn/update-center.json,安装插件的时候会很慢。
docker run -d \
--name jenkins \
--restart=unless-stopped \
-p 19009:8080 \
-p 50000:50000 \
-v jenkins_home:/var/jenkins_home \
-e JAVA_OPTS="-Djenkins.update.center=https://mirrors.huaweicloud.com/jenkins/update-center.json" \
-e JAVA_OPTS="-Dhudson.model.UpdateCenter.connectionCheckUrl=https://www.baidu.com" \
jenkins/jenkins:2.541.3-lts-jdk17
2.访问ip:端口
进入jenkins页面要求输入密码,这里运行命令
docker exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword
会展示一个字符串,例如:116125d432e24411afa2f1a906946485 复制进去点击继续
3.安装插件
安装默认的插件,不要跳过,否则还得自己一个一个的安装,可能会漏装插件,导致搭建自动部署的时候报错
4.设置账号密码
插件安装完成之后,我设置了账号密码,但是在另一个浏览器登录的时候显示密码错误,所以在原来的浏览器中又找到设置---user---account ----security---修改了账户密码,这样就能登录了
5.安装ssh插件
命令
docker exec -u root jenkins bash -c 'apt-get update && apt-get install -y sshpass openssh-client
6. 配置git凭据和其他服务器的凭据



凭据创建好之后

7全局配置jdk和maven
由于我的jenkins默认的是jdk17,项目使用的是jdk21 ,所以还需要安装一个jdk21在容器中
# 进入容器(用户一般是 jenkins,装软件用 root)
docker exec -u root -it jenkins bash
mkdir -p /var/jenkins_home/tools
cd /var/jenkins_home/tools
# 下载 Temurin 21(若清华慢可换官方或其它镜像)
curl -fL -o jdk21.tar.gz \
"https://mirrors.tuna.tsinghua.edu.cn/Adoptium/21/jdk/x64/linux/OpenJDK21U-jdk_x64_linux_hotspot_21.0.6_7.tar.gz"
tar -xzf jdk21.tar.gz
mv jdk-21.0.12+8 jdk-21
# 建固定软链,方便配置
ln -sfn "$(ls -d jdk-21* | head -1)" jdk-21
/var/jenkins_home/tools/jdk-21/bin/java -version
# 应显示 21.x


8.新建流水线任务
点击左上角那个jenkins返回主页面,新建一个任务

2填写描述


脚本代码
/**
* Spring Boot 宿主机部署 Pipeline(Jenkins 跑在 Docker 内)
*
* 前置条件:
* 1) Jenkins 容器能访问宿主机 SSH(推荐),启动示例:
* docker run -d --name jenkins --restart=unless-stopped \
* -p 8080:8080 -p 50000:50000 \
* -v jenkins_home:/var/jenkins_home \
* -v /var/run/docker.sock:/var/run/docker.sock \
* jenkins/jenkins:2.541.3-lts-jdk17
* 2) 本项目编译需要 JDK21(pom 中 release=21)。Jenkins 控制器可以是 jdk17 镜像,
* 但构建必须用 JDK21:Manage Jenkins → Tools 配置 Name=jdk21 的 JDK。
* 3) 宿主机运行 jar 也需要 JDK21;openssh-server;部署目录已放 deploy-on-host.sh
* 4) 插件:Pipeline、Git、SSH Agent;Tools 中 Maven Name=maven
* 5) 凭据:git-test、host-ssh
*
* 报错 release version 21 not supported = 构建仍在用 JDK17,按下面配 jdk21。
*/
pipeline {
agent any
tools {
jdk 'JDK21'
maven 'maven'
}
options {
timestamps()
disableConcurrentBuilds()
buildDiscarder(logRotator(numToKeepStr: '20'))
}
parameters {
string(name: 'GIT_BRANCH', defaultValue: 'develop', description: 'Git 分支')
booleanParam(name: 'SKIP_TESTS', defaultValue: true, description: '是否跳过测试')
}
environment {
// ==== 按实际项目修改 ====
APP_NAME = 'appname'
GIT_URL = 'https://替换你自己的地址.git'
GIT_CREDENTIALS_ID = '替换自己的凭据git-test' //cred
// 宿主机 SSH:从 Jenkins 容器访问宿主机网关,常见为 172.17.0.1
// 也可用宿主机内网 IP / 配置的 host 名
HOST_IP = '项目启动的服务ip'
HOST_USER = 'root'
HOST_SSH_CRED_ID = '替换这里是配置的凭据host-ssh'
HOST_DEPLOY_DIR = '替换发布的文件夹地址/etc/apps/'
JAR_NAME = '替换.jar' // 部署后的统一文件名
// Maven 坐标打包名不确定时,用下面通配;最终仍会 scp 成 JAR_NAME
JAVA_OPTS = '-Xms256m -Xmx512m'
SPRING_PROFILE = 'prod'
APP_PORT = '替换端口'
// ========================
WORK_JAR_GLOB = 'target/*.jar'
}
stages {
stage('Checkout') {
steps {
cleanWs()
git branch: "${params.GIT_BRANCH}",
credentialsId: "${env.GIT_CREDENTIALS_ID}",
url: "${env.GIT_URL}"
}
}
stage('Maven Build') {
steps {
script {
def skip = params.SKIP_TESTS ? '-DskipTests' : ''
// tools 会注入 JAVA_HOME;再强制校验必须是 21
sh """
set -e
echo "JAVA_HOME=\$JAVA_HOME"
java -version
javac -version
# 确认 compiler 支持 --release 21
javac --release 21 -version
mvn -version
mvn -B -U clean package ${skip}
ls -lh target/*.jar
"""
}
}
}
stage('Pick Artifact') {
steps {
script {
def jars = sh(
script: '''
ls -1 target/*.jar 2>/dev/null \
| grep -v '\\.original$' \
| grep -v sources \
| grep -v javadoc \
|| true
''',
returnStdout: true
).trim().split('\n').findAll { it?.trim() }
if (jars.isEmpty()) {
error('未找到可部署的 jar,请检查 Maven packaging')
}
env.BUILT_JAR = jars[0]
echo "构建产物: ${env.BUILT_JAR}"
}
}
}
stage('Deploy to Host') {
steps {
// host-ssh 是 Username with password,不能用 sshUserPrivateKey
withCredentials([usernamePassword(
credentialsId: env.HOST_SSH_CRED_ID,
usernameVariable: 'SSH_USER',
passwordVariable: 'SSH_PASS'
)]) {
sh """
set -e
if ! command -v sshpass >/dev/null 2>&1; then
echo "Jenkins 容器缺少 sshpass,请执行:"
echo " docker exec -u root jenkins bash -c 'apt-get update && apt-get install -y sshpass openssh-client'"
exit 1
fi
export SSHPASS="\$SSH_PASS"
SSH_OPTS="-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null"
REMOTE="\${SSH_USER}@${HOST_IP}"
# 1) 进入部署目录,删除旧 jar
sshpass -e ssh \$SSH_OPTS \$REMOTE "mkdir -p '${HOST_DEPLOY_DIR}' && cd '${HOST_DEPLOY_DIR}' && rm -f '${JAR_NAME}' *.jar"
# 2) 把构建产物传到 HOST_DEPLOY_DIR,统一命名为 JAR_NAME
sshpass -e scp \$SSH_OPTS "${env.BUILT_JAR}" "\$REMOTE:${HOST_DEPLOY_DIR}/${JAR_NAME}"
# 3) 启动服务
sshpass -e ssh \$SSH_OPTS \$REMOTE "cd '${HOST_DEPLOY_DIR}' && bash start.sh"
"""
}
}
}
stage('Health Check') {
steps {
withCredentials([usernamePassword(
credentialsId: env.HOST_SSH_CRED_ID,
usernameVariable: 'SSH_USER',
passwordVariable: 'SSH_PASS'
)]) {
sh """
set -e
export SSHPASS="\$SSH_PASS"
SSH_OPTS="-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null"
REMOTE="\${SSH_USER}@${HOST_IP}"
for i in 1 2 3 4 5 6 7 8 9 10; do
if sshpass -e ssh \$SSH_OPTS \$REMOTE \
"curl -fsS http://127.0.0.1:${APP_PORT}/actuator/health \
|| curl -fsS -o /dev/null -w '%{http_code}' http://127.0.0.1:${APP_PORT}/ | grep -E '200|302|401'"; then
echo "健康检查通过"
exit 0
fi
echo "等待服务启动... (\$i/10)"
sleep 3
done
echo "健康检查失败,请查看宿主机日志: ${HOST_DEPLOY_DIR}/app.log"
exit 1
"""
}
}
}
}
post {
success {
echo "部署成功: ${APP_NAME} -> ${HOST_IP}:${APP_PORT}"
}
failure {
echo "部署失败,请检查构建日志与宿主机 ${HOST_DEPLOY_DIR}/app.log"
}
always {
archiveArtifacts artifacts: 'target/*.jar', fingerprint: true, allowEmptyArchive: true
}
}
}