目录
项目背景
项目要求
项目开发过程
1、apt服务器的搭建
2、实现自定义指定源文件列表来实现apt update更新
3、实现软件启动时自动更新
4. source.list中镜像源地址的格式
项目开发的难点/坑点
总结
项目背景
前面写过一篇“利用Nginx搭建一个apt服务器”, 但只是前期铺垫工作,只适合用于简单的场景,并没有细化,简单实现能用apt安装就可以了。现在我们来细化一下,添加一下要求,使其更加实用,适用于大型项目。
项目要求
- 远程服务器(实际应用会部署在阿里云上)搭建apt服务器,建立软件包管理仓库,以提高软件包下载速度,并保存有软件包仓库的地址、发行版代号、组件等信息;
- 本地可用apt install来安装软件;
- 本地可用apt update来检查是否有软件更新;
- 检查是否有更新或更新软件时,只涉及本apt服务器所在的源地址,不涉及其他源地址;
- 每当软件启动时,会自动检查更新,当有更新时自动更新;
项目开发过程
1、apt服务器的搭建
首先需要在服务器上建立一个本地软件包镜像仓库,而建立仓库有多种手段,可以借助工具来实现,比如:apt-mirror 、reprepro
和aptly
等都是可以的,选其一即可。在此我选择了reprepro,它是一个由Debian项目提供的开源软件包管理工具,用于构建和管理Debian软件包仓库,可以帮助用户轻松地创建本地APT仓库并进行软件包的管理、发布和分发。
- 安装
reprepro
:
首先,在您的服务器上安装reprepro
软件包管理工具。您可以使用以下命令进行安装:
$ sudo apt update
$ sudo apt install reprepro
- 创建
reprepro
仓库:
创建一个目录用于存储reprepro
的仓库,例如/var/www/html/apt-repository
。
进入到reprepro
仓库目录,并使用以下命令初始化reprepro
仓库
$ mkdir /var/www/html/apt-repository
$ cd /var/www/html/apt-repository
$ mkdir conf
$ cd conf
$ touch distributions
distributions
用于指定软件包仓库的不同发行版(distribution)的信息。
编辑distributions
配置文件并添加必要的信息。您可以参考下面的示例配置文件内容:
Origin: Your_Origin // 指定软件包仓库的来源,通常是您或您的组织的名称
Label: Your_Label // 给软件包仓库设置一个标签,用于标识仓库
// 每个发行版都有一个代号,比如
stable
、testing
、unstable
等Codename: Your_Codename
// 指定软件包支持的架构,比如
amd64
、i386
、arm64
等Architectures: Your_Architectures
// 指定软件包仓库的组件,比如
main
、contrib
、non-free
等Components: main
Description: Your_Description
// 指定用于对软件包进行签名的GPG密钥ID
SignWith: YOUR_KEY_ID
GPG密钥的生成:
gpg --gen-key
按照提示创建你的GPG密钥。
gpg --list-keys //显示密钥
gpg --list-keys --keyid-format LONG //显示密钥和密钥ID
密钥ID通常是8byte的16进制组合。
确保配置文件中的信息正确无误后,再次尝试使用以下命令初始化reprepro
仓库:
$ cd /var/www/html/apt-repository
$ reprepro export
执行后,目录下应该会有以下文件生成:
$ ls
conf db dists lists
现在仓库初始化完成。
-
添加软件包到
reprepro
仓库:
将您的软件包文件拷贝到服务器的某一
目录下,例如/home/w/publish/ 。
使用以下命令将软件包添加到reprepro
仓库中:
$ reprepro includedeb YourCodename
/home/w/publish/package.deb
其中,YourCodename
为您在配置文件中设置的Codename,当然
这里也可以写软件包镜像仓库的路径,但不如写codename来的方便。
-
发布版本:
使用以下命令发布版本到reprepro
仓库中:
$ reprepro export
执行的时候会需要再次输入密钥的短语,确认后即可。
可以看一下目录架构:
$ tree
成功后会生成一个“pool”的文件夹,存放安装包。
-
配置
Nginx
:
安装Nginx
并配置为代理reprepro
仓库的静态文件。您可以使用以下命令安装Nginx
:
$ sudo apt-get install nginx
编辑Nginx
的配置文件/etc/nginx/sites-available/default
,添加类似以下配置来代理reprepro
仓库:
server {
listen 80;
root /var/www/html/apt-repository;
server_name _;
location / {
autoindex on;
}
}
nginx默认的路径是“/var/www/html”,将其改为仓库的路径,或者在location中使用alias命令:
location / {
alias /var/www/html/apt-repository;
autoindex on;
}
保存配置文件并重启Nginx
服务:
$ sudo systemctl restart nginx
-
本地配置访问APT服务器:
现在,您可以通过浏览器或者使用apt-get
命令来访问您搭建的APT服务器。
在客户端的/etc/apt/sources.list
文件中添加以下行来指向您的APT服务器:
deb http://192.168.2.103/ codename main
codename
为您的发行版名称,main
为您的软件包组。
sudo apt update
之后就可以通过
sudo apt install xxx
来安装软件了。
2、实现自定义指定源文件列表来实现apt update更新
下面说一下实现自定义指定源文件列表来实现apt update更新,在 /etc/apt/sources.list 定义了软件源外,/etc/apt/sources.list.d 目录下的文件中也会定义一些第三方的软件源或者叫 PPA(Personal Package Archives)。如果将apt服务器的源地址写在source.list 文件中的话,每次update的时候都要将系统上所有的镜像源全都检查一遍,耗时较多,并不符合我们此次的项目的目的。如果使用软件启动时采用自检查更新的方案的话,这将会造成软件启动慢、客户体验不佳的问题。因此,单独设置apt服务器源地址是有必要的。
-
在
/etc/apt/sources.list.d/
目录下创建一个新的源文件,比如mirror.list
,可以使用以下命令创建:$ sudo touch /etc/apt/sources.list.d/mirror.list
-
编辑这个新创建的源文件
mirror.list
,并添加您想要使用的镜像源地址,例如:deb http://your-mirror-server/ubuntu bionic main
-
确保
mirror.list
中的源地址格式正确,包括deb或者deb-src开头,并且每行只包含一个源地址。 -
运行
apt update -o Dir::Etc::sourcelist=/etc/apt/sources.list.d/mirror.list
命令来更新APT,这样APT会按照mirror.list
中的源地址来更新软件包信息。
3、实现软件启动时自动更新
程序启动时需要启动的脚本:
#!/bin/bash
# 执行 apt update 命令检查更新
apt update -o Dir::Etc::sourcelist=/etc/apt/sources.list.d/mirror.list > /dev/null
# 检查 apt update 命令的返回状态
if [ $? -eq 0 ]; then
echo "检查更新成功"
# 检查是否有可用更新
if apt list --upgradable | grep -qE '\[upgradable\]'; then
echo "发现可用更新,执行升级操作"
apt upgrade -y
echo "软件包已升级"
else
echo "没有可用更新"
fi
else
echo "检查更新失败,请检查网络连接或软件源配置"
fi
软件启动时,采用自动检查是否有更新,如果有更新,则自动更新的方案避免了用户手动更新的问题,毕竟不能要求所有用户都会使用linux系统。
4. source.list中镜像源地址的格式
-
源地址的格式:
- 源地址通常以
deb
或deb-src
开头,分别表示二进制软件包和源代码软件包。 - 紧接着是软件包的下载地址,可以是HTTP、FTP等协议的URL。
- 接下来是发行版的代号,例如Ubuntu中的版本代号(如bionic、focal等)。
- 最后是软件包的组件,如main、restricted、universe、multiverse等。
- 源地址通常以
-
源地址的组成:
- 主要组件(main):包含由官方团队维护的自由软件。
- 受限组件(restricted):包含受限制的软件,不是完全自由的。
- 宇宙组件(universe):包含社区维护的自由软件。
- 多元宇宙组件(multiverse):包含非自由软件。
项目开发的难点/坑点
- 问题1,将软件包文件包含进仓库的时候报错:
$ reprepro includedeb immortal
/home/w/publish/benan-test-gateway_1.0.2_amd64.deb
// error
“no section given for '.deb',skipping”
“no priority given for '.deb',skipping”
这个并不是distributions
配置文件的设置问题,不要被误导,这其实是因为.deb安装包打的有问题,.deb安装包打包的时候,其control文件的设置中缺少了“section”、“priority”属性。
control 文件的属性一般如下,
package: packagename // 软件包的名称
version: 1.0.2 // 软件包的版本号,通常遵循特定的版本号规范,此属性必须有
architecture: amd64 // 软件包适用的架构,例如
amd64
、i386
等,此属性必须有maintainer: name <email> //软件包的维护者信息,包括姓名和邮箱地址,可不写
depends: dpkg //软件包的运行时依赖关系,没有的话可以不写
recommends: npm,sudo // 软件包的建议性依赖关系,可不写
description: 描述信息,随便写
//软件包所属的分类,用于组织软件包在软件包管理器中的显示,此属性必须有
section: default
// 软件包的优先级,指定软件包在安装时的优先级,此属性必须有
priority: optional
homepage: https://xxxx/ //软件包的官方网站或主页链接,可不写
conflicts: xxx //软件包的冲突关系,可不写
所以,打包.deb安装包的时候尽量使用规范的写法哦。
- 问题2,
W: GPG 错误:http://192.168.2.103 immortal InRelease: 由于没有公钥,无法验证下列签名: NO_PUBKEY 密钥ID
由于apt服务器的软件包镜像仓库使用了GPG加密,该加密为非对称加密,有公钥和私钥。该问题是因为系统没有该仓库的公钥用于验证软件包的签名。所以需要将其公钥下载下来并导入本地软件包仓库。
使用下面的命令来下载公钥:
sudo apt-key adv --keyserver http://192.168.2.103 --recv-keys 密钥ID
其中,“http://192.168.2.103” 替换成apt服务器的地址,“密钥ID”替换成真实的密钥ID。
如果不能下载的话,可以手动将密钥文件下载到本地,然后导入:
gpg --output public_key.asc --armor --export 密钥ID //生成密钥文件
将生成的.asc公钥文件传输到本地,然后
sudo apt-key add <public_key.asc>
然后,
sudo apt update
就可以了。
总结
这样的搭配才是最实用的。
动手操作才会发现更多的细节。