问题背景
截至目前做了3个和部署相关的项目了。其中有1个是先连接远程桌面,再进行部署的(因为会有内网权限问题);另外2个是直接本地部署到服务器的。
对于直接本地部署到服务器的项目,需要手动执行以下操作:
- 登录到服务器
- 停止服务器上正在运行的进程
- 删除服务器上旧的部署文件(这里是为了保证上传新的部署文件是不会出现问题)
- 回到本地
- 打包本地项目,生成新的部署文件(比如压缩文件夹或者是构建jar包)
- 将新的部署文件上传至服务器
- 再次登录到服务器
- 根据新的部署文件启动服务
可以看到,还是比较繁琐的,也比较机械。由于项目没有写测试,部署后经常会出现一些问题,所以就需要本地修改再进行部署,这样就会反复执行上述所有操作,比较麻烦。而且如果写的是前端项目,可能会在短期内频繁出现改个字号、调个颜色类似这种很小的改动,那重复执行这些枯燥的操作就更会让人觉得无聊了。
资料调研
程序员嘛,总是想着怎么方便怎么弄。那为了省事,我希望以上部署的流程能够在我修改完代码后自动进行,即自动化部署。我查阅了一些资料,主要有两种方案:
- 通过jenkins实现自动化部署
- 通过脚本实现自动化部署
其中第一种查到的资料比较多,应该算比较主流。但是了解后发现比较麻烦,配置比较复杂、学习成本相对较高,而且我也不需要那么多功能。所以我就采用了第二种方案。
那脚本实现的前提是:这些操作都能用代码实现。很幸运的是,确实都可以:
- 登录到服务器:
ssh
连接服务器 - 停止服务器上正在运行的进程:Linux的
kill
命令 - 删除服务器上旧的部署文件:Linux的
rm
命令 - 回到本地:
exit
退出ssh
会话 - 打包本地项目,生成新的部署文件:
zip
或者mvn package
- 将新的部署文件上传至服务器:
scp
命令 - 再次登录到服务器:
ssh
连接服务器 - 根据新的部署文件启动服务:项目的启动命令
总之,每一步都可以通过一行命令实现。
自动化部署脚本
这里我先贴上代码:
#!/bin/bash
# -------------------------------------------------
### 服务器信息
ip="xxx.xxx.xxx.xxx"
username="xxx"
project_path="xxx"
### 脚本
start_process_script="xxx.sh" # 启动服务的脚本
kill_process_script="xxx.sh" # 关闭服务的脚本
### 部署文件
jar_file="xxx"
### 本地打包后上传到服务器的文件
uploaded_files="xxx"
### 本地电脑私钥路径
private_key_path="xxx"
# -------------------------------------------------
### ssh连接到服务器
### 1. 切换到指定目录
### 2. 运行脚本停止jar包进程
ssh -i ${private_key_path} ${username}@${ip} << EOF
echo "成功连接到服务器."
cd ${project_path} # 切换到项目的目录
bash ${kill_process_script} # 执行杀死进程的脚本
# 删除旧的部署文件
if [ -f "${jar_file}" ]; then
rm -rf ${jar_file}
fi
# 断开服务器连接
exit
echo "连接已断开."
EOF
# -------------------------------------------------
### 本地打包jar包
mvn clean package
echo "打包完成."
### 将打包的文件上传到服务器
scp -i ${private_key_path} ${uploaded_files} ${username}@${ip}:${project_path}
echo "文件上传成功."
# -------------------------------------------------
### ssh连接到服务器
### 1. 切换到指定目录
### 2. 启动新的jar包进程
ssh -i ${private_key_path} ${username}@${ip} << EOF
echo "成功连接到服务器."
cd ${project_path} # 切换到项目目录
bash ${start_process_script} # 通过脚本启动进程
# 断开服务器连接
exit
echo "连接已断开."
EOF
echo "自动化部署完成."
这段代码复制改一改应该就能直接用。这里有几个特别说明的部分:
ssh
命令后面要写<< EOF
,最后要写EOF
,这样才能让这段代码在服务器端执行,而不是在本地执行- 为了避免每次
ssh
都要输入密码,这里把本机的公钥上传到服务器了,同时在使用ssh
和scp
命令时指定了私钥路径 - 这个脚本比较繁琐,主要是涉及到了3次
ssh
会话连接:第一次ssh
、第二次scp
(底层是ssh
)、第三次ssh
。暂时先没有进行优化,毕竟功能优先
接下来要解决的需求是:如何在我本地修改完代码后自动执行这个脚本?
由于我用了Git管理项目,之前又看到过别人有这样的操作:执行git push
之后服务器就自动进行了更新。所以问了一下ChatGPT这是什么操作,最后了解到Githooks
可以实现这个功能。
Githooks是什么?
先来看一段介绍(来自:https://githooks.com/):
What are Git Hooks?
Git Hooks are scripts that Git can execute automatically when certain events occur, such as before or after a commit, push, or merge. There are several types of Git Hooks, each with a specific purpose. Pre-commit hooks, for example, can be used to enforce code formatting or run tests before a commit is made. Pre-push hooks can be used to prevent pushes to certain branches or run additional tests before pushing. Post-merge hooks can be used to perform actions after a merge is completed, such as updating dependencies or generating documentation.
These hook scripts are only limited by a developer’s imagination. Some example hook scripts include:
- pre-commit: Check the commit message for spelling errors.
- pre-receive: Enforce project coding standards.
- post-commit: Email/SMS team members of a new commit.
- post-receive: Push the code to production.
简单来说,就是一些能够在某些特定Git操作发生之前或者之后自动执行的脚本。那这正好满足我的需求。于是我就把脚本写在了post-commit
文件里。这样每次git commit
后,部署流程就会自动化进行。
Githooks配置
Githooks
的所有脚本默认是在项目根目录下的.git/hooks
路径里的。可以通过命令git config core.hooksPath <特定路径>
修改路径。
总结
本文实现的方案是基于Git
的,即项目要先用Git
管理起来,然后编写Githooks
脚本实现自动化部署。实现完了之后,体验还是非常棒的。每次git commit
后都自动部署到服务器,也不需要输入密码。
方案需要准备的环境:
- 能够运行
shell
脚本的环境:git-bash
或者wsl
- 利用
git
管理项目(其实不用这个也可以,直接手动运行shell
脚本也能完成部署)
学到的知识点:
Githooks
脚本:一些能够在某些特定Git操作发生之前或者之后自动执行的脚本ssh
免密登录:本地生成公钥,并将文件内容复制到服务器的/root/.ssh/authorized_keys
文件中shell
脚本的一些语法