feat: 增加通用编译/推送脚本
This commit is contained in:
+198
@@ -0,0 +1,198 @@
|
||||
#!/bin/sh
|
||||
|
||||
# 通用镜像编译和推送脚本
|
||||
# 用于在 CI/CD 环境中构建和推送多架构 Docker 镜像到 SWR 注册表
|
||||
|
||||
set -e
|
||||
|
||||
# 脚本配置说明:
|
||||
# - 需要设置 CI/CD 工具的 Secret 环境变量 SWR_REGISTRY, SWR_USERNAME, SWR_PASSWORD
|
||||
# - 支持 CI_REPO_NAME, CI_COMMIT_TAG, CI_COMMIT_SHA, CI_COMMIT_BRANCH 等 CI/CD 变量
|
||||
# - 默认构建 linux/amd64,linux/arm64 双架构镜像
|
||||
# - main 分支推送时会额外推送 latest 标签
|
||||
|
||||
# 全局变量,记录生成的镜像及所有标签
|
||||
IMAGES_TRACKED=""
|
||||
|
||||
# 验证必需的环境变量
|
||||
validate_env() {
|
||||
if [ -z "${SWR_REGISTRY:-}" ]; then
|
||||
echo "错误: SWR_REGISTRY 环境变量未设置"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "${SWR_USERNAME:-}" ] || [ -z "${SWR_PASSWORD:-}" ]; then
|
||||
echo "错误: SWR_USERNAME 或 SWR_PASSWORD 未设置"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 登录到 SWR 注册表
|
||||
docker_login() {
|
||||
if [ -n "${SWR_USERNAME:-}" ] && [ -n "${SWR_PASSWORD:-}" ]; then
|
||||
echo "登录到注册表: ${SWR_REGISTRY:-}"
|
||||
# 使用管道避免密码在命令行中暴露
|
||||
echo "${SWR_PASSWORD:-}" | docker login -u "${SWR_USERNAME:-}" --password-stdin "${SWR_REGISTRY:-}"
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "错误: 无法登录到注册表 ${SWR_REGISTRY:-}"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "错误: SWR_USERNAME 或 SWR_PASSWORD 未设置"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 从 TAG 生成版本标签 (vx.y.z -> vx.y, vx)
|
||||
generate_version_tags() {
|
||||
local tag="$1"
|
||||
local repo="$2"
|
||||
local tags="$repo:$tag"
|
||||
|
||||
# 检查是否为语义化版本格式 (vx.y.z 或 x.y.z)
|
||||
if echo "$tag" | grep -E '^[vV]?[0-9]+\.[0-9]+\.[0-9]+' >/dev/null 2>&1; then
|
||||
# 提取主版本号 (vx -> x)
|
||||
local major=$(echo "$tag" | sed -E 's/^([vV])?([0-9]+)\..*/\2/')
|
||||
if [ -n "$major" ] && [ "$major" != "$tag" ]; then
|
||||
tags="$tags,$repo:$major"
|
||||
fi
|
||||
|
||||
# 提取次版本号 (vx.y -> x.y)
|
||||
local minor=$(echo "$tag" | sed -E 's/^([vV])?([0-9]+\.[0-9]+)\..*/\2/')
|
||||
if [ -n "$minor" ] && [ "$minor" != "$tag" ] && [ "$minor" != "$major" ]; then
|
||||
tags="$tags,$repo:$minor"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "$tags"
|
||||
}
|
||||
|
||||
# 记录镜像标签到全局变量
|
||||
track_image() {
|
||||
local image="$1"
|
||||
if [ -z "$IMAGES_TRACKED" ]; then
|
||||
IMAGES_TRACKED="$image"
|
||||
else
|
||||
IMAGES_TRACKED="$IMAGES_TRACKED,$image"
|
||||
fi
|
||||
}
|
||||
|
||||
# 构建并推送镜像
|
||||
build_and_push() {
|
||||
# 确定镜像标签
|
||||
local IMAGE_TAG=""
|
||||
if [ -n "${CI_COMMIT_TAG:-}" ]; then
|
||||
IMAGE_TAG="${CI_COMMIT_TAG:-}"
|
||||
else
|
||||
# 使用 cut 截取前8位字符
|
||||
IMAGE_TAG=$(echo "${CI_COMMIT_SHA:-}" | cut -c1-8)
|
||||
fi
|
||||
|
||||
# 确定传入 Dockerfile 的 APP_VER 参数
|
||||
local APP_VER_ARG=""
|
||||
if [ "${CI_COMMIT_BRANCH:-}" = "main" ] || [ "${CI_COMMIT_BRANCH:-}" = "master" ]; then
|
||||
# 主分支编译时不传版本信息(使用 Dockerfile 中的默认值)
|
||||
APP_VER_ARG=""
|
||||
elif [ -n "${CI_COMMIT_TAG:-}" ]; then
|
||||
# 基于 tag 编译时,传入不含 v 前缀的版本号
|
||||
local CLEAN_TAG=$(echo "${CI_COMMIT_TAG:-}" | sed 's/^vV*//' )
|
||||
APP_VER_ARG="--build-arg APP_VER=${CLEAN_TAG}"
|
||||
else
|
||||
# 基于其他分支编译时,传入不含 v 前缀的分支名称
|
||||
local CLEAN_BRANCH=$(echo "${CI_COMMIT_BRANCH:-}" | sed 's/^vV*//' )
|
||||
APP_VER_ARG="--build-arg APP_VER=${CLEAN_BRANCH}"
|
||||
fi
|
||||
|
||||
# 支持自定义注册表路径
|
||||
if [ -z "${SWR_REGISTRY_REPO:-}" ]; then
|
||||
SWR_REGISTRY_REPO="${SWR_REGISTRY:-}/colovu/${CI_REPO_NAME:-}"
|
||||
fi
|
||||
|
||||
# 初始化TAGS变量以避免未定义错误
|
||||
local TAGS=""
|
||||
|
||||
echo "=== Debug Variables ==="
|
||||
echo "CI_REPO: ${CI_REPO:-empty}"
|
||||
echo "CI_REPO_NAME: ${CI_REPO_NAME:-empty}"
|
||||
echo "CI_COMMIT_TAG: ${CI_COMMIT_TAG:-empty}"
|
||||
echo "CI_COMMIT_SHA: ${CI_COMMIT_SHA:-empty}"
|
||||
echo "CI_COMMIT_BRANCH: ${CI_COMMIT_BRANCH:-empty}"
|
||||
echo "SWR_REGISTRY: ${SWR_REGISTRY_REPO:-empty}"
|
||||
echo "IMAGE_TAG: ${IMAGE_TAG:-empty}"
|
||||
echo "APP_VER_ARG: ${APP_VER_ARG:-empty}"
|
||||
echo "========================"
|
||||
|
||||
# 根据是否为标签版本构建镜像
|
||||
if [ -n "${CI_COMMIT_TAG:-}" ]; then
|
||||
# 生成版本标签 (包括主版本、次版本等)
|
||||
TAGS=$(generate_version_tags "$IMAGE_TAG" "$SWR_REGISTRY_REPO")
|
||||
|
||||
# 如果是 main 分支,添加 latest 标签
|
||||
if [ "${CI_COMMIT_BRANCH:-}" = "main" ]; then
|
||||
TAGS="$TAGS,$SWR_REGISTRY_REPO:latest"
|
||||
fi
|
||||
|
||||
# 构建并推送镜像
|
||||
echo ""
|
||||
echo "Build and push image: $TAGS"
|
||||
# 将逗号分隔的标签转换为 docker buildx 参数
|
||||
local build_args=""
|
||||
IFS=','
|
||||
for tag in $TAGS; do
|
||||
build_args="$build_args -t $tag"
|
||||
track_image "$tag"
|
||||
done
|
||||
unset IFS
|
||||
|
||||
docker buildx build --platform linux/amd64,linux/arm64 $APP_VER_ARG $build_args --push --provenance=false --sbom=false .
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "错误: 镜像构建或推送失败"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
# 非标签版本,只构建单个标签
|
||||
echo ""
|
||||
echo "Build and push image: $SWR_REGISTRY_REPO:$IMAGE_TAG"
|
||||
docker buildx build --platform linux/amd64,linux/arm64 -t "$SWR_REGISTRY_REPO:$IMAGE_TAG" $APP_VER_ARG --push --provenance=false --sbom=false .
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "错误: 镜像构建或推送失败"
|
||||
exit 1
|
||||
fi
|
||||
track_image "$SWR_REGISTRY_REPO:$IMAGE_TAG"
|
||||
fi
|
||||
|
||||
echo "Image pushed: $SWR_REGISTRY_REPO:$IMAGE_TAG"
|
||||
}
|
||||
|
||||
# 清理构建缓存
|
||||
cleanup() {
|
||||
echo ""
|
||||
echo "Cleaning up images and build cache..."
|
||||
|
||||
# 删除记录的所有镜像标签
|
||||
if [ -n "$IMAGES_TRACKED" ]; then
|
||||
echo "Removing tracked images: $IMAGES_TRACKED"
|
||||
IFS=','
|
||||
for image in $IMAGES_TRACKED; do
|
||||
echo "Removing image: $image"
|
||||
docker rmi "$image" 2>/dev/null || true
|
||||
done
|
||||
unset IFS
|
||||
fi
|
||||
|
||||
docker buildx prune -f
|
||||
docker rmi "$(docker images -f "dangling=true" -q)" 2>/dev/null || true
|
||||
}
|
||||
|
||||
# 主函数
|
||||
main() {
|
||||
validate_env
|
||||
docker_login
|
||||
build_and_push
|
||||
cleanup
|
||||
}
|
||||
|
||||
# 执行主函数
|
||||
main
|
||||
|
||||
|
||||
Reference in New Issue
Block a user