Files
novalon-website/scripts/setup-cicd/lib/jenkins-setup.sh
T
张翔 929f3ed250 chore: 添加设计分析参考和辅助脚本
- IHG设计分析HTML参考页面
- 布局检查、DOM诊断、验收测试等辅助脚本
2026-06-07 16:22:11 +08:00

307 lines
9.5 KiB
Bash
Executable File

#!/bin/bash
setup_jenkins_container() {
show_banner "配置 Jenkins Docker 容器"
log_info "停止现有 Jenkins 容器..."
docker stop ${JENKINS_CONTAINER_NAME} 2>/dev/null || true
docker rm ${JENKINS_CONTAINER_NAME} 2>/dev/null || true
log_info "启动新的 Jenkins 容器(挂载 SSH 密钥)..."
if [ ! -d ~/.ssh ]; then
log_error "~/.ssh 目录不存在!"
log_info "请先生成 SSH 密钥: ssh-keygen -t rsa -b 4096"
exit 1
fi
docker run -d \
--name ${JENKINS_CONTAINER_NAME} \
--restart unless-stopped \
--user root \
-p "${JENKINS_PORT}:8080" \
-p "50000:50000" \
-v jenkins_data:/var/jenkins_home \
-v ~/.ssh:/var/jenkins_home/.ssh:ro \
-e JAVA_OPTS="-Djenkins.install.runSetupWizard=false" \
-e TZ="Asia/Shanghai" \
--network ${DOCKER_NETWORK} \
${JENKINS_IMAGE}
if [ $? -eq 0 ]; then
log_success "Jenkins 容器已启动"
log_info "容器名称: ${JENKINS_CONTAINER_NAME}"
log_info "访问地址: ${JENKINS_URL}"
else
log_error "Jenkins 容器启动失败!"
exit 1
fi
}
install_jenkins_tools() {
show_banner "安装 Jenkins 必要工具"
log_info "在 Jenkins 容器中安装 rsync, curl, openssh-client..."
docker exec -u root ${JENKINS_CONTAINER_NAME} bash -c "
apt-get update && \
apt-get install -y \
rsync \
curl \
openssh-client \
jq \
&& rm -rf /var/lib/apt/lists/* \
&& echo '✅ 工具安装完成'
"
if [ $? -eq 0 ]; then
log_success "工具安装成功"
echo ""
log_info "验证安装结果:"
docker exec ${JENKINS_CONTAINER_NAME} bash -c '
echo "--- rsync ---"
rsync --version | head -1 || echo "❌ 未安装"
echo ""
echo "--- curl ---"
curl --version | head -1 || echo "❌ 未安装"
echo ""
echo "--- ssh ---"
ssh -V || echo "❌ 未安装"
echo ""
echo "--- jq ---"
jq --version || echo "❌ 未安装"
'
else
log_error "工具安装失败!请手动执行:"
echo "docker exec -u root ${JENKINS_CONTAINER_NAME} bash -c 'apt-get update && apt-get install -y rsync curl openssh-client'"
exit 1
fi
test_ssh_connection
}
test_ssh_connection() {
show_banner "测试 SSH 连接到生产服务器"
log_info "测试连接到 ${SERVER_USER}@${SERVER_IP}..."
local result=$(docker exec ${JENKINS_CONTAINER_NAME} ssh \
-o StrictHostKeyChecking=no \
-o ConnectTimeout=5 \
-o BatchMode=yes \
${SERVER_USER}@${SERVER_IP} \
"hostname && whoami && pwd" 2>&1)
if [ $? -eq 0 ]; then
log_success "SSH 连接成功!"
echo "$result" | while IFS= read -r line; do
log_info " $line"
done
else
log_warning "SSH 连接失败(部署阶段将无法工作)"
log_error "错误信息: $result"
log_info "可能原因:"
log_info " 1. SSH 密钥未正确挂载到容器"
log_info " 2. 生产服务器的 authorized_keys 不包含公钥"
log_info ""
log_info "解决方案:"
log_info " 1. 在宿主机上测试: ssh ${SERVER_USER}@${SERVER_IP}"
log_info " 2. 如果宿主机可以免密登录,检查 docker run 的 -v 参数"
log_info " 3. 复制公钥到服务器: ssh-copy-id ${SERVER_USER}@${SERVER_IP}"
read -p "是否继续配置(跳过 SSH 测试)?(y/N): " continue_without_ssh
if [[ ! "$continue_without_ssh" =~ ^[Yy]$ ]]; then
exit 1
fi
fi
}
setup_jenkins_credentials() {
show_banner "配置 Jenkins 凭据"
create_gitea_credentials
}
create_gitea_credentials() {
log_info "创建 Gitea 访问凭据..."
local credentials_xml="<com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl>
<scope>GLOBAL</scope>
<id>gitea-credentials</id>
<description>Gitea 仓库访问凭据</description>
<username>${GITEA_USERNAME}</username>
<password>${GITEA_PASSWORD}</password>
</com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl>"
local result=$(jenkins_api_call "POST" "/credential-store/domain/createCredential" "
{
\"credentials\": {
\"scope\": \"GLOBAL\",
\"id\": \"gitea-credentials\",
\"username\": \"${GITEA_USERNAME}\",
\"password\": \"${GITEA_PASSWORD}\",
\"description\": \"Gitea 仓库访问凭据\",
\"\$class\": \"com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl\"
}
}
")
if echo "$result" | grep -q "error"; then
log_warning "凭据可能已存在,尝试更新..."
else
log_success "Gitea 凭据创建成功 (ID: gitea-credentials)"
fi
}
setup_jenkins_global_tools() {
show_banner "配置全局工具"
configure_nodejs
}
configure_nodejs() {
log_info "配置 Node.js ${NODE_VERSION}..."
jenkins_api_call "POST" "/pluginManager/plugins/nodescript/configure" > /dev/null 2>&1 || true
jenkins_api_call "POST" "/toolLocation/updateNodeJS" "
{
\"nodeJSHome\": \"/var/jenkins_home/tools/jenkins.plugins.nodejs.tools.NodeJSInstallation/NodeJS_${NODE_VERSION}\",
\"name\": \"${NODE_VERSION}\",
\"properties\": [
{
\"installSource\": {
\"installers\": [
{
\"id\": \"${NODE_VERSION}.x\"
}
]
},
\"stapler-class\": \"hudson.tools.InstallSourceProperty\"
}
]
}" > /dev/null 2>&1
log_success "Node.js 配置完成 (版本: ${NODE_VERSION})"
}
install_required_plugins() {
show_banner "安装 Jenkins 插件"
local plugins=(
"generic-webhook-trigger"
"nodejs"
"htmlpublisher"
"workspace-cleanup"
"git"
"credentials-binding"
"ssh-credentials"
"timestamper"
"ansicolor"
)
log_info "需要安装的插件: ${#plugins[@]} 个"
local plugin_list=$(IFS=','; echo "${plugins[*]}")
local install_result=$(jenkins_api_CALL "POST" "/pluginManager/installNecessaryPlugins" "
{
\"<dynamic-install>\": [${plugin_list}]
}" 2>/dev/null) || true
jenkins_api_call "POST" "/scriptText" "script=
import jenkins.model.*
import hudson.model.*
def plugins = [
'generic-webhook-trigger',
'nodejs',
'htmlpublisher',
'workspace-cleanup',
'timestamper',
'ansicolor'
]
def pm = Jenkins.instance.pluginManager
def uc = Jenkins.instance.updateCenter
pm.plugins.each { plugin ->
if (plugins.contains(plugin.shortName)) {
println \"✅ 已安装: \${plugin.shortName}\"
}
}
plugins.each { pluginName ->
def plugin = pm.getPlugin(pluginName)
if (!plugin) {
println \"📦 安装中: \${pluginName}\"
uc.getPlugin(pluginName).deploy(true).get()
}
}
println '✅ 插件安装完成'
return 'success'
" > /dev/null 2>&1
log_success "插件安装请求已提交(可能需要重启)"
log_info "建议手动重启 Jenkins 使插件生效:"
log_info " docker restart ${JENKINS_CONTAINER_NAME}"
}
create_pipeline_job() {
show_banner "创建 Pipeline 任务"
local job_config="<?xml version='1.0' encoding='UTF-8'?>
<flow-definition>
<description>Novalon Website CI/CD Pipeline (自动生成)</description>
<keepDependencies>false</keepDependencies>
<properties>
<hudson.model.ParametersDefinitionProperty>
<parameterDefinitions>
<hudson.model.BooleanParameterDefinition>
<name>DEPLOY_TO_PRODUCTION</name>
<description>是否部署到生产环境(仅在 main 分支且所有测试通过后可用)</description>
<defaultValue>false</defaultValue>
</hudson.model.BooleanParameterDefinition>
</parameterDefinitions>
</hudson.model.ParametersDefinitionProperty>
</properties>
<definition class=\"org.jenkinsci.plugins.workflow.cps.CpsScmFlowDefinition\" plugin=\"workflow-cps@\">
<scm class=\"hudson.plugins.git.GitSCM\" plugin=\"git@\">
<configVersion>2</configVersion>
<userRemoteConfigs>
<hudson.plugins.git.UserRemoteConfig>
<url>${GITEA_URL}/${REPO_OWNER}/${REPO_NAME}.git</url>
<credentialsId>gitea-credentials</credentialsId>
</hudson.plugins.git.UserRemoteConfig>
</userRemoteConfigs>
<branches>
<hudson.plugins.git.BranchSpec>
<name>*/main</name>
</hudson.plugins.git.BranchSpec>
</branches>
<doGenerateSubmoduleConfigurations>false</doGenerateSubmoduleConfigurations>
<submoduleCfg class=\"list\"/>
<extensions/>
</scm>
<scriptPath>Jenkinsfile</scriptPath>
<lightweight>true</lightweight>
</definition>
<triggers/>
<disabled>false</disabled>
</flow-definition>"
local result=$(jenkins_api_call "POST" "/createItem?name=${JOB_NAME}" "$job_config")
if [ $? -eq 0 ] && ! echo "$result" | grep -q "error"; then
log_success "Pipeline 任务创建成功: ${JOB_NAME}"
log_info "任务地址: ${JENKINS_URL}/job/${JOB_NAME}/"
else
log_warning "任务可能已存在,尝试更新配置..."
jenkins_api_call "POST" "/job/${JOB_NAME}/config.xml" "$job_config" > /dev/null
log_success "Pipeline 任务更新成功: ${JOB_NAME}"
fi
}