#!/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=" GLOBAL gitea-credentials Gitea 仓库访问凭据 ${GITEA_USERNAME} ${GITEA_PASSWORD} " 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" " { \"\": [${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=" Novalon Website CI/CD Pipeline (自动生成) false DEPLOY_TO_PRODUCTION 是否部署到生产环境(仅在 main 分支且所有测试通过后可用) false 2 ${GITEA_URL}/${REPO_OWNER}/${REPO_NAME}.git gitea-credentials */main false Jenkinsfile true false " 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 }