使用 JS 开发 Github Actions 实现自动部署前后台项目到自己服务器
不想看前面这么多废话的可以直接跳到具体实现
Github Actions 是什么?
说到 Github Actions 不得不提一下。
- 持续集成(continuous integration):高质量的让产品快速迭代
- 持续交付(continuous delivery):交付给团队测试
- 持续部署(continuous deployment):持续交付的下一步核心概念团队测试完成后自动部署到生产环境
CI/CD 是由很多操作组成的(如:执行单元测试、语法检查、打包、部署等等)。Github 把这些操作称为action,不同的项目很多的操作都是类似,Github 把这些操作整合成了一个市场允许大家发布或使用别人写好的action。
Github Actions 的核心概念
操作(Action)
action是工作流中最小的可移植模块- 可以创建属于自己的
action,使用 Github 社区提供的action以及自定义公开的action - 在工作流中使用需要将其作为
steps包含 - 使用是 用户名/仓储名/版本(或分支) 如:
actions/checkout@master
事件(Event)
- 触发工作流运行的特定事件
- Github 本身事件
提交、创建问题、PR等 - 使用 webhook 配置发生在外部的事件
GitHub-hosted runner
| 虚拟主机环境 | YAML 工作流标签 |
|---|---|
| Windows Server 2019 | windows-latest or windows-2019 |
| Ubuntu 20.04 | ubuntu-20.04 |
| Ubuntu 18.04 | ubuntu-latest or ubuntu-18.04 |
| Ubuntu 16.04 | ubuntu-16.04 |
| macOS Catalina 10.15 | macos-latest or macos-10.15 |
作业(Job)
- 在同一个运行程序上执行的一组步骤。
- 可以为作业在工作流文件中的运行方式定义依赖关系规则。
- 作业可以同时并行运行,也可以按顺序运行,具体取决于前一个作业的状态。例如,一个工作流可以有两个连续的作业来生成和测试代码,其中测试作业取决于生成作业的状态。如果生成作业失败,测试作业将不会运行。
- 对于 GitHub 托管的运行程序,工作流中的每个作业都在虚拟环境的新实例中运行。
步骤(Step)
- 步骤是可以运行命令或操作的单个任务。
- 一个作业可配置一个或多个步骤。
- 作业中的每个步骤都在同一个运行器上执行,从而允许该作业中的操作使用文件系统共享信息。
工作流(Workflow)
- 可配置的自动化过程。测试、打包、发布或部署等等。
- 工作流由一个或多个作业组成,可以通过事件计划或激活。
工作流配置文件(Workflow file)
- 所有需要执行的工作流都必须放在 GitHub 存储库的根目录下的
.gitHub/workflows目录中。 - 需要使用
YAML文件配置并以.yml后缀结尾
我为什么要使用 Github Actions
在没有使用 Github Actions 我部署程序是这样的。
如何使用?
使用 Github Actions 后。
为什么要自己写一个 Github Actions
- 出来很久一直在用有点好奇是怎么处理的
- 网上找了一些各种测试不成功(其实这才是主要原因哈哈)
开始动手了
目录结构
shh-deploy
|—— dist(编译后的目录可用直接运行)
| |—— index.js
|—— lib(TS输出文件)
|—— src(源码文件)
| |—— main.ts
| |—— sftp.ts
| |—— ssh-deploy.ts
| action.yml(Github Actions的配置文件)
| tsconfig.json(TS配置文件)
思考?
我们既然要实现自动部署。
- 需要连接到服务器
ip、port、username、password - 需要哪些文件(
source) - 部署到服务器哪个目录下(
target) - 文件复制完后需要执行安装依赖重启服务等等之内的工作(
after command)
知道我们需要什么后,接下来就来看具体实现。
Github Actions 具体实现
# action.yml 配置文件
name: 'SSH Auto Deploy' # 名称
description: 'ssh auto deploy' # 描述
author: 'hengkx' # 作者
branding:
icon: 'crosshair' # 使用的是Feather的图标
color: 'gray-dark' # 图标颜色
inputs: # 输入参数
HOST: # 服务器地址
description: 'remote host' # 参数描述
required: true # 是否必填
USERNAME: # 用户名
description: 'username'
required: true
PASSWORD: # 密码
description: 'password'
required: true
PORT: # 端口
description: 'port'
default: 22 # 默认值
SOURCE: # 源目录
description: 'local path'
required: true
TARGET: # 目标目录
description: 'remote target'
required: true
AFTER_COMMAND: # 文件上传文成后执行
description: 'upload success execute command'
runs: # 运行环境
using: 'node12'
main: 'dist/index.js' # 所执行的文件
有一点需要注意我们所提交的代码包含node_modules或者使用@zeit/ncc直接打包成可执行文件
// main.ts
import * as core from '@actions/core';
import { Client } from 'ssh2';
import Sftp from './sftp';
function exec(conn: Client, command: string) {
return new Promise((resolve, reject) => {
conn.exec(command, (err, stream) => {
if (err) return reject(err);
stream
.on('close', function (code) {
resolve(code);
})
.on('data', function (data) {
core.info(data.toString());
})
.stderr.on('data', function (data) {
core.error(data.toString());
});
});
});
}
export async function run() {
try {
const host = core.getInput('HOST'); // 使用这个方法来获取我们在action.yml配置文件中设置的输入参数
const port = parseInt(core.getInput('PORT'));
const username = core.getInput('USERNAME');
const password = core.getInput('PASSWORD');
const src = core.getInput('SOURCE');
const dst = core.getInput('TARGET');
const afterCommand = core.getInput('AFTER_COMMAND');
// 下面为ssh链接服务器上传文件并执行命令
const conn = new Client();
conn.on('ready', async () => {
const sftp = new Sftp(conn);
core.info('begin upload');
await sftp.uploadDir(src, dst);
core.info('end upload');
let code: any = 0;
if (afterCommand) {
core.info('begin execute command'); // 输出一条日志
code = await exec(conn, `cd ${dst} && ${afterCommand}`);
core.info('end execute command');
}
conn.end();
if (code === 1) {
core.setFailed(`command execute failed`); // 告诉Github Actions执行失败了
}
});
conn.connect({ host, port, username, password });
} catch (error) {
core.setFailed(error.message);
}
}
我的项目配置文件
name: Deploy
on: # 在master分支上提交代码执行
push:
branches: [master]
jobs: # 作业
build-and-deploy: # 作业名称
runs-on: ubuntu-latest # 运行的环境
steps: #步骤
- name: Checkout # 步骤名
uses: actions/checkout@master # 所使用的action
- name: Setup Node.js environment
uses: actions/setup-node@v2.1.0
with:
node-version: '12.x'
- name: Build Project
run: yarn && yarn run ci
- name: Deploy to Server
uses: hengkx/ssh-deploy@v1.0.1
with: # 以下为参数
USERNAME: ${{ secrets.DEPLOY_USER }} # 为了用户信息安全对敏感数据可以在secrets中配置请看下图
PASSWORD: ${{ secrets.DEPLOY_PASSWORD }}
HOST: ${{ secrets.DEPLOY_HOST }}
SOURCE: 'dist'
TARGET: '/root/task-market/api'
AFTER_COMMAND: 'npm run stop && npm install --production && npm run start'
参考链接
使用 JS 开发 Github Actions 实现自动部署前后台项目到自己服务器的更多相关文章
- 使用GitHub Actions实现自动化部署
前言 大家在工作中想必都是通过自动化部署来进行前端项目的部署的,也就是我们在开发完某个需求时,我们只需要将代码推送到某个分支,然后就能自动完成部署,我们一般不用关心项目是如何build以及如何depl ...
- Jenkins自动部署Tomcat项目
Jenkins自动部署Tomcat项目 1.安装jenkins 插件 启动Jenkins,进入系统管理-插件管理: 选择Deploy to container Plugin 插件安装:
- mac下配置Node.js开发环境、express安装、创建项目
mac下配置Node.js开发环境.express安装.创建项目 一.node.js的安装 去官网下载对应的平台版本就可以了,https://nodejs.org 二.express安装 sudo n ...
- jenkins自动部署代码到多台服务器
下面讲一下如何通过一台jenkins服务器构建后将代码分发到其他的远程服务器,即jenkins自动部署代码到多台服务器. 1.下载 pulish over ssh 插件 2.系统管理 -> 系统 ...
- 自动部署Springboot项目脚本小脚本
#!/bin/bash echo '自动部署Springboot项目脚本...' # aaa.jar 项目jar包 pid=`ps -ef|grep aaa.jar|grep -v grep|grep ...
- 使用electron开发桌面级小程序自动部署系统
那一天我二十一岁,在我一生的黄金时代,我有好多奢望.我想爱,想吃,还想在一瞬间变成天上半明半暗的云,后来我才知道,生活就是个缓慢受锤的过程,人一天天老下去,奢望也一天天消逝,最后变得像挨了锤的牛一样. ...
- 简进祥-SVN版本控制方案:多分支并行开发,多环境自动部署
两地同时开发一个产品,目前线上有3个环境:测试环境.预发布环境.生产环境.目前系统部署采用jenkins自动化部署工具 用jenkins部署的方案 jenkins 测试环境:配置了各个分支的svn 地 ...
- svn版本控制方案:多分支并行开发,多环境自动部署
背景 keywords:svn,trunk,branch,jenkins,maven,merge 两地同时开发一个产品,目前线上有3个环境:测试环境.预发布环境.生产环境.目前系统部署采用jenkin ...
- Gitlab-runner+Docker自动部署SpringBoot项目
本文基于Gitlab CI/CD及Docker快速实现项目的自动部署. 注意:本文较长,浏览需要12分钟左右. 1.环境要求 以下服务器的操作系统均为Centos7 服务器A:Gitlab 服务器B: ...
随机推荐
- 用字典优化过长的if 语句
如果代码中,if 语句,后面elif 过多,完全可以用字典来优化代码. def response(method): if method == "POST": return &quo ...
- Python中的字段分割
很多时候我们要完成分词的任务,这篇文章讲的非常非常好.生动形象,原文是https://www.cnblogs.com/douzi2/p/5579651.html,作者是宋桓公.
- 也来聊聊 HTTPS.
前言: 网上聊 HTTPS 的文章已经数都数不过来了吧,厚着脸皮,整理下读书笔记,结合平常项目的实践,也来聊聊 HTTPS. 一.为什么需要 HTTPS? 众所周知,HTTP 协议具有无连接.不可靠. ...
- FreeSql.Generator命令行代码生成器是如何实现的
目录 FreeSql介绍 FreeSql.Generator RazorEngine.NetCore 源码解析 FreeSql.Tools FreeSql FreeSql 是功能强大的对象关系映射技术 ...
- Swoole 绑定域名 80 端口 (Nginx 反向代理)
启动 Swoole 的 http server,可以使用 IP + 端口 进行访问 创建 Nginx 虚拟域名 vim swotp.liuguofeng.com.conf server { liste ...
- EntityFramework Core 迁移忽略主外键关系
前言 本文来源于一位公众号童鞋私信我的问题,在我若加思索后给出了其中一种方案,在此之前我也思考过这个问题,借此机会我稍微看了下,目前能够想到的也只是本文所述方案. 为何要忽略主外键关系 我们不仅疑惑为 ...
- JVM垃圾回收概述
垃圾回收概述 什么是垃圾 什么是垃圾( Garbage) 呢? 垃圾是指在运行程序中没有任何指针指向的对象,这个对象就是需要被回收的垃圾. 如果不及时对内存中的垃圾进行清理,那么,这些垃圾对象所占的内 ...
- 深入理解JVM(③)Java的模块化
前言 JDK9引入的Java模块化系统(Java Platform Module System ,JPMS)是 对Java技术的一次重要升级,除了像之前JAR包那样充当代码的容器之外,还包括: 依赖其 ...
- 浅谈dfs
搜索(dfs) 搜索分为bfs与dfs 他们的算法思路都是相同的--穷举 可以说,搜索是万能的,但是复杂度往往是指数级的,往往是穷途末路才用的最后方案 dfs dfs核心操作:回溯+前进 想想你第一次 ...
- 08 . Kubernetes之 ingress及Ingress Controller
Ingress简介 ingress是什么? 上篇文章介绍service时有说了暴露了service的三种方式ClusterIP.NodePort与LoadBalance,这几种方式都是在service ...