整体架构 开发者 push/PR ↓ esc to interrupt Gitee 私有仓库 ↓ Webhook Jenkins(自建) ↓ ┌───────────────────────────────┐ │ Stage1: 拉取代码 │ │ Stage2: Composer 安装依赖 │ │ Stage3: 静态分析 + 单元测试 │ │ Stage4: 构建 Docker 镜像 │ │ Stage5: 推送 ACR/Harbor │ │ Stage6: SSH 部署到目标服务器 │ │ Stage7: 通知钉钉/企业微信 │ └───────────────────────────────┘ --- 第一步:安装 Jenkins(Docker 方式,国内加速)1.1docker-compose.yml version:'3.8'services: jenkins: image: jenkins/jenkins:lts-jdk17 container_name: jenkins restart: unless-stopped privileged:trueuser: root ports: -"8080:8080"-"50000:50000"volumes: - /data/jenkins:/var/jenkins_home - /var/run/docker.sock:/var/run/docker.sock# Docker-outside-Docker- /usr/bin/docker:/usr/bin/docker environment: -TZ=Asia/Shanghai -JAVA_OPTS=-Duser.timezone=Asia/Shanghai-Xmx2gdocker-composeup-d# 获取初始密码dockerexecjenkinscat/var/jenkins_home/secrets/initialAdminPassword1.2切换国内插件源(解决插件下载慢) Jenkins 启动后,进入 Manage Jenkins → Plugin Manager → Advanced,将 Update Site URL 替换为清华镜像: https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json 或者直接修改配置文件:# 进入 Jenkins 数据目录sed-i's|https://updates.jenkins.io/update-center.json|https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-ce nter.json|g'\/data/jenkins/hudson.model.UpdateCenter.xml1.3必装插件清单 在 Manage Jenkins → Plugin Manager → Available 搜索安装: ┌─────────────────────┬───────────────────────────────────┐ │ 插件名 │ 用途 │ ├─────────────────────┼───────────────────────────────────┤ │ Gitee │ Gitee Webhook 触发 + 构建状态回写 │ ├─────────────────────┼───────────────────────────────────┤ │ Pipeline │ Jenkinsfile 声明式流水线 │ ├─────────────────────┼───────────────────────────────────┤ │ Git │ 拉取 Git 仓库 │ ├─────────────────────┼───────────────────────────────────┤ │ Publish Over SSH │ SSH 部署到远程服务器 │ ├─────────────────────┼───────────────────────────────────┤ │ Credentials Binding │ 安全注入密钥/密码 │ ├─────────────────────┼───────────────────────────────────┤ │ AnsiColor │ 彩色日志输出 │ ├─────────────────────┼───────────────────────────────────┤ │ DingTalk │ 钉钉通知 │ ├─────────────────────┼───────────────────────────────────┤ │ Docker Pipeline │ Pipeline 内构建推送镜像 │ ├─────────────────────┼───────────────────────────────────┤ │ Workspace Cleanup │ 构建前清理工作区 │ └─────────────────────┴───────────────────────────────────┘ --- 第二步:Jenkins 全局配置2.1配置 Gitee 连接 Manage Jenkins → Configure System → Gitee 配置: - Gitee 链接名称:gitee - Gitee 域名:https://gitee.com - 证书令牌:添加 → Jenkins → 类型选 Gitee API 令牌 → 填入 Gitee 私人令牌2.2配置 SSH 远程服务器(Publish Over SSH) Manage Jenkins → Configure System → Publish over SSH: Name: production-server Hostname:192.168.1.100 Username: deploy Remote Directory: /data/www 私钥粘贴到 Key 字段(Jenkins 服务器的 ~/.ssh/id_rsa 内容)。2.3配置 Credentials(凭据) Manage Jenkins → Credentials → System → Global → Add Credentials: ┌─────────────────┬───────────────────────────────┬─────────────────────┐ │ ID │ 类型 │ 用途 │ ├─────────────────┼───────────────────────────────┼─────────────────────┤ │ gitee-ssh-key │ SSH Username with private key │ 拉取 Gitee 私有仓库 │ ├─────────────────┼───────────────────────────────┼─────────────────────┤ │ composer-auth │ Secret text │ COMPOSER_AUTH JSON │ ├─────────────────┼───────────────────────────────┼─────────────────────┤ │ acr-credentials │ Username/Password │ 推送 Docker 镜像 │ ├─────────────────┼───────────────────────────────┼─────────────────────┤ │ dingtalk-token │ Secret text │ 钉钉机器人 Token │ └─────────────────┴───────────────────────────────┴─────────────────────┘ --- 第三步:Hyperf 项目配置3.1项目根目录添加 Jenkinsfile // Jenkinsfile pipeline{agent any // 环境变量 environment{APP_NAME='hyperf-app'DEPLOY_PATH='/data/www/hyperf-app'PHP_BIN='/usr/local/php/bin/php'COMPOSER_BIN='/usr/local/bin/composer'// Docker 镜像仓库(阿里云 ACR) IMAGE_REGISTRY='registry.cn-hangzhou.aliyuncs.com'IMAGE_NAMESPACE='your-namespace'IMAGE_TAG="${IMAGE_REGISTRY}/${IMAGE_NAMESPACE}/${APP_NAME}:${BUILD_NUMBER}"// 注入 Composer 私有仓库认证 COMPOSER_AUTH=credentials('composer-auth')}// 触发条件 triggers{// Gitee 插件触发(push 到 main/master 分支) GenericTrigger(genericVariables:[[key:'ref', value:'$.ref']], causeString:'Triggered by Gitee push to $ref', token:'your-webhook-token', regexpFilterText:'$ref', regexpFilterExpression:'refs/heads/(main|master|release/.*)')}options{// 保留最近10次构建记录 buildDiscarder(logRotator(numToKeepStr:'10'))// 超时30分钟 timeout(time:30, unit:'MINUTES')// 彩色日志 ansiColor('xterm')// 不允许并发构建 disableConcurrentBuilds()}stages{// ── Stage1: 清理工作区 ────────────────────────────── stage('Prepare'){steps{cleanWs()checkout scmecho"✅ 代码拉取完成,分支:${env.GIT_BRANCH},Commit:${env.GIT_COMMIT[0..7]}"}}// ── Stage2: 安装 Composer 依赖 ───────────────────── stage('Composer Install'){steps{sh'''${PHP_BIN}${COMPOSER_BIN}install\--no-dev\--optimize-autoloader\--no-interaction\--prefer-dist'''}}// ── Stage3: 代码质量检查 ──────────────────────────── stage('Code Quality'){parallel{stage('PHPStan'){steps{sh'''${PHP_BIN}vendor/bin/phpstan analyse\--level=5\--no-progress\app/'''}}stage('Unit Tests'){steps{sh'''${PHP_BIN}vendor/bin/phpunit\--configurationphpunit.xml\--log-junit reports/junit.xml\--coverage-clover reports/coverage.xml'''}post{always{// 发布测试报告 junit'reports/junit.xml'}}}}}// ── Stage4: 生成 Hyperf 注解缓存 ─────────────────── stage('Build Cache'){steps{sh'${PHP_BIN} bin/hyperf.php di:init-proxy'}}// ── Stage5: 构建 Docker 镜像 ──────────────────────── stage('Docker Build'){when{// 只有 main/master/release 分支才构建镜像 anyOf{branch'main'branch'master'branch pattern:'release/.*', comparator:'REGEXP'}}steps{withCredentials([usernamePassword(credentialsId:'acr-credentials', usernameVariable:'ACR_USER', passwordVariable:'ACR_PASS')]){sh'''dockerlogin${IMAGE_REGISTRY}-u${ACR_USER}-p${ACR_PASS}dockerbuild\--build-argAPP_ENV=production\--label"git-commit=${GIT_COMMIT}"\--label"build-number=${BUILD_NUMBER}"\-t${IMAGE_TAG}\-t${IMAGE_REGISTRY}/${IMAGE_NAMESPACE}/${APP_NAME}:latest\.dockerpush${IMAGE_TAG}dockerpush${IMAGE_REGISTRY}/${IMAGE_NAMESPACE}/${APP_NAME}:latestdockerrmi${IMAGE_TAG}||true'''}}}// ── Stage6: 部署到测试环境 ────────────────────────── stage('Deploy Staging'){when{branch'main'}steps{sshPublisher(publishers:[sshPublisherDesc(configName:'staging-server', transfers:[sshTransfer(// 不传文件,只执行远程脚本 execCommand:"""cd/data/www/hyperf-app-staginggitpull origin main /usr/local/php/bin/php /usr/local/bin/composerinstall--no-dev --optimize-autoloader /usr/local/php/bin/php bin/hyperf.php di:init-proxy# 平滑重启 Worker(不断开连接)PID=\$(catruntime/hyperf.pid2>/dev/null)if[-n"\$PID"];thenkill-USR1\$PIDelsesupervisorctl restart hyperf-stagingfi""", execTimeout:120000)], failOnError:true)])}}// ── Stage7: 部署到生产环境(需人工确认)──────────── stage('Deploy Production'){when{branch'master'}input{message"确认部署到生产环境?"ok"确认部署"submitter"admin,ops-team"parameters{choice(name:'DEPLOY_MODE', choices:['rolling','restart'], description:'部署方式')}}steps{sshPublisher(publishers:[sshPublisherDesc(configName:'production-server', transfers:[sshTransfer(execCommand:"""set-ecd/data/www/hyperf-appecho">>> 备份当前版本..."cp-r./data/backup/hyperf-app-\$(date+%Y%m%d%H%M%S)2>/dev/null||trueecho">>> 拉取最新代码..."gitpull origin masterecho">>> 安装依赖..."/usr/local/php/bin/php /usr/local/bin/composerinstall--no-dev --optimize-autoloaderecho">>> 重建注解缓存..."/usr/local/php/bin/php bin/hyperf.php di:init-proxyecho">>> 平滑重启..."PID=\$(catruntime/hyperf.pid2>/dev/null)if["${DEPLOY_MODE}"="rolling"]&&[-n"\$PID"];thenkill-USR1\$PIDecho">>> SIGUSR1 已发送,Worker 平滑重启中..."elsesupervisorctl restart hyperf-appfiecho">>> 部署完成 ✅"""", execTimeout:180000)], failOnError:true)])}}}// ── 构建后通知 ─────────────────────────────────────────── post{success{script{dingTalk(robot:'dingtalk-robot-id', type:'MARKDOWN', title:"✅ 构建成功 -${APP_NAME}", text:["## ✅ 构建成功","- **项目**:${APP_NAME}","- **分支**:${env.GIT_BRANCH}","- **Commit**:${env.GIT_COMMIT[0..7]}","- **构建号**: #${BUILD_NUMBER}","- **耗时**:${currentBuild.durationString}","> [查看构建详情](${BUILD_URL})"])}}failure{script{dingTalk(robot:'dingtalk-robot-id', type:'MARKDOWN', title:"❌ 构建失败 -${APP_NAME}", text:["## ❌ 构建失败","- **项目**:${APP_NAME}","- **分支**:${env.GIT_BRANCH}","- **失败阶段**:${env.STAGE_NAME}","> [查看失败日志](${BUILD_URL}console)"], at:['all'])}}always{// 清理 Docker 悬空镜像sh'docker image prune -f || true'}}}--- 第四步:Gitee 配置 Webhook 在 Gitee 仓库 → 管理 → WebHooks → 添加: URL: http://your-jenkins.com:8080/gitee-project/hyperf-app 密码: your-webhook-token(与 Jenkinsfile 中 token 一致) 触发事件: ✅ Push ✅ Pull Request Jenkins 任务配置中勾选: - 构建触发器 → Gitee webhook 触发构建 - 填写 Webhook 密码 --- 第五步:多分支流水线(推荐) 比单任务更强大,自动发现所有分支和 PR。 New Item → Multibranch Pipeline: // 分支源配置(Jenkins UI 中填写) // Branch Sources → Gitee // Credentials: gitee-ssh-key // Owner: your-org // Repository: hyperf-app // 扫描触发:Gitee Webhook 推送时自动扫描 // Orphaned Item Strategy: 保留3天 分支策略(在 Jenkinsfile 中用 when 控制): ┌───────────┬─────────────────┬──────────────────────┐ │ 分支 │ 触发动作 │ 部署目标 │ ├───────────┼─────────────────┼──────────────────────┤ │ feature/* │ 只跑测试 │ 无 │ ├───────────┼─────────────────┼──────────────────────┤ │ main │ 测试 + 构建镜像 │ 测试环境(自动) │ ├───────────┼─────────────────┼──────────────────────┤ │ master │ 测试 + 构建镜像 │ 生产环境(人工确认) │ ├───────────┼─────────────────┼──────────────────────┤ │ release/* │ 测试 + 构建镜像 │ 预发布环境 │ └───────────┴─────────────────┴──────────────────────┘ --- 第六步:Hyperf 项目适配 phpunit.xml(测试配置)<?xmlversion="1.0"encoding="UTF-8"?><phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"bootstrap="vendor/autoload.php"colors="true"><testsuites><testsuitename="Unit"><directory>test/Unit</directory></testsuite><testsuitename="Feature"><directory>test/Feature</directory></testsuite></testsuites><coverage><include><directory>app</directory></include></coverage><php><envname="APP_ENV"value="testing"/><envname="DB_DRIVER"value="sqlite"/><envname="DB_DATABASE"value=":memory:"/></php></phpunit>phpstan.neon(静态分析) parameters: level:5paths: - app excludePaths: - app/Exception/Handler ignoreErrors: -'#Call to an undefined method Hyperf\\Di\\Container#'.env.testing(CI 测试环境变量)APP_ENV=testingAPP_DEBUG=falseDB_DRIVER=sqliteDB_DATABASE=:memory:REDIS_HOST=127.0.0.1CACHE_DRIVER=array --- 第七步:Jenkins Agent 安装 PHP 环境 如果 Jenkins 运行在 Docker 容器内,需要在容器中安装 PHP + Swoole:# 自定义 Jenkins 镜像FROM jenkins/jenkins:lts-jdk17USERroot# 安装 PHP 8.1 + 必要扩展RUNapt-getupdate&&apt-getinstall-y\php8.1-cli php8.1-mbstring php8.1-xml\php8.1-curl php8.1-zip php8.1-redis\php8.1-pdo php8.1-mysqlgitunzip\&&rm-rf/var/lib/apt/lists/*# 安装 ComposerRUNcurl-sShttps://getcomposer.org/installer|php\&&mvcomposer.phar /usr/local/bin/composer\&&composerconfig-grepo.packagistcomposer\https://mirrors.aliyun.com/composer/# 安装 Swoole(PHPStan/测试不需要,但如果要跑集成测试需要)RUN peclinstallswoole\&&echo"extension=swoole.so">>/etc/php/8.1/cli/php.ini\&&echo"swoole.use_shortname=Off">>/etc/php/8.1/cli/php.iniUSERjenkins --- 关键注意事项 ┌──────────────────────┬──────────────────────────────────────────────────────────────────────────────────────────┐ │ 问题 │ 解决方案 │ ├──────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────┤ │ Gitee Webhook │ Jenkins 必须有公网 IP 或内网穿透(frp/ngrok) │ │ 国内延迟 │ │ ├──────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────┤ │ Composer 下载慢 │ 全局配置阿里云镜像:composer config-grepo.packagistcomposer│ │ │ https://mirrors.aliyun.com/composer/ │ ├──────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────┤ │ 生产部署不中断 │ 用kill-USR1$PID触发 Hyperf Worker 平滑重启 │ ├──────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────┤ │ 凭据安全 │ 所有密码/Token 存 Jenkins Credentials,Jenkinsfile 中用 credentials()注入,绝不硬编码 │ ├──────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────┤ │ 并发构建冲突 │ disableConcurrentBuilds()防止同分支并发部署 │ ├──────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────┤ │ 构建产物清理 │dockerimage prune-f+ buildDiscarder 防止磁盘爆满 │ └──────────────────────┴──────────────────────────────────────────────────────────────────────────────────────────┘hyperf对接 项目接入 Jenkins 国内 CI/CD 实践
张小明
前端开发工程师
Vue 3项目里用Lottie动画,从LottieFiles下载到交互控制(附完整代码)
Vue 3深度整合Lottie动画:从资源获取到高级交互控制实战 在当今追求极致用户体验的前端开发领域,精致的动画效果已成为提升产品质感的标配。而Lottie技术通过将After Effects动画转换为轻量级JSON文件,完美解决了传统动画资源体积大、性能开销…
别再只会用memtester了!试试这个更“暴力”的内存压力测试工具stressapptest(附Ubuntu 22.04编译踩坑实录)
超越memtester:stressapptest内存压力测试实战指南 在嵌入式开发和硬件测试领域,内存稳定性测试是确保系统可靠性的关键环节。许多工程师习惯使用memtester这类基础工具进行检测,但当面对现代复杂计算场景时,传统工具往往显得力不…
别再让单机处理百万数据了!手把手教你用XXL-Job分片广播实现10倍性能提升
从单机到分布式:XXL-Job分片广播技术解锁千万级数据处理新姿势 凌晨三点的办公室,咖啡杯早已见底,而你的Spring Boot应用还在吭哧吭哧处理着第87万条用户数据。这不是电影里的场景,而是许多中高级开发者真实经历过的"数据噩梦…
从Hello World到指针:用5个实际代码片段,彻底搞懂C语言的核心概念与内存模型
从Hello World到指针:用5个实际代码片段,彻底搞懂C语言的核心概念与内存模型 1. 全局变量与局部变量的内存差异 让我们从一个最简单的程序开始: #include <stdio.h>int global_var 42; // 全局变量void test_func() {int local_var …
ArcGIS Pro 2.9.5补丁来了!修复符号窗口闪退,附详细安装与回滚指南
ArcGIS Pro 2.9.5补丁深度解析:从闪退修复到版本管理全攻略 如果你正在使用ArcGIS Pro 2.9版本进行地理信息处理工作,最近可能遭遇了一个令人头疼的问题——当尝试打开符号窗口或修改符号属性时,软件突然崩溃闪退。这个看似随机的故障实际上源…
UHD:软件定义无线电开发的终极解决方案
UHD:软件定义无线电开发的终极解决方案 【免费下载链接】uhd The USRP™ Hardware Driver Repository 项目地址: https://gitcode.com/gh_mirrors/uh/uhd 想象一下,您正在开发一个无线通信系统,需要同时支持多种硬件平台,编…