如何在Ubuntu 16.04上设置带有CI的连续集成管道

Concourse CI是一种现代可扩展的连续集成系统,旨在通过可组合的声明式语法来自动化测试管道。在以前的指南中,我们[在Ubuntu 16.04上安装了大厅

介绍

Concourse CI是一种现代可扩展的连续集成系统,旨在通过可组合的声明式语法来自动化测试管道。 在以前的指南中,我们在Ubuntu 16.04服务器上安装了Concourse,并使用“ 加密”中的SSL证书保护了Web UI

在本指南中,我们将演示如何在将更改提交到存储库时使用Concourse自动运行项目的测试套件。 为了演示,我们将配置一个使用Hapi.js (一个Node.js Web框架)编写的“hello world”应用程序的连续集成流程。

为了确保构建和测试过程始终与其相关联的代码保持同步,我们将将CI定义添加到应用程序存储库本身。 之后,我们将使用大厅的fly命令行工具将管道装载到大厅。 最后,我们将更改备份到存储库,以更永久地保存它们,并在新的CI工作流程中启动新的测试。

先决条件

在开始之前,您将需要一个至少有1G RAM的Ubuntu 16.04服务器。 完成以下指南以设置非root用户,安装和配置Concourse,安装Nginx,获取TLS / SSL证书,并在Concourse Web UI中设置安全的反向代理。 您将需要在您的Concourse服务器上指向的域名才能正确保护它:

在本教程中,大部分工作将在本地计算机上完成,而不是Concourse服务器。 因此,您还需要确保本地机器上有几个工具可用。 您将需要一个文本编辑器(您可能会在各种操作系统中找到的例子是nanovim ,TextEdit,Sublime Text,Atom或Notepad)来创建和修改存储库中的文件。 您还需要在本地系统上安装和设置Git,您可以通过遵循我们贡献于开源的Git指南入门

当您设置了Concourse服务器并在本地计算机上安装Git和文本编辑器时,请继续下面。

本地安装Fly命令行工具

当我们在先决条件下在服务器上安装Concourse时,我们将fly命令行工具安装到服务器上,以便我们可以从命令行管理Concourse实例。 但是,对于日常使用,在本地系统上安装通用开发工具和源代码可用的二进制文件副本更为方便。

要获取与您的服务器版本匹配的本地副本,请访问您的Web浏览器中的Concourse实例:

https://your_concourse_url

如果您已经注销,或者当前没有配置管道,则会在窗口中央显示各种平台下载的链接:

大厅下载链接大

如果您已经登录并配置了管道,则屏幕右下角将提供下载的fly链接:

广场飞小下载链接

单击代表本地计算机操作系统的图标下载fly二进制文件。

接下来,按照平台的具体说明在本地系统上设置fly

Linux或macOS

如果您的本地计算机运行Linux或macOS,请在下载相应的二进制文件后按照以下说明操作。

首先,将下载的二进制文件标记为可执行文件 我们假设您已将文件下载到~/Downloads目录,因此如有必要,请调整下载位置:

chmod +x ~/Downloads/fly

接下来,通过键入以下内容将二进制文件安装到PATH中的某个位置:

sudo install ~/Downloads/fly /usr/local/bin

您可以键入以下内容来验证可执行文件是否可用:

fly --version
3.3.1

如果您能够显示该版本,则fly已成功安装。

视窗

如果您的本地计算机运行Windows,请按键盘上的Windows键 ,键入powershell ,然后按ENTER键

在出现的窗口中,输入以下内容,创建一个bin文件夹:

mkdir bin

接下来,通过键入以下命令将fly.exe文件从“ Downloads文件夹移动到新的bin文件夹:

mv Downloads/fly.exe bin

检查PowerShell配置文件是否已经可用:

Test-Path $profile

如果响应为True ,则您已经有一个配置文件。

如果响应为False ,则需要键入以下命令创建一个:

New-Item -path $profile -type file -force

    Directory: C:\User\Sammy\Documents\WindowsPowerShell

Mode              LastWriteTime       Length Name
----              -------------       ------ ----
-a----       7/9/2017   5:46 PM            0 Microsoft.PowerShell_profile.ps1

一旦你有一个配置文件,你可以用编辑器进行编辑:

notepad.exe $profile

在编辑器窗口(如果您必须创建您的配置文件将为空),请添加以下行:

Microsoft.PowerShell_profile.ps1
$env:path += ";C:\Users\Sammy\bin"

完成后保存并关闭文件。

接下来,将执行策略设置为当前用户的“RemoteSigned”,以允许PowerShell读取配置文件:

Set-ExecutionPolicy -scope CurrentUser RemoteSigned

最后,键入以下内容来源自PowerShell配置文件:

. $profile

您现在应该能够从任何位置调用fly.exe可执行文件。 通过二进制打印其版本来测试:

fly.exe --version
3.3.1

在本指南中,您将需要用fly.exe替换fly命令的每个实例以匹配Windows命令。

与大厅服务器认证

安装fly ,登录到您的远程Concourse服务器,以便您可以在本地管理CI环境。 单一的二进制文件可用于联系和管理多个Concourse服务器,因此该命令使用一个称为“目标”的概念作为标签来标识要发送命令的服务器。

我们正在使用main作为本指南中的Concourse服务器的目标名称,但您可以替换所需的任何目标名称。 -c选项之后,输入您的Concourse服务器的域名,完成https://协议规范,以指示您的服务器位置:

fly -t main login -c https://example.com

系统将提示您输入您在/etc/concourse/web_environment服务器上的/etc/concourse/web_environment文件中配置的用户名和密码:

logging in to team 'main'

username: sammy
password: 

target saved

验证完成后,该fly工具将创建一个名为~/.flyrc的配置文件,以便将来的命令存储您的凭据。

注意:如果您稍后升级Concourse版本,可以通过键入以下命令来安装匹配版本的fly命令:

fly -t main sync

这将更新您的系统上的fly二进制文件,同时保持您的配置不变。

分离和克隆示例存储库

现在您已经在系统上安装了fly ,我们可以继续设置我们将要使用的存储库来演示Concourse管道。

在您的网络浏览器中,访问GitHub上“hello hapi”应用程序 ,我们将作为我们的示例。 此应用程序是一个简单的“hello world”程序,具有使用Hapi.js (一个Node.js Web框架)编写的几个单元和集成测试。

由于此示例用于演示各种连续集成系统,因此您可能会注意到一些用于为其他系统定义管道的文件。 对于大厅,我们将在我们自己的仓库中创建持续的集成管道。

要创建存储库的分支,请登录到GitHub并导航到项目存储库 点击右上角的“ 叉”按钮,在您的帐户中创建存储库的副本:

你好的hapi叉仓库

如果您是GitHub组织的成员,则可能会询问您要在哪里分叉存储库。 选择帐户或组织后,存储库的副本将被添加到您的帐户中。

接下来,在本地计算机的终端中,移动到您的主目录:

cd $HOME

使用以下命令将存储库克隆到本地计算机,替换您自己的GitHub用户名:

git clone git@github.com:your_github_user/hello_hapi

将在您的主目录中创建一个名为hello_hapi的新目录。 输入新的目录开始:

cd hello_hapi

我们将为此存储库中的示例项目定义一个连续的集成管道。 在进行任何更改之前,最好在Git中创建并切换到新的分支,以隔离我们的更改:

git checkout -b pipeline
Switched to a new branch 'pipeline'

现在我们有一个新的分支工作,我们可以开始定义我们的持续集成管道。

设置应用程序的连续集成过程

我们将在项目存储库本身中定义我们的管道及其所有相关文件。 这有助于确保连续集成过程始终与其测试代码保持一致。

测试套件已经在一个名为test的目录中定义。 它包括一个单元测试和两个基本集成测试。 运行测试的命令是在package.json文件中的scripts对象内的name test下定义的。 在安装了npm和Node.js的环境中,您可以通过键入npm test (在使用npm install项目依赖关系后) npm test 这些是我们需要在我们的管道中复制的过程。

要开始,在资源库中创建一个名为ci的目录,以容纳项目的持续集成资产。 我们还将创建两个名为ci/tasksci/scripts子目录,以保存管道引用和任务调用的脚本的各个任务定义。

键入以下命令创建必要的目录结构:

mkdir -p ci/{tasks,scripts}

接下来,我们可以开始创建Concourse将使用的单个文件。

定义管道

使用文本编辑器在ci目录下创建并打开一个名为pipeline.yml的文件(我们将在本指南中显示nano编辑器,但应该将文本编辑器替换为系统)。 如扩展名所示,Concourse文件使用YAML数据序列化格式定义:

nano ci/pipeline.yml

我们现在可以开始设置我们的管道。

定义NPM缓存资源类型

在文件中,我们将首先定义一个新的资源类型:

CI / pipeline.yml
---
resource_types:
  - name: npm-cache
    type: docker-image
    source:
      repository: ymedlop/npm-cache-resource
      tag: latest

为了将持续集成中的进程与通过系统的数据进行分离,Concourse将所有状态信息卸载到称为资源的抽象中。 资源是大厅可以用来从中提取信息或将信息推送到的数据的外部来源。 这就是所有数据如何进入连续集成系统以及工作之间如何共享所有数据。 大厅不提供在内部存储或传递状态的任何机制。

resource_types标题允许您定义可以在管道中使用的新类型的资源,例如电子邮件通知,Twitter集成或RSS源。 我们定义的新资源类型告诉Concourse如何使用npm-cache-resource ,一个作为Docker映像提供的资源 ,它允许Concourse安装一个Node.js项目的依赖关系,并在作业之间共享它们。

定义存储库和缓存资源

接下来,我们需要定义管道的实际资源:

CI / pipeline.yml
. . .

resources:
  - name: hello_hapi
    type: git
    source: &repo-source
      uri: https://github.com/your_github_user/hello_hapi
      branch: master
  - name: dependency-cache
    type: npm-cache
    source:
      <<: *repo-source
      paths:
        - package.json

本节定义了Concourse CI作业完成任务所需的两个资源。 Concourse使用资源定义来观察上游系统的变化,并了解当作业需要资源时如何下拉资源。 默认情况下,Concourse每分钟检查一次新版本的每个资源。 要求具有“触发器”选项的资源的作业将在新版本可用时自动启动新构建。

第一个资源代表您在GitHub上的hello_hapi存储库的hello_hapi “源”行包含一个称为“repo-source”的YAML锚点,锚点标记该元素以供将来参考。 这允许我们将元素的内容(“uri”和“branch”定义))包含在文档后面的不同位置。

称为“依赖缓存”的第二个资源使用我们定义的“npm-cache”资源类型来下载项目的依赖关系。 在这个资源的“源”规范中,我们使用<<: *repo-source行来引用扩展 &repo-source锚点指向的元素。 这将把我们的应用程序资源库中的uri和分支设置插入到这个第二个资源中。 称为“路径”的附加元素指向定义项目依赖关系的package.json文件。

定义依赖关系收集和测试作业

最后,我们使用Concourse 作业定义实际的连续集成过程:

CI / pipeline.yml
. . .

jobs:
  - name: Install dependencies
    plan:
      - get: hello_hapi
        trigger: true
      - get: dependency-cache
  - name: Run tests
    plan:
      - get: hello_hapi
        trigger: true
        passed: [Install dependencies]
      - get: dependency-cache
        passed: [Install dependencies]
      - task: run the test suite
        file: hello_hapi/ci/tasks/run_tests.yml

在本节中,我们定义了两个作业,每个作业都包含一个名称和一个计划。 反过来,每个计划都可以包含“获取”或“任务”元素。 任务项目指定如何在获取项目指示任务的资源依赖性时执行操作。

第一个工作没有任何任务声明。 这有点不寻常,但是当我们看看它在做什么以及如何使用它时,这是有道理的。 第一个get语句需要hello_hapi资源,并指定trigger: true选项。 每当在hello_hapi存储库中检测到新的提交时,这将告诉Concourse自动获取存储库并开始此作业的新构建。

第一个作业( get: dependency-cache )中的第二个get语句需要我们定义的资源来下载并缓存项目的Node.js依赖项。 此语句评估package.json文件中的要求并下载它们。 没有为此作业定义任务,则不会执行其他操作,但下载的依赖关系将可用于后续作业。

注意 :在这个具体的例子中,只有一个额外的工作,所以缓存Node.js依赖关系作为一个独立的步骤的好处并没有完全实现(将get语句添加到下面的测试工作就足够下载依赖关系)。 然而,几乎所有使用Node.js的工作都需要项目依赖关系,因此如果您有可能并行完成的独立作业,则单独依赖关系缓存的好处将变得更加清晰。

第二个工作( name: Run tests )通过声明相同的依赖关系,并显示一个显着差异。 “传递”约束导致get语句仅匹配已成功遍历管道中以前步骤的资源。 这就是形成工作之间的依赖关系,将流程流程链接在一起。

在get语句之后,定义了一个名为“运行测试套件”的任务。 它不是定义完成内联的步骤,而是告诉Concourse从其获取的存储库中的文件中提取定义。 我们将在下面创建此文件。

完成后,完整的管道应如下所示:

CI / pipeline.yml
---
resource_types:
  - name: npm-cache
    type: docker-image
    source:
      repository: ymedlop/npm-cache-resource
      tag: latest

resources:
  - name: hello_hapi
    type: git
    source: &repo-source
      uri: https://github.com/your_github_user/hello_hapi
      branch: master
  - name: dependency-cache
    type: npm-cache
    source:
      <<: *repo-source
      paths:
        - package.json

jobs:
  - name: Install dependencies
    plan:
      - get: hello_hapi
        trigger: true
      - get: dependency-cache
  - name: Run tests
    plan:
      - get: hello_hapi
        trigger: true
        passed: [Install dependencies]
      - get: dependency-cache
        passed: [Install dependencies]
      - task: run the test suite
        file: hello_hapi/ci/tasks/run_tests.yml

完成后保存并关闭文件。

定义测试任务

虽然管道定义概述了我们持续集成过程的结构,但它推迟将实际测试任务定义到另一个文件。 提取任务有助于保持管道定义简洁易读,但要求您读取多个文件以了解整个过程。

在名为run_tests.ymlci/tasks目录下打开一个新文件:

nano ci/tasks/run_tests.yml

要定义任务,您需要指定工作人员需要的操作系统类型,定义用于运行任务的映像,命名任务将使用的任何输入或输出,并指定要运行的命令。

粘贴以下内容以设置我们的测试任务:

CI /任务/ run_tests.yml
---
platform: linux

image_resource:
  type: docker-image
  source:
    repository: node
    tag: latest

inputs:
  - name: hello_hapi
  - name: dependency-cache

run:
  path: hello_hapi/ci/scripts/run_tests.sh

在上述配置中,我们指定此任务需要一个Linux工作。 Concourse服务器本身可以满足此要求,无需其他配置。

接下来,我们指出一个将由工作人员用于运行任务的映像。 虽然您可以创建和使用自己的图像类型,但在实践中,这几乎总是一个Docker图像。 由于我们的存储库是一个Node.js应用程序,所以我们选择最新的“node”映像来运行我们的测试,因为它已经安装了相应的工具。

交流任务可以指定输入和输出,以指示其需要访问的资源及其产生的工件。 输入对应于较早在“作业”级别下拉的资源。 这些资源的内容可以作为任务运行中可以操作的顶级目录提供给任务环境。 这里,应用程序存储库将在hello_hapi目录下可用,Node.js依赖项将在名为dependency-cache的目录下可用。 您的执行步骤可能需要在任务开始时将文件或目录移动到其预期位置,并在任务结束时将工件放置在输出位置。

最后, 运行项目列出要运行的命令的路径 每个任务只能是带有参数的单个命令,因此,通过编写一个bash字符串可以内联构造一个命令,将任务指向一个脚本文件是比较常见的。 在这种情况下,我们指向位于hello_hapi/ci/scripts/run_tests.shhello_hapi输入目录中的hello_hapi/ci/scripts/run_tests.sh 我们将在下面创建此脚本。

完成后保存并关闭文件。

定义测试脚本

最后,我们需要创建任务执行的脚本。 打开位于ci/scripts/run_tests.sh名为run_tests.sh的新文件:

nano ci/scripts/run_tests.sh

该脚本将操纵测试环境的输入以将项目移动到正确的位置。 然后,它将通过运行npm test运行存储库中定义的测试套件。

将以下内容粘贴到新文件中:

CI /脚本/ run_tests.sh
#!/usr/bin/env bash

set -e -u -x

mv dependency-cache/node_modules hello_hapi
cd hello_hapi && npm test

首先,我们指出这个脚本应该由Docker容器的bash解释器执行。 set选项修改shell的默认行为,导致任何错误或未设置变量停止脚本执行,并在执行命令时打印每个命令。 这些帮助使脚本更安全,并为调试目的提供更大的可见性。

我们运行的第一个命令将位于node_modules目录中的缓存依赖关系从dependency-cache目录中移动到hello_hapi目录。 请记住,这两个目录都可用,因为我们将它们指定为任务定义中的输入。 这个新的位置是npm将寻找所需的下载的依赖项。

之后,我们进入应用程序库并运行npm test来执行定义的测试套件。

完成后,保存并关闭文件。

在移动之前,将新脚本标记为可执行文件,以便可以直接运行:

chmod +x ci/scripts/run_tests.sh

我们的管道和所有相关文件现已被定义。

在大厅设置管道

在将pipeline分支合并到main ,将其推送到GitHub之前,我们应该将管道加载到大厅中。 广场将观察我们的存储库的新提交,并在检测到更改时运行我们的持续集成程序。

当我们需要手动加载管道时,由于Concourse执行管道,它将从存储库中的目录读取任务和脚本。 对管道本身的任何更改都将需要重新加载到大会堂才能生效,但是由于我们没有将所有内容定义在一起,因此在作为提交的一部分上传时,将自动注意到任务或脚本的更改。

要设置新的管道,请使用set-pipeline操作使用fly命令定位Concert服务器。 我们需要使用-p选项传递新管道的名称,并使用-c选项传递管道配置文件:

fly -t main set-pipeline -p hello_hapi -c ci/pipeline.yml

在继续之前,将提示您确认配置。 键入y 并按ENTER键

. . .

apply configuration? [yN]: y
pipeline created!
you can view your pipeline here: https://example.com/teams/main/pipelines/hello_hapi

the pipeline is currently paused. to unpause, either:
  - run the unpause-pipeline command
  - click play next to the pipeline in the web ui

如输出所示,管道已被接受,但当前已暂停。 您可以使用fly或web UI取消暂停管道。 我们将使用Web UI。

在您的Web浏览器中,访问您的Concourse服务器并登录。您应该看到您的新管道可视化地定义:

大厅不活动管道

待处理作业由灰色框表示,资源较小,较暗的块。 资源更改触发的作业通过实线连接,而非触发资源使用虚线。 流出工作的资源表明已经在下一个作业中设置了passed约束。

蓝色标题表示管道当前已暂停。 单击左上角的菜单图标 (三个堆叠的水平线)打开菜单。 您应该看到一条管道的条目(如果管道不可见,则可能需要注销并重新输入)。 点击管道旁边的蓝色播放图标取消暂停:

大厅取消了管道

管道现在应该是不开放的,并将开始运行。

一开始,各种资源和工作可能会变成橙色,表明发生错误。 这是因为需要下载各种Docker图像,并且pipeline分支仍需要合并到我们的存储库的main分支中,以使任务和脚本文件可用。

承诺改变Git

既然已经定义了持续的集成过程,我们可以将其提交到我们的git仓库并将其添加到大厅。

通过键入以下内容将新的ci目录添加到分段区域:

git add ci

通过检查状态验证要提交的文件:

git status
On branch pipeline
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   ci/pipeline.yml
    new file:   ci/scripts/run_tests.sh
    new file:   ci/tasks/run_tests.yml

通过键入以下提交更改:

git commit -m 'Add Concourse pipeline'

这些变化现在都归功于我们的pipeline分公司。 我们可以通过切换分支和合并将分支合并到master分支中:

git checkout master
git merge pipeline

现在,将master分支推送到GitHub:

git push origin master

提交将在六十秒内启动新的构建,并且在下拉更改之后,Concourse将可以访问管道任务和脚本。

查看新建

回到Concourse的Web UI中,新的构建将在下一分钟内开始进行:

大厅运行测试套件

黄色轮廓表示该作业正在进行中。 要监视进度,请单击运行测试作业以查看当前输出。 作业完成后,完整的输出将可用,作业将变为绿色:

大会成功测试

单击主图标返回到主管道屏幕。 每个作业的绿色状态表示最新的提交已通过管道的所有阶段:

大厅通过所有工作

管道将继续监视存储库,并在更改发生时自动运行新的测试。

结论

在本指南中,我们设置了一个Concourse管道来自动监视存储库以进行更改。 检测到更改时,Concourse会拉下存储库的最新版本,并使用Docker容器来安装和缓存项目依赖关系。 然后,构建将进行到依赖关系被复制的测试阶段,并且运行存储库的测试套件以检查是否引入了任何突破性更改。

广场提供了很多灵活性和权力来定义隔离的测试过程并将其存储在存储库本身中。 如果您想了解更多关于如何利用Concourse进行自己的项目, 请查看官方文档