GitHub Actions,卧槽!牛批!

阅读本文大概需要 19 分钟。

前段时间我更新了我的分布式爬虫管理框架—— Gerapy(话都说到这儿了打个广告,跟繁琐的命令行说拜拜!Gerapy分布式爬虫管理框架来袭!,哇,哇,就是,哇!)

现在 DevOps 的理念可谓是相当火,其中 CI/CD(持续集成、持续部署)是必不可少的环节。有了它们,我们开发完软件之后,一些测试、构建、部署的环节就可以自动化完成了。

我开发的的这款分布式爬虫管理框架—— Gerapy,代码也是放在了 GitHub 上面,但在之前 GitHub 上面是缺少原生的 CI/CD 功能支持的,可能需要根据第三工具或者 Webhook 等来配合实现项目的自动测试、构建和部署。

比如我可能有这么一些需求:

•每次合并代码到 master 分支时,想测试这个项目能否在各个版本的 Python 环境下正常安装和运行。•我为 Gerapy 新建了一个独立的 Repo,叫做 Gerapy/Gerapy,在 docs 文件夹下存放文档说明,但我还另外新建了一个 Repo 专门用来存放文档,叫做 Gerapy/Docs,希望能把 Gerapy/Gerapy 的 docs 子文件夹下的内容整个自动同步到 Gerapy/Docs 这个 Repo 的根目录。•每次 Gerapy 发布新版本的时候,自动构建 Docker 镜像,并上传到 Docker Hub,打上 latest 标签和版本号标签。•每次 master 分支提交代码的时候,自动构建 Docker 镜像,并上传到 Docker Hub,打上 master 标签,代表当前 master 分支版本。

上面的功能之前有一部分工作是手工操作的,有一部分是借助于第三方工具来自动操作的,感觉并不是一个很好的解决方案

在最近一段时间,GitHub 上面上线了 Actions 功能,它就是为 CI/CD 而生的,和 GitHub 项目原生紧密结合。然而几个月以来一直处于内测阶段。就在 11 月 13 日,GitHub Actions 功能正式上线了。

上线之后,我就开始正式使用这个功能了,是真的香!

上面的四个需求,我用 GitHub Actions 已经完全实现了自动化,非常简单方便。

接下来简单介绍下我的一些实现方式。

GitHub Actions

首先简单介绍下 GitHub Actions,其官方介绍页面为:https://github.com/features/actions,介绍语如下:

Automate your workflow from idea to production. GitHub Actions makes it easy to automate all your software workflows, now with world-class CI/CD. Build, test, and deploy your code right from GitHub. Make code reviews, branch management, and issue triaging work the way you want.

简而言之就是提供了一个高效易用的 CI/CD 工作流,帮助我们自动构建、测试、部署我们的代码。

另外它支持三大平台—— Linux、MacOS、Windows,支持任何编程语言,而且官方提供了许许多多的 Actions 库供我们直接使用,帮助我们更快地搭建工作流。

GitHub Actions 的官方文档可以见:https://help.github.com/en/actions/automating-your-workflow-with-github-actions,如果大家想好好研究下的话,一定要好好看看。

下面我就介绍我使用 GitHub Actions 实现上文所述的四个需求的方法。

自动测试

由于我开发的 Gerapy 是一个 Python Package,因此我看重的是测试它是否可以在各个 Python 平台下安装和正常使用,于是我新建了一个 GitHub Action,它会自动在项目目录下生成一个 .github/workflows/*.yml 文件,内容如下:

name: buildon:   push:    branches:     - master    - devjobs:  test:    runs-on:     - ubuntu-latest    strategy:      max-parallel: 3      matrix:        python-version: [3.5, 3.6, 3.7]    steps:    - uses: actions/checkout@v1    - name: Set up Python ${{ matrix.python-version }}      uses: actions/setup-python@v1      with:        python-version: ${{ matrix.python-version }}    - name: Install Dependencies      run: |        python -m pip install --upgrade pip        pip install .    - name: Run Gerapy      run: |        gerapy -v        gerapy init        cd gerapy        gerapy migrate        gerapy initadmin

其实在这里一个 Action 就是一个 YAML 文件,其后缀为 yml,它规定了一系列语法规则,我们根据它的语法规则写出一些工作流,在符合一定条件时,这些工作流会被触发,自动执行。

比如这里最开头,on 就是监听某个事件,其内容为 push,意思就是当 push 代码的时候,就会触发。再进一步地,这里定义了两个分支 master 和 dev。这什么意思呢?就是当我往 master 或者 dev 分支 push 代码的时候,我们定义的工作流就会执行。

下面的 jobs 就是工作流的定义了,包括在什么平台运行,具体执行什么步骤。

比如这里 runs-on 我就定义了在 ubuntu-latest 版本上运行,另外定义了一些并行策略和参数,比如这里就定义了 Python 的三个版本参数,在 3.5、3.6、3.7 版本上运行。

下面的 steps 就是具体执行哪些步骤了。第一步和第二步,我们可以看到它都有一个 uses 参数,内容都为 actions 开头,这就说明我们使用了 GitHub 提供的写好的 Action,我们只需要引用它的名字就能使用了。这两步运行完毕之后,Python 环境会被初始化,同时会从 GitHub Clone Gerapy 项目代码到本地。

在第三步和第四步,就是我自定义的 Task 了,这里自持直接写入 Shell 脚本。在这里我分了两步。

第三步 Install Dependencies 就是安装 pip 和 Gerapy 安装包,其中一句 pip install . 就是安装当前 Gerapy 目录下的内容到系统中,安装完成之后,就可以使用 gerapy 命令了。

于是第四步 Run Gerapy 就是测试了 gerapy 命令的一些初始化使用,包括初始化工作环境、数据库迁移、初始化账号等等,当然还有更多,比如运行某些测试,运行服务等等,这里我只把一些必要的内容写进去了。

好,基本内容就是这样。

保存这个 Action,命名为 build.yml,它会保存为 .github/workflows/build.yml 文件。同时在保存的时候,我们就相当于执行了一次 Push 任务,这时候我们就可以看到这个 Action 已经启动了,页面如下:

我们所定义的每一个步骤以及对应的执行结果都会显示在控制台中,一目了然。

可以看到这里初始化了三个版本的 Python 环境,同时都运行了其中的测试流程。如果测试成功,会打绿色的勾,如果失败,会提示红色的叉,并有邮件提示。

这样以来,一些自动化的测试就完成了!!!

同步文档到新的 Repo

接下来我这个需求可以说稍微有点奇葩了。

写项目免不了的要写文档,这里文档我是用 Sphinx 来写的,可以借助于 ReadTheDocs 自动构建并分发到 readthedocs.io 上面,类似这样子:

但文档的源代码我是放在了 Gerapy/Gerapy 这个 Repo 的 docs 文件夹,向 Scrapy 看齐,是这样子的:

但我想着还新建一个 Repo,来单独存放文档,比如我新建一个 Gerapy/Docs 这个 Repo,我在 Gerapy/Gerapy docs 子文件夹下的内容可以被自动同步到 Gerapy/Docs 根目录下面,这样我只需要往 Gerapy/Gerapy 上面提交代码,docs 子文件夹下面的内容变了,Gerapy/Docs 下面的内容也会跟着变。

那这个能不能做到呢?能!(我问你答,快乐神仙;自问自答,法力无边~~

这个流程可以分为四步:

•下载 Gerapy/Gerapy Repo 的源代码。•利用 git 的 subtree 命令将 docs 文件夹下的内容分离到新的分支。•将新分离的分支推送到 Docs 这个 Repo 下面。•推送 Docs 这个 Repo 到远程 Gerapy/Docs Repo。

这里面就有一个关键地方,那就是怎样无需密码将内容推送到远程 Gerapy/Docs 这个 Repo 下面,当然就是 SSH 了。(啊,超爽der)

那 SSH 的话应该怎么设置呢?我们首先要有一对公钥和私钥,这个我们用 ssh-keygen 命令自己生成就好了。

那接下来 Gerapy/Docs 里面需要存有公钥,怎么办呢?我们可以借助于 GitHub 提供的 Deploy Key 配置好公钥即可:

然后我们需要将私钥上传到 Action 所运行的虚拟机里面,但我们又不能明文将其放在 yml 文件里面,那这个怎么做到呢?只需要将其配置到 Secrets 里面即可,Action 是有权限访问到的:

嗯,做好这两部分工作之后,接下来完善一下 yml 文件就好了,内容如下:

name: sync docson:   push:    branches:     - masterjobs:  sync:    runs-on: ubuntu-latest    steps:    - name: Set SSH Environment      env:        DOCS_DEPLOY_KEY: ${{ secrets.DOCS_DEPLOY_KEY }}      run: |        mkdir -p ~/.ssh/        echo "$DOCS_DEPLOY_KEY" > ~/.ssh/id_rsa        chmod 600 ~/.ssh/id_rsa        ssh-keyscan github.com > ~/.ssh/known_hosts        chmod 700 ~/.ssh && chmod 600 ~/.ssh/*        git config --global user.email "cqc@cuiqingcai.com"        git config --global user.name "Germey"    - name: Sync Docs of Gerapy      run: |        cd /tmp        git clone git@github.com:Gerapy/Docs.git docs        cd docs        git branch -D docs || true        git push origin --delete docs || true        git clone https://github.com/Gerapy/Gerapy.git gerapy        cd gerapy        git subtree split --prefix=docs --squash -b docs        git checkout docs        git push /tmp/docs docs:docs        cd /tmp/docs        git checkout docs        git checkout -b master || git checkout master || true        git reset --hard docs        git push origin master --force

可以看到,这里主要就分了两步。

第一部分就是设置虚拟机的 SSH 环境,这里 secrets.DOCS_DEPLOY_KEY 就是我们刚才在 Secrets 里面定义的私钥,对应的运行命令就是将私钥添加到 ~/.ssh/id_rsa 里面。

第二部分就是分离 docs 文件夹到新的分支,然后将其上传到新的 Repo 下了。

那么这里有两条比较关键的命令:

git subtree split --prefix=docs --squash -b docs

这条命令就是将 docs 文件夹的内容分离到一个新的分支的根目录下,新的分支的名称为 docs。

git push /tmp/docs docs:docs

这条命令就是将本地的分支推送到另外一个本地 Repo 下,注意这里 push 的目标不一定是远端的 Repo 地址,也可以是本地的 Repo 地址。

最后,将新的 Repo 内容强制推送到远程即可。

这样我们就可以实现,Gerapy/Gerapy Repo docs 文件夹下内容的变动,会自动更新到 Gerapy/Docs Repo 了。

例如 docs 下是这样的:

Gerapy/Docs Repo 下和子文件的内容会一直维持同步,并在 master 分支上面:

自动构建 Docker 镜像

由于 Gerapy 是一个 Web 工程,所以它非常适合于打包一个 Docker 镜像。对于 Docker 的镜像,我期望有三个版本:

•当前 master 分支的版本,比较稳定,但未发布版本。•最新版本,latest,代表最新的发布版本。•每个历史版本,每次发布版本的版本号,都标记一个 tag。

最后我们自动构建的镜像都自动 Push 到 Docker Hub 上面,这样大家都可以使用了。

那这个怎么做到呢,同样借助于 GitHub Action 也可以轻松做到。

首先 master 版本,由于没有发版,所以前端需要自行 build,然后 Python Package 需要安装本地代码。废话不多说了,上代码:

name: build docker image masteron:  push:    branches:     - master    paths:    - .github/workflows/**    - gerapy/**jobs:  build:    runs-on: ubuntu-latest    steps:    - name: Checkout Source      uses: actions/checkout@v1    - name: Docker Login      run: docker login -u germey -p ${{ secrets.DOCKERHUB_LOGIN_PASSWORD }}    - name: Setup Node.js      uses: actions/setup-node@v1.1.0      with:        version: 10.x    - name: Build Frontend Source      run: |        cd gerapy/client        npm install        npm run build    - name: Build the Docker Image      run: |        docker build -t germey/gerapy:master -f ./docker/Dockerfile .    - name: Push the Docker Image      run: docker push germey/gerapy:master

可以看到这里,监听了 master 分支的变动,同时限定了路径 workflows 文件夹和 gerapy 文件夹下变动。

流程包括了前端的构建和 Docker 的打包,Docker 打包的时候使用了 -f 命令指定了 Dockerfile 的路径,并将打包完成之后的镜像标记为 gerapy:master,推送到 Docker Hub 即可。

对于发布新版本的时候,则直接监听 tag 的变动即可:

name: build docker image releaseon:  push:    tags:      - 'v*.*.*'jobs:  build:    runs-on: ubuntu-latest    steps:    - name: Checkout Source      uses: actions/checkout@v1    - name: Docker Login      run: docker login -u germey -p ${{ secrets.DOCKERHUB_LOGIN_PASSWORD }}    - name: Setup Node.js      uses: actions/setup-node@v1.1.0      with:        version: 10.x    - name: Build Frontend Source      run: |        cd gerapy/client        npm install        npm run build    - name: Build and Push the Docker Image      run: |        tag=${GITHUB_REF:11}        echo "Build Tag '$tag'"        docker build -t germey/gerapy:$tag -f ./docker/Dockerfile .        docker push germey/gerapy:$tag        regex='^([0-9]+\.){0,2}(\*|[0-9]+)$'        if [[ $tag =~ $regex ]]; then          echo "Build Stable Version '$tag'"          docker tag germey/gerapy:$tag germey/gerapy:latest          docker push germey/gerapy:latest        fi

可以看到这里监听的配置改成了 tags,tag 也变成了一个变量,可以通过 ${GITHUB_REF:11} 获取到。

同时这里还加了一个正则判断是不是正式的发版,如果是 beta、rc 版本,则不构建正式 latest 的 Docker 镜像。

最后我们看看我再一次发版之后,构建完成之后,Docker Hub 的效果:

可以看到,我发布了 0.9.2 版本之后,它就自动构建了 0.9.2 版本的镜像,同时将 latest 镜像指向 0.9.2 版本。另外对应 maser 版本也构建了一个版本。

这样,以后妈妈再也不用担心我忘记打 Docker 镜像啦。

以上便是我将 GitHub Actions 应用到我的开源项目上的记录。

最后,如果大家对 Scrapy 爬虫感兴趣的话,也(非常)欢迎大家(高高兴兴的)了解一下我写的 Gerapy 框架,利用它我们可以(无敌)更方便地管理(呀)、监控(呀)、(或者是)部署 Scrapy 爬虫项目(什么的)。

其 GitHub 地址为:https://github.com/Gerapy/Gerapy,文档:https://docs.gerapy.com/。

好文和朋友一起看~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/312805.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

平衡二叉树AVL详解

一、平衡二叉树的定义 平衡二叉树(Balanced Binary Tree)又被称为AVL树,它且具有以下性质: (1)它是一棵空树或它的左右两个子树的高度差的绝对值不超过1; (2)并且左右两个…

【壹个小技巧】一看就会的CI/CD :Github Actions

什么是 CI/CD?我这里先不说概念,先说一个平时开发的场景问题:我们平时开发一个项目,经常会遇到这些“小”问题:就是如何保证自己的项目是正确的,至少拿给别人的时候,可以编译运行的?或者说多人…

Hyper-V虚拟机自动添加检查点和导出备份

背景说明笔者使用Hyper-V在内部搭建了大量的环境和系统,比如:k8s内部集群Azure Devops Server(TFS>VSTS>Azure Devops Server)SharePoint…大部分基本上都是用于内部研究、测试等场景,但是为了避免很多麻烦,必要的备份还是必…

哈夫曼树详解

一、哈夫曼树的定义 (1)简单路径长度 所谓树的简单路径长度,是指从树的跟节点到每个节点的路径长度之和。 完全二叉树是简单路径长度更小的二叉树。 (2)加权路径长度 所谓树的加权路径长度,是指树中所以带…

深入理解.NET Core的基元(三) - 深入理解runtimeconfig.json

原文:Deep-dive into .NET Core primitives, part 3: runtimeconfig.json in depth作者:Nate McMaster[1]译文:深入理解.NET Core 的基元(三) - 深入 runtimeconfig.json作者:Lamond Lu前情回顾深入理解.NE…

B-树、B+树、B*树详解

一、B树 B树是一种多路搜索树(并不是二叉的),性质如下: 1、定义任意非叶子结点最多只有M个儿子;且M>2; 2、根结点的儿子数为[2, M]; 3、除根结点以外的非叶子结点的儿子数为[M/2, M]&#…

微软正在开发基于Rust的安全编程语言

此前,微软表示正探索将 Rust 作为 C 和 C 的安全替代方案,并且也对外展示了使用 Rust 重写 Windows 组件的体验。根据微软的说法,Rust 是一种从根本上考虑安全性的编程语言,他们将尝试使用 Rust 重写各种产品,因为在过…

堆树(最大堆、最小堆)详解

一、堆树的定义 堆树的定义如下: (1)堆树是一颗完全二叉树; (2)堆树中某个节点的值总是不大于或不小于其孩子节点的值; (3)堆树中每个节点的子树都是堆树。 当父节点的键…

HttpClientFactory日志不好用,自己扩展一个?

前言.NetCore2.1新推出HttpClientFactory工厂类, 替代了早期的HttpClient,并新增了弹性Http调用机制 (集成Policy组件)。替换的初衷还是简单说下:① using(var client new HttpClient()) 调用Dispose()方法,并不会很快释放底层So…

树、二叉树简介

一、树的定义 树是由n(n>1)个有限节点组成一个具有层次关系的集合,它有如下特点: 1、每个节点有零个或多个子节点; 2、没有父节点的节点称为根节点; 3、每一个非根节点有且只有一个父节点; 4…

Quartz.net定时任务的使用及获取正在运行的JOB

定时任务管理类实现了如下功能:1、对定时任务进行管理 2、创建定时任务,需要给定时任务一个job的名称 3、判断给定的job的任务是否已存在 4、停止定时任务的功能namespace MyUKD.Quartz{ public class QuartzSchedulerMgr { private static readonly ILo…

漫谈认证与授权

漫谈认证与授权Intro认证与授权一直以来都是很多人在讨论的话题,之所以想这次谈一谈认证和授权,主要是因为最近看到许多文章都把认证和授权混为一谈,把认证方式当作是授权方式。所以想写篇文章谈谈我眼中的认证与授权。Authentication什么是认…

【译】gRPC vs HTTP APIs

本文翻译自 ASP.NET Blog | gRPC vs HTTP APIs,作者 James,译者 Edison Zhou。现在,ASP.NET Core使开发人员可以构建gRPC服务。gRPC是一个远程过程调用框架,专注于高性能和开发人员的生产力。ASP.NET Core 3.0中集成了gRPC&#x…

.NET Core 3.0 的新改进:针对分布式应用程序的故障诊断和监控

由于分布式应用是由多个组件组成的,且这些组件往往是由不同的团队拥有和操作,所以在与应用程序发生交互时,就会需要跨多个组件执行代码的分布式跟踪。如果用户遇到了问题,想要确定是哪个组件出现了差错,基本就是一件不…

【翻译】.NET Core3.1发布

.NET Core3.1发布我们很高兴宣布.NET Core 3.1的发布。实际上,这只是对我们两个多月前发布的.NET Core 3.0的一小部分修复和完善。最重要的是.NET Core 3.1是长期支持(LTS)版本,并且将支持三年。和过去一样,我们希望花…

JVM(1)——JVM内存分区

一、JVM简介 JVM,即Java虚拟机(Java Virtual Machine),一种能够运行Java bytecode的虚拟机,是Java实现跨平台的基础。 引入Java语言虚拟机后,Java语言在不同平台上运行时不需要重新编译。Java语言使用Java虚…

使用Azure Pipelines从GitHub发布NuGet包

[本文目录]ps: 阅读本文大概需要20分钟欢迎大家点击上方公众号链接关注我,了解新西兰码农生活什么是 YAML?name/value 名称/值collections 集合multiple data types 复合数据类型comments 注释Pipelines 的 YAML 结构在 Azure DevOps Pipelines 中创建第一个任务为…

JVM(2)——JVM类加载机制

一、JVM类加载机制简介 虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制。 在Java语言里面,类型的加载和连接过程都是在程序运…

PYPL 12月榜单发布,编程语言、IDE与数据库市场如何?

PYPL(PopularitY of Programming Language,编程语言流行指数)12 月份的榜单已经发布了。PYPL 是非常流行的参考指标,其榜单数据的排名均是根据榜单对象在 Google 上相关的搜索频率进行统计排名,原始数据来自 Google Tr…

JVM(3)——JVM类加载器

一、类加载器简介 虚拟机设计团队把类加载阶段中的“通过一个类的全限定名来获取描述此类的二进制字节流”这个动作放到Java虚拟机外部去实现,以便让应用程序自己决定如何去获取所需要的类。实现这个动作的代码模块被称为“类加载器”。 类加载器虽然只用于实现类的…