步骤一、创建子目录
$ mkdir -p ./packages/
步骤二、创建配置信息文件 meta.json
{
"container_name": "aptly-repo-builder",
"remote_server": "xx.xx.xx.xx",
"remote_dir": "<remote-dir>",
"docker_image": "<local-target-docker-image-address>",
"distribution": "latest",
"component": "main"
}
步骤三、创建 build.sh 文件
#!/usr/bin/env bash
set -e
# 日志函数
# 日志颜色代码:URL_ADDRESS# 日志颜色代码:https://misc.flogisoft.com/bash/tip_colors_and_formatting
# 日志格式:时间 [日志级别] 日志内容
# 日志级别:DEBUG, INFO, OK, WARN, ERROR
# 日志颜色:蓝色, 青色, 绿色, 黄色, 红色
# 日志输出:标准输出, 标准错误
# 日志示例:2021-01-01 00:00:00 +0800 [ DEBUG ] hello world.
# 日志示例:2021-01-01 00:00:00 +0800 [ INFO ] hello world.
# 日志示例:2021-01-01 00:00:00 +0800 [ OK ] hello world.
# 日志示例:2021-01-01 00:00:00 +0800 [ WARN ] hello world.
# 日志示例:2021-01-01 00:00:00 +0800 [ ERROR ] hello world.
if [[ "${TERM}" =~ ^(xterm|screen|vt100) ]]; then
log_debug() { echo -e "$(date '+%Y-%m-%d %H:%M:%S %z') [ \033[34mDEBUG\033[0m ] $*"; }
log_info() { echo -e "$(date '+%Y-%m-%d %H:%M:%S %z') [ \033[36mINFO\033[0m ] $*"; }
log_success() { echo -e "$(date '+%Y-%m-%d %H:%M:%S %z') [ \033[32mOK\033[0m ] $*"; }
log_warn() { echo -e "$(date '+%Y-%m-%d %H:%M:%S %z') [ \033[33mWARN\033[0m ] $*" >&2; }
log_error() { echo -e "$(date '+%Y-%m-%d %H:%M:%S %z') [ \033[31mERROR\033[0m ] $*" >&2; }
else
log_debug() { echo -e "$(date '+%Y-%m-%d %H:%M:%S %z') [ DEBUG ] $*"; }
log_info() { echo -e "$(date '+%Y-%m-%d %H:%M:%S %z') [ INFO ] $*"; }
log_success() { echo -e "$(date '+%Y-%m-%d %H:%M:%S %z') [ OK ] $*"; }
log_warn() { echo -e "$(date '+%Y-%m-%d %H:%M:%S %z') [ WARN ] $*" >&2; }
log_error() { echo -e "$(date '+%Y-%m-%d %H:%M:%S %z') [ ERROR ] $*" >&2; }
fi
# Get to workdir
cd "$(realpath "$(dirname "$(realpath "${BASH_SOURCE[0]}")")")"
# jq command is required
command -v jq >/dev/null 2>/dev/null || (log_error "command required: jq" && false)
# aptly command is required
command -v aptly >/dev/null 2>/dev/null || (log_error "command required: aptly" && false)
workdir="$(pwd)"
export APTLY_ROOT_DIR="${workdir}/aptly"
mkdir -p "${APTLY_ROOT_DIR}"
tmpdir="$(mktemp -d)"
config_file="${tmpdir:?}/aptly.conf.json"
< aptly.conf.json.envsubst envsubst > "${config_file}"
distribution="$(jq -r '.distribution' meta.json)"
component="$(jq -r '.component' meta.json)"
log_info "distribution: ${distribution}"
log_info "component: ${component}"
if ! aptly -config="${config_file}" repo show "${distribution}"; then
# 创建 repo
aptly -config="${config_file}" repo create -distribution="${distribution}" -component="${component}" "${distribution}"
# 添加包
aptly -config="${config_file}" repo add "${distribution}" ./packages/
# 发布时禁用硬链接
aptly -config="${config_file}" publish repo "${distribution}"
else
# 更新包
aptly -config="${config_file}" repo add "${distribution}" ./packages/
# 更新发布时禁用硬链接
aptly -config="${config_file}" publish update "${distribution}"
fi
echo "$(date -R) [ INFO ] aptly build repo successfully."
rm -rf "${tmpdir:?}/"
步骤四、创建 Dockerfile 文件
FROM docker.1ms.run/library/debian:13
COPY debian.sources /etc/apt/sources.list.d/debian.sources
RUN \
apt update && \
apt upgrade -y && \
apt install -y aptly jq gettext-base
步骤五、创建文件 debian.sources
Types: deb
URIs: http://mirrors.tuna.tsinghua.edu.cn/debian
Suites: trixie trixie-updates trixie-backports
Components: main contrib non-free non-free-firmware
Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
Types: deb
URIs: http://mirrors.tuna.tsinghua.edu.cn/debian-security
Suites: trixie-security
Components: main contrib non-free non-free-firmware
Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
步骤六、创建文件 aptly.conf.json.envsubst
{
"rootDir": "${APTLY_ROOT_DIR}",
"downloadConcurrency": 4,
"downloadSpeedLimit": 0,
"downloadRetries": 0,
"downloader": "default",
"databaseOpenAttempts": -1,
"architectures": [],
"dependencyFollowSuggests": false,
"dependencyFollowRecommends": false,
"dependencyFollowAllVariants": false,
"dependencyFollowSource": false,
"dependencyVerboseResolve": false,
"gpgDisableSign": true,
"gpgDisableVerify": true,
"gpgProvider": "gpg",
"downloadSourcePackages": false,
"skipLegacyPool": true,
"ppaDistributorID": "debian",
"ppaCodename": "",
"skipContentsPublishing": false,
"skipBz2Publishing": false,
"FileSystemPublishEndpoints": {},
"S3PublishEndpoints": {},
"SwiftPublishEndpoints": {},
"AzurePublishEndpoints": {},
"AsyncAPI": false,
"enableMetricsEndpoint": false
}
步骤七、创建 Makefile 文件
SHELL := /bin/bash
container_name := $(shell jq -r '.container_name' meta.json)
remote_server := $(shell jq -r '.remote_server' meta.json)
remote_dir := $(shell jq -r '.remote_dir' meta.json)
docker_image := $(shell jq -r '.docker_image' meta.json)
help:
@cat Makefile | grep '# `' | grep -v '@cat Makefile'
.PHONY: docker-image
docker-image:
docker build \
--progress plain \
--pull \
--tag ${docker_image} \
--file Dockerfile \
.
# `make build` Build
.PHONY: build
build: docker-image
docker run \
--rm \
--name "${container_name}" \
-v "$$(pwd)/:/data/" \
${docker_image} \
bash /data/build.sh
# `make shell` Shell
.PHONY: shell
shell: docker-image
docker run \
--rm \
-it \
-v "$$(pwd)/:/data/" \
--workdir /data \
${docker_image} \
bash
# `make publish` Publish
.PHONY: publish
publish:
ssh 'root@${remote_server}' mkdir -p '${remote_path}/'
rsync \
-a -r --no-i-r \
--info=progress2 --info=name0 \
--no-owner --no-group --no-perms \
--delete \
"$$(pwd)/aptly/public/" \
'root@${remote_server}:${remote_dir}/'
# `make clean` Clean
.PHONY: clean
clean:
docker stop ${container_name} >/dev/null 2>&1 || true
docker rm ${container_name} >/dev/null 2>&1 || true