20260626 ARM64 Docker Compose部署与live TA首轮刷新

This commit is contained in:
2026-06-27 11:08:39 +08:00
parent f1a73bd2d1
commit 79a77f6f6e
12 changed files with 832 additions and 5 deletions

View File

@@ -0,0 +1,185 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
IMAGE_TAG="${IMAGE_TAG:-ours-rp-runtime-arm64:dev}"
BUILDER_IMAGE="${BUILDER_IMAGE:-ours-rp-base-rust-amd64:1-bookworm}"
RUNTIME_IMAGE="${RUNTIME_IMAGE:-ours-rp-base-debian-arm64:bookworm-slim}"
OUT_DIR="${OUT_DIR:-$REPO_ROOT/target/arm64-docker}"
DOCKERFILE="${DOCKERFILE:-$REPO_ROOT/docker/ours-rp-runtime.Dockerfile}"
BUILDER_NAME="${BUILDER_NAME:-default}"
INSTALL_BINFMT="${INSTALL_BINFMT:-1}"
SAVE_IMAGE="${SAVE_IMAGE:-1}"
LOAD_IMAGE="${LOAD_IMAGE:-1}"
usage() {
cat <<'USAGE'
Usage:
scripts/docker/build_arm64_runtime_image.sh [options]
Options:
--image <tag> Docker image tag (default: ours-rp-runtime-arm64:dev)
--out-dir <path> Directory for docker save tar.gz (default: target/arm64-docker)
--dockerfile <path> Dockerfile path
--builder <name> buildx builder name
--no-binfmt Do not install binfmt/qemu
--no-save Build image but do not docker save it
--no-load Use buildx output tar instead of --load
-h, --help Show this help
USAGE
}
while [[ $# -gt 0 ]]; do
case "$1" in
--image)
IMAGE_TAG="$2"
shift 2
;;
--out-dir)
OUT_DIR="$2"
shift 2
;;
--dockerfile)
DOCKERFILE="$2"
shift 2
;;
--builder)
BUILDER_NAME="$2"
shift 2
;;
--no-binfmt)
INSTALL_BINFMT=0
shift
;;
--no-save)
SAVE_IMAGE=0
shift
;;
--no-load)
LOAD_IMAGE=0
shift
;;
-h|--help)
usage
exit 0
;;
*)
echo "unknown option: $1" >&2
usage >&2
exit 2
;;
esac
done
require_command() {
command -v "$1" >/dev/null 2>&1 || {
echo "missing required command: $1" >&2
exit 2
}
}
safe_tag_name() {
printf '%s' "$1" | tr '/:' '--'
}
require_command docker
mkdir -p "$OUT_DIR"
require_docker_image() {
local image="$1"
if ! docker image inspect "$image" >/dev/null 2>&1; then
cat >&2 <<EOF
missing required local Docker image: $image
This script intentionally builds with local base image tags to avoid
multi-architecture tag ambiguity during cross builds.
Prepare the default base tags with:
docker pull --platform linux/amd64 rust:1-bookworm
docker tag rust:1-bookworm ours-rp-base-rust-amd64:1-bookworm
docker pull --platform linux/arm64 debian:bookworm-slim
docker tag debian:bookworm-slim ours-rp-base-debian-arm64:bookworm-slim
EOF
exit 2
fi
}
require_docker_image "$BUILDER_IMAGE"
require_docker_image "$RUNTIME_IMAGE"
if [[ "$INSTALL_BINFMT" == "1" ]]; then
echo "installing binfmt/qemu for arm64"
docker run --rm --privileged tonistiigi/binfmt --install arm64
fi
if [[ "$BUILDER_NAME" != "default" ]] && ! docker buildx inspect "$BUILDER_NAME" >/dev/null 2>&1; then
docker buildx create --name "$BUILDER_NAME" --driver docker-container --use >/dev/null
else
docker buildx use "$BUILDER_NAME" >/dev/null
fi
docker buildx inspect --bootstrap >/dev/null
metadata_path="$OUT_DIR/$(safe_tag_name "$IMAGE_TAG").build-metadata.json"
tar_path="$OUT_DIR/$(safe_tag_name "$IMAGE_TAG").tar.gz"
build_log="$OUT_DIR/$(safe_tag_name "$IMAGE_TAG").build.log"
echo "building linux/arm64 image: $IMAGE_TAG"
echo "repo: $REPO_ROOT"
echo "dockerfile: $DOCKERFILE"
echo "builder_image: $BUILDER_IMAGE"
echo "runtime_image: $RUNTIME_IMAGE"
start_epoch="$(date +%s)"
if [[ "$LOAD_IMAGE" == "1" ]]; then
docker buildx build \
--platform linux/arm64 \
--builder "$BUILDER_NAME" \
--load \
--build-arg BUILDKIT_INLINE_CACHE=1 \
--build-arg "BUILDER_IMAGE=$BUILDER_IMAGE" \
--build-arg "RUNTIME_IMAGE=$RUNTIME_IMAGE" \
--metadata-file "$metadata_path" \
-t "$IMAGE_TAG" \
-f "$DOCKERFILE" \
"$REPO_ROOT" 2>&1 | tee "$build_log"
else
raw_tar_path="$OUT_DIR/$(safe_tag_name "$IMAGE_TAG").tar"
docker buildx build \
--platform linux/arm64 \
--builder "$BUILDER_NAME" \
--output "type=docker,dest=$raw_tar_path" \
--build-arg BUILDKIT_INLINE_CACHE=1 \
--build-arg "BUILDER_IMAGE=$BUILDER_IMAGE" \
--build-arg "RUNTIME_IMAGE=$RUNTIME_IMAGE" \
--metadata-file "$metadata_path" \
-t "$IMAGE_TAG" \
-f "$DOCKERFILE" \
"$REPO_ROOT" 2>&1 | tee "$build_log"
gzip -f "$raw_tar_path"
tar_path="${raw_tar_path}.gz"
fi
elapsed_secs=$(( $(date +%s) - start_epoch ))
if [[ "$SAVE_IMAGE" == "1" && "$LOAD_IMAGE" == "1" ]]; then
echo "saving image to $tar_path"
docker save "$IMAGE_TAG" | gzip -c > "$tar_path"
fi
{
echo "image=$IMAGE_TAG"
echo "platform=linux/arm64"
echo "builder_image=$BUILDER_IMAGE"
echo "runtime_image=$RUNTIME_IMAGE"
echo "elapsed_secs=$elapsed_secs"
echo "metadata=$metadata_path"
echo "tar=$tar_path"
echo "tar_size_bytes=$(wc -c < "$tar_path" 2>/dev/null || echo 0)"
echo "git_commit=$(git -C "$REPO_ROOT" rev-parse --short HEAD 2>/dev/null || echo unknown)"
echo "git_status_count=$(git -C "$REPO_ROOT" status --short 2>/dev/null | wc -l | tr -d ' ')"
echo "built_at_utc=$(date -u +%Y-%m-%dT%H:%M:%SZ)"
} > "$OUT_DIR/$(safe_tag_name "$IMAGE_TAG").build-summary.env"
echo "build complete: elapsed=${elapsed_secs}s tar=$tar_path"

View File

@@ -0,0 +1,159 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
REMOTE_HOST="${REMOTE_HOST:-root@47.77.204.233}"
REMOTE_ROOT="${REMOTE_ROOT:-/root/ours-rp-arm64-compose}"
IMAGE_TAG="${IMAGE_TAG:-ours-rp-runtime-arm64:dev}"
IMAGE_TAR="${IMAGE_TAR:-$REPO_ROOT/target/arm64-docker/ours-rp-runtime-arm64-dev.tar.gz}"
EXECUTE="${EXECUTE:-0}"
INSTALL_DOCKER="${INSTALL_DOCKER:-1}"
INSTALL_BINFMT="${INSTALL_BINFMT:-1}"
START_CORE="${START_CORE:-0}"
START_SIDECARS="${START_SIDECARS:-0}"
usage() {
cat <<'USAGE'
Usage:
scripts/docker/deploy_remote233_arm64_compose.sh [options]
Default is dry-run. Pass --execute to modify the remote host.
Options:
--execute Actually install/copy/load/start on remote
--remote <ssh-host> SSH host (default: root@47.77.204.233)
--remote-root <path> Remote compose root
--image <tag> Image tag loaded by docker load
--image-tar <path> Local docker save tar.gz
--no-install-docker Skip Docker installation
--no-binfmt Skip binfmt/qemu installation
--start-core Start ours-rp-soak after deploy
--start-sidecars Start artifact metrics, Prometheus and Grafana after deploy
-h, --help Show this help
USAGE
}
while [[ $# -gt 0 ]]; do
case "$1" in
--execute)
EXECUTE=1
shift
;;
--remote)
REMOTE_HOST="$2"
shift 2
;;
--remote-root)
REMOTE_ROOT="$2"
shift 2
;;
--image)
IMAGE_TAG="$2"
shift 2
;;
--image-tar)
IMAGE_TAR="$2"
shift 2
;;
--no-install-docker)
INSTALL_DOCKER=0
shift
;;
--no-binfmt)
INSTALL_BINFMT=0
shift
;;
--start-core)
START_CORE=1
shift
;;
--start-sidecars)
START_SIDECARS=1
shift
;;
-h|--help)
usage
exit 0
;;
*)
echo "unknown option: $1" >&2
usage >&2
exit 2
;;
esac
done
require_command() {
command -v "$1" >/dev/null 2>&1 || {
echo "missing required command: $1" >&2
exit 2
}
}
run_or_echo() {
if [[ "$EXECUTE" == "1" ]]; then
"$@"
else
printf 'DRY-RUN:'
printf ' %q' "$@"
printf '\n'
fi
}
remote_run() {
if [[ "$EXECUTE" == "1" ]]; then
ssh "$REMOTE_HOST" "$@"
else
printf 'DRY-RUN: ssh %q %q\n' "$REMOTE_HOST" "$*"
fi
}
require_command ssh
require_command rsync
[[ -f "$IMAGE_TAR" ]] || {
echo "missing image tar: $IMAGE_TAR" >&2
exit 2
}
compose_src="$REPO_ROOT/deploy/arm64-compose/"
[[ -f "$compose_src/docker-compose.yml" ]] || {
echo "missing compose source: $compose_src" >&2
exit 2
}
echo "remote=$REMOTE_HOST"
echo "remote_root=$REMOTE_ROOT"
echo "image=$IMAGE_TAG"
echo "image_tar=$IMAGE_TAR"
if [[ "$INSTALL_DOCKER" == "1" ]]; then
remote_run "if ! command -v docker >/dev/null 2>&1; then apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y docker.io; fi; if ! docker compose version >/dev/null 2>&1; then if apt-cache show docker-compose-plugin >/dev/null 2>&1; then DEBIAN_FRONTEND=noninteractive apt-get install -y docker-compose-plugin; elif apt-cache show docker-compose-v2 >/dev/null 2>&1; then DEBIAN_FRONTEND=noninteractive apt-get install -y docker-compose-v2; elif apt-cache show docker-compose >/dev/null 2>&1; then DEBIAN_FRONTEND=noninteractive apt-get install -y docker-compose; else echo 'no docker compose package found' >&2; exit 2; fi; fi; systemctl enable --now docker || true"
fi
remote_run "mkdir -p '$REMOTE_ROOT/images'"
run_or_echo rsync -a --delete "$compose_src" "$REMOTE_HOST:$REMOTE_ROOT/"
run_or_echo rsync -a "$IMAGE_TAR" "$REMOTE_HOST:$REMOTE_ROOT/images/"
remote_tar="$REMOTE_ROOT/images/$(basename "$IMAGE_TAR")"
remote_run "cd '$REMOTE_ROOT' && test -f .env || cp .env.example .env"
remote_run "gunzip -c '$remote_tar' | docker load"
if [[ "$INSTALL_BINFMT" == "1" ]]; then
remote_run "docker run --rm --privileged tonistiigi/binfmt --install arm64"
fi
remote_run "docker run --rm --platform linux/arm64 '$IMAGE_TAG' uname -m"
remote_run "docker run --rm --platform linux/arm64 '$IMAGE_TAG' /opt/ours-rp/bin/rpki --help >/tmp/ours-rp-arm64-help.txt && head -5 /tmp/ours-rp-arm64-help.txt"
if [[ "$START_CORE" == "1" ]]; then
remote_run "cd '$REMOTE_ROOT' && docker compose --profile core up -d ours-rp-soak"
fi
if [[ "$START_SIDECARS" == "1" ]]; then
remote_run "cd '$REMOTE_ROOT' && docker compose --profile sidecar --profile monitor up -d artifact-metrics prometheus grafana"
fi
remote_run "cd '$REMOTE_ROOT' && docker compose ps"

View File

@@ -19,15 +19,19 @@ RIRS=afrinic,apnic,arin,lacnic,ripe
# TAL/TA 输入模式。
# file-with-ta:使用 package 内置 fixtures/tal + fixtures/ta,完全离线固定输入。
# file-live-ta:使用 package 内置 fixtures/tal;每轮后台 best-effort 刷新 TA 到 state/live-ta,
# 子进程不等待刷新,直接使用当前已有的 state/live-ta,首次缺失时从 fixtures/ta 初始化。
# file-live-ta:使用 package 内置 fixtures/tal;snapshot 轮默认先阻塞完成 live TA 获取再启动子进程,
# delta 轮后台 best-effort 刷新 TA 到 state/live-ta,子进程使用当前已有的 state/live-ta。
# url:直接把 TAL URL 传给子进程,由子进程处理 TAL/TA 获取。
TAL_INPUT_MODE=file-with-ta
# file-live-ta 后台刷新 TA 的 curl 超时配置。刷新失败只写日志,不阻断本轮 run。
# file-live-ta live TA 刷新 curl 超时配置。
LIVE_TA_REFRESH_CONNECT_TIMEOUT_SECS=15
LIVE_TA_REFRESH_MAX_TIME_SECS=120
# file-live-ta 在 snapshot 轮是否先完成 live TA 获取再启动子进程。
# 建议保持 1,避免 clean state 首轮 snapshot 使用旧 fixture TA。
LIVE_TA_REFRESH_BEFORE_SNAPSHOT=1
# 运行根目录。默认使用 package 根目录;如需把产物写到独立数据盘,可改成绝对路径。
RUN_ROOT="${PACKAGE_ROOT}"

View File

@@ -47,6 +47,7 @@ INVALID_ROOT="$STATE_ROOT/invalid"
LIVE_TA_REFRESH_DIR="${LIVE_TA_REFRESH_DIR:-$META_DIR/live-ta-refresh}"
LIVE_TA_REFRESH_CONNECT_TIMEOUT_SECS="${LIVE_TA_REFRESH_CONNECT_TIMEOUT_SECS:-15}"
LIVE_TA_REFRESH_MAX_TIME_SECS="${LIVE_TA_REFRESH_MAX_TIME_SECS:-120}"
LIVE_TA_REFRESH_BEFORE_SNAPSHOT="${LIVE_TA_REFRESH_BEFORE_SNAPSHOT:-1}"
RPKI_BIN="$BIN_DIR/rpki"
RPKI_DAEMON_BIN="$BIN_DIR/rpki_daemon"
@@ -309,12 +310,83 @@ start_live_ta_refresh_for_rir() {
printf '%s\n' "$pid" > "$pid_file"
}
prepare_live_ta_inputs_for_run() {
wait_for_previous_live_ta_refresh_for_rir() {
local rir_name="$1"
local pid_file
local pid
local deadline_epoch
pid_file="$(live_ta_refresh_pid_file_for_rir "$rir_name")"
[[ -f "$pid_file" ]] || return 0
if reap_finished_live_ta_refresh_for_rir "$rir_name"; then
return 0
fi
pid="$(cat "$pid_file" 2>/dev/null || true)"
deadline_epoch=$(( $(date +%s) + LIVE_TA_REFRESH_MAX_TIME_SECS + 60 ))
echo "live-ta-refresh wait rir=$rir_name reason=previous_refresh_running pid=$pid"
while ! reap_finished_live_ta_refresh_for_rir "$rir_name"; do
if (( $(date +%s) > deadline_epoch )); then
die "timed out waiting for previous live TA refresh for $rir_name pid=$pid"
fi
sleep 1
done
}
refresh_live_ta_blocking_for_run() {
local run_id="$1"
local rir_name
local pid
local failed=0
local pids=()
local names=()
local log_path
local pid_file
for rir_name in "${RIR_LIST[@]}"; do
wait_for_previous_live_ta_refresh_for_rir "$rir_name"
done
for rir_name in "${RIR_LIST[@]}"; do
mkdir -p "$LIVE_TA_REFRESH_DIR" "$LOG_ROOT"
pid_file="$(live_ta_refresh_pid_file_for_rir "$rir_name")"
log_path="$LOG_ROOT/live-ta-refresh-$run_id-$rir_name.log"
refresh_live_ta_for_rir "$rir_name" "$run_id" "$log_path" &
pid=$!
printf '%s\n' "$pid" > "$pid_file"
pids+=("$pid")
names+=("$rir_name")
done
local index
for index in "${!pids[@]}"; do
pid="${pids[$index]}"
rir_name="${names[$index]}"
pid_file="$(live_ta_refresh_pid_file_for_rir "$rir_name")"
if wait "$pid"; then
rm -f "$pid_file"
else
failed=1
rm -f "$pid_file"
echo "live-ta-refresh failed before snapshot rir=$rir_name log=$LOG_ROOT/live-ta-refresh-$run_id-$rir_name.log" >&2
fi
done
if (( failed != 0 )); then
die "live TA refresh failed before snapshot run=$run_id; see $LOG_ROOT/live-ta-refresh-$run_id-*.log"
fi
echo "live-ta-refresh completed before snapshot run=$run_id rirs=${#RIR_LIST[@]}"
}
prepare_live_ta_inputs_for_run() {
local run_id="$1"
local sync_mode="$2"
local rir_name
if [[ "$TAL_INPUT_MODE" != "file-live-ta" ]]; then
return 0
fi
if [[ "$sync_mode" == "snapshot" ]] && is_true "$LIVE_TA_REFRESH_BEFORE_SNAPSHOT"; then
refresh_live_ta_blocking_for_run "$run_id"
return 0
fi
for rir_name in "${RIR_LIST[@]}"; do
ensure_live_ta_for_rir "$rir_name"
done
@@ -726,7 +798,7 @@ run_one_round() {
"$snapshot_reason" "$previous_run_id" "$previous_success_value" "$started_at" "" \
"$INVALID_DB_PATH" "$INVALID_STATE_PATH" "$INVALID_TMP_PATH" "" "$PACKAGE_ROOT" "$ENV_FILE"
prepare_live_ta_inputs_for_run "$run_id"
prepare_live_ta_inputs_for_run "$run_id" "$sync_mode"
build_child_args
if is_true "$RPKI_ANALYZE"; then
CHILD_ARGS+=(--analyze --analysis-out "$run_dir/analyze")