之前弄了个Linux虚拟机准备自己捣鼓捣鼓,可惜一直没时间,再加上不是很适应纯命令行的操作方式,导致一拖再拖。正好最近不是很忙,过一遍SpringBoot+SpringCloud项目的部署流程,查漏补缺一下,也确实是发现了很多问题。
下面就一步一步复现整个过程。
上面是需要在Linux中安装的基本依赖,几种安装软件的途径,yum/wget/tar包/rpm,之前的一篇文章里介绍过各自的优缺点,在这里不作赘述。原则就是能用yum就用yum,全程yum -y install还是很方便的;yum如果没有,就安装一个EPEL(Extra Packages for Enterprise Linux),相当于扩充了你的yum源;如果这样还不行,那就用tar包安装吧。
在用yum之前记得要设置一下国内的镜像源,之前用网易的感觉不是很理想,换到阿里以后下载速度1M每秒吧,还凑合。大概步骤如下:
//记得先把原配置文件备份一下
mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup
//下载新的阿里镜像源配置文件,注意要对应系统版本号
wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
//更新一下缓存
yum clean all
yum makecache
在这之前我打算先试试能不能让本机访问到Linux虚拟机,就先顺手安个Nginx。
yum -y install nginx
然后用whichis nginx找安装的目录,去启动一下。在本机访问虚拟机IP看看效果(看IP用ifconfig,没有的话用yum安装):
OK,松一口气,没什么奇怪的问题出现。
yum -y install java-1.8.0-openjdk-devel.x86_64
等屏幕不闪了调用一下 java -version,能正常显示信息即可,然后去修改一下环境变量信息,vim /etc/profile后在后面追加:
//注意这里的openjdk-***,要和你安装的信息保持一致,可以调用下whereis java看看安装的目录名称
export JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.342.b07-1.el7_9.x86_64
export PATH=$PATH:$JAVA_HOME/bin
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tool.jar
yum源没找到MySQL 5.7,所以只能先获取到rpm包,再进行安装:
//下载rpm包到本地
wget -i -c http://dev.mysql.com/get/mysql57-community-release-el7-10.noarch.rpm
//安装
yum -y install mysql57-community-release-el7-10.noarch.rpm
yum -y install mysql-community-server
安装碰到了一个奇怪的问题,提示我“公钥尚未安装”,去搜索了一下要去先获取公钥才行,所以先调用获取一下公钥再进行安装即可:
rpm --import https://repo.mysql.com/RPM-GPG-KEY-mysql-2022
安装好后 systemctl start mysqld.service启动MySQL服务,status查看运行状态,如果为“active(running)”则说明运行成功。之后就需要登录一下MySQL,默认生成的密码我们需要去安装的日志里查看一下,这时就涉及第一个常用命令的扩展知识点:grep。
grep是个很常用的正则搜索命令,一般日志查询和定位都要用到它。一般用法如下,更复杂点的正则匹配可以自己再去了解。
//这里的na作用为:显示行数+不忽略二进制数据
grep -na "搜索内容" /路径/路径
//此处的用法
grep -an "password" /var/log/mysqld.log
2022-08-30T02:33:52.142942Z 1 [Note] A temporary password is generated for root@localhost: le-d16iLpco5
然后用这个密码登录进MySQL,修改密码后操作数据库,由于MySQL对密码强度有一定的要求,在设置简单的纯数字密码时会提示密码强度太低。所以我们先设置一个复杂点的密码,进入系统修改密码策略后,再设置一个简单密码。其实是不建议这样做,但是由于只是用于个人学习,搞个简单点的密码比较好。
步骤主要如下:
//降低密码强度策略
set global validate_password_policy=0;
//降低密码最小长度
set global validate_password_length=1;
//然后修改密码
ALTER USER 'root'@'localhost' IDENTIFIED BY '123456';
//最后记得刷新权限,不然不生效
flush privileges;
最后去配置一下远程连接,MySQL默认是不支持的,还需要关闭一下selinux或者防火墙,或者开放3306端口。增加权限的语句如下:
grant all privileges on *.* to root@'%' identified by '密码';
flush privileges;
之后就可以在本机用可视化工具来操作SQL,用Navicat把表结构和数据都复制进去,MySQL环境就准备好了。
Redis安装倒是很简单,直接 yum -y install redis就行,主要是要学习如何开启Redis的远程访问。和MySQL相同,Redis也是默认不允许远程访问的,可以去修改以下配置:
//找到redis.conf的位置
whereis redis.conf
//修改如下几个配置项
bind 0.0.0.0 或 本机ip
//关闭保护模式
protected-mode no
//设置为守护进程,用于后台启动
daemonize yes
设置完上述配置项后,可以用RedisDesktopManager试一试能不能连接上,能连上就说明Redis已经成功运行且配置文件生效。如果连不上,说明可能是Redis没有正常启动,或者配置项没有生效。可以先查Redis进程是否启动成功,或者直接查6379端口号有没有被监听;使用 ps -ef|grep redis 查进程,修改配置如果不生效就杀进程再启动;或者 netstat -an|grep 6379,查询6379端口是否被监听,或是 netstat -ntlp查看所有端口监听情况。
由于要部署的是一个微服务项目,用Nacos作为注册和配置中心,因此还需要先安装好Nacos才能实现服务注册和配置管理。
Nacos是用tar包安装的,先去官网下载好 nacos-server-1.4.1.tar.gz,用WinSCP扔到虚拟机上直接解压启动即可。要注意的一点是,由于tar包解压不属于常规的安装方法,在rpm和yum中是无法查询到的,只能查文件夹所在位置。
解压完毕后cd到bin目录,输入 sh startup.sh -m standalone &,意为单体模式,加上“&”让他后台运行。运行后可以输入 netstat -ntlp看看所有端口的监听情况,如下图:
可以看到3306/6379/8848端口都已监听,且最后面显示了程序的名称,说明MySQL、Redis、Nacos都已正常运行。可以去本机访问一下ip:8848/nacos,如果能正常登录就说明没问题。
至此,所有项目运行所需的依赖都已经安装完毕,下面只需要把项目正常打包并运行在Linux上即可。
由于是一个Maven父子工程,所以只需要把整个父工程先Clean再Install即可。把整个工程Install完之后,每个子工程下会生成一个Target目录,里面的Jar包就是我们需要的。
将单个工程拖进Linux准备运行一下,在运行 java -jar xxxxx.jar后,连SpringBoot启动的日志都没看到,直接报出“no main manifest attribute in xxx.jar”。分析一下这个报错,是由于当前Jar包中没有指定主入口,简单来说就是没指定主启动Main方法。
经过查阅一些资料,发现这些信息是在Jar包的“MANIFEST.MF”中指定的,这个清单说明了该工程的所有信息。用压缩包形式打开我打包的Jar包,在/META-INF下确实有这么个MANIFEST,打开看了看其中的内容:
Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Built-By: 52Hz
Created-By: Apache Maven 3.5.2
Build-Jdk: 1.8.0_311
这看着确实是少了点什么,资料说少了下面几个东西:
要把这些信息打包进去,那肯定要从Maven下手了,因为包管理都是靠Maven实现的。需要做的就是在pom.xml的
org.springframework.boot
spring-boot-maven-plugin
repackage
要注意的是,首先要设置 repackage属性,它才会重写MANIFEST,否则有时会无法生效。
其次这个插件不能放在父工程中,因为使用他的前提是当前工程必须有主启动类,才能正常打包,否则就会报错。一开始我为了偷懒直接放在父工程,让每个子工程获取他,对父工程调用Install后发现,总是到某个子工程就会报错。经过排查后发现,报错的子工程没有主启动类和Main方法,只是作为一个依赖存在。把父工程的插件去掉,再给有主启动类的子工程挨个加上,对父工程Install就正常了。
现在再来看看正常的MANIFEST文件内容:
Manifest-Version: 1.0
Spring-Boot-Classpath-Index: BOOT-INF/classpath.idx
Archiver-Version: Plexus Archiver
Built-By: 52Hz
Spring-Boot-Layers-Index: BOOT-INF/layers.idx
Start-Class: com.blog.BlogApplication
Spring-Boot-Classes: BOOT-INF/classes/
Spring-Boot-Lib: BOOT-INF/lib/
Spring-Boot-Version: 2.7.3
Created-By: Apache Maven 3.5.2
Build-Jdk: 1.8.0_311
Main-Class: org.springframework.boot.loader.JarLauncher
这次就齐活了,下一步就是把项目扔到Linux启动。
让项目运行起来,听起来是很简单,直接java -jar不就行了吗?但实际上还是有很多问题可以探讨的。
首先第一点,如何让程序在后台运行?因为我们部署的是一个微服务项目,需要同时启动非常多服务,都前台执行是不现实的,Ctrl+C就直接退出去了。
前面我们提到过一个“&”,可以让程序后台运行,这里我们的第一种实现方式就是“java -jar xxxx.jar &”。这种方式对大部分情况是够用的,但当窗口或账户退出时,程序也会自动退出,这就不是很理想了。
针对这种想让程序一直在后台挂着的情况,我们可以用nohup(no hang up)不挂断模式,具体指令为“nohup java -jar my-blog-1.0-SNAPSHOT.jar &”。这种方式可以在账户退出或终端退出时,仍然让程序运行。
但其实还不够,运行日志在程序问题和Debug排查过程中,是一个非常重要的工具,这两种方法无疑是看不到日志的。我们可以针对nohup指令,再改进一下。
nohup还有一个很重要的扩展功能,就是可以自动输出日志。在“nohup java -jar my-blog-1.0-SNAPSHOT.jar &”这种情况下,我们没有指定输出的日志文件,他就会自动将日志输出到当前目录下的 nohup.out文件中。可是每个文件夹都有一个 nohup.out是一件很诡异的事,你要如何区分哪个是哪个的日志呢?这些也可以指定。
可以使用“nohup java -jar my-blog-1.0-SNAPSHOT.jar >>/home/Shelter/log/blog.log 2>&1 &”,这段指令的总体意思是“将my-blog程序后台运行,并将其运行日志输出到blog.log文件中”,我们来分段解释一下:
nohup java -jar my-blog-1.0-SNAPSHOT.jar >>/home/Shelter/log/blog.log 2>&1 &
//前面这段就是挂起执行Jar包
nohup java -jar my-blog-1.0-SNAPSHOT.jar
//显示指定要输出的日志文件路径,前面的“>>”意为追加写入,如果是“>”则为覆盖
>>/home/Shelter/log/blog.log
//将 标准错误输出2 重定向到 标准输出&1,再将 &1 重定向到指定的log文件中
2>&1
//后台运行
&
在启动程序后,可以用“tail -f blog.log”查看日志的实时输出。
将所有微服务启动后去Nacos查看,所有服务都被成功注册,在本机调用接口和Feign也都能正常得到结果。说明这次部署就圆满完成啦,确实是捣鼓了半天,不过是有意义的。学会了很多常用的指令和排查问题的方法,比如ps查进程号kill了重开,netstat查端口监听情况。还有最好用的reboot指令,出啥问题了解决不了就reboot,以后谁问电脑问题统一建议重启。
下面是一些常用指令的总结: