如何在FreeBSD上设置Buildbot

Buildbot是一种通常用于持续集成的作业调度系统,这是一种软件开发实践,通常包括定期自动构建和测试软件以及每次更改。在本指南中,我们将介绍Buildbot组件背后的基础知识,并将它们安装在FreeBSD系统上。

作者选择了开放互联网/言论自由基金作为Write for DOnations计划的一部分接受捐赠。

介绍

Buildbot是一种通常用于持续集成 (CI)的作业调度系统。 CI是一种软件开发实践,通常包括定期自动构建和测试您的软件以及每次更改。 虽然它通常用作CI平台,但Buildbot也可用于在计算机上运行的任何自动化任务。 Buildbot的任务执行配置包括四个组件:

  • 更改源 :这些检测更改 - 例如Git存储库中的更改 - 并通知调度程序有关它们
  • 调度程序 :调度程序根据传入的更改触发构建器
  • 构建器 :它们包含实际的构建步骤,例如软件项目的编译
  • 记者 :记者使用构建结果发送失败的电子邮件或其他通知

Buildbot通过至少一个Buildbot master运行并检查所有构建配置和其他设置,并将实际构建分发给其worker。 此外,主服务器还提供基于浏览器的用户界面子组件,如果启用该子组件,则子组件用于触发或查看构建并检查状态报告和其他设置。 还有一个或多个Buildbot worker连接到master并接收命令,即运行构建。

在本指南中,您将使用FreeBSD jails在单独的隔离环境中安装和运行每个Buildbot组件。 然后,您将使用Nginx Web服务器为Buildbot提供服务,并使用本地计算机上的Web浏览器访问其Web界面。 完成本指南后,您将拥有一个带有示例项目构建的工作设置,可以为您自己的CI或其他用例进行扩展。

先决条件

在开始本指南之前,您需要:

  • 运行FreeBSD 11.2的服务器,虽然FreeBSD的新版本和旧版本也应该可以运行。 如果您刚开始使用FreeBSD,您可能会发现按照我们的如何开始使用FreeBSD的指南来定制此服务器会很有帮助。
  • Nginx安装在您的服务器上。 按照我们关于如何在FreeBSD 11.2上安装Nginx的指南,阅读如何设置它。

如果要使用安全HTTPS托管Buildbot Web界面,还需要以下内容:

  • 您拥有并控制的注册域名。 如果您还没有注册域名,可以在那里注册一个域名注册商之一(例如Namecheap,GoDaddy等)。
  • DNS A记录 ,将您的域指向服务器的公共IP地址。 这是必需的,因为Let's Encrypt如何验证您拥有其颁发证书的域。 例如,如果要获取example.com的证书,则该域必须解析到您的服务器才能使验证过程正常工作。 您可以按照此DNS快速入门指南获取有关如何添加此内容的详细信息。 在本教程中,我们将使用example.com作为示例域名。
  • 适用于您的域的SSL / TLS证书。 按照如何在FreeBSD上使用Let的加密来保护Nginx以进行设置。

第1步 - 为Buildbot Master和Worker设置Jails

由于Buildbot允许外部贡献者在您的系统上运行代码,因此建议您隔离其各种组件以防止任意或恶意代码占用您的服务器资源。 在本教程中,您将使用FreeBSD jails执行此操作。

与LXC,Docker和其他容器机制类似,FreeBSD jails提供了与主机系统的轻量级隔离。 在jail中运行的进程只能访问jail已被授予访问权限的资源; 否则,它们的行为与任何其他FreeBSD环境一样。 Jails共享相同的内核,但通常运行在具有FreeBSD基本系统副本的文件系统上,该系统可能是与主机内核兼容的任何FreeBSD版本。 对于大多数工作负载,在主机上运行任务与在监狱中执行任务之间的性能差异并不明显。

有几个外部软件包可以帮助创建和管理FreeBSD jails。 由于它们都不是事实上的标准,我们将使用操作系统的内置jail配置机制

首先,我们要为系统的jails创建一个单独的网络接口。 在jails中,内核将网络连接重写为分配给jail的第一个IPv4 / IPv6地址。 例如,如果第一个分配的IP地址是公共的,并且jail中的服务监听127.0.0.1:1234 ,则端口1234将可公开访问。 建议的做法是为jails提供单独的网络接口。 我们将遵循这种“克隆”主环回接口( lo0 )到单独接口( lo1 )的建议。 我们将使用网络10.0.0.0/24 ,但任何其他非重叠网络也可以使用。

首先配置要在引导时创建的克隆接口。 sysrc命令将规则写入/etc/rc.conf文件,但不创建接口本身:

sudo sysrc cloned_interfaces+=lo1

接下来,使用以下命令创建网络接口:

sudo service netif cloneup

您可以使用以下命令检查接口状态和IP:

ifconfig lo1
lo1: flags=8008<LOOPBACK,MULTICAST> metric 0 mtu 16384
    options=600003<RXCSUM,TXCSUM,RXCSUM_IPV6,TXCSUM_IPV6>
    nd6 options=21<PERFORMNUD,AUTO_LINKLOCAL>
    groups: lo

输出显示该接口存在,但尚未列出并附加到其上的IP地址。 其标志LOOPBACK表示此接口仅在本地可用,并不代表实际的硬件设备。

接下来,使用首选编辑器为主jail打开一个新配置文件。 在这里,我们将使用ee

sudo ee /etc/jail.buildbot-master.conf

然后将以下内容添加到该文件,该文件将配置名为buildbot-master的主监狱:

/etc/jail.buildbot-master.conf
buildbot-master {
    host.hostname = buildbot-master.localdomain;
    ip4.addr = "lo1|10.0.0.2/24";
    path = "/usr/jails/buildbot-master";
    exec.start = "/bin/sh /etc/rc";
    exec.stop = "/bin/sh /etc/rc.shutdown";
    mount.devfs; # need /dev/*random for Python
    persist;
}

此代码在jail网络接口10.0.0.2上分配固定的主机名和IP地址,并指定根文件系统/usr/jails/buildbot-master 这里使用的exec.startexec.stop值声明jail的startstop服务将像启动进程一样运行,并使用/etc/目录中的启动和关闭脚本。 即使所有进程都已完成, persist选项也可以使jail继续运行。

要了解有关可能的主jail设置的更多信息,请查看jail(8)联机帮助页。

添加此内容后,保存并退出编辑器。 如果您正在使用ee ,请按CTRL+C ,键入exit ,然后按ENTER

master jail的配置文件与全局jail配置文件/etc/jail.conf是分开的。 因此,您需要将主jail的名称添加到已知jail列表中:

sudo sysrc "jail_list+=buildbot-master"

然后启用jail_list列出的任何jail在启动时自动启动:

sudo sysrc jail_enable=YES

如果您的系统上已经配置了使用/etc/jail.conf全局文件的jail,但之前没有使用过jail_list ,启用此设置将意味着只有jail_list中的jail_list会自动启动,您可能想要添加现有的监狱列表。

注意: 如果您使用ZFS文件系统,建议您为jail的文件创建单独的数据集,以便以后轻松备份,克隆或销毁它。 以下命令假定您的zpool具有标准名称zroot 如果您不确定zpool的名称,可以使用以下命令找到它:

zpool list

首先,为所有jails创建父数据集:

sudo zfs create zroot/usr/jails

接下来,创建主jail的数据集:

sudo zfs create zroot/usr/jails/buildbot-master

接下来,我们将创建主jail的根目录并解压缩FreeBSD系统。

确保jail的根文件系统目录存在。 如果您在上一个注释中运行了ZFS命令,那么这已经完成,您可以跳过此命令:

sudo mkdir -p /usr/jails/buildbot-master

然后下载一个FreeBSD 11.2基本系统档案。 我们首先安装根证书以信任下载服务器:

sudo pkg install ca_root_nss

此命令将提示您批准ca_root_nss包的安装。 y然后按ENTER

接下来,下载存档:

fetch -o /tmp/base.txz "https://download.freebsd.org/ftp/releases/amd64/11.2-RELEASE/base.txz"

将此文件的内容解压缩为jail的根文件系统:

sudo tar -x -f /tmp/base.txz -C /usr/jails/buildbot-master

本指南描述了只安装一个工作程序(也包含在jail中)的过程,您将按照与主服务器相同的方式对其进行配置,重新使用刚刚下载的基本系统。 使用ee命令为worker jail打开另一个新配置文件:

sudo ee /etc/jail.buildbot-worker0.conf

将以下内容添加到此文件:

/etc/jail.buildbot-worker0.conf
buildbot-worker0 {
    host.hostname = buildbot-worker0.localdomain;
    ip4.addr = "lo1|10.0.0.3/24";
    path = "/usr/jails/buildbot-worker0";
    exec.start = "/bin/sh /etc/rc";
    exec.stop = "/bin/sh /etc/rc.shutdown";
    mount.devfs; # need /dev/*random for Python
    persist;
}

查看这些行,请注意worker jail如何从master获取不同的主机名,IP和根文件系统目录。 保存并关闭此文件。

同样,因为我们使用单独的jail配置文件而不是全局/etc/jail.conf ,所以将名称添加到已知jail列表中:

sudo sysrc "jail_list+=buildbot-worker0"

注意:与主jail一样,如果使用ZFS文件系统,建议您为worker jail的文件创建单独的数据集。 同样,以下命令创建worker jail的数据集,并假设您的zpool具有标准名称zroot

sudo zfs create zroot/usr/jails/buildbot-worker0

像对主服务器那样提取已经下载的FreeBSD 11.2基本系统:

sudo mkdir /usr/jails/buildbot-worker0
sudo tar -x -f /tmp/base.txz -C /usr/jails/buildbot-worker0

此时,两个jails都已配置并包含一个FreeBSD基本系统,没有安装额外的软件包。 让我们开始监狱:

sudo service jail start

通过使用以下命令列出系统上所有正在运行的jail来检查启动是否成功:

jls

这将返回类似于以下的输出,显示当前在您的服务器上运行的jails:

   JID  IP Address      Hostname                      Path
     1  10.0.0.2        buildbot-master.localdomain   /usr/jails/buildbot-master
     2  10.0.0.3        buildbot-worker0.localdomain  /usr/jails/buildbot-worker0

这证实了jails正在按预期运行。 但是,此时,他们无法访问互联网,这意味着您将无法在其中安装Buildbot软件包。 继续阅读以解决此问题。

第2步 - 为Jails设置Internet访问

虽然主人和工人监狱都在运行,但它们都是从互联网上关闭的。 打开它们是必要的,因为它们必须能够安装包以及彼此通信。

要解决此问题,请将主机的DNS解析程序配置复制到两个jails:

sudo cp /etc/resolv.conf /usr/jails/buildbot-master/etc/resolv.conf
sudo cp /etc/resolv.conf /usr/jails/buildbot-worker0/etc/resolv.conf

接下来,从监狱路由传出的互联网流量。 为此,请使用IPFW(FreeBSD的内置防火墙)来设置NAT(网络地址转换)网络规则。 完成此步骤后,从监狱网络流出的流量将转换为主机的公共IP地址。

如果您遵循先决条件中的Let's Encrypt教程 ,您将已配置防火墙以允许访问您的Web服务器。 在这种情况下,下面的一些步骤将是多余的,但再次运行它们没有任何害处。

警告:对防火墙配置执行错误更改可能导致远程主机无法通过SSH访问,因此确保您可以使用其他方法登录计算机非常重要。 例如,如果您使用的是从DigitalOcean获得的服务器,则可以通过“控制台访问”功能访问它。

要通过此功能启用访问,请使用以下命令设置root密码:

sudo passwd

或者,您可以通过键入以下内容为当前用户设置密码:

passwd

使用以下命令在rc.conf文件中包含预定义的workstation防火墙规则。 workstation规则保护服务器但仍允许基本服务,例如ping主机或动态主机配置协议:

sudo sysrc firewall_type="workstation"

接下来,允许从外部世界访问Web服务器端口。 以下命令允许通过端口22进行流量访问SSH; 端口80 ,允许通过HTTP提供Buildbot; 和端口443 ,允许通过HTTPS提供Buildbot。 如果您使用Let's Encrypt保护您的服务器,则所有这三个端口都是必需的,但如果您还没有并且不打算这样做,那么您可以排除端口443

sudo sysrc firewall_myservices="22/tcp 80/tcp 443/tcp"

允许从任何IP地址访问firewall_myservices指令中指定的端口:

sudo sysrc firewall_allowservices="any"

配置防火墙以在启动时启动:

sudo sysrc firewall_enable=YES

然后使用基本规则启动防火墙。 以下nohup命令可以避免中断防火墙启动,还可以将stderrstdout重定向到临时日志文件。 这很重要,以免将防火墙规则置于不一致状态,这可能会使您的远程主机无法通过SSH访问:

sudo nohup service ipfw start >/tmp/ipfw.log 2>&1

如果您使用的是cshtcsh shell,则此重定向将导致Ambiguous output redirect. 出现在您的输出中。 如果您正在使用这些shell中的任何一个,请运行sudo nohup service ipfw start >&/tmp/ipfw.log以改为启动ipfw

此时,防火墙服务将启动并开始保护主机免受与不安全端口的连接。

注意:如果出现问题或您使用了不同的防火墙类型,防火墙可能还不知道您的SSH连接状态,导致您与服务器的连接停止。 你可以通过在shell中输入内容来找到答案。 在连接失效期间,不会在远程端打印字符。 如果是这种情况,您可以等到SSH注意到超时,或者通过一个接一个地按这些键退出挂机终端: ENTER~

SSH连接关闭后,从本地计算机重新连接到服务器:

ssh freebsd@your_server_ip

如果无法重新建立SSH连接,则需要使用备用方法连接到该连接。 例如,如果您使用的是DigitalOcean Droplet,则可以使用其“控制台访问”功能以root用户身份使用之前设置的密码进行登录。

重新获得访问权限后,停用防火墙:

sudo service ipfw stop

防火墙停止后,您可以自由调试问题。

接下来,您需要确定连接到Internet的主机的网络接口。 通过运行找到这个:

ifconfig

该命令可以输出几个不同的接口。 主机用于连接到Internet的是包含服务器的公共IP地址的那个。 为了说明,以下示例输出显示vtnet0是主机使用的网络接口:

vtnet0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
    options=6c07bb<RXCSUM,TXCSUM,VLAN_MTU,VLAN_HWTAGGING,JUMBO_MTU,VLAN_HWCSUM,TSO4,TSO6,LRO,VLAN_HWTSO,LINKSTATE,RXCSUM_IPV6,TXCSUM_IPV6>
    ether 9a:3e:fa:2a:5f:56
    hwaddr 9a:3e:fa:2a:5f:56
    inet6 fe80::983e:faff:fe2a:5f56%vtnet0 prefixlen 64 scopeid 0x1
    inet public_server_ip netmask 0xffffffc0 broadcast broadcast_ip
    inet 10.10.0.23 netmask 0xffff0000 broadcast 10.10.255.255
    nd6 options=21<PERFORMNUD,AUTO_LINKLOCAL>
    media: Ethernet 10Gbase-T <full-duplex>
    status: active
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> metric 0 mtu 16384
    options=600003<RXCSUM,TXCSUM,RXCSUM_IPV6,TXCSUM_IPV6>
    inet6 ::1 prefixlen 128
    inet6 fe80::1%lo0 prefixlen 64 scopeid 0x2
    inet 127.0.0.1 netmask 0xff000000
    nd6 options=21<PERFORMNUD,AUTO_LINKLOCAL>
    groups: lo
lo1: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> metric 0 mtu 16384
    options=600003<RXCSUM,TXCSUM,RXCSUM_IPV6,TXCSUM_IPV6>
    inet 10.0.0.2 netmask 0xffffff00
    inet 10.0.0.3 netmask 0xffffff00
    inet6 fe80::1%lo1 prefixlen 64 scopeid 0x3
    nd6 options=21<PERFORMNUD,AUTO_LINKLOCAL>
    groups: lo

记下此接口,然后全局配置其名称:

sudo sysrc firewall_nat_interface=vtnet0

打开新的防火墙配置脚本文件:

sudo ee /usr/local/etc/ipfw.rules

然后将以下内容添加到文件中,为IPFW定义防火墙规则:

/usr/local/etc/ipfw.rules
#!/bin/sh
set -e

# Add basic rules as defined by firewall_type, firewall_myservices, etc.
. /etc/rc.firewall

# External network interface
ext_if="$firewall_nat_interface"

# The interface we chose for communication between jails
jail_if="lo1"

for interface in "$ext_if" "$jail_if"; do
    if [ -z "$interface" ]; then
        >&2 echo "Missing network interface"
        exit 1
    fi
    if ! ifconfig $interface >/dev/null 2>&1; then
        >2 echo "No such network interface: $interface"
        exit 1
    fi
done

ipfw nat 123 config if $ext_if
ipfw add 1 allow all from any to any via $jail_if
ipfw add 2 nat 123 ip4 from any to any in via $ext_if
ipfw add 3 skipto 20000 udp from any to any 53 out via $ext_if keep-state
ipfw add 4 skipto 20000 udp from any to any 67 out via $ext_if keep-state
ipfw add 5 skipto 20000 tcp from any to any out via $ext_if setup keep-state
ipfw add 6 skipto 20000 icmp from any to any out via $ext_if keep-state
ipfw add 19999 deny all from any to any
ipfw add 20000 nat 123 ip4 from any to any out via $ext_if
ipfw add 20001 allow ip from any to any

以下是脚本的每个部分的作用:

  • . /etc/rc.firewall . /etc/rc.firewall包含系统预定义的IPFW规则脚本,该脚本根据/etc/rc.conf firewall_*变量的配置添加基本规则。
  • 下一个块检查是否存在所有已配置的接口。 这是为了您的安全,如果配置错误,请尽早退出脚本。
  • ipfw开头的指令添加了实际的防火墙配置和规则。 每个规则 - 添加在以ipfw add开头的行中 - 都有一个数字。 防火墙使用这些数字按顺序评估规则。
    • ipfw nat 123 config if $ext_if创建一个ID为“123”的内核NAT设施,则使用面向公众的网络接口转换流量。
    • ipfw add 1 allow all from any to any via $jail_if允许所有jails之间的流量。 请注意,如果allow规则匹配,则规则处理将停止并允许数据包通过。
    • ipfw add 2 nat 123 ip4 from any to any in via $ext_if转换外部接口上的所有传入IPv4数据包。 这需要作为传出数据包转换的对应部分,如ipfw add 20000...的说明中所述。
    • ipfw add 3 skipto 20000 udp from any to any 53 out via $ext_if keep-state并且以下skipto规则定义允许和考虑用于网络地址转换的出站流量。 如果存在匹配,则通过跳转到执行NAT的规则20000继续处理。
    • 在规则619999 ,有一个故意的差距,其中/etc/rc.firewall脚本插入基本规则。 如果上述skipto规则都不匹配,则基本规则将负责允许不同类型的流量,包括环回,传入ICMP ping消息和firewall_myservices指定的端口。
    • ipfw add 19999 deny all from any to any在所有基本规则之后ipfw add 19999 deny all from any to any并确保非NAT规则处理的结束,基本上不允许所有与先前allow规则不匹配的流量。
    • ipfw add 20000 nat 123 ip4 from any to any out via $ext_if转换外部接口上留下的所有出站IPv4数据包的地址。 这里只需要IPv4,因为在本教程中,jails仅为IPv4地址分配。
    • ipfw add 20001 allow ip from any to any只有你关闭了nat规则的一次通过模式,在这种情况下,处理将在完成规则20000之后继续,要求你明确允许这些数据包通过一个单独的规则。 对于默认的一次通过模式,防火墙将停止nat规则的处理,因此忽略规则20001

保存文件并退出编辑器。

由于我们希望使用ipfw.rules脚本中定义的规则修改预定义的基本防火墙规则,因此我们必须在rc.conf文件中指向此脚本。 以下命令将配置脚本在防火墙启动时执行:

sudo sysrc firewall_script="/usr/local/etc/ipfw.rules"

此设置使用IPFW的内核NAT支持,因此您必须告诉系统在引导时加载相应的内核模块。 此外,无需重启即可立即加载模块:

sudo sysrc -f /boot/loader.conf ipfw_nat_load=YES
sudo kldload ipfw_nat

重新启动防火墙以使扩展防火墙规则脚本生效:

sudo nohup service ipfw restart >/tmp/ipfw.log 2>&1

同样,如果您正在使用csh shell或其衍生产品之一(如tcsh ),请运行sudo nohup service ipfw restart >&/tmp/ipfw.lo而不是上一个命令来重启防火墙:

检查防火墙规则是否已正确加载:

cat /tmp/ipfw.log

这会列出防火墙规则,然后是成功消息:

Flushed all rules.
00100 allow ip from any to any via lo0
[...]
10001 allow ip from any to any
Firewall rules loaded.

您还可以使用以下命令随时查看已安装的防火墙规则:

sudo ipfw list
00001 allow ip from any to any via lo1
00002 nat 123 ip from any to any in via em0
[...]
65535 deny ip from any to any

有了所有防火墙规则,您的监狱现在可以访问互联网。 您可以通过尝试从监狱中下载网页来进行检查:

sudo jexec buildbot-master fetch -q -o- http://example.com/
<!doctype html>
<html>
<head>
    <title>Example Domain</title>
[...]

有了这个,你已经成功地准备好两个jail像常规操作系统一样运行,为每个jail设置Internet访问,并启动它们。 本教程中的后两个步骤将指导您安装master和worker组件,然后将它们作为服务运行。

第3步 - 安装和运行Buildbot Master

Buildbot的组件分为几个包。 您只需要安装py36-buildbot包来运行主组件,但在本指南中我们还将讨论如何安装Web界面包py36-buildbot-www

由于我们使用jails来分割各种组件,首先在主jail中打开一个root shell:

sudo jexec buildbot-master csh

请注意,在本指南中,如果必须在jail shell中执行shell命令块,则使用不同的颜色标记它们。 此外,命令提示符将反映哪些命令必须在其下运行的jail的用户配置文件( root用户或非特权用户buildbot-master用户)。

安装包:

pkg install py36-buildbot py36-buildbot-www

如果您尚未在此jail中安装或使用pkg软件包管理器,它将提示您确认是否允许它自行引导。 为此,请按y ,然后按ENTER 然后,再次输入y ,批准安装Buildbot软件包。

接下来,创建一个常规的,无特权的用户来运行主服务。 以下命令将为该用户分配随机密码,但您不需要记住它,因为主机的root用户(jail之外)可以更改它或成为jail中没有密码的任何用户:

pw useradd -n buildbot-master -m -w random

在此之后,创建将存储配置的主目录:

mkdir /var/buildbot-master

并授予服务用户所有权:

chown buildbot-master:buildbot-master /var/buildbot-master

从现在开始,所有与主要相关的设置和更改都应该作为非特权用户执行,因为这将有助于保持所有权和权限的一致性。

切换到非特权用户:

su -l buildbot-master

然后使用内置的buildbot实用程序在指定的目录中创建目录和配置结构:

buildbot create-master /var/buildbot-master

与Jenkins等其他CI软件不同,Buildbot的行为直接在其配置文件中定义,该文件使用Python进行解释。 这允许简化版本的配置,而使用脚本语言可以自由编写自定义构建配置并扩展现有的Buildbot功能。

Buildbot软件包附带了一个示例主配置文件,您可以将其用作自己配置的模板。 复制示例配置并将其命名为master.cfg

cp /var/buildbot-master/master.cfg.sample /var/buildbot-master/master.cfg

然后使用首选文本编辑器打开基本配置文件。 在这里,我们将使用ee

ee /var/buildbot-master/master.cfg

配置文件包含工作人员连接到主服务器所需的密码。 使用您选择的安全密码替换默认pass 此外,我们的工作者名称将是worker0 ,因此在WORKERSBUILDERS部分中也将example-worker替换为worker0

完成后,您需要编辑的文件部分如下所示:

/var/buildbot-master/master.cfg
####### WORKERS

# ...
c['workers'] = [worker.Worker("worker0", "your_secure_password")]
# ...

####### BUILDERS

# ...
c['builders'] = []
c['builders'].append(
    util.BuilderConfig(name="runtests",
      workernames=["worker0"],
      factory=factory))
# ...

保存并关闭此文件,然后运行exit命令切换回jail中的root用户:

exit

因为示例配置git://github.com/buildbot/hello-world.git Git存储库git://github.com/buildbot/hello-world.git作为其更改源,所以还需要安装Git:

pkg install git-lite

这样,您就创建了主目录结构和配置,但该服务尚未运行。 要手动运行Buildbot,可以从主目录/var/buildbot-master运行命令buildbot start 但是,这不会考虑启动时启动或其他系统范围的配置。 相反,我们将使用rc脚本 ,FreeBSD的标准方法来运行服务。 具体来说,我们将使用service实用程序执行此操作。

出于本教程的目的,我们希望使服务能够在每次启动时运行。 在jails的情况下,这意味着jail的开始事件。 使用以下命令定义主目录的位置:

sysrc buildbot_basedir=/var/buildbot-master

然后指定该服务应在buildbot-master用户下运行:

sysrc buildbot_user=buildbot-master

接下来,启用服务以在jail启动时运行:

sysrc buildbot_enable=YES

然后,启动服务:

service buildbot start

该服务应该从没有错误开始。 您可以通过查看日志文件的内容来验证成功:

tail /var/buildbot-master/twistd.log
2018-06-08 15:14:52+0000 [-] Starting BuildMaster -- buildbot.version: 0.9.11
2018-06-08 15:14:52+0000 [-] Loading configuration from '/var/buildbot-master/master.cfg'
[...]
2018-06-08 15:14:52+0000 [-] BuildMaster is running

要返回主机shell,请从jail shell运行exit

exit

您已成功配置并启动了Buildbot主服务。 第二个组件worker是实际运行构建所必需的。 您将在第二个jail中的下一部分中安装一个worker,然后配置其与主服务的连接。

第4步 - 安装和运行Buildbot Worker

虽然Buildbot主服务器正在运行,但由于您至少需要运行一个工作程序,因此不会发生任何构建。 此步骤与前一步类似,我们将首先设置一个单独的jail,然后安装该服务。 但是,这一次,Buildbot工作组件将连接到主服务器以监听命令并将结果报告回来。

此步骤中的说明几乎与主设置相同,只是工作组件是另一个包的一部分,并且您将进行的唯一配置更改涉及添加有关将其连接到主服务器的详细信息以及有关工作程序本身的一些显示信息。

确保您在主机外壳中,而不是在监狱内。 然后在worker jail中打开一个root shell:

sudo jexec buildbot-worker0 csh

请记住,在本指南中,如果命令块必须在jail shell中执行,则命令块将标记为不同的颜色,命令提示将反映命令应在哪个用户配置文件下运行。

使用以下命令安装Buildbot worker包:

pkg install py36-buildbot-worker

当此命令运行时,它将提示您确认是否要引导pkg软件包管理实用程序。 通过输入y这样做。 它还会要求您确认是否批准了软件包的安装,因此在出现提示时再次输入y

接下来,创建一个常规的,无特权的用户来运行工作服务:

pw useradd -n buildbot-worker -m -w random

然后创建worker目录。 这是存储工作者配置,显示信息和构建目录的位置:

mkdir /var/buildbot-worker

授予服务用户所有权:

chown buildbot-worker:buildbot-worker /var/buildbot-worker

从现在开始,所有与工作人员相关的设置和更改都应该作为非特权用户执行。 为此,切换到buildbot-worker用户:

su -l buildbot-worker

使用内置的buildbot-worker实用程序在/var/buildbot-worker目录中创建目录和配置结构。 指定我们在上一步中选择的主监狱的IP地址 - 10.0.0.2 - 因此工作人员可以连接到它并将pass替换为您在主配置文件中定义的密码:

buildbot-worker create-worker /var/buildbot-worker 10.0.0.2 worker0 'pass'

要完成设置,请填写有关系统管理员和工作人员目的的一些详细信息:

echo 'Your Name <your.email.address@example.com>' >/var/buildbot-worker/info/admin
echo 'Description of this worker' >/var/buildbot-worker/info/host

在此之后,运行exit命令切换回jail中的root用户:

exit

因为示例配置克隆了Git存储库git://github.com/buildbot/hello-world.git来构建示例项目,所以还需要在这个jail中安装Git。 注意Buildbot master如何还需要Git,因为更改源在master上运行。 此外,构建器使用名为trial的测试运行器,它是py27-twisted包的一部分,因此请将其与git-lite一起安装:

pkg install git-lite py27-twisted

用于运行worker的内置机制是buildbot-worker start ,它应该从worker目录/var/buildbot-worker 但是,这不会启动启动时启动,也不能确保它将在正确的用户下运行。 正如您对主服务器所做的那样,通过使用service实用程序来利用打包的rc脚本来管理服务。

使用以下命令定义worker目录以及运行服务的用户和组:

sysrc buildbot_worker_basedir=/var/buildbot-worker
sysrc buildbot_worker_uid=buildbot-worker
sysrc buildbot_worker_gid=buildbot-worker

接下来,启用服务以在jail启动时运行:

sysrc buildbot_worker_enable=YES

在撰写本文时, py36-buildbot-worker软件包有一个阻止服务启动的错误 (请参阅此错误报告 )。 在修复此问题之前,您需要通过从buildbot-worker jail运行以下命令来手动修补启动脚本:

sed -i '' 's|command="/usr/local/bin/twistd"|command="/usr/local/bin/twistd-3.6"|' /usr/local/etc/rc.d/buildbot-worker

最后,启动worker组件:

service buildbot-worker start

该服务应该从没有错误开始。 您可以通过查看日志文件的最新条目来验证它是否成功:

tail /var/buildbot-worker/twistd.log

如果服务成功启动,则显示Connected to 10.0.0.2:9989; worker is ready的消息Connected to 10.0.0.2:9989; worker is ready Connected to 10.0.0.2:9989; worker is ready将出现在日志文件中。 如果您在此步骤中之前忘记指定新密码,则该服务将无法连接到主服务器。 在这种情况下,编辑文件/var/buildbot-worker/buildbot.tac ,然后运行service buildbot-worker restart以解决此问题。

一旦服务正确启动,通过从jail shell运行exit命令exit到主机shell:

exit

有了这个,第二个jail已经配置好,你拥有运行Buildbot所需的所有基本组件。 为了方便您的用户使用,建议您还设置基于Web的用户界面。 这样做将允许您控制Buildbot并更方便地查看构建结果。

第5步 - 设置Buildbot Web界面

Buildbot具有基于Web的用户界面,可显示构建概述和结果,并允许您在配置“强制”调度程序时手动触发构建,如示例配置中的情况。

您的主配置已设置www组件以通过端口8010提供HTTP。 在生产设置中,您不会提供未加密的HTTP或将非标准端口8010打开到外部,因为这会使您的系统出现安全漏洞。 Also, the web interface can be served from any URL path, which means that it does not need to be the only application on your domain. For example, you could serve build outputs or logs to your users. Hence, we will serve the UI to users with a separate web server – Nginx – in order to support HTTPS, protect internal ports, and gain the ability to serve other content alongside the Buildbot web interface.

Open up the Nginx configuration file for editing:

sudo ee /usr/local/etc/nginx/nginx.conf

Add the following highlighted location blocks within the file's existing server block:

/usr/local/etc/nginx/nginx.conf
 . . .
http {
 . . .
    server {

 . . .
        location / {
            root /usr/local/www/nginx;
            index index.html index.htm;
        }

        location /buildbot/ {
            proxy_pass http://10.0.0.2:8010/;
        }
        location /buildbot/sse/ {
            # proxy buffering will prevent sse to work
            proxy_buffering off;
            proxy_pass http://10.0.0.2:8010/sse/;
        }
        # required for websocket
        location /buildbot/ws {
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
            proxy_pass http://10.0.0.2:8010/ws;
            # raise the proxy timeout for the websocket
            proxy_read_timeout 6000s;
        }

        error_page 500 502 503 504 /50x.html;
        location = /50x.html {
            root /usr/local/www/nginx-dist;
        }

                . . .

    }
}

This configuration forwards all requests below the URL path /buildbot/ to the web interface and enables WebSocket support, which is used by the interface to receive updates that it will display such as the log output of a running build.

Save and close the Nginx configuration file. Then, reload the Nginx service:

sudo service nginx reload

Open up your preferred web browser on your local machine and access the Buildbot web interface by going to the following URL:

https://example.com/buildbot/

Alternatively, if you did not set up a domain name for your server, you'll instead need to enter your server's public IP address, http:// your_server_ip /buildbot/ .

When you arrive at the interface, you will see an overview similar to the following:

Web interface overview

The main page may show a warning that the Buildbot URL is misconfigured. This occurs if the hostname provided in the nginx.conf file mismatches what's listed in master Buildbot configuration. Since build result emails contain links to the Buildbot web interface by default, the master must know the correct URL where it can be reached.

Note that, in our example configurations, we have not set up this email service. If you're interested in configuring this, see Buildbot's documentation about reporters for more information:

With that said, to resolve the warning and send emails that contain the correct content, edit the Buildbot master configuration to point to your domain.

sudo ee /usr/jails/buildbot-master/var/buildbot-master/master.cfg

Find the line that begins with c['buildbotURL'] and replace the default option with your domain name, followed by /buildbot/ :

/var/buildbot-master/master.cfg
####### PROJECT IDENTITY
# ...
c['buildbotURL'] = 'https://example.com/buildbot/'
# ...

保存并关闭文件。 Then, to apply the new configuration, reload the buildbot service:

sudo jexec buildbot-master service buildbot reload

Refresh the Buildbot web interface in your browser, and the warning will disappear.

Continuous Integration servers often serve other purposes besides CI. For example, a CI server might serve build outputs for FreeBSD packages or logs over HTTPS. It's therefore recommended that you reserve the URL path /buildbot/ for the web interface. This allows you to host more applications under different paths. For the moment, we will create a simple home page that redirects to the web interface. You can add more links once you implement more use cases for the web server.

Run the following command to open an index file in your web root – replacing example.com with your own domain – to create an automatic redirect to the Buildbot web interface:

sudo ee /usr/local/www/example.com/html/index.html

Note: If you did not follow the prerequisite Nginx tutorial and create a new web root for your Nginx configuration, you will instead need to create an index file under the default Nginx web root by running sudo ee /usr/local/www/nginx/index.html .

Replace any existing file content with the following lines:

/usr/local/www/nginx/index.html
<html>
<body>
<a href="/buildbot/">buildbot</a>
<script>
    // Auto-redirect while only the web interface should be served
    window.location.href = "/buildbot/";
</script>
</body>
</html>

Save and close this file, then enter your domain name or IP address in the URL bar of your browser. It should automatically redirect you to the Buildbot interface.

You've finished the installation of all the Buildbot components, including its web-based control and viewing interface. With all of this in place, let's run an actual build as specified in the sample configuration which we have set up for the master.

The builder has a "force" scheduler configured by default, which allows you to trigger your first build. In the web interface, click Builds > Builders > runtests > force > Start Build and see how the build runs. If you see any errors, check the server's internet connection and whether all the dependent packages were installed as described previously.

Sample build success screenshot

You can find the artifacts from this build (and others) by looking at the contents of the build directory:

ls /usr/jails/buildbot-worker0/var/buildbot-worker/runtests
build

You have successfully configured a permanently running and versatile CI system and can now begin implementing your own builds.

结论

By completing this tutorial, you practiced creating FreeBSD jails and learned some of the basics of the Buildbot automation framework, resulting in a ready-to-use installation. To learn more about Buildbot and its configuration, we encourage you to read through the official Buildbot documentation .

From here, you're free to implement your own Continuous Integration and automation practices. In order to have a secure, stable and performant setup for production use, you may want to take these optional configuration steps:

  • Use HTTPS only (as explained in this tutorial)
  • In the tutorial, you used a separate, host-internal network lo1 for your jails. In this guide, we used ipfw for NAT purposes, but other firewalls have this feature as well. Check out the FreeBSD documentation about available firewalls . Unless your use case requires otherwise, it is recommended to keep the jail network inaccessible from the outside through the use of NAT or other mechanisms.
  • Buildbot's web interface does not require a login or check user permissions by default. To implement these, you will have to enable user authentication .

分享按钮