-
Notifications
You must be signed in to change notification settings - Fork 183
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Vue SSR 持续集成部署(CI/CD):Travis + PM2 自动化部署 Node 应用 #104
Comments
一、前言在部署纯前端应用时,只要想办法把打包后的静态资源放到服务器就行,至于在本地还是线上服务器打包,那也只是选择的问题 而做服务端渲染时,涉及到Node服务器的部署,不仅仅是静态资源的构建与搬运,有小伙伴说可以每次更新完代码后上服务器手动重启Node服务器,但这可不符合程序员的懒学,而且手动操作得多就一定有误操作的风险 有道说懒是第一生产力,今天我们来个懒到极致的想法:只需要git push代码到远程分支,后续的构建、测试、自动部署、自动重启Node服务等工作全部自动化,变成一条自动生产线,其实就是常说的持续集成(Continuous Integration)与持续部署(Continuous Deployment) 二、基于Travis+PM2的 CI & CD 核心流程本文将会沿着这个图展开,就算现在不理解也没事,等实践完再回来看就那么简单一回事 首先本地要有一个基础服务端渲染的项目,我这里是用Vue + Koa 对着Vue服务端渲染官方文档搭的,客户端和服务端的构建配置都可以直接跑,然后是推上Github,用github账号登录 https://travis-ci.com,并激活仓库,Travis监听仓库文件改动,有更新时根据我们配置的 这里面比较核心的一个问题,是解决Github、Travis服务器、远程服务器之间的账号信任问题,本质上都是利用了SSH 总结起来,我们要解决的事情主要有这么几项 三、Linux服务器初始化从购买到初始化,俺手把手的准备好了 买了☁️服务器后,第一步要干啥。。。? 四、基础 Node SSR 应用我准备好了 一个Vue服务器渲染的demovue-ssr,克隆该项目的 至于vue服务端渲染的实现,可以看官方文档,或者这篇 ,这里就略过了,本文以CI/CD为核心 执行下面命令项目就能跑了 git clone git@github.com:amandakelake/vue-ssr.git
# 切换到ssr分支
cd vue-ssr && git checkout ssr
# 安装依赖,构建客户端和服务端静态资源
yarn && yarn build
# 启动 Node 服务
yarn start 然后直接访问 没问题后,在自己的github上创建一个仓库,关联推上去吧,后面要用了 五、使用Travis CI5.1 Travis解决了什么问题?当我们上传最新代码奥github后,我希望有一个工具能够自动拉取最新代码,然后按照我们的预设任务自动执行,然后自动发布到我们的个人服务器上,这个工具就是 Travis CI
5.2 使用Travis要解决的核心问题Travis需要权限来帮我们把静态资源复制到个人部署服务器上,或者登陆服务器进行操作,但travis不提供交互终端输入账号密码什么的,所以需要使用SSH免密登录服务器,这样才是自动化 5.3 SSH免密登录原理SSH的免密登录原理也比较简单:在客户端(这里的客户端可以是任何机子)生成一对公私钥,将公钥存到服务器 5.4 Travis如何解决SSH的私钥安全性问题本质上让travis装成一个客户端去连接我们的个人服务器,但是这个私钥保存在哪呢? 所以在这个地方,我们可以举一反三的解决上面一个问题:基于SSH解决本机、Github、Travis服务器、远程服务器的信任通信 在本机生成一份SSH公私钥,然后把公钥 5.5 激活Travis监听github仓库用github账号登录 travis-ci.com , 会看到你的所有仓库,然后点开开关(界面交互,一眼就会) 然后在项目中新建 language: node_js
node_js:
- stable
branchs:
only:
- master
cache:
directories:
- node_modules
before_install:
install:
- yarn install
scripts:
- yarn build
after_success: 搞完这两步,然后你推送一个代码更新上去看看,应该能在travis官网看到执行了 就是这么简单,我们推送代码,travis自动执行任务 接下来我们要解决SSH免密登录的问题,先在本机安装travis来搞 5.6 本机安装Travis
# 先安装rvm(rvm与ruby的关系,就跟nvm与node的关系一样)
curl -sSL https://get.rvm.io | bash -s stable
# 安装完需要启动rvm,具体路径在上面的输出结果中有
source /Users/lgc/.rvm/scripts/rvm
# 看一下rvm的版本,输出数字代表成功
rvm --version
# 用rvm安装ruby 这一步我自己等了15分钟~
rvm install ruby
# 安装完看下ruby版本 有数字代表成功
ruby --version
# 有了ruby,就可以用gem安装travis了
# 但gem的官方镜像可能被墙了,先换下镜像源,自带梯子的同学可以忽略
# 添加中国镜像源 删除原来的官方镜像源
gem sources --add https://gems.ruby-china.org/ --remove https://rubygems.org/
# 看下是不是切换到中国的镜像源了
gem sources -l
# 安装travis
gem install travis
# 安装完检测一下 有输出代表成功
travis
# 先进入项目目录,然后用github账号密码登录travis
travis login 5.7 Travis配置SSH免密登录一般来说,我们开发同学本地已经有一份私钥 ssh-keygen -t rsa -C "你的邮箱"
# 在询问路径时可以修改文件名,如下图,如果不需要一直回车就可以了,默认名是id_rsa #登陆成功后用travis加密本地私钥,--add参数会把加密的私钥解密命令插入到.travis.yml,Travis解密时要用到的
travis encrypt-file ~/.ssh/id_rsa_travis --add
# 成功后项目根目录下会多出一个文件 id_rsa.enc
# 然后.travis.yml文件内会被自动插入下面两行内容,是用来自动解密用的
# - openssl aes-256-cbc -K $encrypted_574f1c23860c_key -iv $encrypted_574f1c23860c_iv
# -in id_rsa_travis.enc -out ~/.ssh/id_rsa_travis -d
# 然后添加信任关系 向个人服务器添加公钥
# 添加成功后 所有使用该公钥对应的私钥访问服务器都会直接认证通过
ssh-copy-id -i ~/.ssh/id_rsa_travis.pub [服务器用户]@[服务器IP] 加密私钥时的输出如上图,要狠认真的读一下 解释一下这两行的意思,首先travis执行任务时会先把我们的代码拉到travis自己的服务器上 这里有个坑,官方工具的bug(不知道同学们现在看的时候修复了没),上面生成的命令的 另外, travis上面的私钥权限,就算已经加密过了,也不能给其他组的用户读写,得搞个700和600权限(linux的权限设置可以看下这个Linux 文件权限 · Issue #103 · amandakelake/blog · GitHub),否则travis本身的任务也不能通过 before_install:
- openssl aes-256-cbc -K $encrypted_574f1c23860c_key -iv $encrypted_574f1c23860c_iv
-in id_rsa_travis.enc -out ~/.ssh/id_rsa -d
- chmod 700 ~/.ssh/
- chmod 600 ~/.ssh/id_rsa travis的配置暂时告一段落,我们先把后面的构建和PM2部署等流程搞完,再回来添加 六、使用PM2管理Node应用PM2的基本使用此处也不多讲了,直接看如何用PM2部署Node应用,参考PM2 - Deployment # 全局安装pm2 如果已安装可以直接忽略
yarn global add pm2
# 项目根目录新建 pm2 配置文件
touch ecosystem.config.js 先把下面的配置写上,重要的注释都在里面 module.exports = {
apps: [
{
name: 'vue-ssr',
script: './server/server.js',
watch: [
// 监控变化的目录,一旦变化,自动重启
'src',
'server',
'config',
],
ignore_watch: [
// 忽视这些目录的变化
'node_modules',
'dist',
],
error_file: './logs/err.log',
out_file: './logs/out.log',
log_date_format: 'YYYY-MM-DD HH:mm:ss',
},
],
deploy: {
production: {
// 服务器用户名(我这里偷懒用了root,权限太高了,应该新建一个用户的,别学我)
user: 'root',
// 服务器IP地址
host: '45.32.33.18',
// 要拉取的git分支
ref: 'origin/master',
// git仓库地址
repo: 'https://github.com/amandakelake/vue-ssr',
// 拉取到服务器的哪个目录下
path: '/root/projects/vue-ssr',
// 自动将 github 加入远程服务器的信任列表
ssh_options: 'StrictHostKeyChecking=no',
'pre-deploy-local': '',
// 部署前执行
'pre-deploy': 'git fetch --all',
// 部署后执行 自动重启
'post-deploy': 'yarn --ignore-engines && pm2 reload ecosystem.config.js --env production',
'pre-setup': '',
env: {
NODE_ENV: 'production',
},
},
},
};
在首次部署时,我们需要先初始化远程服务器项目,这一步会在远程服务器创建项目 # 在本机执行即可,因为本机跟远程服务器之间也有SSH关系
pm2 deploy ecosystem.config.js prod setup 然后执行部署 pm2 deploy ecosystem.config.js production 后面PM2的配置文件 pm2 deploy ecosystem.config.js production update 这几步在本机或者travis服务器执行都行,反正都有SSH的免密登录,都是为了让远程个人服务器自动重启Node应用 其实除了setup,后面的两步可以都集成到travis的配置中去,完成一个真正的CD流程,完全不需要手动处理 七、 Travis + PM2 持续部署给 after_success:
# StrictHostKeyChecking=no 必传
# 将前端构建好的静态资源目录 dist 整个复制到远程服务器上
# -i ~/.ssh/id_rsa 要指定使用哪份私钥 默认的是id_rsa
- scp -o stricthostkeychecking=no -i ~/.ssh/id_rsa -r ./dist root@45.32.33.18:/root/projects/vue-ssr/source
# 通知PM2执行更新
- yarn global add pm2 && pm2 deploy ecosystem.config.js production update 注意 所以我们要把构建输出目录 所以到目前为止,我们两份核心的配置文件如下 Travis的配置文件 language: node_js
node_js:
- stable
branchs:
only:
- master
cache:
directories:
- node_modules
before_install:
- openssl aes-256-cbc -K $encrypted_64c70e4da8b9_key -iv $encrypted_64c70e4da8b9_iv
-in id_rsa.enc -out ~/.ssh/id_rsa -d
- chmod 700 ~/.ssh/
- chmod 600 ~/.ssh/id_rsa
install:
- yarn install
scripts:
- yarn build
after_success:
# StrictHostKeyChecking=no 必传
# 将前端构建好的静态资源目录 dist 整个复制到远程服务器上
# -i ~/.ssh/id_rsa 要指定使用哪份私钥 默认的是id_rsa
- scp -o stricthostkeychecking=no -i ~/.ssh/id_rsa -r ./dist root@45.32.33.18:/root/projects/vue-ssr/source
# 通知PM2执行更新
- yarn global add pm2@latest && pm2 deploy ecosystem.config.js production update PM2的配置文件 module.exports = {
apps: [
{
name: 'ssr',
script: './server/server.js',
watch: [
// 监控变化的目录,一旦变化,自动重启
'src',
'server',
'config',
],
ignore_watch: [
// 忽视这些目录的变化
'node_modules',
'dist',
],
exec_mode: 'cluster_mode',
error_file: './logs/err.log',
out_file: './logs/out.log',
log_date_format: 'YYYY-MM-DD HH:mm:ss',
env_production: {
NODE_ENV: 'production',
},
},
],
deploy: {
production: {
// 服务器用户名
user: 'root',
// 服务器IP地址
host: '45.32.33.18',
// 要拉取的git分支
ref: 'origin/master',
// git仓库地址
repo: 'https://github.com/amandakelake/vue-ssr',
// 拉取到服务器的哪个目录下
path: '/root/projects/vue-ssr',
// 自动将 github 加入远程服务器的信任列表
ssh_options: 'StrictHostKeyChecking=no',
'pre-deploy-local': '',
// 部署前执行
'pre-deploy': 'git fetch --all',
// 部署后执行 自动重启
'post-deploy': 'yarn --ignore-engines && pm2 reload ecosystem.config.js --env production',
'pre-setup': '',
env: {
NODE_ENV: 'production',
},
},
},
}; 八、Nginx配置反向代理这一步其实就是把服务反向代理到Node服务对应的端口去 # 端口要跟node服务启动的端口一致
upstream {
server 127.0.0.1:[端口];
}
server {
# 省略其他配置
location / {
proxy_pass http://ssr;
}
} 我这里是直接把服务端渲染应用给打到根目录了,如果想通过二级路径来区分不同应用,比如分配到二级路径 server {
# 省略其他配置 以/ssr作为二级路径 暂时会找不到资源
location /ssr {
proxy_pass http://ssr;
}
} 以上配置好后,比如我的 https://luogc.dev/bar 就可以看到直出的效果了,之后我只需要更新代码推送上github,后面的流程都是自动化完成的 九、小结
整套流程走下来,其实涉及到前端写代码的内容不多(Vue SSR相关的可以在另一篇额外学习),但涉及到的实操知识却不少:Linux基本操作、Node基础了解、SSH、CI/CD、travis、PM2 我不能保证你对着我的步骤做就一定顺风顺水,而且极有可能在实操过程中踩各种各样的坑,会遇到陌生的领域,不过只要你能坚持查漏补缺,不懂就学,踩坑就查,慢慢总结,最后一定能跑完整个流程,对建立体系化的知识结构有帮助,反正我也是这么而且正在走着这条路,跟同学一起共勉吧,加油。 |
建议上docker。最开始我博客的ci是docker+jenkins+阿里云镜像服务,现在都自建了。docker + harbor +drone +traefik。吐槽一句国内用travis真的太慢了 |
No description provided.
The text was updated successfully, but these errors were encountered: