
1. 部署方式选型与安装环境准备1.1 三种主流部署方式怎么选先说一个很多人上来就问的问题Jenkins到底应该怎么装我最早接触Jenkins那会儿还是Hudson时代装起来无非是丢进Tomcat的webapps目录里解压启动。后来用久了发现不同部署方式背后对应的是完全不同的维护思路选错了后续会让你很难受。现在主流的部署方式大概有三种war包部署、原生安装包部署、Docker容器化部署。war包部署是最传统的玩法适合已经有Tomcat环境、不想额外引入容器化组件的团队。你把jenkins.war丢进Tomcat重启一下就完事了。优点是和现有环境融合好缺点是Jenkins自身升级、环境依赖JDK版本、Tomcat线程数全都要自己操心而且和新版Jenkins的某些插件兼容性容易出问题。原生安装包部署是目前最推荐的单机方案尤其是你在CentOS或者Ubuntu服务器上跑。官方提供了yum/apt源一条命令装好服务由systemd托管开机自启、崩溃拉起都省心。我个人在生成环境上基本都是用这个方式稳定、干净、好排查问题。Docker部署适合本来就有Kubernetes或Docker Compose基础、需要快速拉起临时环境或做多租户隔离的团队。Docker方式最大的优势是环境隔离和可复现性Jenkins依赖的JDK、工具链版本都固化在镜像里换机器、扩容节点都很快。缺点是数据卷、网络、权限处理不好容易埋坑尤其是挂载宿主机Docker套接字的时候安全性要格外小心。三种方式我做一个表方便你按自己的场景选部署方式适用场景优点缺点维护难度war包 Tomcat已有Tomcat环境、不想动架构和环境融合好升级麻烦、依赖显式管理中原生安装包yum/apt单机稳定运行、生产环境首选系统化托管、升级方便、稳定性高无法快速迁移环境低Docker容器微服务架构、弹性伸缩、多租户环境隔离、可复现、资源可控网络与权限配置复杂中高如果你只是自己学习、本地调试怎么方便怎么来Docker一条命令就能跑起来如果是公司内部要做持续集成枢纽我更建议原生安装包维护成本实打实是最低的。我在团队内部署Jenkins的时候选的就是yum方式三年多几乎没有因为“Jenkins服务本身”出过事。1.2 环境要求与安装步骤在开始动手之前先聊一下硬件和软件的前置条件这块经常被忽略。JDK版本是第一个坑。新版Jenkins2.4xx以上要求JDK 11或17而且从2022年之后发布的LTS版本对Java 8的支持已经逐步移除了。很多人还在服务器上只装了Java 8结果解压启动就报UnsupportedClassVersionError这就是没看版本矩阵。我建议直接用JDK 17兼容性和性能都均衡。内存建议至少2GB起步4GB更稳。如果服务器内存只有1GBJenkins光JVM堆就能吃掉一大半构建一跑起来很可能就OOM了。我在一台2C2G的云服务器上跑过一个中型Java项目构建高峰期曾出现构建卡死的情况后来升级到4G内存彻底解决。我这里以CentOS 7/8环境为例给出完整的安装过程# 1. 安装JDK 17以OpenJDK为例 sudo yum install -y java-17-openjdk java-17-openjdk-devel # 2. 验证JDK java -version # 3. 导入Jenkins官方yum源 sudo wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat-stable/jenkins.repo sudo rpm --import https://pkg.jenkins.io/redhat-stable/jenkins.io-2023.key # 4. 安装Jenkins sudo yum install -y jenkins # 5. 启动并设置开机自启 sudo systemctl start jenkins sudo systemctl enable jenkins # 6. 确认状态 sudo systemctl status jenkins装完之后Jenkins默认监听8080端口在浏览器访问http://服务器IP:8080就能看到解锁页面。如果服务器有自己的防火墙记得把8080端口放行云服务器则需要在安全组里加一条入站规则这一步忘了的话怎么访问都打不开页面。然后有个细节Jenkins默认的用户是jenkins它运行时的HOME目录在/var/lib/jenkins。如果你要构建的代码要访问服务器上其他路径的文件必须处理好目录权限否则构建过程中会莫名其妙报Permission denied。我踩过很多次这个坑后面会专门讲。1.3 初始化配置与国内镜像源加速第一次打开Jenkins页面会要你输入一个初始管理员密码这个密码在服务器上sudo cat /var/lib/jenkins/secrets/initialAdminPassword输入密码进入插件安装界面后这里就是第二个高频坑点如果直接点击“安装推荐的插件”在国内网络环境下大概率会卡住或者等了十几分钟最后提示一堆插件安装失败。原因是Jenkins默认插件源放在国外服务器访问速度极不稳定。解决办法是把插件升级站点源替换成国内镜像源。操作很简单进入“Manage Jenkins” - “Plugins” - “Advanced settings”把“Update Site”里的URL改为https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json改完之后点击“Submit”再点击“Check now”刷新一下。这里有个容易误的操作——改完URL立刻去“Available”标签页搜索插件可能还是搜不到因为插件元数据还在下载稍等几分钟再刷新就正常了。插件安装这一步我的建议是不要贪多。基础必备的有Git Plugin拉取代码Pipeline Plugin流水线核心Credentials Binding Plugin凭据管理Build Timeout构建超时控制Docker Pipeline如果要用容器构建DingTalk Plugin如果要钉钉通知用国内团队很多选择这个其他插件建议遇到实际需求再装不要一口吃成胖子。插件越多Jenkins启动越慢插件之间的兼容性问题也越多而且每个插件都是潜在的攻击面。我曾经见过一个测试环境的Jenkins装了100多个插件启动要差不多五分钟而且隔三差五出安全告警最后痛定思痛全清了重装。初始化之后就是创建管理员账户按提示填写就行。建议用公司邮箱格式的账号权限好管理后续要做SSO对接也方便。2. 核心概念与代码仓库集成2.1 必须先搞懂的几个基础概念在开始配置第一个构建任务之前有几组基础概念必须理清楚。很多教程上来就写“新建一个Job”然后把步骤贴出来但新手往往不知道Job到底是个什么东西、和构建有什么关系。把Jenkins想象成一个餐厅厨房**任务Job**是菜谱**构建Build**是按照菜谱做一次菜**工作空间Workspace**是厨房的操作台**插件Plugin**是各种厨具**凭据Credential**是仓库门禁的钥匙卡**节点Node**是灶台。这样说大家就好理解了。一个Job就是一套构建流程的定义告诉Jenkins“从哪儿拉代码、用什么工具构建、构建完怎么处理”每次实际跑一遍这套流程就是一次Build构建过程中用到的文件、拉下来的代码都放在Workspace里要从GitLab/GitHub拉取私有仓库的代码就需要用到Credential里的账号或SSH密钥如果构建任务特别多一台机器跑不过来就加几个Node分摊压力Jenkins主节点负责调度从节点跑实际构建。还有一个概念叫流水线Pipeline这个稍后在第三章单独讲它是用代码的形式定义整套CI/CD流程比传统的“构建步骤配置”更灵活、更可维护。对新手来说先把这几个概念装进脑子后面看到界面上各种术语就不晕了。我在带新人入门时经常发现很多人其实不是操作不会而是界面上的字认识、意思不懂不知道自己点下去会发生什么。2.2 凭据管理与仓库认证接下来要做的就是让Jenkins能拉取你们代码仓库里的代码。国内大部分团队用GitLab也有用GitHub、Gitee的。这里我用GitLab举例GitHub流程基本一致。登录Jenkins后进入“Manage Jenkins” - “Credentials” - “System” - “Global credentials”点“Add Credentials”。这里有几种类型可选Username with password直接填代码平台的账号密码简单但不太安全适合临时测试SSH username with private key最推荐的方式用私钥认证安全且不易过期Secret text存API Token适合Pipeline里调用其他接口时用我推荐用SSH方式。具体做法在Jenkins服务器上生成一对SSH密钥然后把公钥添加到GitLab账号的SSH Keys里私钥配置到Jenkins凭据中。ssh-keygen -t rsa -b 4096 -C jenkinsyourcompany.com -f /var/lib/jenkins/.ssh/id_rsa注意生成目录因为Jenkins跑任务时用的是jenkins用户私钥文件路径最好放在jenkins用户的家目录下否则可能会出现“could not read from remote repository”的权限报错。然后在Jenkins凭据页面里类型选“SSH username with private key”Username填gitGitLab的SSH用户固定是gitPrivate Key把私钥内容粘贴进去保存即可。实操里还有个常见坑在Pipeline脚本里要用到凭据时必须给凭据设置一个IDIdentifier。默认情况下Jenkins会生成一串UUID但很难记忆。建议在Add页面的ID字段里自定义一个比如gitlab-ssh-key后面写Pipeline时就能通过credentials(gitlab-ssh-key)直接引用清晰得多。2.3 连接代码仓库与Webhook触发凭据搞定后新建一个自由风格任务Freestyle project在“源码管理”里选Git填入仓库地址比如gitgitlab.example.com:group/project.git然后在Credentials下拉框里选中刚才加好的凭据。如果地址、凭据都正确红色报错信息会消失。但很多团队到了这一步就停了构建还要手动点“立即构建”。真正的持续集成应该是开发推送代码到仓库自动触发构建。这就轮到Webhook上场。Webhook的配置思路是GitLab在push事件发生时主动给Jenkins发一个HTTP请求Jenkins收到请求后判断是哪个Job如果该Job配置了“触发远程构建”或“GitLab Webhook”就开始执行构建。具体配置分两头在GitLab这个项目里进入Settings - WebhooksURL填http://jenkins服务器IP:8080/project/你的任务名Secret Token填一个你自定义的字符串。然后在Jenkins对应Job的配置页里勾选“Build when a change is pushed to GitLab”把同样的Secret Token填进去。这里有个大坑就是如果Jenkins和GitLab都是HTTPS访问Webhook里要保证证书有效如果是HTTP访问GitLab侧要允许“Allow requests to the local network”取决于GitLab版本和网络环境。不然你推送了代码GitLab报了“Hook executed successfully but returned HTTP 403”这种提示Jenkins端却毫无反应排查半天发现是证书或网络白名单的问题。另外如果代码仓库里分支很多建议在Job里配置“分支过滤器”只接受你想要的分支触发构建比如main、release-*避免开发随便开个功能分支都触发一堆构建白白耗费资源。3. 流水线核心与实践3.1 自由风格任务与流水线的比较讲到这一章我得先说明一点自由风格任务Freestyle和流水线Pipeline是两种不同的构建任务定义方式。很多教程一会儿讲Freestyle一会儿讲Pipeline没有交代清楚它们的关系容易把人绕晕。简单理解Freestyle是用界面点选的方式配置构建步骤好处是简单直观、适合新手和简单场景坏处是一旦构建流程复杂配置会散落在界面各处版本管理、复用都很麻烦而且很难通过代码审查来保证质量。Pipeline则是用Jenkinsfile文件描述构建流程这个文件可以放在代码仓库里跟着项目走。好处显而易见整个构建流程像代码一样有版本、可测试、可评审不同分支可以定义不同的Jenkinsfile任何环境只要支持Jenkins都能直接跑同一套流程。我给团队定了一个简单规则临时任务、一次性任务用Freestyle正式项目的持续集成/持续部署一律使用Pipeline。比较项自由风格任务Freestyle流水线Pipeline配置方式界面点选Jenkinsfile代码复杂流程支持弱强版本化管理不支持支持复用性低高学习门槛低中高适合场景临时任务、简单构建正式CI/CD流程3.2 声明式流水线基本语法Pipeline分为两种写法脚本式Scripted和声明式Declarative。对绝大多数团队来说用声明式就对了。声明式更结构化语法限制更多但正因为限制多写出来的流水线才更规范、更容易维护。我贴一个最基础的声明式Pipeline结构麻雀虽小五脏俱全pipeline { agent any stages { stage(Checkout) { steps { echo 拉取代码... checkout scm } } stage(Build) { steps { echo 构建中... } } stage(Test) { steps { echo 测试中... } } stage(Deploy) { steps { echo 部署中... } } } }对新手来说记住这几个核心关键字就够了pipeline整个流水线的根节点agent指定这个Pipeline跑在哪个节点上any表示任意可用节点也可以指定标签stages所有阶段的容器stage一个阶段比如“构建”“测试”steps一个阶段内的具体操作步骤post每个阶段或整个流水线结束后的操作比如发通知、清理工作区post块是很多人会忽略但实际非常实用的东西。它支持always、success、failure、unstable等条件块可以在构建成功后发邮件、构建失败时钉钉告警。3.3 Java项目完整流水线拆解说了半天理论直接上一个完整的Java项目流水线例子。假设你有一个基于Maven构建的Spring Boot项目目标是push到main分支后自动完成 拉代码 - 编译 - 单元测试 - 打包 - 部署到测试服务器。pipeline { agent any environment { // Maven全局工具名称在Manage Jenkins - Tools里配置 M2_HOME tool Maven-3.8 PATH ${M2_HOME}/bin:${env.PATH} APP_NAME demo-service SERVER_IP 192.168.1.100 SERVER_USER deploy DEPLOY_PATH /opt/apps/demo-service } parameters { string(name: BRANCH, defaultValue: main, description: 要构建的分支) } stages { stage(检查代码) { steps { git branch: ${params.BRANCH}, credentialsId: gitlab-ssh-key, url: gitgitlab.example.com:group/demo-service.git echo 开始构建分支${params.BRANCH} } } stage(Maven构建与测试) { steps { sh mvn clean package -DskipTestsfalse } post { success { junit **/target/surefire-reports/*.xml } } } stage(归档构建产物) { steps { archiveArtifacts artifacts: target/*.jar, fingerprint: true } } stage(部署到测试服务器) { steps { sh scp target/${APP_NAME}*.jar ${SERVER_USER}${SERVER_IP}:${DEPLOY_PATH}/app.jar ssh ${SERVER_USER}${SERVER_IP} systemctl restart ${APP_NAME} } } } post { failure { echo 流水线失败了通知相关人 } success { echo 流水线成功了 } } }这段代码里我先进行了分支参数化允许运行者在触发构建时通过界面选择要构建的分支默认是main。Maven阶段没有跳过测试并且把单测报告收集起来了这样在Jenkins界面上直接能看测试趋势比拿到一个全绿或全红的构建界面直观得多。归档阶段把jar包收集到Jenkins机同时保留了指纹。这一步的作用是“留痕”以后任何一次构建的产物都能追溯是哪个版本、哪次提交构建出来的。上线出了问题回滚找到对应版本非常快。部署阶段我直接用scp和ssh把jar包传到目标服务器然后通过systemctl重启服务这是最朴素的部署方式适合中小团队。如果你已经上了容器化可以把这一步替换成docker builddocker pushkubectl rollout restart。关于Maven中央仓库慢的问题也要在settings.xml里配置国内镜像源阿里云、华为云等否则每次构建光下依赖就能等死人。我在实际中见过一个项目第一次构建下依赖花了25分钟换镜像源之后缩短到了40秒体感差距巨大。3.4 参数化构建与构建产物管理参数化构建是让流水线“活”起来的关键。你可以把代码分支、要部署的环境、版本号等作为参数暴露出来运行者在构建时填一次流水线里用params.xxx引用。除了自定义参数Jenkins还内置了很多环境变量写脚本时经常用得到${BUILD_NUMBER}当前构建序号同一个Job内递增${BUILD_URL}本次构建的完整URL发通知时直接带上让人点进去看${JOB_NAME}任务名${WORKSPACE}工作区路径${GIT_COMMIT}当前构建对应的Git提交ID排查问题时特别有用${GIT_BRANCH}当前Git构建分支有一次线上排查问题公司研发问我“现在跑的这个版本是哪个commit出来的”我直接打开Jenkins构建历史把GIT_COMMIT对应的地址贴给他半分钟定位。这就是Jenkins流水线的可追溯性价值。构建产物管理同样重要。Jenkins默认会把工作空间里构建出来的jar包、镜像文件等清理掉因为每次构建都重新拉代码、重新生成所以一定要用archiveArtifacts把产物存下来。此外建议在“Manage Jenkins” - “System”里配置“丢弃旧构建”策略限制每个任务最多保留多少天、保留多少个构建。否则项目的构建次数一多产物、日志占满磁盘Jenkins就会变得极其卡顿。3.5 回滚方案设计说句实话很多团队CI做得挺好CD却只做了“部署”没做“回滚”。一旦新版本出问题上线流程就变成所有人手忙脚乱找旧包。最简单的回滚方案是每成功构建一次把产物用带版本号的方式保留下来部署脚本里允许手动指定一个历史版本号来回滚。举一个实际例子在部署脚本中# 版本号采用 BUILD_NUMBER每次构建递增 APP_VERSION${BUILD_NUMBER} # 远程服务器上的目录按版本号区分 ssh deployserver mkdir -p /opt/apps/demo-service/releases/${APP_VERSION} scp target/demo-service.jar deployserver:/opt/apps/demo-service/releases/${APP_VERSION}/ ssh deployserver ln -sfn /opt/apps/demo-service/releases/${APP_VERSION}/demo-service.jar /opt/apps/demo-service/current.jar ssh deployserver systemctl restart demo-service如果要回滚只需要修改current.jar软链接指向上一版本再重启服务即可。整个过程可以在Jenkins里做一个“回滚任务”类型选择参数化构建输入要回滚到的版本号然后执行一段替换软链接的脚本。这套方案不需要额外复杂的发布系统就足够应付绝大多数中小团队的发布需求了。如果有能力做更完善的回滚比如流量灰度、数据库版本兼容那是后话但至少要确保有一个“能把服务恢复到上一个可用版本”的简单路径。4. 常见问题与运维避坑4.1 插件安装失败与构建卡死问题插件安装失败是我收到最多的求助问题。大部分情况就是网络导致更新站点连不上。把Update Site改成国内镜像源是最常见的解决办法我在1.3节已经详细说过了。还有一种场景是插件本身装上了但Jenkins启动时某个插件初始化失败了导致整个Jenkins启动卡住。排查方法是用systemctl status jenkins看日志或者直接看/var/lib/jenkins/log/jenkins.log。如果是某个插件引发启动失败可以进入/var/lib/jenkins/plugins目录把对应插件目录临时改名重启Jenkins让它跳过有问题的插件。这里要提醒一个动作操作plugins目录前最好先停掉Jenkins服务改动后手动启动再观察。我见过有人直接在线删插件目录结果Jenkins进程还在运行文件锁导致后续怎么启动都不正常最后花了不少时间清理。4.2 构建失败的常见排查套路代码都配置好了但点构建就是失败不要慌有套路。第一类问题Git相关。日志里有Could not read from remote repository一般是凭据配置错了或SSH密钥路径/权限不对。检查Jenkins运行时用户是否是jenkins私钥是否在jenkins用户家目录.ssh下以及.ssh目录权限是否过宽不能是其他用户可写。第二类问题Maven构建报依赖下载失败。先排查settings.xml是否配置了国内镜像再检查网络是否能访问到Maven中央仓库。加了镜像也失败的话看是不是公司内网有防火墙限制。第三类问题脚本无权限。日志里有Permission denied大概率是jenkins用户对目标目录没有写权限。用sudo chown -R jenkins:jenkins或把目录加入jenkins用户组解决。这里不建议给jenkins用户直接提权到sudo安全风险很大更合理的做法是配置/etc/sudoers里白名单式的命令权限。第四类问题编译/打包通过但shell脚本执行报错。多半是脚本里的换行符问题——在Windows上编写的.sh文件带到Linux执行会报\r相关的错误用sed -i s/\r$// deploy.sh清理一下。4.3 日常运维要点Jenkins用久了会发现它就像一个越用越臃肿的厨房不清理就会堆满油污。日常运维有几件必须做的事。磁盘空间清理Jenkins的构建日志、归档产物、Docker镜像缓存都很占空间。建议在“Manage Jenkins” - “System”里设置全局构建保留策略同时定期用jenkins-cli.jar清理旧构建。也可以用脚本定时执行java -jar jenkins-cli.jar -s http://localhost:8080 -auth admin:pass delete-builds 任务名 1..100JENKINS_HOME备份Jenkins的所有配置、凭据、构建记录都在/var/lib/jenkins目录下。有条件的话每天对这个目录做增量备份恢复的时候整体解压回去即可。有一次我遇到磁盘故障靠着备份完整恢复了所有任务配置没有重头搭建省掉的折腾时间无法估量。插件和Jenkins版本升级升级前要先在测试环境验证生产环境的升级尽量选在低峰期升级前做目录快照或备份。不要一有新版就去升级稳定才是第一位的。权限管理如果团队有多个开发用同一个Jenkins一定要控制好权限。至少保证普通开发只有创建任务、执行构建的权限管理员账号用于系统配置和插件管理。我在团队里创建了三个角色管理员、开发、访客权限分明出了问题也好追溯。4.4 高频问题速查表最后把我实际遇到过的高频问题整理成一张速查表可以收藏起来备查问题现象可能原因处理思路页面打不开端口未放行/服务未启动检查systemd状态、防火墙、安全组初始密码找不到服务未完全启动或HOME目录被改确保安装后启动过至少一次插件列表空/下载失败官方源访问慢配置国内镜像源Update SiteGit代码拉不下来凭据错误或SSH权限不对检查凭据ID、SSH密钥、仓库地址Maven构建卡死依赖下载慢settings.xml配国内镜像源构建产物找不到路径写错或未归档检查workspace路径使用archiveArtifacts定时构建不触发时区设置错误系统管理里设置时区为Asia/ShanghaiJenkins启动变慢插件过多或旧构建堆积清理插件和旧构建Webhook触发无效网络白名单或Token不匹配检查两端网络配置和Secret Token这个表格里的每一条都是我在实际项目里真金白银踩出来的。把这些处理思路刻在脑子里处理日常Jenkins问题基本上游刃有余。从安装到仓库集成从流水线编写到回滚方案再到常见问题的排查思路这条链路走完你手里的Jenkins已经从一个“自动构建工具”变成一个真正能承载团队持续交付流程的枢纽。我个人在实际操作中最深的感受是Jenkins功能强大但不要一上来就把所有东西都配齐从一个最简单可靠的构建开始跑通了再逐步叠加复杂能力。这种“先让流程走起来再慢慢优化”的思路比一次性搭建一个庞大复杂、谁也维护不了的CI/CD系统靠谱得多。如果后续有兴趣可以往多分支流水线、容器化构建、Kubernetes动态agent这些方向扩展你会发现持续集成的玩法还有更多可能性。