资讯详情

资讯详情

SpringBoot部署到阿里云CentOS7:环境配置与systemd运维

1. 部署前的通盘思考为什么这一套流程值得你完整走一遍SpringBoot项目写完只是第一步真正让它跑在云服务器上才是很多开发者从“本地写代码”跨向“线上可用”的一道坎。我见过太多人卡在这一步本地启动一切正常一上服务器就各种报错——端口不通、数据库连不上、Java版本不对、内存不够、服务跑起来没一会儿就挂了。说到底部署这件事的难点不在于某个单一环节而在于整个链条的完整性操作系统、运行时、数据库、缓存、打包方式、进程管理、网络放行、日志排查任何一个环节掉链子整个服务就起不来。这篇文章基于“在阿里云服务器Centos7上部署Springboot项目的全过程包括环境部署”这个标题把我实际踩过的坑和最终稳定运行的完整步骤整理成文。适合两类人看第一类是刚买了云服务器、第一次部署Java后端项目的新手照着做基本能走通第二类是已经部署过但总是出奇奇怪怪问题的人可以重点看第5章的排查思路很多问题不是偶然而是某个系统配置没到位。我一贯的观点是部署不是“把jar包丢上去跑起来”这么简单而是要让服务具备可控、可查、可重启、可自愈的基本素养。所以这篇文章不只讲命令还会把每个步骤背后的原因讲清楚比如为什么要用systemd而不是nohup、为什么要单独配置MySQL的远程访问权限、为什么安全组和防火墙要同时看。先从最基础的服务器初始化说起。2. 服务器初始配置选型、登录、安全组2.1 云服务器的规格选择与系统版本买服务器这件事看起来简单但配置选错了后面很被动。我的建议是如果是个人项目、小型生产环境选择2核4G起步内存是SpringBoot部署最容易忽视的瓶颈1G内存跑Java应用经常会因为堆内存分配不足直接OOMOut Of Memory崩溃。系统镜像选择CentOS 7.6或7.9虽然CentOS 7已经停止官方维护但大量存量服务器和云厂商的镜像源仍然支持它而且网上资料最多遇到问题更容易搜到解决方案。磁盘的话40G起步日志文件和数据库文件比你想象中膨胀得快。带宽选按固定带宽计费个人项目5Mbps足够不要选“按使用流量”计费否则一次异常流量可能产生让你意外的账单。系统初始化的过程中云厂商会要求设置root密码这个密码要保存好后续通过SSH登录和su切换都要用它。如果使用密钥对登录私钥文件的权限必须设置为600chmod 600 xxx.pem这也是很多新手用密钥登录时报Permission denied的关键原因。2.2 安全组规则最容易踩的“隐形门槛”阿里云的服务器有一个安全组的概念这是云平台层面的网络访问控制。很多人在服务器上关了防火墙、开了端口但外部还是访问不了十有八九就是安全组没放行。安全组规则在云控制台的“实例 → 安全组 → 配置规则”里配置。入方向规则至少需要放行这几个端口端口用途建议授权对象22SSH远程登录建议设置为特定IP或IP段不要对全互联网开放80HTTP访问0.0.0.0/0443HTTPS访问后续如果要上SSL0.0.0.0/08080SpringBoot默认端口如果直接暴露应用需要放行配合Nginx后可以关闭3306MySQL远程连接建议仅放行特定IP不要直接暴露公网注意MySQL端口的安全问题直接对全网开放3306很快就会被扫描工具盯上暴力破解密码只是时间问题。我的实践是3306端口一律不对公网开放需要远程连接时通过跳板机或SSH隧道访问本地开发调试再单独开临时规则。2.3 通过SSH登录服务器第一步是先确认自己能稳定连上服务器。Windows下最常用的是Xshell也可以用VS Code的Remote-SSH插件直接在编辑器里操作服务器文件这比来回传文件方便很多。Mac和Linux用户直接使用终端ssh root你的服务器公网IP第一次连接会提示确认主机指纹输入yes回车即可。如果在配置密钥登录还需要确认登录用户是否为root。不少人在配置密钥时把公钥放到了/home/某个用户/.ssh/authorized_keys但实际登录用的还是root账号这样永远登录不上去这类细节很折磨人。进入系统后建议第一时间做几个基础设置# 更新系统软件包索引 yum update -y # 安装基础工具vim、lrzsz用于上传下载文件、net-tools提供netstat等命令 yum install -y vim lrzsz net-tools # 查看系统版本确认 cat /etc/redhat-release这里提醒一句更新系统包之后建议先不要重启服务器等所有部署完成再统一重启否则你会在重复重启中浪费时间。3. 基础环境安装JDK、MySQL、Redis逐个攻破3.1 JDK安装不要用yum默认自带的版本CentOS 7自带的OpenJDK是1.8版本而且是通过yum仓库管理的。如果只是跑普通SpringBoot项目OpenJDK 8完全够用但如果项目用了较新的语法特性建议直接用JDK 11或17。我个人的习惯是手动下载tar.gz包安装好处是版本可控、目录清晰、环境变量自己说了算。这里以JDK 8为例兼容性最好SpringBoot 2.x项目基本上都是基于它# 下载源码包在/home目录下操作 cd /home wget https://某镜像地址/jdk-8u202-linux-x64.tar.gz # 解压到/usr/local目录 tar -zxvf jdk-8u202-linux-x64.tar.gz -C /usr/local # 重命名目录方便后续配置 mv /usr/local/jdk1.8.0_202 /usr/local/java # 配置环境变量 vim /etc/profile在/etc/profile文件末尾追加以下内容export JAVA_HOME/usr/local/java export PATH$JAVA_HOME/bin:$PATH export CLASSPATH.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar然后执行source /etc/profile让配置立即生效再用java -version验证。正常会输出类似这样的信息java version 1.8.0_202 Java(TM) SE Runtime Environment (build 1.8.0_202-b08) Java HotSpot(TM) 64-Bit Server VM (build 25.202-b08, mixed mode)这里有个坑必须提醒你/etc/profile的配置是在用户登录时才会加载如果你用非交互式SSH命令远程执行java -version可能会提示找不到命令这不代表安装失败而是环境变量还没加载。重新登录一次就正常了。3.2 MySQL安装与初始化字符集和远程访问权限是重灾区CentOS 7系统中yum默认仓库里自带的MySQL是MariaDB虽然兼容MySQL命令但不少团队会刻意避开它选择安装官方MySQL。两种方式都行这里讲官方MySQL 5.7的安装步骤因为目前大量SpringBoot项目的依赖还是基于MySQL 5.7设计的。# 下载并安装MySQL的yum仓库配置 wget https://某镜像地址/mysql57-community-release-el7-11.noarch.rpm rpm -ivh mysql57-community-release-el7-11.noarch.rpm # 安装MySQL服务端 yum install -y mysql-community-server # 启动MySQL并设置开机自启 systemctl start mysqld systemctl enable mysqldMySQL 5.7在首次启动时会生成一个临时密码记录在日志文件里grep temporary password /var/log/mysqld.log用这个临时密码登录MySQL后系统会强制你重置密码。这里要注意MySQL 5.7默认启用了密码复杂度校验策略validate_password插件密码至少要包含大写字母、小写字母、数字和特殊字符长度不低于8位。很多新手在这里设置一个简单密码会一直报错可以先按规则设置一个强密码后面再调整策略或关闭校验。重置密码并在登录后执行授权命令-- 重置root密码 ALTER USER rootlocalhost IDENTIFIED BY 新密码; -- 创建一个应用程序专用账号并授权指定数据库推荐做法不要直接用root远程登录 CREATE USER app_user% IDENTIFIED BY 强密码; GRANT ALL PRIVILEGES ON 你的数据库名.* TO app_user%; FLUSH PRIVILEGES;这里面有一个关键点MySQL默认的字符集是latin1不是utf8mb4。如果项目的表里要存中文、emoji表情或者涉及全文检索字符集不对会导致乱码或报错。建议在/etc/my.cnf的[mysqld]段下追加character-set-serverutf8mb4 collation-serverutf8mb4_general_ci改完配置重启MySQL生效systemctl restart mysqld还有一个高频问题Java连接MySQL报Public Key Retrieval is not allowed。这是MySQL 8.0.x的一个特性针对5.7版本一般不会遇到但如果你用的是新版本驱动连老版本数据库也会被这个错误坑到。解决方案是在JDBC连接串上加allowPublicKeyRetrievaltrue或者确认驱动版本和服务端版本匹配。3.3 Redis安装与配置后台运行和密码保护缺一不可SpringBoot项目通常还会用到Redis做缓存或会话存储。CentOS 7的yum仓库自带Redis版本较老建议直接编译安装新版本步骤也不麻烦。# 安装编译依赖 yum install -y gcc gcc-c # 下载并解压Redis源码包以6.2.x为例 wget https://某镜像地址/redis-6.2.6.tar.gz tar -zxvf redis-6.2.6.tar.gz cd redis-6.2.6 # 编译并安装到/usr/local/redis make make install PREFIX/usr/local/redisRedis默认在前台运行CtrlC或SSH断开就会停止。必须修改配置文件让它后台运行并设置密码mkdir -p /usr/local/redis/conf cp redis.conf /usr/local/redis/conf/ vim /usr/local/redis/conf/redis.conf关键配置项如下daemonize yes requirepass 你的Redis密码 bind 127.0.0.1如果Redis只给本机的SpringBoot应用用bind一定要设为127.0.0.1不要对外暴露。如果确实需要远程访问建议配合安全组限定来源IP并且设置一个足够强壮的密码。这里我踩过一次坑最开始Redis没设密码bind设成了0.0.0.0结果被陌生IP刷了一堆异常键后来只能清空数据重来。Redis的匿名访问风险比MySQL更高因为它默认端口6379经常被自动化脚本扫描。启动Redis/usr/local/redis/bin/redis-server /usr/local/redis/conf/redis.conf确认是否启动成功/usr/local/redis/bin/redis-cli -a 你的Redis密码 ping能输出PONG就代表服务正常。4. 项目打包与文件上传4.1 Maven打包环境配置的多环境管理SpringBoot项目部署前的最后一步是打包。很多项目的配置文件里包含数据库密码、Redis地址等环境相关的信息本地开发配置和线上配置不一样如果每次上线前都手动改配置文件既容易漏改又容易改错。我建议项目从一开始就引入Spring Boot的多环境配置机制。典型的项目配置结构长这样src/main/resources/ ├── application.yml ├── application-dev.yml └── application-prod.ymlapplication.yml作为公共配置只放不变的配置项比如应用名称、端口号等。环境相关的配置放到对应profile的文件里。打包时通过-Dspring.profiles.activeprod指定激活的环境mvn clean package -DskipTests -Dspring.profiles.activeprod跳过测试的-DskipTests是必须的否则Maven会在打包时执行测试类里的Spring上下文加载如果连不上数据库直接构建失败。如果你的测试类本身写了一些需要外部依赖的用例构建失败会让你怀疑人生。打包完成后target目录下会生成两种jar包一个是普通jar一个是xxx.jar.original。部署时用的必须是普通jar——也就是SpringBoot的可执行jar包。识别方法是用jar tf xxx.jar | grep BOOT-INF能查看到BOOT-INF/classes目录就是正确的可执行jar。4.2 应用配置适配数据库连接、Redis连接、日志路径打包前还有一个步骤是确认线上配置文件的正确性。以application-prod.yml为例至少需要检查以下几项server: port: 8080 spring: datasource: url: jdbc:mysql://127.0.0.1:3306/你的数据库名?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai username: app_user password: 你的数据库强密码 redis: host: 127.0.0.1 port: 6379 password: 你的Redis密码 database: 0 logging: file: path: /home/logs数据库连接串里面的serverTimezoneAsia/Shanghai非常关键如果缺失Java连接MySQL会报时区错误。日志路径建议统一放到一个独立目录方便后续查看和清理。这一步完成之后在本地先把配置改好、启动一次验证没有报错再上传服务器。很多人跳过了本地验证直接传服务器出了问题还要连服务器看日志效率差很多。4.3 上传jar包scp、宝塔或FTP工具都行jar包上传的方式很多我推荐用命令行的scp尤其是jar包只有几十兆的时候一个命令搞定scp target/你的项目.jar root服务器IP:/home/app/提前在服务器上建好目录mkdir -p /home/app如果你的服务器带宽小或者jar包很大建议先本地压缩再传输到服务器上解压能节约不少时间。也可以用宝塔面板的图形化文件管理器上传但宝塔面板本身也会监听一个8888端口务必做好访问控制。5. 部署方案选择从nohup到systemd的进化5.1 nohup快速启动简单但不推荐长期使用最快的启动方式是nohup加重定向日志cd /home/app nohup java -jar -Xms512m -Xmx512m 你的项目.jar app.log 21 nohup的意思是忽略挂断信号让进程在SSH断开后继续运行。21是把标准错误输出合并到标准输出统一写入日志文件。这种方式部署最快但问题也很明显如果服务器重启进程不会自动恢复如果进程意外崩溃也不会自动拉起。对个人开发环境、测试环境可以用但正式环境不建议。还有一个细节是nohup启动后你无法通过systemd统一管理想看服务状态只能ps aux | grep java显得很混乱。5.2 用systemd管理SpringBoot服务正式环境的正确姿势systemd是CentOS 7自带的系统服务管理器它最大的优势是服务崩溃后自动重启、开机自启、日志统一由journald接管。为SpringBoot应用写一个服务单元文件只需要几步。在/etc/systemd/system/下创建一个你的应用名.service文件[Unit] DescriptionYour SpringBoot Application Afternetwork.target mysqld.service redis.service [Service] Userroot WorkingDirectory/home/app ExecStart/usr/local/java/bin/java -Xms512m -Xmx512m -jar /home/app/你的项目.jar --spring.profiles.activeprod Restartalways RestartSec10 StandardOutputjournal StandardErrorjournal [Install] WantedBymulti-user.target参数说明After指定了服务启动顺序确保网络、MySQL、Redis这些依赖服务先启动。ExecStart写的是Java的绝对路径这个很关键——因为systemd服务不经过用户登录不会加载/etc/profile里的JAVA_HOME。Restartalways让服务在异常退出时自动重启RestartSec10是重启前的等待时间防止频繁重启把机器拖垮。StandardOutputjournal和StandardErrorjournal表示日志交给journald统一管理。配置完成后加载并启动systemctl daemon-reload systemctl start 你的应用名 systemctl enable 你的应用名查看服务状态和日志systemctl status 你的应用名 journalctl -u 你的应用名 -f用systemd管理服务后服务器的所有运维操作都变成了标准的systemctl start/stop/restart/status配合开机自启即使服务器意外重启服务也能自动恢复。这一步投入不到10分钟但长期维护体验完全不一样。5.3 引入Nginx做反向代理静态资源与访问入口的收拢SpringBoot内嵌的Tomcat处理动态请求完全没问题但如果是前后端分离项目静态资源HTML、CSS、JS、图片放在Tomcat里处理效率偏低而且80端口直接被应用占用后续扩展也不方便。引入Nginx作为反向代理是更合理的架构。安装Nginxyum install -y nginx systemctl start nginx systemctl enable nginx然后修改/etc/nginx/nginx.conf核心配置长这样server { listen 80; server_name _; location / { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } location /static/ { alias /home/static/; expires 7d; } }Nginx监听80端口所有请求转发到内部8080端口。静态资源直接从磁盘读取不经过Java进程压力小得多。配置完成后nginx -t systemctl reload nginxnginx -t是检查配置文件格式一定要先跑这一步否则一个括号错位直接导致Nginx起不来。改完配置用reload而不是restart可以做到平滑重载不中断现有连接。6. 常见问题与排查技巧实录6.1 一张排查速查表部署过程中遇到的问题绝大多数是几个常见原因。下面这张表是我实际排障时最常用的思路清单症状最常见原因排查手段外部访问不到应用但服务器本地能通安全组未放行端口控制台检查入方向规则本地能通、公网也能通端口但应用就是连不上数据库数据库账号授权host不对或字符集问题登录MySQL执行SHOW GRANTS服务启动后马上退出配置文件错误或端口被占用journalctl -u 服务名 -f看错误日志内存持续飙高最终OOM堆内存设置过大或代码问题free -m观察JVM加-Xmx限制修改了代码重新部署但行为没变进程没杀掉老服务还在跑ps aux数据库查询超时或连接池耗尽连接串配置错误或连接未释放看应用日志检查连接池参数6.2 journal日志定位SpringBoot启动失败的实战系统服务启动失败第一步一定是看日志。journald的日志做得好的一点是会自动带上时间、进程PID、错误级别方便快速定位。常见操作# 查看最近50行服务日志 journalctl -u 你的应用名 -n 50 # 持续跟踪日志输出 journalctl -u 你的应用名 -f # 查看指定时间段的日志排查定时重启很有用 journalctl -u 你的应用名 --since 2024-01-01 10:00:00 --until 2024-01-01 12:00:00遇到SpringBoot启动失败日志里最常见的一句话是APPLICATION FAILED TO START这行字下面的Description部分会直接告诉你原因端口冲突、数据源连接失败、Bean创建失败等。顺着这个线索排查效率最高不要盲目地猜测。6.3 资源与进程状态即时诊断服务器上任何一个异常先看三样东西内存、磁盘、进程状态。以下命令形成肌肉记忆# 内存和swap使用 free -m # 磁盘占用 df -h # 按CPU或内存排序查看进程 top -c # 查看特定端口是否被监听 netstat -tlnp | grep 8080 # 查看Java进程的详细JVM参数 ps -ef | grep java其中free -m里的swap列值得多说一句。如果服务器内存不大1G或2G建议增加swap空间SpringBoot应用在内存吃紧时的表现会好很多。给服务器加2G swap是很多团队的标准做法配置方式不复杂这里不展开。6.4 我曾经遇到的一次典型“疑难杂症”有一次部署完应用本地通过公网IP访问始终超时但服务器上curl 127.0.0.1:8080完全正常。防火墙也关了、安全组也放行了8080排查了很久最后发现问题是服务器上还跑着一个旧版本Nginx配置里没写proxy_pass到8080直接返回了502而浏览器缓存了502页面。这种“看着像网络问题其实是服务栈问题”的坑最容易让人绕远路。所以排查顺序我一直遵循一个原则从最内层开始往外层验证——先确认Java进程在跑、再确认端口监听、再确认Nginx转发、最后确认安全组和防火墙。7. 个人实践经验小结前前后后我部署过几十次SpringBoot项目踩过的坑比写过的代码还多。最后分享几点个人感受。第一部署脚本化非常值得投入。当你需要反复部署同一个项目时把上传、备份、重启服务这几步写成一个Shell脚本能省下大量重复劳动也减少手动操作的失误。比如一键部署脚本大致做这几件事备份当前jar包、上传新jar包、重启服务、检查状态。第二日志一定要有轮转意识。SpringBoot应用如果不配置日志大小限制几个月下来日志文件可能膨胀到几十G把磁盘撑爆。推荐在配置里用logback或log4j2的滚动策略按天或按文件大小切割并定期清理老日志。第三备份永远要留一手。数据库和jar包都要定期备份云厂商一般都有快照功能在重大变更前打一个磁盘快照成本很低但关键时刻能救你一次。部署这件事没有太多高深的技术就是一步步搭好地基、放好砖块、对外开好门。希望这篇文章能帮你少走一点我当初走过的弯路。写完之后再补一句实操建议把这个部署过程完整地在测试环境服务器上演练一遍再上生产别拿生产当实验场。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →