Run Your Own OBS 编译系统
Lapin Gris Lv3

OBS(Open Build Service)是一个由 SUSE 开源的操作系统发行版的构建系统,可以用来创建和分发软件包。OBS支持几乎所有的主流发行版的包,比如说 SUSE系,RedHat系,Debian系,Arch系等等。

下载

安装 OBS 最简单的方式就是使用 openbuildservice 网站提供的镜像(iso/qcow2/vmdk/vdi),将镜像部署机器上就获得一个 OBS 实例。

通常情况下,使用 SUSE 制作好的虚拟机镜像是最省时间的,比如,

  • 使用 qemu-kvm, 下载 qcow2 镜像
  • 使用 VMware, 下载 vmdk 镜像
  • 使用 virtualbox, 下载 vdi 镜像

也可以使用 SUSE 提供的 ISO 镜像重新安装一台 OBS 实例,缺点是需要等待 ISO 安装完成才能得到一台 OBS 实例,使用虚拟机镜像,启动后就可以获得 OBS 实例,节省了 ISO 的安装时间。

启动

在 Linux 平台部署 OBS 应该是大多数人的需求。当然也很简单,Linux 平台下大家经常使用 libvirt/qemu 组合创建虚拟机,使用 virt-install 会比写 libvirt xml 或写 qemu 命令行简单一些

可以使用 virt-install 命令行快速创建一个 OBS 实例,

#!/usr/bin/bash

VM_NAME="OBS"
DISK="obs-server.x86_64-qcow2.qcow2"

virt-install \
--name "${VM_NAME}" \
--memory 32768 \
--vcpus 16 \
--import \
--os-variant opensuse15.3 \
--disk "${DISK}" \
--network network=default,model=virtio \
--graphics none \
--virt-type kvm

注:cpu 和 内存可以根据 host 机器的实际 cpu 和内存进行调整,示例是 16 核 32g 的配置,网络是 libvirt 创建的默认网络 default

默认的登录名和密码分别是 root / opensuse 。登录方式为, virsh console <VM_NAME>.

Host 配置端口转发

注:如果你是使用笔记本等拥有显示器的 host 机器,忽略本步骤。

注:如果你能为这台 OBS 实例分配单独的 IP,忽略本步骤。

OBS 实例安装完成,为了能够在浏览器上访问这台 IP 为 192.168.x.x 的实例页面。我们需要在 Host 上配置端口转发,将 OBS 实例的流量转发到 host 机器上对应端口。

使用 nginx 实现端口转发,

修改 /etc/nginx/nginx.conf, 添加 server 转发规则,

配置 443 端口转发,

server {
listen 443 ssl;
server_name _; # 不需要填,使用 _ 代替即可

ssl_certificate /etc/nginx/ssl/nginx.crt;
ssl_certificate_key /etc/nginx/ssl/nginx.key;

ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;

ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;

location / {
proxy_set_header Host $host;
proxy_set_header X-Real-Ip $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_pass https://192.168.122.100:443; # 转发目标地址
}
}

443 转发需要配置证书的,本地使用 openssl 自签一个,一直回车即可,

mkdir /etc/nginx/ssl
openssl req -x509 -nodes -days 36500 -newkey rsa:2048 -keyout /etc/nginx/ssl/nginx.key -out /etc/nginx/ssl/nginx.crt

解释:转发配置的是将 host 443 端口的 http 流量全部转发到 http://192.168.122.100:443

为了简单,我这里选择的是同端口映射,也就是 443 映射 443,也可以把 listen 443; 换成 listen 4433; 等其他端口。那么访问时候,带上端口号即可。

配置 80 端口转发(可以不配置,OBS 不需要这个端口),

server {

listen 80;
server_name _;
location / {

proxy_pass http://192.168.122.100:80;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}

配置完成后, 执行 systemctl reload nginx reload NGINX

现在打开浏览器,可以看到 OBS 的页面了。

配置

OBS 镜像首次启动至少需要 10 分钟,使用 vnc 连接服务器就可以看到 OBS 实例的启动卡在这个地方,待会会介绍这里进行的实际是 OBS 读取 fqdn,默认超时时间是 10 mins (shit code…)

A start job is running for OBS API Setup (8min 34s / no limit )

journal 看日志可以看到,setup-appliance.sh 脚本在持续等待 fqdn,而且超时时间设置为 600 秒,也就是 10mins,感觉时间设置的过长了,如果本地网络比较好的话,改下脚本将超时时间设置为 十几秒就够了
image.png

/usr/lib/obs/server/setup-appliance.sh

function get_hostname {

if [[ $1 && $BOOTSTRAP_TEST_MODE == 1 ]];then
FQHOSTNAME=$1
else
TIMEOUT=600
while [ -z "$FQHOSTNAME" -o "$FQHOSTNAME" = "localhost" ];do
FQHOSTNAME=`hostname -f 2>/dev/null`
TIMEOUT=$(($TIMEOUT-1))
[ "$TIMEOUT" -le 0 ] && break
echo "Waiting for FQHOSTNAME ($TIMEOUT)"
sleep 1
done
fi
...
}

超时时间设置为 600 s ,在目前的网络条件下可能是没有必要的,改为十几秒足够了
注:在目前版本的 OBS Git 仓库上,超时时间已经被调整为 30 s 了(functions.setup-appliance.sh),感觉这才是比较合理的值

设置 ssh 服务开机自启

默认 OBS 2.10 镜像是没有开启 ssh 远程连接的,推荐开启,方便远程登录

systemctl enable --now sshd

云厂商虚拟机可以先通过控制台的 vnc 连接到服务器,执行以上命令。之后可以通过 ssh 连接 OBS 实例了,OBS 镜像默认的登录用户名和密码是 root/opensuse 。

现在针对各个云服务器的攻击非常多,保持默认密码很容易被攻击者入侵服务器,导致服务器成为肉鸡。。
为了安全起见,在以下几种方案里选择一个方式保护自己的云服务器
1、禁用密码登录、采用公钥登录,目前最安全的方案
2、禁用 root 远程登录,新增一个用户用于远程登录,修改默认 ssh 端口号,安全性适中
3、不禁用 root 远程登录,但是修改一个复杂一点的密码,修改默认 ssh 端口号,安全性弱

更换国内镜像源

OBS 默认的镜像源速度不是很理想,换成国内源加快安装软件包的速度

# 禁用已有所有镜像源
zypper mr -da

# 使用 USTC 的软件源
zypper ar -fcg https://mirrors.ustc.edu.cn/opensuse/distribution/leap/\$releasever/repo/oss USTC:OSS
zypper ar -fcg https://mirrors.ustc.edu.cn/opensuse/distribution/leap/\$releasever/repo/non-oss USTC:NON-OSS
zypper ar -fcg https://mirrors.ustc.edu.cn/opensuse/update/leap/\$releasever/oss USTC:UPDATE-OSS
zypper ar -fcg https://mirrors.ustc.edu.cn/opensuse/update/leap/\$releasever/non-oss USTC:UPDATE-NON-OSS
zypper ar -fcg https://mirrors.ustc.edu.cn/opensuse/update/leap/\$releasever/sle USTC:UPDATE-SLE

注:SUSE 系列 OS 存放 repo 文件的目录是/etc/zypp/repos.d

数据分盘(强烈推荐)

如果你是想搭建一个试一下或者自己使用,并不是用于企业的生产环境,可以跳过这一步。
OBS 作为一个打包系统,数据虽然不是特别的重要,但是还是建议将 OBS 的数据分盘存储。
在介绍数据分盘的逻辑前,先介绍一下 OBS 镜像本身,下载下来的 OBS 镜像安装好后是一个 openSUSE leap 15.3 系统,我们的 OBS 服务安装在 openSUSE 操作系统上的,更具体来说,是安装在/srv 目录下,所以数据分盘的逻辑就很显而易见了。将 OBS /srv 目录单独放到一个数据盘上,剩下的作为系统盘。

分盘操作原理

我们可以很轻松的联想到,单独给我们 OBS 虚拟机通一块数据盘,将数据盘挂在到 /srv 分区,将原有的数据拷贝到数据盘上就可以实现 OBS 服务与系统盘脱钩。

查看磁盘的情况

查看系统的磁盘情况,此处挂了一块 100G 的磁盘,被 Linux 系统标识为 /dev/vdb

注:这里的 vda 是 /dev/vda,是系统盘,vda1 是在系统盘上分区,这里分区设置是将整个磁盘的空间全部分给 vda1,这里没必要讲磁盘分区。官方提供的 OBS 镜像里做了分区,那就保持这样就好了,系统盘和我们的数据分盘操作关系不大。

# lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sr0 11:0 1 368K 0 rom
vda 253:0 0 100G 0 disk
`-vda1 253:1 0 100G 0 part /
vdb 253:16 0 100G 0 disk

磁盘需要格式化为文件系统

将单独的数据盘 vdb 全盘格式化为 ext4 文件系统,此处不需要将磁盘分区为 1,2,3。(可以,但没必要)

mkfs -t ext4 /dev/vdb

将格式化好的磁盘挂在到 /mnt 目录,(挂载到 /mnt 目录下是为了拷贝数据用的,算是个临时目录 )接着将 /srv 目录下的所有文件同步到 /mnt 目录,也就是同步到单独的数据盘上

mount /dev/vdb /mnt
rsync -av --progress /srv/ /mnt

设置开机挂载

在 systemd 启动 OBS 服务之前,我们需要将我们的数据盘 mount 到 /sev 目录下,隐藏原有的文件。这样当 systemd 拉起 OBS 服务是时候,读取的数据就是从
通过 lsblk -f 命令查询 /dev/vdb 磁盘的 uuid 号,将数据盘开机挂载到 /srv 目录, Linux mount 会隐藏原有目录的内容,不用担心 /srv 目录非空,OBS 运行过程中对 /srv 目录下的文件读写会写到系统盘上的位置,这种情况是不会发生的,这个是文件系统的实现,mount 过后,对 /srv 路径下所有文件读写都会被文件系统重定向到 mount 的数据盘上。
mount 之后,这样每次 OBS 服务启动时读取的数据都是从单独的数据盘上读的,这样实现数据分离。

# cat /etc/fatab
UUID=bedc29dd-b6c7-408d-917e-05d13111e056 / ext4 defaults 1 1
UUID=ba63af21-95d4-4fcc-b77e-a4e8de89280c /srv ext4 defaults 1 1

这里有一个问题,要不要在上一步的 rsync 过后,将原有的 /srv 目录清空,其实是可以的,但是没有必要。

此时我们已经完成了 OBS 的数据分盘。

为 OBS 添加 build target

默认情况下,新创建的 OBS 是没有 build target。添加了对应发行版的 build target 后,就可以为对应的发行版编译软件包了。
我们查看 https://build.opensuse.org 网站上,发现拥有许多 build target,比如说 CentOS 7, CentOS 8,CentOS Stream,SUSE SLE,openSUSE,AlmaLinux,RockyLinux,Debian 等等。

推荐先创建一个 Meta 项目,在以这个 Meta 项目作为基石,创建 AlmaLinux:9 的编译环境。

1) 为发行版编译项目创建一个 meta 项目

创建 meta 项目是必要的,后面会介绍。

osc meta -e prj Meta:AlmaLinux:9
<project name="Meta:AlmaLinux:9">
<title>Meta AlmaLinux 9</title>
<description/>
<person userid="Admin" role="maintainer"/>

<repository name="standard">
<arch>x86_64</arch>
</repository>

</project>

编写好项目的 build target 之后,会自动创建如下目录
/srv/obs/build/AlmaLinux:9/standard/x86_64

2) 添加编译依赖 rpm 包(BuildRequire )

对于 AlmaLinux 来说,以 repo粒度来说最小化的依赖包是 baseos 和 appstream 里面的包。但是通常情况下,这些包是不够用的,比如说编译 kernel, 还需要 crb 和 epel 里的包。
这里推荐将发行版的,baseos, appstream, crb, epel 仓库的对应 arch 的包都下载到 :full 路径下作为依赖。

mkdir /srv/obs/build/Meta:AlmaLinux:9/standard/x86_64/:full

cp <needed-packages-to-build-packages>/*.rpm /srv/obs/build/Meta:AlmaLinux:9/standard/x86_64/:full/
chown -R obsrun.obsrun /srv/obs/build/Meta:AlmaLinux:9

3) 添加项目的配置文件

没添加 project config 之前,项目是处于 broken 状态的
obs-broken-status

添加也很简单,将 openSUSE 网站的 project conf 复制过来即可
https://build.opensuse.org/projects/AlmaLinux:9/prjconf

4) 扫描项目解决依赖

obs_admin --rescan-repository Meta:AlmaLinux:9 standard x86_64

执行完 rescan-repository 命令后,如果出现 :repodone 文件代表文件扫描完毕
如果配置不完整,查下目录下的文件里面的内容,可以看出报错出在哪里

# ls /srv/obs/build/AlmaLinux:9/standard/x86_64
:bininfo :depends :full :full.solv :packstatus :repodone :repoinfo :schedulerstate

5)以 meta 项目为基础创建发行版编译项目
添加完 build target 之后,就可以为这个发行版构建软件包了
obs-public-status

5)如法炮制,创建一个用于发行版编译的项目

前面 4 个步骤中,我们已经创建了 一个 Meta 项目,但是这个项目并不能作为发行版编译的项目,需要以 meta 项目为模板创建用于发行版编译的项目
因为在 OBS 里所有的项目都是一样的,这里和创建 meta 项目一样创建一个用于发行版编译的项目。
这里的区别是,repository 标签的写法,我们复用了之前创建的 meta 项目。创建完成,扫描仓库解决依赖后就可以正式用作编译的仓库了。

osc meta -e prj AlmaLinux:9
<project name="AlmaLinux:9">
<title>AlmaLinux 9</title>
<description>AlmaLinux 9 distribution project.

</description>
<person userid="Admin" role="maintainer"/>
<repository name="standard">
<path project="Meta:AlmaLinux:9" repository="standard"/>
<arch>x86_64</arch>
</repository>
</project>

obs_admin --rescan-repository AlmaLinux:9 standard x86_64

现在可以为 AlmaLinux 编译软件包了,如下图
obs-build-success-status

已知问题

OBS 使用 qemu-kvm 作为构建环境会构建失败

OBS 默认采用 qemu-kvm 创建的虚拟机作为编译环境,采用 qemu-kvm 作为构建方式很多情况下会报错,导致构建失败。这个问题没有仔细研究过,有一个 workaround 可以比较简单的解决这个问题,那就是将 qemu-kvm 命令重命名,然后重启 obsworker.service 。

mv /usr/bin/qemu-kvm /usr/bin/qemu-kvm.bak
systemctl restart obsworker.service

waiting for 8 compliant workers (8 of them bad)

执行以下命令可以解决这个问题

obs_admin --drop-badhosts

warning: Signature not supported. Hash algorithm SHA1 not available

因为 OBS 默认采用 SHA1 算法为 RPM 包签名,在一些系统上比如 RHEL 9 上 sha1 算法被弃用。因为 OBS 为了保证兼容性,默认的签名算法依然是 sha1。
通过编辑 sign.conf 文件可以将签名算法改为 sha256。

# vim /etc/sign.conf
user: obsrun@localhost
server: 127.0.0.1
allowuser: obsrun
allow: 127.0.0.1
hash: sha256
phrases: /srv/obs/gnupg/phrases

obs 页面点击下载会被重定向回首页

修改 external_frontend 可以解决这个问题。

# vim /srv/www/obs/api/config/options.yml

external_frontend_host: <ip or hostname>
external_frontend_port: 443
external_frontend_protocol: https

Reference

1、Archive:Build Service adding build targets
https://en.opensuse.org/Archive:Build_Service_adding_build_targets
2、Local OBS doesn’t build anymore (waiting for 4 compliant workers (4 of them bad))
https://lists.opensuse.org/archives/list/buildservice@lists.opensuse.org/thread/EGWPVEZXSBAB3TTFKPERUNBU5SWECYNB/
3、Enhancing RHEL Security: Understanding SHA-1 deprecation on RHEL 9
https://www.redhat.com/en/blog/rhel-security-sha-1-package-signatures-distrusted-rhel-9
4、man sign.conf
5、初始化Linux数据盘
https://support.huaweicloud.com/qs-ecs/zh-cn_topic_0085634797.html
6、openSUSE 源使用帮助
https://mirrors.ustc.edu.cn/help/opensuse.html