最近在开发自己的博客系统,每次迭代完一次代码就要重新手动部署一次,有时候部署后才发现一些bug,又要回过头来重新部署,十分的麻烦。自己的项目托管在github上,因此想实现每次push完代码到master分支上后,github可以自动的帮我进行部署这一步骤,这样就可以避免频繁的手动部署。
0 我的博客
线上地址:wk-blog
github 地址:项目 github
项目简介:项目采用的是前后端分离的模式,前端的主要技术框架是 Vue3,后端使用的是 express
博客预览:
1 Github Actions 简介
参考文章:
在我们前端常规的开发流程中,每次向远程分支推送完本次代码后,接下来进行的就是打包生成静态资源,再推送至服务器。这些步骤的特点就是在不同的项目中是类似的,且需要反复重复这些步骤。有没有一种方法可以在每次push完代码后,自动的去执行这些重复的动作呢?Giuthub Actions 就很好的解决了这一个问题。
GitHub Actions 是 GitHub 推出的一款持续集成(CI/CD)服务,它给我们提供了虚拟的服务器资源,让我们可以基于它完成自动化测试、集成、部署等操作,Github 把这些操作称作 actions。如果我们需要在push完代码后执行某一个action,我们可以直接引用他人写好的 action 即可。
官方文档传送门:Github Actions
1.1 基本概念
workflow (工作流程):持续集成一次运行的过程,就是一个 workflow。
- name:工作流程的名称
- on:触发工作流程的事件名称
job (任务):一个 workflow 由一个或多个 jobs 构成,含义是一次持续集成的运行,可以完成多个任务。
-
runs-on:任务运行的虚拟环境
# 目前可用的环境 Windows Server 2019 windows-latest 或 windows-2019 Ubuntu 20.04 ubuntu-20.04 Ubuntu 18.04 ubuntu-latest 或 ubuntu-18.04 Ubuntu 16.04 ubuntu-16.04 macOS Catalina 10.15 macos-latest 或 macos-10.15 # 使用 runs-on: ubuntu-latest
step(步骤):每个 job 由多个 step 构成,一步步完成。
- name:步骤名称
- run:该步骤的命令或 action
- env:所需要的环境变量
- uses:选择任务步骤中一部分运行的操作。其实就是步骤使用的
actions
,可以是一个或多个
action (动作):每个 step 可以依次执行一个或多个命令(action)。因为很多操作在不同项目中都是类似的,所以 GitHub 把 action 设计为一个独立的脚本文件,可以存放到代码仓库里,让其他开发者使用。所以在实际的使用中,可以直接使用别人写好的 action 而不必所有的都自己写。GitHub也为此做了一个marketplace,这里就是action的官方市场。
2 Github Actions 小实验
实验代码:CI-CD
本次实验的目的是实现 vue 项目的自动化部署。当我们本地开发完项目向远程分支推送代码时,GitHub会帮我们自动构建,生成静态资源,并部署到远程服务器上。
实验大致分以下几个步骤:
- 准备好服务环境
- 创建 github 项目并创建 workflow
- 拉取 github 仓库,并新建一个 vue 项目,本地 push 代码
- 查看自动化部署是否完成
step1 服务环境准备
这里我使用的是阿里云的轻量服务器,服务器使用的操作系统是 ubuntu-20.04。
这里你可以使用自己的服务器,安装的操作系统自己也要记住,因为在后面我们会使用到。我们进入自己的服务器,并使用 Linux 命令创建好存放静态资源的文件夹,你可以选择自己常用的文件夹,但是需要记住这个路径,后面会使用到。
// 这个文件夹是我部署项目的地方,你可以选择自己常用的文件夹,但是需要记住这个路径,后面会使用到
cd /www
sudo mkdir actionTest
step2 创建 github 项目
在 github 上新建一个项目,这很 easy,不多赘述。
因为需要连接远程服务器,在创建 workflow 之前,我们需要创建一些需要使用的暗号。这个暗号就是一个变量名,然后它的值只有你和 Github 知道是什么,在需要使用的地方使用这个变量名,Github便能领会到这是一个私密的信息,并在执行流程时使用它真正的值去代替变量名。
按照上面的顺序我们便可以创建暗号了。我们以此建立三个暗号,他们的变量名分别是:
- DR_HOST:你的服务器IP地址
- DR_USER:你的服务器账号,一般是 root
- DR_PASS:你的 SSH 登录密码
准备好上面的内容我们就可以创建一个 workflow 了
最后我们能看到如下的界面:
我们将里面的代码删除,并换成下面的代码
name: build
on:
push:
branches:
- main # 这里表示push到main分支就会触发流程
jobs:
build-and-deploy:
runs-on: ubuntu-20.04
steps:
# 这是github官方的一个action,用于clone该仓库的源码到工作流中,
- name: Checkout 🛎️
uses: actions/checkout@v2
with:
persist-credentials: false
- name: Build
run: |
cd my-project # 进入项目目录
npm install # 安装依赖
npm run build # 执行打包
# 连接到ssh,并且做一个拷贝操作的action
- name: Deploy 🚀
uses: cross-the-world/scp-pipeline@master
env:
WELCOME: "ssh scp ssh pipelines"
LASTSSH: "Doing something after copying"
with:
host: ${{ secrets.DR_HOST }}
user: ${{ secrets.DR_USER }}
pass: ${{ secrets.DR_PASS }}
connect_timeout: 10s
local: './my-project/dist/*' # 这里是下一步要创建的vue项目构建完成后的静态资源路径
remote: /www/actionTest # 这里是 step1 中,在服务器上创建用于存放静态资源的文件夹
最后我们提交这部分代码,这里相当于在github仓库创建了一个 /.github/workflows/build.yml
的文件
这里我们相当于提交了一次代码到 main 分支上,因此会执行流程,但因为我们还没有创建 vue 项目,因此流程不会执行成功。我们接着进行下一步。
step3 本地开发
Vue脚手架官网传送地址:Vue CLI
接着我们拉取远程分支的代码,并使用 vue-cli 创建一个 vue 项目,最后再提交代码到 main 分支上。
step4 验证实验结果
在 github 中的 action 中可以查看到工作流程正常执行
点进去也可以看到核心的 build 和 deploy 也正常执行了
-
正常构建
-
正常部署
我们再上服务器进行验证,可以发现 vue 项目打包后的 dist 中的内容正常部署到了我们服务器的目标文件夹中
3 博客项目部署踩坑日记
在开头已经介绍过我的博客项目,前端使用的是 vue3,具体的部署和上述实验差不多。但是中间在执行 npm install 时遇到了问题,最后通过指定 node 版本解决了问题。代码如下:
name: frontend-build
on:
push:
branches:
- main
jobs:
build-and-deploy:
runs-on: ubuntu-20.04
steps:
- name: Checkout 🛎️
uses: actions/checkout@v2
with:
persist-credentials: false
# 指定 node 版本
- uses: actions/setup-node@v2
with:
node-version: '14'
- name: Build
run: |
cd blog-frontend # 进入项目目录
npm install # 安装依赖
npm run build # 执行打包
- name: Deploy 🚀
uses: cross-the-world/scp-pipeline@master
env:
WELCOME: "ssh scp ssh pipelines"
LASTSSH: "Doing something after copying"
with:
host: ${{ secrets.DR_HOST }}
user: ${{ secrets.DR_USER }}
pass: ${{ secrets.DR_PASS }}
connect_timeout: 10s
local: './blog-frontend/dist/*'
remote: /www/wk-blog/dist
last_ssh: |
nginx -s reload # 部署成功后需要重启nginx
后端代码使用的是 express,服务器上使用 pm2 开启项目。因为数据库中的博客信息是通过 js 脚本解析的,因此最后还需要执行脚本重新解析所有的博客文件,当上传新的博客时会更新数据库中的信息。
name: backend-build
on:
push:
branches:
- main
jobs:
backend:
runs-on: ubuntu-20.04
steps:
- name: Checkout 🛎️
uses: actions/checkout@v2
with:
persist-credentials: false
- uses: actions/setup-node@v2
with:
node-version: '14'
- name: Deploy 🚀
uses: cross-the-world/scp-pipeline@master
env:
WELCOME: "ssh scp ssh pipelines"
LASTSSH: "Doing something after copying"
with:
host: ${{ secrets.DR_HOST }}
user: ${{ secrets.DR_USER }}
pass: ${{ secrets.DR_PASS }}
connect_timeout: 10s
local: './express-backend/*'
remote: /www/wk-blog/backend
- name: ssh pipelines - npm install
uses: cross-the-world/ssh-pipeline@master
env:
WELCOME: "ssh pipeline"
with:
host: ${{ secrets.DR_HOST }}
user: ${{ secrets.DR_USER }}
pass: ${{ secrets.DR_PASS }}
connect_timeout: 10s
script: |
cd /www/wk-blog/backend
npm install
- name: ssh pipelines - read blogs
uses: cross-the-world/ssh-pipeline@master
env:
WELCOME: "ssh pipeline"
with:
host: ${{ secrets.DR_HOST }}
user: ${{ secrets.DR_USER }}
pass: ${{ secrets.DR_PASS }}
connect_timeout: 10s
script: |
cd /www/wk-blog/backend
node parse.js
- name: ssh pipelines - restart www
uses: cross-the-world/ssh-pipeline@master
env:
WELCOME: "ssh pipeline"
with:
host: ${{ secrets.DR_HOST }}
user: ${{ secrets.DR_USER }}
pass: ${{ secrets.DR_PASS }}
connect_timeout: 10s
script: |
cd bin
pm2 restart www