一文搞定前后端项目部署

Linux常用命令:

1
2
3
4
5
6
7
8
9
10
11
lsof -i:8090 //查看端口是否被占用
kill -s 9 pid //杀死进程
jps //查看启动的java应用进程
scp -P 22(服务器端口号) smpe-system-1.0.0-RELEASE.jar root@ip地址:/data/nginx/www/cloudsafe/cloudsafe_server(服务器中文件夹的绝对路径)
//远程复制,将本地的xx.jar, 上传到服务器的xxxx/cloudsafe_server文件夹,注:()为解释,执行时自行删除,此命令是在jar的所在目录下执行的。

docker exec -it a4f598cc4268(容器id) mysqldump -uroot -p*********(数据库密码) --opt research_keyuan(数据库名称) > /root/mysql_file_backup/mysqlbakup_research_keyuan.sql (用来保存sql文件的路径及文件名)
//此命令用来备份docker中的mysql数据库sql文件

docker exec -i a4f598cc4268(容器id) mysql -uroot -p*****(数据库密码) research_keyuan < /root/mysql_file_backup/xxxx.sql
//此命令是用来将sql文件导入到docker中的mysql容器的mysql的指定数据库

环境准备

下面的环境只适用于Centos 7.x

Docker

添加yum源

1
yum update //检查更新
1
yum install epel-release -y //添加yum的软件仓库

安装docker

1
yum install docker-io -y

运行docker

1
systemctl start docker

检查安装结果

1
docker info

停止docker

1
systemctl stop docker

重启docker

1
systemctl restart docker

docker的常用命令

1
2
3
4
5
6
7
8
9
10
docker pull xxx //拉取应用镜,如拉取nginx镜像:docker pull nginx
docker images //查看已有镜像
docker rmi 镜像id //删除镜像
docker ps //查看启动的容器
docker ps -a //查看容器,包含了未启动的容器
docker stop 容器id //停止容器
docker rm 容器id //删除容器,需要停止容器
docker exec -it 容器id/名称 bash //进入容器内部
docker inspect 容器id/名称 | grep Mounts -A 20 //查看容器与服务器的映射目录
docker inspect 容器id/名称 | grep IPAddress //查看容器的ip地址

下面需要安装一些公共服务如:mysql ,redis, nginx

两种方案:在docker中安装,在服务器中直接安装,两种方式都可,建议选择一种,仁者见仁吧,根据方式不一样,后端的部署也会有些细微变动。

一、Docker安装各种服务

Docker 安装mysql

安装

1
docker pull mysql //后面不加版本号,默认最高版本

启动

1
docker run -itd --name mysql-test -p 3307:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql
  • 参数说明:
    • *-p 3306:3307 :映射容器的 3306端口到宿主机的 3307 端口,外部主机可以直接通过 宿主机ip:3307 访问到 MySQL 的服务。
    • MYSQL_ROOT_PASSWORD=123456:设置 MySQL 服务 root 用户的密码。
    • 注:启动后,如果需要远程访问,需要开启服务器的相应端口号

检查

1
docker ps //查看是否安装成功
Docker 安装Redis

安装

1
docker pull redis

启动

1
docker run --name redis -p 6379:6379 -d --restart=always redis redis-server --appendonly yes --requirepass "这是密码"
  • 参数说明
    • -p 6379:6379 端口映射:前表示服务器的端口,:后表示容器的端口。
    • –name myredis 指定该容器名称,查看和进行操作都比较方便。
    • -d redis 表示后台启动redis
    • appendonly yes 开启redis 持久化
Docker 安装nginx

由于内容有点多,都记录到此篇博客中基于Docker使用Nginx

二、服务器安装各种服务

服务器中,我是采用yum源来安装各种服务,这种方式比较简单(强烈推荐)

yum安装Mysql

1、检查系统是否安装有mysql

1
2
yum list installed mysql*
rpm -qa | grep mysql*

2、安装客户端

1
yum install mysql

3、安装服务端

1
2
3
4
5
6
7
yum install mysql-server
注:可能提示为安装失败
原因:CentOS7自带有MariaDB而不是MySQL,MariaDB和MySQL一样也是开元的数据库
解决方案:如果必须要安装MySQL,首先必须添加mysql社区repo通过输入命令:
sudo rpm -Uvh http://dev.mysql.com/get/mysql-community-release-el7-5.noarch.rpm
//执行后, 继续执行
yum install mysql-server

4、执行

1
yum install mysql-devel

5、配置数据库

vim /etc/my.cnf

在配置文件中加入默认字符集:

default-character-set=uft-8

6、启动或关闭

1
2
[root@localhost ~]#service mysqld start      --启动mysql[root@localhost ~]#service mysqld stop       --关闭mysql
[root@localhost ~]#lsof -i:3306 --数据库端口是否开启

7、设置开机启动mysql服务

1
chkconfig --add mysqld

8、创建root管理员

1
mysqladmin -u root password 密码

9、进入mysql设置远程访问

1
2
3
4
//依次执行
mysql -u root -p
use mysql;
UPDATE user SET `Host` = '%' WHERE `User` = 'root' LIMIT 1;

10、在服务器的控制台中防火墙,将数据库端口打开(安全组规则中添加3306端口)

yum安装redis

1、yum install redis

2、yum isntall epel-release

3、启动服务

systemctl start redis

4、查看状态

systemctl status redis

5、停止服务

systemctl stop redis

6、重启服务

systemctl restart redis

7、查看redis进程

ps -ef | grep redis

8、设置开机自启动

systemctl enable redis

9、设置远程连接

进入配置文件

vi /etc/redis.conf

注释bind 127.0.0.1

设置protected-mode no

img

修改密码为111111

img

10、保存并退出编辑重启redis

systemctl restart redis

11、在服务器的控制台的安全组规则,开放redis端口号6379

yum 安装git

1、安装

1
yum install git

2、配置

1
2
3
//设置用户名称和登录邮箱
git config --global user.name '用户名'
git config --global user.email '邮箱'

3、生成密钥,方便拉取远程仓库代码

建议在服务器根目录执行,**cd / ** 可以切换到根目录

1
ssh-keygen -t rsa -C '登录邮箱'

执行之后,不建议输入密码,直接一直Enter跳过

完成后,一般会在**/root/.ssh/文件夹中生成两个文件,大家id-rsa.pub**文件的内容,全部复制,找到github个人账户设置,在ssh key 中的菜单中新增ssh key,将内容粘贴进去即可。

配置Nginx代理

此方案基于Docker容器中的Nginx

1、查看Nginx挂载目录

1
docker inspect nginx | grep Mounts -A 40

image-20211108161137330

Source对应服务器的文件夹,Destination对应nginx_config文件夹

注:如果你看的我博客进行配置的,会看到有五个挂载目录,有两个目录,很重要,其他是配置文件和日志的。

image-20211108162847392

2、在conf.d文件夹加入项目的nginx配置

文件名:xxx.conf(xxx自己随意命名)

详细的解释,请仔细看注释

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
upstream myserver{
#172.17.0.6是项目所在容器的ip地址,8000为项目的端口,请根据实际情况修改;如果项目是在服务器裸奔的,可以直接用127.0.0.1:端口
server 172.17.0.6:8000;
}

server{
#监听的端口
listen 80;
#域名,根据实际情况修改,(没域名,可以直接写成ip地址)
server_name kygl.ruanzhuinfo.com;
client_max_body_size 500m;

access_log /var/log/nginx/host.access.log main;
#后台
location /admin {
#root 后面路径在服务器的路径为:/data/nginx/www/kygl_v2/dist_web
#因为nginx需要代替(代理)你访问文件,nginx是在一个docker容器中和服务器不是在一个环境下,
#所以需要路径改成在容器中的路径,dist_web为前端的打包的文件夹,要保证dist_web中有index.html
root /nginx_config/www/kygl_v2/dist_web/;
try_files $uri $uri/ /index.html?s=$uri&$args;
index index.html index.htm index.php;
}
#前台,如果有前台,可以配置,同上,因为root只能存在一个,所以下面用的alias来配置另一个虚拟目录
#location /front {
# alias /nginx_config/www/kygl_v2/dist_front/;
# try_files $uri $uri/ /index.html?s=$uri&$args;
# index index.html index.htm index.php;
#}

#后端
location /api {
proxy_pass http://myserver;
index index.html index.htm;
}
location /auth {
proxy_pass http://myserver;
index index.html index.htm;
}

#下面是配置访问swagger
location /swagger-ui.html {
proxy_pass http://myserver;
index index.html index.htm;
}

location /webjars {
proxy_pass http://myserver;
index index.html index.htm;
}

location /swagger-resources {
proxy_pass http://myserver;
index index.html index.htm;
}

location /v2 {
proxy_pass http://myserver;
index index.html index.htm;
}
}

3、记得每次修改nginx的相关配置,都需要重新加载下

1
2
3
4
5
6
//进入nginx容器
docker exec -it nginx bash
//测试,看下配置文件是否有问题
nginx -t
//重新加载
nginx -s reload

image-20211108172223927

如果遇到修改配置后,没有生效,请执行下面的命令

1
2
3
nginx -s reopen
nginx -s stop //此命令执行后,会退出容器,重新进入即可
nginx -reload

部署后端(SpringBoot项目)

如果你是把各种服务放到了docker中,请选择方案一;如果你把各种服务安装到了服务器中,请选择方案二

下面的所有步骤将以我的github项目为例

克隆项目

1
git clone https://github.com/zglgithubx/ourchat.git

切换到分支develop

1
git checkout develop

方案一

这个方案用到了一个脚本文件demo.sh,一个Dockerfile文件,说下demo.sh脚本都做了哪些工作:执行Dockerfile文件构建CentoS镜像,在镜像中安装了vim 、git、jdk 、maven—>根据centos镜像启动了一个容器---->在centos容器中拉取项目—>将项目打包成jar包—>启动项目jar包

1、准备文件

下面是脚本文件demo.sh和Dockerfile,部署时请将这两文件放到后端的根目录下

注:如果部署自己的项目需将SERVER_NAME 、JAR_PATH、Root_File_Name参数修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#!/bin/bash

# 镜像名字
IMAGE_NAME=centos7_mvn_git_java8

# docker 容器名字或者jar名字,这里都命名为这个(*必填)
SERVER_NAME=ourchat

#这里的JAR_PATH为jar包所在位置,这路径是jar相对于脚本文件的路径。(*必填)
JAR_PATH=./target/demo-0.0.1-RELEASE.jar

#项目根目录文件夹名称(*必填)
Root_File_Name=ourchat

profile=$2
port=$3
#Xms=$4
#Xmx=$5

#使用说明,用来提示输入参数
usage() {
echo "Usage: sh 执行脚本.sh [init|start|stop|restart|status|pull] [profile] [port]"
exit 1
}

#初始化——构建镜像和容器(在宿主机执行)
init(){
#容器id
CID=$(docker ps | grep "$SERVER_NAME" | awk '{print $1}')
#镜像id
IID=$(docker images | grep "$IMAGE_NAME" | awk '{print $3}')
# 构建docker镜像
if [ -n "$IID" ]; then
echo "Exit $SERVER_NAME image,IID=$IID"
else
echo "NOT exit $SERVER_NAME image,start build image..."
# 根据项目个路径下的Dockerfile文件,构建镜像
docker build -t $IMAGE_NAME .
echo "$SERVER_NAME image has been builded"
fi

if [ -n "$CID" ]; then
echo "Exit $SERVER_NAME container,CID=$CID. ---Remove container"
docker stop $SERVER_NAME # 停止运行中的容器
docker rm $SERVER_NAME ##删除原来的容器
fi

# 构建容器
echo "$SERVER_NAME container,start build..."
# 运行容器
# --name 容器的名字
# -d 容器后台运行
# -p 指定容器映射的端口和主机对应的端口
# -v 将主机的目录挂载到容器的目录中(不可少)
docker run -e TZ="Asia/Shanghai" -id -m 512M --memory-swap=1G --name $SERVER_NAME -v $PWD/../:/project/$Root_File_Name $IMAGE_NAME
echo "$SERVER_NAME container build end"
}

#检查程序是否在运行
is_exist(){
pid=`ps -ef|grep $JAR_PATH|grep -v grep|awk '{print $2}' `
#如果不存在返回1,存在返回0
if [ -z "${pid}" ]; then
return 1
else
return 0
fi
}

#启动方法
start(){
is_exist
if [ $? -eq "0" ]; then
echo "${SERVER_NAME} is already running. pid=${pid} ."
else
echo --------Starting application --------
nohup java -server -XX:-DisableExplicitGC -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -jar $JAR_PATH --spring.profiles.active=${profile:-dev} --server.port=${port:-8000} > start.log 2>&1 &
echo --------------Started!---------------

fi
}

#停止方法
stop(){
is_exist
if [ $? -eq "0" ]; then
kill -9 $pid
echo -----------Application Stopped------------
else
echo "${JAR_PATH} is not running"
fi
}

#输出运行状态
status(){
is_exist
if [ $? -eq "0" ]; then
echo "${JAR_PATH} is running. Pid is ${pid}"
else
echo "${JAR_PATH} is NOT running."
fi
}

#重启
restart(){
stop
start
}

#mvn
pull(){
echo "----------git:find status---------"
git status
echo "----------git:pull new coads---------"
git pull origin develop
if [ $? -ne 0 ]; then
exit
fi
echo "----------mvn clean package -Dmaven.test.skip=true---------"
mvn clean package -Dmaven.test.skip=true
if [ $? -ne 0 ]; then
exit
fi
echo "----------Preparing start application ---------"
is_exist
if [ $? -eq "0" ]; then
restart
else
start
fi
}

#根据输入参数,选择执行对应方法,不输入则执行使用说明
case "$1" in
"init")
init
;;
"start")
start
;;
"stop")
stop
;;
"status")
status
;;
"restart")
restart
;;
"pull")
pull
;;
*)
usage
;;
esac

Dockerfile

1
2
3
4
5
6
7
8
FROM centos:latest
RUN yum -y update \
&& yum -y install vim \
&& yum -y install git \
&& yum -y install java-1.8.0-openjdk-devel.x86_64 \
&& yum install -y maven \
&& mkdir ~/.m2
RUN echo '<?xml version="1.0" encoding="UTF-8"?><settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd"><mirrors><mirror><id>alimaven</id><mirrorOf>central</mirrorOf><name>aliyun maven</name><url>http://maven.aliyun.com/nexus/content/repositories/central/</url></mirror></mirrors></settings>' > ~/.m2/settings.xml

2、初始化、构建镜像

切换到后端项目根目录

1
cd xxxx/ourchat_api/

执行初始化命令

1
sh demo.sh init

image-20211108111350473

完成后,会有成功的提示

image-20211108111147161

3、查看容器是否启动

1
docker ps

image-20211108111526577

status为up 即为启动成功

4、进入容器

1
docker exec -it ourchat bash

image-20211108111634691

5、切换到容器中的项目后端目录

1
cd project/ourchat/ourchat_api/

image-20211108111846333

6、脚本命令介绍

到这一步骤,环境基本都搭建完毕了,下面介绍脚本的命令

上面的初始化命令只需要执行一次,之后代码更新,只需要执行:

1
2
3
注:下面的命令需要用ssh的方式和远程仓库建立连接,即配置centos容器中git,生成ssh key,将id.res_pub文件内容的key添加到github或coding服务器的个人账户中
#拉取新代码,重新打包项目,并重新启动
sh demo.sh pull

下面的命令是脚本的其他命令:

1
2
3
4
5
6
7
8
#查看项目启动状态
sh demo.sh status
#启动项目,后面的参数是选填的,dev:环境,8000:项目端口号
sh demo.sh start dev 8000
#停止项目
sh demo.sh stop
#重新启动项目
sh demo.sh restart

方案二

方案一的好处有很多,项目交付时,服务器可能会发生迁移,新服务器不用再手动安装一些环境,只需要安装docker ,剩下的环境,执行Dockerfile就可以了。

方案二适合在个人服务器部署个人项目,不需要考虑服务器的迁移,可以把所有环境都装到服务器,节省空间

你如果选择了方案二,默认你已经把mysql、redis、及git都已经安装完毕

为了能够启动后端项目,还需要安装maven、jdk

1、安装maven

1
yum install maven

2、安装jdk1.8

1
yum install java-1.8.0-openjdk-devel.x86_64

3、准备脚本文件

其实这文件是根据demo.sh修改的,也是只需要把这个文件放到后端项目的根目录,如果自己使用只需要更改SERVER_NAME、JAR_PATH这两个参数

ourchat.sh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#!/bin/bash

# docker 容器名字或者jar名字,这里都命名为这个
SERVER_NAME=ourchat

#这里的JAR_PATH为jar包所在位置
JAR_PATH=./target/demo-0.0.1-RELEASE.jar

profile=$2
port=$3

#使用说明,用来提示输入参数
usage() {
echo "Usage: sh 执行脚本.sh [build|start|stop|restart|status|pull] [profile] [port]"
exit 1
}
build(){
echo "----------mvn clean package -Dmaven.test.skip=true---------"
mvn clean package -Dmaven.test.skip=true
if [ $? -ne 0 ]; then
exit
fi
echo "----------Preparing start application ---------"
is_exist
if [ $? -eq "0" ]; then
restart
else
start
fi
}

#检查程序是否在运行
is_exist(){
pid=`ps -ef|grep $JAR_PATH|grep -v grep|awk '{print $2}' `
#如果不存在返回1,存在返回0
if [ -z "${pid}" ]; then
return 1
else
return 0
fi
}

#启动方法
start(){
is_exist
if [ $? -eq "0" ]; then
echo "${SERVER_NAME} is already running. pid=${pid} ."
else
echo --------Starting application --------
nohup java -server -Xms512m -Xmx512m -XX:SurvivorRatio=4 -Xss256k -XX:PermSize=256m -XX:MaxPermSize=512m -XX:-DisableExplicitGC -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -jar $JAR_PATH --spring.profiles.active=${profile:-prod} --server.port=${port:-8000}> start.log 2>&1 &
echo --------------Started!---------------
fi
}

#停止方法
stop(){
is_exist
if [ $? -eq "0" ]; then
kill -9 $pid
echo -----------Application Stopped------------
else
echo "${JAR_PATH} is not running"
fi
}

#输出运行状态
status(){
is_exist
if [ $? -eq "0" ]; then
echo "${JAR_PATH} is running. Pid is ${pid}"
else
echo "${JAR_PATH} is NOT running."
fi
}

#重启
restart(){
stop
start
}

#mvn
pull(){
echo "----------git:find status---------"
git status
echo "----------git:pull new coads---------"
git pull origin develop
if [ $? -ne 0 ]; then
exit
fi
echo "----------mvn clean package -Dmaven.test.skip=true---------"
mvn clean package -Dmaven.test.skip=true
if [ $? -ne 0 ]; then
exit
fi
echo "----------Preparing start application ---------"
is_exist
if [ $? -eq "0" ]; then
restart
else
start
fi
}

#根据输入参数,选择执行对应方法,不输入则执行使用说明
case "$1" in
"build")
build
;;
"start")
start
;;
"stop")
stop
;;
"status")
status
;;
"restart")
restart
;;
"pull")
pull
;;
*)
usage
;;
esac

4、在项目后端根目录执行build命令

这个命令会将项目打包并运行

1
sh ourchat.sh build

其他命令同方案一中介绍的命令一样

项目代码更新后,重新部署时,只需要执行

1
sh ourchat.sh pull

部署前端(Vue项目)

前端的部署,不外乎将打包好的dist文件夹上传到服务器,可能有的人直接在服务器安装webpack,然后再安装一系列的前端需要的配置,使用git将项目拉取到服务器,然后在服务器运行打包命令。我感觉前端的部署不应该那么复杂,有人可能要说了,直接把dist包每次在本地打包,然后复制到服务器的指定目录不就好了,这都2021年了,其实也不需要那么步骤。下面我介绍一款前端部署插件,可以用来简化这些步骤。

安装fe-deploy-cli

1
2
//此为全局安装,一次安装受益终身
npm i fe-deloy-cli -g

安装之后,在前端项目根目录打开命令行

执行:

1
deploy init

执行完之后,在项目根目录会生成:deploy文件夹

文件deploy.config.js大概是这样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
module.exports = {
privateKey: '', //(选填) 本地私钥地址,位置一般在C:/Users/xxx/.ssh/id_rsa,非必填,有私钥则配置
passphrase: '', // (选填)本地私钥密码,非必填,有私钥则配置
projectName: 'xxxx', // 项目名称
// 根据需要进行配置,如只需部署prod线上环境,请删除dev测试环境配置,反之亦然,支持多环境部署
dev: { // 开发环境
name: '开发环境',
script: "npm run build", // 测试环境打包脚本
host: 'xxxx', // 测试服务器地址
port: xx, // ssh port,一般默认22
username: 'xxxx', // 登录服务器用户名
password: 'xxxxx', // 登录服务器密码
distPath: 'dist', // 本地打包dist目录
webDir: '/MyProject/docker/nginx/html', // // 测试环境服务器地址
},
prod: { // 线上环境
同上
}
// 再还有多余的环境按照这个格式写即可
}

上面变量都有注释,可以只配置一个环境,只需要把prod的内容删除,如果prod环境你没有配执行时会有报错。

配置完,在项目根目录执行

1
deploy dev //这代表打包开发环境

执行之后,需要你确认下,输入yes就行,执行过程为:打包前端项目–>压缩打包文件–>压缩包上传到指定服务器的文件夹–>解压—>部署成功