mirror of
https://github.com/open-webui/open-webui.git
synced 2025-12-13 21:05:19 +00:00
215 lines
5.3 KiB
Bash
Executable file
215 lines
5.3 KiB
Bash
Executable file
#!/bin/bash
|
|
# build-and-push.sh - 本地构建并推送镜像到 GHCR
|
|
# 使用方法: ./scripts/build-and-push.sh
|
|
|
|
set -e # 遇到错误立即退出
|
|
|
|
# ============ 颜色输出 ============
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m' # No Color
|
|
|
|
echo_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
|
|
echo_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
|
|
echo_error() { echo -e "${RED}[ERROR]${NC} $1"; }
|
|
echo_step() { echo -e "${BLUE}[STEP]${NC} $1"; }
|
|
|
|
# ============ 配置变量 ============
|
|
REGISTRY="ghcr.io"
|
|
IMAGE_NAME="ai-friend-coming/open-webui-next"
|
|
FULL_IMAGE_NAME="${REGISTRY}/${IMAGE_NAME}"
|
|
|
|
# 获取 Git 信息
|
|
BUILD_HASH=$(git rev-parse HEAD)
|
|
SHORT_HASH=$(git rev-parse --short HEAD)
|
|
BRANCH=$(git branch --show-current)
|
|
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
|
|
|
|
# 检查工作目录
|
|
if [ ! -f "Dockerfile" ]; then
|
|
echo_error "请在项目根目录运行此脚本"
|
|
exit 1
|
|
fi
|
|
|
|
echo_info "========================================="
|
|
echo_info "构建信息:"
|
|
echo_info " 仓库: ${IMAGE_NAME}"
|
|
echo_info " 分支: ${BRANCH}"
|
|
echo_info " Commit: ${SHORT_HASH} (${BUILD_HASH:0:40}...)"
|
|
echo_info " 时间: ${TIMESTAMP}"
|
|
echo_info "========================================="
|
|
echo ""
|
|
|
|
# 检查未提交的更改
|
|
if [ -n "$(git status --porcelain)" ]; then
|
|
echo_warn "存在未提交的更改:"
|
|
git status --short
|
|
echo ""
|
|
read -p "继续构建? (y/n): " -n 1 -r
|
|
echo
|
|
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
echo_info "已取消"
|
|
exit 0
|
|
fi
|
|
fi
|
|
|
|
# ============ 镜像标签生成 ============
|
|
TAGS=(
|
|
"${FULL_IMAGE_NAME}:slim" # 主标签
|
|
"${FULL_IMAGE_NAME}:${BRANCH}-slim" # 分支标签
|
|
"${FULL_IMAGE_NAME}:git-${SHORT_HASH}-slim" # Git commit 标签
|
|
)
|
|
|
|
# 如果在 main 分支,添加 latest-slim 标签
|
|
if [ "$BRANCH" = "main" ]; then
|
|
TAGS+=("${FULL_IMAGE_NAME}:latest-slim")
|
|
fi
|
|
|
|
# 构建标签参数
|
|
TAG_ARGS=""
|
|
for tag in "${TAGS[@]}"; do
|
|
TAG_ARGS="${TAG_ARGS} -t ${tag}"
|
|
done
|
|
|
|
echo_info "将构建以下标签:"
|
|
for tag in "${TAGS[@]}"; do
|
|
echo " - ${tag}"
|
|
done
|
|
echo ""
|
|
|
|
# ============ 构建镜像 ============
|
|
echo_step "步骤 1/4: 构建 Docker 镜像"
|
|
echo_info "开始构建镜像 (这可能需要 5-10 分钟)..."
|
|
echo ""
|
|
|
|
docker buildx build \
|
|
--platform linux/amd64 \
|
|
--build-arg BUILD_HASH="${BUILD_HASH}" \
|
|
--build-arg USE_SLIM=true \
|
|
${TAG_ARGS} \
|
|
--load \
|
|
.
|
|
|
|
echo ""
|
|
echo_info "✅ 镜像构建成功!"
|
|
echo ""
|
|
|
|
# ============ 验证镜像 ============
|
|
echo_step "步骤 2/4: 验证镜像"
|
|
|
|
IMAGE_SIZE=$(docker images ${FULL_IMAGE_NAME}:slim --format "{{.Size}}")
|
|
IMAGE_ID=$(docker images ${FULL_IMAGE_NAME}:slim --format "{{.ID}}")
|
|
|
|
echo_info "镜像信息:"
|
|
echo " - ID: ${IMAGE_ID}"
|
|
echo " - 大小: ${IMAGE_SIZE}"
|
|
echo ""
|
|
|
|
# ============ 测试镜像 ============
|
|
echo_step "步骤 3/4: 测试镜像"
|
|
read -p "是否运行健康检查测试? (y/n): " -n 1 -r
|
|
echo
|
|
|
|
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
|
echo_info "启动测试容器 (端口 8081)..."
|
|
|
|
CONTAINER_ID=$(docker run -d -p 8081:8080 ${FULL_IMAGE_NAME}:slim)
|
|
echo_info "容器 ID: ${CONTAINER_ID}"
|
|
echo ""
|
|
|
|
echo_info "等待服务启动 (最多 120 秒)..."
|
|
HEALTH_CHECK_PASSED=false
|
|
|
|
for i in {1..120}; do
|
|
if curl -sf http://localhost:8081/health > /dev/null 2>&1; then
|
|
echo_info "✅ 健康检查通过 (耗时 ${i} 秒)"
|
|
HEALTH_CHECK_PASSED=true
|
|
break
|
|
fi
|
|
|
|
# 每 10 秒显示一次进度
|
|
if [ $((i % 10)) -eq 0 ]; then
|
|
echo_info " 等待中... (${i}/120 秒)"
|
|
fi
|
|
|
|
sleep 1
|
|
done
|
|
|
|
if [ "$HEALTH_CHECK_PASSED" = false ]; then
|
|
echo_error "健康检查超时!"
|
|
echo_error "容器日志:"
|
|
docker logs ${CONTAINER_ID} | tail -50
|
|
docker stop ${CONTAINER_ID} > /dev/null
|
|
docker rm ${CONTAINER_ID} > /dev/null
|
|
exit 1
|
|
fi
|
|
|
|
# 清理测试容器
|
|
echo_info "清理测试容器..."
|
|
docker stop ${CONTAINER_ID} > /dev/null
|
|
docker rm ${CONTAINER_ID} > /dev/null
|
|
echo ""
|
|
else
|
|
echo_warn "跳过健康检查"
|
|
echo ""
|
|
fi
|
|
|
|
# ============ 推送镜像 ============
|
|
echo_step "步骤 4/4: 推送镜像到 GHCR"
|
|
echo_info "将推送 ${#TAGS[@]} 个标签到 ${REGISTRY}"
|
|
echo ""
|
|
|
|
read -p "确认推送? (y/n): " -n 1 -r
|
|
echo
|
|
|
|
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
|
# 检查登录状态
|
|
if ! docker info 2>/dev/null | grep -q "Username"; then
|
|
echo_error "未登录 GHCR!"
|
|
echo_error "请先执行:"
|
|
echo " export CR_PAT=YOUR_PERSONAL_ACCESS_TOKEN"
|
|
echo " echo \$CR_PAT | docker login ghcr.io -u ai-friend-coming --password-stdin"
|
|
exit 1
|
|
fi
|
|
|
|
echo_info "开始推送镜像..."
|
|
echo ""
|
|
|
|
for tag in "${TAGS[@]}"; do
|
|
echo_info "推送: ${tag}"
|
|
docker push "${tag}"
|
|
done
|
|
|
|
echo ""
|
|
echo_info "✅ 所有镜像推送成功!"
|
|
echo ""
|
|
echo_info "拉取命令:"
|
|
echo " docker pull ${FULL_IMAGE_NAME}:slim"
|
|
echo ""
|
|
echo_info "查看镜像:"
|
|
echo " https://github.com/${IMAGE_NAME}/pkgs/container/open-webui-next"
|
|
echo ""
|
|
else
|
|
echo_warn "跳过推送"
|
|
echo ""
|
|
fi
|
|
|
|
# ============ 清理 ============
|
|
echo_info "清理选项:"
|
|
read -p "是否清理本地构建缓存? (y/n): " -n 1 -r
|
|
echo
|
|
|
|
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
|
echo_info "清理构建缓存..."
|
|
docker builder prune -f
|
|
echo_info "✅ 缓存清理完成"
|
|
else
|
|
echo_warn "保留构建缓存 (下次构建会更快)"
|
|
fi
|
|
|
|
echo ""
|
|
echo_info "========================================="
|
|
echo_info "✅ 构建流程完成!"
|
|
echo_info "========================================="
|