重要链接:
「系列文章目录」
「项目源码(GitHub)」
最近在一篇文章中看到一个观点:
有人认为,人在创作过程中其实会扮演两个角色,既是创作者,同时也是一个鉴赏者,会不断地对自己写出来的、创作出来的东西作一个鉴赏。
有的人一创作出来就是很好的,他就通过了自己鉴赏的标准,这种人属于天赋型选手。
有的人是创作能力比较低,刚开始创作出来的东西并不好,但他有一定的鉴赏能力,所以最终折腾来折腾去,还是能折腾出一些好东西来。
看完我悟了,显然我就是要折腾的这种人,每次写文章我都反复改很多遍。工作中也是,有时候我看到同事写的文档就觉得很别扭,到处都不通顺,有时实在看不下去了也会帮他们改改,但不免会消耗较大精力。
所以更新博客这种事吧咱也不能强求,掌握好节奏,憋了一堆干货不吐不快的时候写最好,是吧?
嗯,我承认,这是一篇水文,因为部署什么的也没什么技术含量,遇到问题搜搜查查总能解决。
但这篇文章还真是非水不可,因为我们的 Web 开发知识版图还有一些大块没有填充。我们过去一直在 Windows 单机实验,与实际生产环境相差甚远,很多知识根本无法提及。现在我们要切换到 Linux、分布式 的语境下,去解决更为实际也更为复杂的问题,比如:
···
这些问题咱们今后慢慢探讨,这一次我们先搭建一个最基础的环境:MySQL 服务器 1 台、Redis 服务器 1 台、前端(Nginx)服务器 1 台、后端(Java)服务器 1 台。操作系统均为 Linux,当然都是在虚拟机里,机器多的土豪请自便。
下面开始动手。
首先,我们需要准备虚拟机环境。市面上的虚拟机软件比较多,Windows 平台上使用比较广泛的是 VirtualBox 和 VMWare Workstation 两种。
可以任选一款,但我比较习惯 VMWare Workstaion,15.X 的版本还是很好用的,如何下载以及嗯哼大家请自行百度。
至于 Linux 的版本,我倾向于 CentOS 7.x,免费且稳定,可惜最近消息说 redhat 打算近两年停止维护 CentOS,很伤,毕竟喜欢 CentOS 的人占了社区相当大的一部分。
CentOS 的安装镜像可以从华为、阿里等平台的镜像站上下载,地址是
https://mirrors.aliyun.com/centos/7.9.2009/isos/x86_64/
如图,有各种不同的版本,DVD 版内置了比较常用的功能,Everything 就是什么都有,Minimal 就是只有基础的功能,因为安装的时候会再次选择需要安装的组件,这里实际上是向下兼容。
镜像文件下载哪种都行,但对于生产环境来说,安装的时候最好选择最小化,以免各种组件之间存在冲突。
下载完成后,就可以创建虚拟机了。打开 VMWare,点击创建新的虚拟机, 选择典型
下一步,选择我们下载的 iso 文件
下一步,设置虚拟机的名称和位置,这里我建议你认真设置一下,因为之后虽然可以改显示的名字,但虚拟机文件的名字改起来比较麻烦。此外我们要安装多台虚拟机,整理好文件夹才能方便后期管理。
我给这台虚拟机起名叫 Pure,之后新建的虚拟机都可以从这台克隆出来,就不用重复安装的步骤了。
点击下一步,磁盘空间上限和存储方式都可以默认。
之后检查配置,勾选创建后开启此虚拟机,点击完成,系统即开始安装。进入第一个界面,可以选择直接安装或者测试媒体并安装,测试媒体并不会花费多少时间,因此可以直接回车进入。
运行一段脚本之后,即进入图形化安装界面。第一步选择语言,建议选择英语,免得之后一些组件出现适配问题。
点击 continue 继续,出现一堆配置,大部分配置会被自动完成,需要我们动手的主要是 Software Selection 和 Installation Destination,我这里是 Minimal 版,所以软件也没什么可选的,默认就是最小化。
安装位置这里必须要点一下才能继续,但也可以直接按照默认配置来,虚拟机以及帮我们分好了一块 20G 的磁盘空间。
Done 之后,点击 Begin Installation,系统和开始安装,同时这里还会提示你设置 root 密码、创建用户。至少要设置一下 root 密码才可以完成安装。
root 密码如果设置的比较简单,第一次点 done 会有提示,再点一次就可以强制完成了。
出于安全考虑,强烈不推荐设置过于简单的 root 密码。
接下来,系统将会自动继续安装,完成后,按照提示重启即可。
OK,这里我们啥也不做,把虚拟机关掉,关掉,全部都关掉。
为了提供 MySQL 服务,我们需要
首先,我们以安装完成的纯净版虚拟机为母体,克隆出新的虚拟机,用于部署 MySQL 服务。
在虚拟机名称处点击右键-管理-克隆,下一步,选择虚拟机中的当前状态(此时我们还没有快照)
下一步,选择创建链接克隆(硬盘空间大可随意)
之后老一套,命名(如 wj-mysql),选择文件夹,点击完成,克隆机即创建完毕。
打开我们的克隆机,登录 root 账号。
此时可以 ping 一下百度或使用 nmcli
(或 ip a
)命令查看网络配置,发现网络并没有连通,原因是网卡还没有获取到 ip 地址。
虚拟机有三种网络类型,仅主机、桥接和 NAT。
一般情况下,VMWare 默认开启的是 NAT 模式,如有需要可以在虚拟机设置中修改。 NAT 模式的网段、网关等信息可以通过 VMWare 的编辑-虚拟网络编辑器进行查看和修改。
可以看到目前我的虚拟机使用的是 192.168.194.0 网段。
点击 NAT 设置,可以看到网关是 192.168.194.2。
这里的 VMnet8 是虚拟网卡的名称,在主机的网络适配器中也可以看到并直接配置。DHCP 默认处于开启状态,为了稳定地提供 MySQL 服务,我们需要配置静态的 IP。
在虚拟机终端中,我们需要编辑网络配置文件。
vi etc/sysconfig/network-scripts/ifcfg-ens33
需要设置的内容,包括将 BOOTPROTO 由 dhcp 修改为 static,将 ONBOOT 由 no 修改为 yes,以及新增 IP 地址(属于 VMnet8 的子网)、子网掩码、网关,完成后保存。
接下来,为了使用域名访问网络,还需要设置 DNS。创建并编辑配置文件
vi /etc/resolv.conf
添加 nameserver
,即 DNS 地址
完成后保存,使用 service network restart
等命令重启网络服务,再测试网络,发现已经成功连通。
CentOS 默认使用 yum 管理软件,我们使用 yum list | grep mysql
命令查看 MySQL 相关的包,发现并没有正经的 mysql-server。
毕竟 MySQL 现在也不是完全开源了,当然,我们还有 MariaDB,不过咱们项目既然用了 MySQL,就一条路走到黑吧。
为了能够安装 MySQL,我们需要手动去官方网站下载包含 repo 源的 rpm 文件。地址是:
https://dev.mysql.com/downloads/repo/yum/
点击下载 Red Hat Enterprise Linux 7 对应的 rpm 包。
接下来,可以通过 WinSCP(下载地址 https://winscp.net/eng/download.php) 或类似的软件传入虚拟机。以 WinSCP 为例,输入主机名(IP)以及用户名和密码建立连接
在 /usr/local 下新建目录 mysql,将刚才下载的文件拖入该目录。
上述步骤也可以在虚拟机上通过 wget 执行,更加方便一点。
获得 rpm 之后,在虚拟机中进入其所在文件夹并安装。
cd /usr/local/mysql
rpm -ivh mysql57-community-release-el7-11.noarch.rpm
此时在 /etc/yum.repos.d 目录下生成了两个 repo 文件。
此时再执行 yum repolist all | grep mysql-community
,发现有了我们想要的东西。
目前默认开启的版本就是 8.0,因此我们不需要做其它修改。如果需要下载其它版本,可以通过 yum-config-manager
设置(需要安装 yum-utils)或编辑 /etc/yum.repos.d/mysql-community.repo
,修改 enable 值即可。
接下来,只需要执行
yum -y install mysql-community-server
等待安装完成即可。这里虽然我们写的是 server,但 client 也会被默认安装上。
启动 MySQL 服务
systemctl start mysqld
第一次启动成功后,MySQL 会生成一个临时初始 root 密码并写入日志里,我们可以通过 cat /var/log/mysqld.log
查看。
获取该密码之后,即可通过本地 root 账号登录 MySQL
mysql -uroot -pFdW5COQNh9.8(your password)
登录后,可以通过如下语句修改 root 密码
ALTER USER 'root'@'localhost' IDENTIFIED BY 'YourNewPass1!'
注意 MySQL 8.0 的密码策略比较严格,需要大写、小写、数字、符号全都有。之前我们项目配置使用了 Admin123!
,这里我们为了方便可以继续沿用这一密码,但还是那句话,在实际生产环境中,强烈不建议使用如此简单的密码,而且 Web 应用尽量不要使用 root 连接数据库,不然一旦被攻击者利用,受害面积将大大增加。
为了让 MySQL 能被 Web 项目访问到,我们还需要进行两步操作。一是开启系统防火墙相应端口,二是在 MySQL 中对远程用户进行授权配置。
CentOS 7 默认使用 firewalld 防火墙,可以看作是 iptables 的封装。开启 MySQL 默认的 3306 端口,可以直接使用
firewall-cmd --permanent --add-service=mysql
或
firewall-cmd --add-port=3306/tcp --permanent
最后重启防火墙服务即可。此时我们可以通过宿主机使用 telnet 测试一下端口是否开放。
telnet 虚拟机ip 3306
可以看到成功收到回显,但此时宿主机还没有访问权限。注意这里主机的 IP 显示为 192.168.194.1
,我们在宿主机的 cmd 中通过 ipconfig
查看,发现此 IP 对应的网卡是 VMnet8,也就是虚拟机在 NAT 网络模式下使用的虚拟网卡 。
我们继续进入 MySQL 中配置。首先新建一个用户 wjadmin
CREATE USER wjadmin IDENTIFIED BY 'Admin456@';
修改 mysql
数据库中的 user
表,使该用户隶属于 192.168.194.1(宿主机),修改后,该用户即可通过宿主机访问 MySQL 服务,但无法访问除 information_schema
之外的数据库。
USE mysql;
UPDATE user SET host='192.168.194.1' WHERE user='wjadmin';
创建数据库 wj
CREATE DATABASE wj;
赋予 192.168.194.1(宿主机) 上的 wjadmin 用户操作 wj
数据库所有数据表(wj.*)的所有权限(ALL PRIVILEGES)
GRANT ALL PRIVILEGES ON wj.* TO 'wjadmin'@'192.168.194.1'
此时我们在宿主机上使用 MySQL 客户端连接虚拟机的服务,输入账号密码,发现连接成功(如果失败,可以尝试在 mysql 中 FLUSH PRIVILEGES
刷新权限)
这里我使用的是 MySQL Workbench。如果使用 Navicat,可能出现由于加密方式不一致导致拒绝连接的问题,可以参照前面的文章解决。其实现在我不是很喜欢用 Navicat 之类的第三方客户端,总觉得不那么靠谱。
在客户端中查看所有数据库,发现我们只能访问 infomation_schema
和 wj
两个数据库,符合我们的预期。
至此,MySQL 的安装与配置就结束了,后续搭建过程中只需把当前对宿主机开放的权限赋给后端服务器所在的虚拟机即可。
同样,我们创建一个克隆,配置好网络(静态 IP)。还是先用 yum list |
查找 yum 仓库里是否有 Redis,发现并没有。可以通过 yum install epel-release
命令添加 EPEL 仓库,再通过 yum install redis
安装,但这个仓库里的 Redis 版本有点低。
因此,我们还是直接从官网下载包吧。首先我们通过 yum install wget
安装一下 wget,然后下载最新稳定版的 Redis 安装包 (可以在 https://redis.io/download 上查看下载地址)。
wget https://download.redis.io/releases/redis-6.0.9.tar.gz
下载完成后,我们把这个包解压到 /usr/src
下
tar zxvf redis-6.0.9.tar.gz -C /usr/src
为了完成编译,我们需要首先安装 gcc。CentOS 7 使用 yum install gcc
默认安装的 gcc 是 4.8.5 版本,而编译 Redis 至少需要 5.3 以上。
正常思路是手动编译安装 gcc,这个过程比较麻烦,有些依赖下载的很慢,下完了编译需要两三个小时,编译完了配置不好还是会报错。
幸亏还是有更方便的选择,我们只需使用 SCL 源安装 Developer Toolset 即可:
yum install -y centos-release-scl
yum install -y devtoolset-8-gcc devtoolset-8-gcc-c++ devtoolset-8-binutils
scl enable devtoolset-8 bash
这里我们安装了 devtoolset-8 这个版本的 gcc、gcc-c++、binutils 三个包,如果不指定则会安装 devtoolset 提供的所有的包。
最后启用 devtoolset-8 的命令是临时的,重启之后就会失效,可以把相关指令写入配置文件中:
echo "source /opt/rh/devtoolset-8/enable" >>/etc/profile
安装完成之后可以执行 gcc -v
查看一下 gcc 的版本。
8.3.1,够用了,当然官网的最新版本是 10.2.0,感兴趣的可以自己折腾一下。
ok,gcc 安装完成,我们进入之前解压的 redis-6.0.9
文件夹,依次执行编译、安装
cd /usr/src/redis-6.0.9
make
make install
这样 Redis 就安装完成了。可以直接用 redis-server
命令启动服务。
通过 redis.conf
文件可以配置服务参数:
daemonize no
为 daemonize yes
,使 redis 能够以守护进程方式在后台运行bind 127.0.0.1
,也就是只有本机可以访问,把这行注释掉可以使所有主机能够访问。但出于安全考虑,我们应该将其配置为后端服务器的 IP。requirepass
一行的注释去掉,设置你想要的密码,如 requirepass Admin789#
如果图省事,可以在配置文件中把 protected-mode yes
修改为 protected-mode no
,关闭保护模式。(在 yes 的情况下,必须设置密码、绑定主机才可远程访问,实际环境不推荐 no)
保存该配置文件,在启动 Redis 时按照 redis-server /path/redis.conf
格式指定该文件即可。建立另存为其它文件,把默认的配置也保存下来。
最后,别忘了 Linux 的防火墙。
克隆,网络,前端的部署还是很简单的。
第一步,修改前端跨域访问配置(config/index.js
)与请求转发地址(main.js
),把原来的 localhost
替换为后端 IP。当然我们要想知道后端 IP 是多少,需要先把后端虚拟机建起来。后端同样也需要配置前端的 IP,循环依赖,不爽。
config.js:
proxyTable: {
'/api': {
target: 'http://192.168.194.129:8443',
changeOrigin: true,
pathRewrite: {
'^/api': ''
}
}
}
main.js:
axios.defaults.baseURL = 'http://192.168.194.129:8443/api'
第二步,npm run build
,打包。
第三步,在服务器上安装 Nginx 并配置,推荐大家使用 OpenResty。
OpenResty 是一个基于 Nginx 与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库、第三方模块以及大多数的依赖项。用于方便地搭建能够处理超高并发、扩展性极高的动态 Web 应用、Web 服务和动态网关。
OpenResty 通过汇聚各种设计精良的 Nginx 模块(主要由 OpenResty 团队自主开发),从而将 Nginx 有效地变成一个强大的通用 Web 应用平台。这样,Web 开发人员和系统工程师可以使用 Lua 脚本语言调动 Nginx 支持的各种 C 以及 Lua 模块,快速构造出足以胜任 10K 乃至 1000K 以上单机并发连接的高性能 Web 应用系统。
执行 yum install openresty
,openresty 会安装到 /usr/local
下,进入其中的 nginx
目录找到 conf 文件,即可对 Nginx 进行配置。
这次我们不修改端口,直接用默认的 80,只配置一下 try_files
,以适配 Vue-Router 的 history 模式。
location / {
try_files $uri $uri/ /index.html;
}
接下来,把打好包的文件(dist
目录下的 static
和 index.html
)放入 Nginx 的 html
文件夹中。
接下来,在 nginx
目录中执行
./sbin/nginx -p `pwd`/ -c conf/nginx.conf
也可以在外部执行命令,替换 pwd 为 nginx
的路径即可。
通过浏览器访问 http://前端 IP
,如 http://192.168.194.138
,可以看到项目前端已经成功部署。(也可以直接在虚拟机执行 curl localhost
意思一下)
为了部署后端项目,首先需要安装 Java 运行环境。
我们这次依旧使用 jar 包部署后端项目,当然也可以使用 war 包 + tomcat 的方式部署,后期优化服务器配置会更加灵活。
运行 jar 包需要 JRE,为了方便后期在服务器上修改源码并编译,也可以选择直接安装 JDK。使用 yum 安装 JDK 还是很简单的。可以先查看可以下载的版本
yum list | grep jdk
看来目前比较受欢迎的还是 JDK 1.8 和 JDK 11。那我们本着选新不选旧的原则安装 11 吧,过去虽然开发时我调到过更高的版本,但并没有用最新的特性,所以这里不影响。
执行 yum install -y java-11-openjdk.x86_64
,等待安装完成后,使用 java -version
命令查看版本信息,成功回显则说明安装成功。
最后,为满足一些软件的需求,需要增加全局环境变量配置。首先使用 which java
查看 jdk 所在路径
接下来,编辑 /etc/profile
文件,增加下面三行,注意根据上面的路径设置 JAVA_HOME
变量
export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-11.0.9.11-2.el7_9.x86_64
export PATH=$JAVA_HOME/bin:$PATH
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
保存,使用 source /etc/profile
使其立即生效,在终端输入 $JAVA_HOME
,信息正常回显,配置成功。
首先是数据源配置,主要是远程服务器的地址、端口和账号密码。
# MySQL 配置
spring.datasource.url=jdbc:mysql://192.168.194.128:3306/wj?characterEncoding=UTF-8&serverTimezone=GMT%2B8
spring.datasource.username=wjadmin
spring.datasource.password=Admin456@
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# Redis 配置
spring.redis.host=192.168.194.131
spring.redis.port=6379
spring.redis.password=Admin789#
···
可以把新建两个配置文件,分别命名为 application-prod.properties
和 application-dev.properties
,把开发环境和生产环境中配置不同的地方区分开,再在 application.properties
中指定需要的配置,比如 spring.profiles.active=prod
。
然后是跨域访问,在 config/MyWebConfigurer
中修改允许跨域的地址为前端服务器地址:
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowCredentials(true)
.allowedOrigins("http://192.168.194.138")
.allowedMethods("POST", "GET", "PUT", "OPTIONS", "DELETE")
.allowedHeaders("*")
.maxAge(3600);
}
在 pom.xml
设置
,执行 mvn clean install
,把生成的 jar 包放入后端服务器 /usr/local/bin
目录下,执行
java -jar wj-1.0.0.jar
因为我们配置了初始化数据库的脚本,数据会被自动注入。接下来就是芜湖起飞。
MD 报错了,我一看,哦,原来是数据库用户权限忘了给后端,进 mysql 服务配置一下就好了。
访问 http:192.168.194.138
,测试一下功能,终于可以正常显示内容了。