feat(release): 统一版本与 embed 部署,推送 lghost/aiops 镜像
- resolve_version 统一二进制/Docker/K8s 版本解析 - docker-compose 简化为 mysql+redis+aiops 单应用容器 - 新增 release/docker push/kubernetes push 构建并推送 Docker Hub - K8s deployment 镜像改为 lghost/aiops:<tag> 语义版本
This commit is contained in:
1 parent
8be51ac514
commit
9f5ce249f1
6 files changed
+295
-155
No files matched your search
+3
-1
@@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
ARG VERSION=dev
|
ARG VERSION=dev
|
||||||
ARG BUILD_TIME=unknown
|
ARG BUILD_TIME=unknown
|
||||||
|
ARG GIT_COMMIT=unknown
|
||||||
|
|
||||||
# ==================== Stage 1: Frontend Builder ====================
|
# ==================== Stage 1: Frontend Builder ====================
|
||||||
FROM node:20-alpine AS frontend-builder
|
FROM node:20-alpine AS frontend-builder
|
||||||
@@ -31,6 +32,7 @@ FROM golang:1.24-alpine AS backend-builder
|
|||||||
|
|
||||||
ARG VERSION
|
ARG VERSION
|
||||||
ARG BUILD_TIME
|
ARG BUILD_TIME
|
||||||
|
ARG GIT_COMMIT
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
@@ -56,7 +58,7 @@ COPY --from=frontend-builder /app/dist/ static/
|
|||||||
# 构建后端二进制(前端已嵌入,注入版本号)
|
# 构建后端二进制(前端已嵌入,注入版本号)
|
||||||
# local 模式需 CGO(SQLite + redka/mattn-sqlite3)// Logan.Li
|
# local 模式需 CGO(SQLite + redka/mattn-sqlite3)// Logan.Li
|
||||||
RUN CGO_ENABLED=1 GOOS=linux GOARCH=amd64 go build \
|
RUN CGO_ENABLED=1 GOOS=linux GOARCH=amd64 go build \
|
||||||
-ldflags="-w -s -X main.Version=${VERSION} -X main.BuildTime=${BUILD_TIME}" \
|
-ldflags="-w -s -X main.Version=${VERSION} -X main.BuildTime=${BUILD_TIME} -X main.GitCommit=${GIT_COMMIT}" \
|
||||||
-o aiops .
|
-o aiops .
|
||||||
|
|
||||||
# ==================== Stage 3: Agent Builder ====================
|
# ==================== Stage 3: Agent Builder ====================
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# deployment.yaml — AIOps 应用 (embed 前端嵌入后端, 单容器单端口)
|
# deployment.yaml — AIOps 应用 (embed 前端嵌入后端, 单容器单端口)
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
# - 镜像 aiops:embed(前端通过 go:embed 内嵌进同一二进制)
|
# - 镜像 lghost/aiops:<tag>(前端通过 go:embed 内嵌进同一二进制)
|
||||||
# - 单端口 8080 = API + WebSocket + 前端 SPA 静态资源
|
# - 单端口 8080 = API + WebSocket + 前端 SPA 静态资源
|
||||||
# - 配置优先级: 环境变量 > config.yaml > 默认值 (viper AutomaticEnv)
|
# - 配置优先级: 环境变量 > config.yaml > 默认值 (viper AutomaticEnv)
|
||||||
# - 环境变量命名: 配置键 database.host → DATABASE_HOST (全大写, 点变下划线)
|
# - 环境变量命名: 配置键 database.host → DATABASE_HOST (全大写, 点变下划线)
|
||||||
@@ -58,7 +58,7 @@ spec:
|
|||||||
mountPath: /vol
|
mountPath: /vol
|
||||||
containers:
|
containers:
|
||||||
- name: aiops
|
- name: aiops
|
||||||
image: 10.10.10.72/library/aiops:embed
|
image: lghost/aiops:dev
|
||||||
imagePullPolicy: Always
|
imagePullPolicy: Always
|
||||||
ports:
|
ports:
|
||||||
- name: http
|
- name: http
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ spec:
|
|||||||
mountPath: /vol
|
mountPath: /vol
|
||||||
containers:
|
containers:
|
||||||
- name: aiops
|
- name: aiops
|
||||||
image: aiops:embed
|
image: lghost/aiops:dev
|
||||||
imagePullPolicy: IfNotPresent
|
imagePullPolicy: IfNotPresent
|
||||||
ports:
|
ports:
|
||||||
- containerPort: 8080
|
- containerPort: 8080
|
||||||
|
|||||||
+10
-30
@@ -1,14 +1,18 @@
|
|||||||
|
# AIOps — 单应用 embed 容器(连接外部 MySQL/Redis,无内置数据库)
|
||||||
|
# 用法: VERSION=v1.0.1 docker compose -f docker-compose.k8s.yml up -d --build
|
||||||
|
# 署名 Logan.Li
|
||||||
|
|
||||||
services:
|
services:
|
||||||
# ======================== Go 后端服务 (连接外部 MySQL/Redis) ========================
|
aiops:
|
||||||
backend:
|
image: ${DOCKERHUB_IMAGE:-lghost/aiops}:${VERSION:-dev}
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: backend/Dockerfile
|
dockerfile: Dockerfile.embed
|
||||||
args:
|
args:
|
||||||
VERSION: ${VERSION:-dev}
|
VERSION: ${VERSION:-dev}
|
||||||
BUILD_TIME: ${BUILD_TIME:-unknown}
|
BUILD_TIME: ${BUILD_TIME:-unknown}
|
||||||
container_name: aiops-backend
|
GIT_COMMIT: ${GIT_COMMIT:-unknown}
|
||||||
hostname: aiops-backend
|
container_name: aiops
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
ports:
|
ports:
|
||||||
- "8080:8080"
|
- "8080:8080"
|
||||||
@@ -16,32 +20,8 @@ services:
|
|||||||
- ./backend/config.external.yaml:/app/config.yaml
|
- ./backend/config.external.yaml:/app/config.yaml
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
|
test: ["CMD", "curl", "-f", "http://localhost:8080/version"]
|
||||||
interval: 30s
|
interval: 30s
|
||||||
timeout: 10s
|
timeout: 10s
|
||||||
retries: 3
|
retries: 3
|
||||||
start_period: 40s
|
start_period: 40s
|
||||||
extra_hosts:
|
|
||||||
- "host.docker.internal:host-gateway"
|
|
||||||
networks:
|
|
||||||
- aiops-network
|
|
||||||
|
|
||||||
# ======================== React 前端 + Nginx ========================
|
|
||||||
frontend:
|
|
||||||
build:
|
|
||||||
context: ./frontend
|
|
||||||
dockerfile: Dockerfile
|
|
||||||
container_name: aiops-frontend
|
|
||||||
hostname: aiops-frontend
|
|
||||||
restart: unless-stopped
|
|
||||||
ports:
|
|
||||||
- "80:80"
|
|
||||||
depends_on:
|
|
||||||
backend:
|
|
||||||
condition: service_healthy
|
|
||||||
networks:
|
|
||||||
- aiops-network
|
|
||||||
|
|
||||||
networks:
|
|
||||||
aiops-network:
|
|
||||||
driver: bridge
|
|
||||||
+26
-31
@@ -1,5 +1,9 @@
|
|||||||
|
# AIOps Docker Compose — embed 单应用容器 + MySQL + Redis
|
||||||
|
# 访问: http://localhost:8080 (API + 前端 SPA 同一端口)
|
||||||
|
# 构建: VERSION=v1.0.1 ./run.sh docker up
|
||||||
|
# 署名 Logan.Li
|
||||||
|
|
||||||
services:
|
services:
|
||||||
# ======================== MySQL 数据库 ========================
|
|
||||||
mysql:
|
mysql:
|
||||||
image: mysql:8.0
|
image: mysql:8.0
|
||||||
container_name: aiops-mysql
|
container_name: aiops-mysql
|
||||||
@@ -28,7 +32,6 @@ services:
|
|||||||
networks:
|
networks:
|
||||||
- aiops-network
|
- aiops-network
|
||||||
|
|
||||||
# ======================== Redis 缓存 ========================
|
|
||||||
redis:
|
redis:
|
||||||
image: redis:7-alpine
|
image: redis:7-alpine
|
||||||
container_name: aiops-redis
|
container_name: aiops-redis
|
||||||
@@ -47,24 +50,35 @@ services:
|
|||||||
networks:
|
networks:
|
||||||
- aiops-network
|
- aiops-network
|
||||||
|
|
||||||
# ======================== Go 后端服务 ========================
|
aiops:
|
||||||
backend:
|
image: ${DOCKERHUB_IMAGE:-lghost/aiops}:${VERSION:-dev}
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: backend/Dockerfile
|
dockerfile: Dockerfile.embed
|
||||||
args:
|
args:
|
||||||
VERSION: ${VERSION:-dev}
|
VERSION: ${VERSION:-dev}
|
||||||
BUILD_TIME: ${BUILD_TIME:-unknown}
|
BUILD_TIME: ${BUILD_TIME:-unknown}
|
||||||
container_name: aiops-backend
|
GIT_COMMIT: ${GIT_COMMIT:-unknown}
|
||||||
hostname: aiops-backend
|
container_name: aiops
|
||||||
|
hostname: aiops
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
ports:
|
ports:
|
||||||
- "8080:8080"
|
- "8080:8080"
|
||||||
environment:
|
environment:
|
||||||
- MODE=${MODE:-release}
|
TZ: Asia/Shanghai
|
||||||
|
MODE: release
|
||||||
|
DATABASE_DRIVER: mysql
|
||||||
|
DATABASE_HOST: mysql
|
||||||
|
DATABASE_PORT: 3306
|
||||||
|
DATABASE_USER: ${MYSQL_USER:-aiops}
|
||||||
|
DATABASE_PASSWORD: ${MYSQL_PASSWORD:-CHANGE_ME}
|
||||||
|
DATABASE_DBNAME: ${MYSQL_DATABASE:-aiops}
|
||||||
|
REDIS_DRIVER: redis
|
||||||
|
REDIS_HOST: redis
|
||||||
|
REDIS_PORT: 6379
|
||||||
|
JWT_SECRET: ${JWT_SECRET:-aiops-jwt-secret-change-me}
|
||||||
volumes:
|
volumes:
|
||||||
- ./backend/config.yaml:/app/config.yaml
|
- aiops_uploads:/app/uploads
|
||||||
- ./backend/data:/app/data
|
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
depends_on:
|
depends_on:
|
||||||
mysql:
|
mysql:
|
||||||
@@ -72,37 +86,18 @@ services:
|
|||||||
redis:
|
redis:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
|
test: ["CMD", "curl", "-f", "http://localhost:8080/version"]
|
||||||
interval: 30s
|
interval: 30s
|
||||||
timeout: 10s
|
timeout: 10s
|
||||||
retries: 3
|
retries: 3
|
||||||
start_period: 40s
|
start_period: 40s
|
||||||
dns:
|
|
||||||
- 127.0.0.11
|
|
||||||
- 114.114.114.114
|
|
||||||
- 223.5.5.5
|
|
||||||
networks:
|
|
||||||
- aiops-network
|
|
||||||
|
|
||||||
# ======================== React 前端 + Nginx ========================
|
|
||||||
frontend:
|
|
||||||
build:
|
|
||||||
context: ./frontend
|
|
||||||
dockerfile: Dockerfile
|
|
||||||
container_name: aiops-frontend
|
|
||||||
hostname: aiops-frontend
|
|
||||||
restart: unless-stopped
|
|
||||||
ports:
|
|
||||||
- "80:80"
|
|
||||||
depends_on:
|
|
||||||
backend:
|
|
||||||
condition: service_healthy
|
|
||||||
networks:
|
networks:
|
||||||
- aiops-network
|
- aiops-network
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
mysql_data:
|
mysql_data:
|
||||||
redis_data:
|
redis_data:
|
||||||
|
aiops_uploads:
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
aiops-network:
|
aiops-network:
|
||||||
|
|||||||
@@ -3,8 +3,8 @@
|
|||||||
# AIOps 智能运维平台 - 统一启动脚本
|
# AIOps 智能运维平台 - 统一启动脚本
|
||||||
# 支持三种部署方式 + 本地开发模式:
|
# 支持三种部署方式 + 本地开发模式:
|
||||||
#
|
#
|
||||||
# 方式 1 — Docker Compose:
|
# 方式 1 — Docker Compose (embed 单应用容器):
|
||||||
# ./run.sh docker up 构建+启动 (MySQL+Redis+Backend+Nginx)
|
# ./run.sh docker up 构建+启动 (MySQL+Redis+AIOps)
|
||||||
#
|
#
|
||||||
# 方式 2 — Kubernetes (embed 单容器):
|
# 方式 2 — Kubernetes (embed 单容器):
|
||||||
# ./run.sh kubernetes deploy 构建镜像+全量部署 (embed 前端嵌入后端)
|
# ./run.sh kubernetes deploy 构建镜像+全量部署 (embed 前端嵌入后端)
|
||||||
@@ -33,6 +33,7 @@ BACKEND_DIR="backend"
|
|||||||
FRONTEND_DIR="frontend"
|
FRONTEND_DIR="frontend"
|
||||||
BACKEND_BIN="aiops-server"
|
BACKEND_BIN="aiops-server"
|
||||||
STANDALONE_BIN="aiops"
|
STANDALONE_BIN="aiops"
|
||||||
|
DOCKERHUB_IMAGE="lghost/aiops"
|
||||||
|
|
||||||
# 日志配置
|
# 日志配置
|
||||||
MAX_LOG_FILES=3
|
MAX_LOG_FILES=3
|
||||||
@@ -433,11 +434,19 @@ ensure_go_path() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# 解析编译版本号(显式 tag 优先,否则取 git describe)// Logan.Li
|
# 判断参数是否像版本号 (v1.0.1 / 1.0.1) // Logan.Li
|
||||||
resolve_build_version() {
|
looks_like_version() {
|
||||||
|
local v=$1
|
||||||
|
[[ "$v" =~ ^v[0-9] ]] || [[ "$v" =~ ^[0-9]+\.[0-9] ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
# 统一版本解析:显式参数 > VERSION 环境变量 > git describe > dev // Logan.Li
|
||||||
|
resolve_version() {
|
||||||
local explicit="${1:-}"
|
local explicit="${1:-}"
|
||||||
if [ -n "$explicit" ]; then
|
if [ -n "$explicit" ]; then
|
||||||
BUILD_VERSION="$explicit"
|
BUILD_VERSION="$explicit"
|
||||||
|
elif [ -n "${VERSION:-}" ]; then
|
||||||
|
BUILD_VERSION="$VERSION"
|
||||||
elif git describe --tags --always --dirty 2>/dev/null | grep -q .; then
|
elif git describe --tags --always --dirty 2>/dev/null | grep -q .; then
|
||||||
BUILD_VERSION=$(git describe --tags --always --dirty 2>/dev/null)
|
BUILD_VERSION=$(git describe --tags --always --dirty 2>/dev/null)
|
||||||
else
|
else
|
||||||
@@ -445,6 +454,108 @@ resolve_build_version() {
|
|||||||
fi
|
fi
|
||||||
BUILD_TIME=$(date -u '+%Y-%m-%dT%H:%M:%SZ')
|
BUILD_TIME=$(date -u '+%Y-%m-%dT%H:%M:%SZ')
|
||||||
GIT_COMMIT=$(git rev-parse --short HEAD 2>/dev/null || echo "unknown")
|
GIT_COMMIT=$(git rev-parse --short HEAD 2>/dev/null || echo "unknown")
|
||||||
|
EMBED_IMAGE="${DOCKERHUB_IMAGE}:${BUILD_VERSION}"
|
||||||
|
export VERSION="$BUILD_VERSION"
|
||||||
|
export BUILD_TIME
|
||||||
|
export GIT_COMMIT
|
||||||
|
}
|
||||||
|
|
||||||
|
# 兼容旧函数名 // Logan.Li
|
||||||
|
resolve_build_version() {
|
||||||
|
resolve_version "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
# 跨平台 sed -i // Logan.Li
|
||||||
|
sed_inplace() {
|
||||||
|
local expr=$1
|
||||||
|
local file=$2
|
||||||
|
if [ "$OS" = "macos" ]; then
|
||||||
|
sed -i '' "$expr" "$file"
|
||||||
|
else
|
||||||
|
sed -i "$expr" "$file"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# 构建 embed Docker 镜像(二进制/K8s/Docker Compose 共用)// Logan.Li
|
||||||
|
build_embed_image() {
|
||||||
|
local version_tag="${1:-}"
|
||||||
|
local no_cache="${2:-0}"
|
||||||
|
local do_push="${3:-0}"
|
||||||
|
|
||||||
|
if ! command -v docker &>/dev/null; then
|
||||||
|
error "Docker 未安装"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
resolve_version "$version_tag"
|
||||||
|
banner "========== 构建 embed 镜像 ($EMBED_IMAGE) =========="
|
||||||
|
clean_frontend_artifacts
|
||||||
|
clean_embed_static
|
||||||
|
|
||||||
|
export DOCKER_BUILDKIT=1
|
||||||
|
local build_args=(
|
||||||
|
-f Dockerfile.embed
|
||||||
|
--build-arg "VERSION=${BUILD_VERSION}"
|
||||||
|
--build-arg "BUILD_TIME=${BUILD_TIME}"
|
||||||
|
--build-arg "GIT_COMMIT=${GIT_COMMIT}"
|
||||||
|
--label "org.opencontainers.image.version=${BUILD_VERSION}"
|
||||||
|
-t "$EMBED_IMAGE"
|
||||||
|
-t "${DOCKERHUB_IMAGE}:dev"
|
||||||
|
.
|
||||||
|
)
|
||||||
|
if [ "$no_cache" -eq 1 ]; then
|
||||||
|
build_args=(--no-cache --pull "${build_args[@]}")
|
||||||
|
info "无缓存全量构建 (--no-cache --pull)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
info "构建中(前端 + 后端 embed)..."
|
||||||
|
docker build "${build_args[@]}" || {
|
||||||
|
error "镜像构建失败"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
local img_size
|
||||||
|
img_size=$(docker images "$EMBED_IMAGE" --format "{{.Size}}" | head -1)
|
||||||
|
success "镜像构建完成: $EMBED_IMAGE ($img_size)"
|
||||||
|
KUBERNETES_BUILT_IMAGE="$EMBED_IMAGE"
|
||||||
|
|
||||||
|
if [ "$do_push" -eq 1 ]; then
|
||||||
|
push_embed_image "$BUILD_VERSION" || return 1
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# 推送镜像到 Docker Hub // Logan.Li
|
||||||
|
push_embed_image() {
|
||||||
|
local version_tag="${1:-}"
|
||||||
|
resolve_version "$version_tag"
|
||||||
|
|
||||||
|
info "推送镜像到 Docker Hub..."
|
||||||
|
docker push "$EMBED_IMAGE" || {
|
||||||
|
error "推送失败: $EMBED_IMAGE(请先 docker login)"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
if [ "$BUILD_VERSION" != "dev" ]; then
|
||||||
|
docker push "${DOCKERHUB_IMAGE}:dev" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
success "已推送: $EMBED_IMAGE"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# 更新 K8s deployment 中的镜像坐标 // Logan.Li
|
||||||
|
kubernetes_update_manifest_image() {
|
||||||
|
local image=$1
|
||||||
|
local files=(
|
||||||
|
"$KUBERNETES_MANIFEST_DIR/deployment.yaml"
|
||||||
|
"$KUBERNETES_MANIFEST_DIR/quick-deploy.yaml"
|
||||||
|
)
|
||||||
|
local f
|
||||||
|
for f in "${files[@]}"; do
|
||||||
|
[ -f "$f" ] || continue
|
||||||
|
sed_inplace "s|image: ${DOCKERHUB_IMAGE}:.*|image: ${image}|g" "$f"
|
||||||
|
sed_inplace "s|image: .*/aiops:.*|image: ${image}|g" "$f"
|
||||||
|
done
|
||||||
|
info "K8s manifest 镜像已更新为: $image"
|
||||||
}
|
}
|
||||||
|
|
||||||
# 编译独立二进制(含 embed 前端,输出到项目根目录 ./aiops)// Logan.Li
|
# 编译独立二进制(含 embed 前端,输出到项目根目录 ./aiops)// Logan.Li
|
||||||
@@ -589,6 +700,7 @@ detect_compose_cmd() {
|
|||||||
|
|
||||||
cmd_docker() {
|
cmd_docker() {
|
||||||
local action=${1:-help}
|
local action=${1:-help}
|
||||||
|
shift || true
|
||||||
|
|
||||||
if ! command -v docker &> /dev/null; then
|
if ! command -v docker &> /dev/null; then
|
||||||
error "Docker 未安装,请先安装 Docker"
|
error "Docker 未安装,请先安装 Docker"
|
||||||
@@ -600,27 +712,38 @@ cmd_docker() {
|
|||||||
error "Docker Compose 未安装 (需要 docker compose 插件或 docker-compose)"
|
error "Docker Compose 未安装 (需要 docker compose 插件或 docker-compose)"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
# 自动从 git tag 获取版本号
|
|
||||||
GIT_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
|
|
||||||
BUILD_TIME=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
||||||
export VERSION="${GIT_TAG:-dev}"
|
|
||||||
export BUILD_TIME
|
|
||||||
info "使用: $DOCKER_COMPOSE"
|
|
||||||
info "版本: $VERSION (构建时间: $BUILD_TIME)"
|
|
||||||
|
|
||||||
# 启用 BuildKit 加速构建(cache mount 跨构建复用 go mod/apk 缓存)// Logan.Li
|
# 解析可选版本号参数 (up v1.0.1 / push v1.0.1) // Logan.Li
|
||||||
|
local version_arg=""
|
||||||
|
local fresh_build=0
|
||||||
|
while [ $# -gt 0 ]; do
|
||||||
|
case "$1" in
|
||||||
|
fresh) fresh_build=1; shift ;;
|
||||||
|
tag)
|
||||||
|
shift
|
||||||
|
version_arg=${1:-}
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
if looks_like_version "$1"; then
|
||||||
|
version_arg=$1
|
||||||
|
fi
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
resolve_version "$version_arg"
|
||||||
|
export DOCKERHUB_IMAGE
|
||||||
|
info "使用: $DOCKER_COMPOSE"
|
||||||
|
info "版本: $BUILD_VERSION | 镜像: $EMBED_IMAGE"
|
||||||
|
|
||||||
export DOCKER_BUILDKIT=1
|
export DOCKER_BUILDKIT=1
|
||||||
export COMPOSE_DOCKER_CLI_BUILD=1
|
export COMPOSE_DOCKER_CLI_BUILD=1
|
||||||
info "BuildKit: 已启用 (增量编译 + 缓存复用)"
|
info "BuildKit: 已启用 (增量编译 + 缓存复用)"
|
||||||
|
|
||||||
case "$action" in
|
case "$action" in
|
||||||
up|upgrade|update)
|
up|upgrade|update)
|
||||||
local fresh_build=0
|
banner "========== Docker Compose 启动/升级 ($BUILD_VERSION) =========="
|
||||||
if [ "${2:-}" = "fresh" ] || [ "$action" = "fresh" ]; then
|
|
||||||
fresh_build=1
|
|
||||||
fi
|
|
||||||
banner "========== Docker Compose 启动/升级 =========="
|
|
||||||
clean_frontend_artifacts
|
|
||||||
if [ "$fresh_build" -eq 1 ]; then
|
if [ "$fresh_build" -eq 1 ]; then
|
||||||
info "全量重建镜像 (--no-cache)..."
|
info "全量重建镜像 (--no-cache)..."
|
||||||
$DOCKER_COMPOSE build --no-cache
|
$DOCKER_COMPOSE build --no-cache
|
||||||
@@ -630,21 +753,19 @@ cmd_docker() {
|
|||||||
$DOCKER_COMPOSE up -d --build --force-recreate --remove-orphans
|
$DOCKER_COMPOSE up -d --build --force-recreate --remove-orphans
|
||||||
fi
|
fi
|
||||||
echo ""
|
echo ""
|
||||||
# 清理历史 build cache 和悬空镜像,防止占满磁盘
|
|
||||||
info "清理历史构建缓存..."
|
info "清理历史构建缓存..."
|
||||||
local before_prune=$(df -h / | awk 'NR==2{print $5}')
|
|
||||||
docker builder prune -f 2>/dev/null || true
|
docker builder prune -f 2>/dev/null || true
|
||||||
docker image prune -f 2>/dev/null || true
|
docker image prune -f 2>/dev/null || true
|
||||||
local after_prune=$(df -h / | awk 'NR==2{print $5}')
|
|
||||||
info "磁盘使用: ${before_prune} → ${after_prune}"
|
|
||||||
echo ""
|
echo ""
|
||||||
info "等待服务就绪..."
|
info "等待服务就绪..."
|
||||||
sleep 5
|
sleep 5
|
||||||
$DOCKER_COMPOSE ps
|
$DOCKER_COMPOSE ps
|
||||||
echo ""
|
echo ""
|
||||||
info "前端地址: http://localhost:80"
|
info "访问地址: http://localhost:8080"
|
||||||
info "后端地址: http://localhost:8080"
|
info "版本检查: http://localhost:8080/version"
|
||||||
info "健康检查: http://localhost:8080/health"
|
;;
|
||||||
|
push)
|
||||||
|
build_embed_image "$version_arg" 0 1 || exit 1
|
||||||
;;
|
;;
|
||||||
down)
|
down)
|
||||||
info "停止 Docker Compose..."
|
info "停止 Docker Compose..."
|
||||||
@@ -688,16 +809,15 @@ cmd_docker() {
|
|||||||
cmd_docker up fresh
|
cmd_docker up fresh
|
||||||
;;
|
;;
|
||||||
help|--help|-h)
|
help|--help|-h)
|
||||||
echo "Docker Compose 部署命令:"
|
echo "Docker Compose 部署命令 (embed 单容器 + MySQL + Redis):"
|
||||||
echo " ./run.sh docker up 增量构建 + 强制重建容器"
|
echo " ./run.sh docker up 增量构建 + 启动"
|
||||||
echo " ./run.sh docker up fresh 无缓存全量重建镜像并启动"
|
echo " ./run.sh docker up v1.0.1 指定版本构建"
|
||||||
echo " ./run.sh docker upgrade 同 up(升级别名)"
|
echo " ./run.sh docker up fresh 无缓存全量重建"
|
||||||
|
echo " ./run.sh docker push v1.0.1 构建并推送到 $DOCKERHUB_IMAGE"
|
||||||
echo " ./run.sh docker down 停止并移除容器"
|
echo " ./run.sh docker down 停止并移除容器"
|
||||||
echo " ./run.sh docker build 仅构建镜像"
|
echo " ./run.sh docker build 仅构建镜像"
|
||||||
echo " ./run.sh docker restart 重启容器"
|
|
||||||
echo " ./run.sh docker logs 查看实时日志"
|
echo " ./run.sh docker logs 查看实时日志"
|
||||||
echo " ./run.sh docker ps 查看容器状态"
|
echo " ./run.sh docker ps 查看容器状态"
|
||||||
echo " ./run.sh docker clean 清理构建缓存/无用镜像"
|
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
error "未知 docker 子命令: $action"
|
error "未知 docker 子命令: $action"
|
||||||
@@ -876,7 +996,6 @@ cmd_binary() {
|
|||||||
# ============================================================
|
# ============================================================
|
||||||
KUBERNETES_NAMESPACE="devops"
|
KUBERNETES_NAMESPACE="devops"
|
||||||
KUBERNETES_MANIFEST_DIR="$SCRIPT_DIR/deploy/kubernetes"
|
KUBERNETES_MANIFEST_DIR="$SCRIPT_DIR/deploy/kubernetes"
|
||||||
KUBERNETES_IMAGE="aiops:embed"
|
|
||||||
KUBERNETES_NODE_PORT=30080
|
KUBERNETES_NODE_PORT=30080
|
||||||
KUBERNETES_BUILT_IMAGE=""
|
KUBERNETES_BUILT_IMAGE=""
|
||||||
|
|
||||||
@@ -918,52 +1037,32 @@ load_image_to_cluster() {
|
|||||||
warning "如集群无法拉取镜像,请手动推送: docker push <registry>/$image"
|
warning "如集群无法拉取镜像,请手动推送: docker push <registry>/$image"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Kubernetes 构建镜像(upgrade 时无缓存 + 时间戳 tag 避免旧层残留)// Logan.Li
|
# Kubernetes 构建镜像 // Logan.Li
|
||||||
cmd_kubernetes_build() {
|
cmd_kubernetes_build() {
|
||||||
local no_cache=${1:-0}
|
local version_tag=""
|
||||||
if ! command -v docker &>/dev/null; then
|
local no_cache=0
|
||||||
error "Docker 未安装"
|
local do_push=0
|
||||||
exit 1
|
while [ $# -gt 0 ]; do
|
||||||
|
case "$1" in
|
||||||
|
1|--no-cache|fresh) no_cache=1; shift ;;
|
||||||
|
push) do_push=1; shift ;;
|
||||||
|
tag)
|
||||||
|
shift
|
||||||
|
version_tag=${1:-}
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
if looks_like_version "$1"; then
|
||||||
|
version_tag=$1
|
||||||
fi
|
fi
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
banner "========== 构建 embed 镜像 =========="
|
build_embed_image "$version_tag" "$no_cache" "$do_push" || return 1
|
||||||
clean_frontend_artifacts
|
load_image_to_cluster "$KUBERNETES_BUILT_IMAGE"
|
||||||
clean_embed_static
|
load_image_to_cluster "${DOCKERHUB_IMAGE}:dev"
|
||||||
|
|
||||||
local version
|
|
||||||
version=$(git describe --tags --abbrev=0 2>/dev/null || echo "dev")
|
|
||||||
local build_time
|
|
||||||
build_time=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
||||||
local image_tag
|
|
||||||
image_tag="${KUBERNETES_IMAGE}-$(date +%Y%m%d%H%M%S)"
|
|
||||||
info "镜像: $KUBERNETES_IMAGE (+ $image_tag)"
|
|
||||||
|
|
||||||
local build_args=(
|
|
||||||
-f Dockerfile.embed
|
|
||||||
--build-arg VERSION="$version"
|
|
||||||
--build-arg BUILD_TIME="$build_time"
|
|
||||||
-t "$KUBERNETES_IMAGE"
|
|
||||||
-t "$image_tag"
|
|
||||||
)
|
|
||||||
if [ "$no_cache" -eq 1 ]; then
|
|
||||||
build_args+=(--no-cache --pull)
|
|
||||||
info "无缓存全量构建 (--no-cache --pull)"
|
|
||||||
fi
|
|
||||||
build_args+=(.)
|
|
||||||
|
|
||||||
info "构建中(前端 + 后端 embed)..."
|
|
||||||
docker build "${build_args[@]}" || {
|
|
||||||
error "镜像构建失败"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
local img_size
|
|
||||||
img_size=$(docker images "$KUBERNETES_IMAGE" --format "{{.Size}}" | head -1)
|
|
||||||
success "镜像构建完成: $KUBERNETES_IMAGE ($img_size)"
|
|
||||||
|
|
||||||
load_image_to_cluster "$KUBERNETES_IMAGE"
|
|
||||||
load_image_to_cluster "$image_tag"
|
|
||||||
KUBERNETES_BUILT_IMAGE="$image_tag"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# 读取 deployment.yaml 中的 replicas(默认 1)// Logan.Li
|
# 读取 deployment.yaml 中的 replicas(默认 1)// Logan.Li
|
||||||
@@ -1020,8 +1119,10 @@ cmd_kubernetes() {
|
|||||||
check_kubernetes_deps
|
check_kubernetes_deps
|
||||||
banner "========== Kubernetes 部署 ($KUBERNETES_NAMESPACE) =========="
|
banner "========== Kubernetes 部署 ($KUBERNETES_NAMESPACE) =========="
|
||||||
|
|
||||||
# 1. 构建镜像
|
# 1. 构建镜像(支持 deploy v1.0.1)
|
||||||
cmd_kubernetes_build
|
shift
|
||||||
|
cmd_kubernetes_build "$@"
|
||||||
|
kubernetes_update_manifest_image "$KUBERNETES_BUILT_IMAGE"
|
||||||
|
|
||||||
# 2. 部署基础设施
|
# 2. 部署基础设施
|
||||||
info "部署 Namespace + Secret + ConfigMap..."
|
info "部署 Namespace + Secret + ConfigMap..."
|
||||||
@@ -1080,7 +1181,9 @@ cmd_kubernetes() {
|
|||||||
live_replicas=$(kubernetes_live_replicas)
|
live_replicas=$(kubernetes_live_replicas)
|
||||||
live_replicas=${live_replicas:-1}
|
live_replicas=${live_replicas:-1}
|
||||||
ensure_cluster_mode_for_replicas "$live_replicas"
|
ensure_cluster_mode_for_replicas "$live_replicas"
|
||||||
cmd_kubernetes_build 1
|
shift
|
||||||
|
cmd_kubernetes_build fresh "$@"
|
||||||
|
kubernetes_update_manifest_image "$KUBERNETES_BUILT_IMAGE"
|
||||||
info "更新 Deployment 镜像: $KUBERNETES_BUILT_IMAGE"
|
info "更新 Deployment 镜像: $KUBERNETES_BUILT_IMAGE"
|
||||||
kubectl -n "$KUBERNETES_NAMESPACE" set image deployment/aiops aiops="$KUBERNETES_BUILT_IMAGE" --record
|
kubectl -n "$KUBERNETES_NAMESPACE" set image deployment/aiops aiops="$KUBERNETES_BUILT_IMAGE" --record
|
||||||
kubectl -n "$KUBERNETES_NAMESPACE" rollout status deployment/aiops --timeout=180s
|
kubectl -n "$KUBERNETES_NAMESPACE" rollout status deployment/aiops --timeout=180s
|
||||||
@@ -1108,7 +1211,13 @@ cmd_kubernetes() {
|
|||||||
;;
|
;;
|
||||||
|
|
||||||
build|image)
|
build|image)
|
||||||
cmd_kubernetes_build
|
shift
|
||||||
|
cmd_kubernetes_build "$@"
|
||||||
|
;;
|
||||||
|
|
||||||
|
push)
|
||||||
|
shift
|
||||||
|
cmd_kubernetes_build push "$@"
|
||||||
;;
|
;;
|
||||||
|
|
||||||
status|ps)
|
status|ps)
|
||||||
@@ -1189,9 +1298,10 @@ cmd_kubernetes() {
|
|||||||
echo " ./run.sh kubernetes port-forward 端口转发到本机 8080"
|
echo " ./run.sh kubernetes port-forward 端口转发到本机 8080"
|
||||||
echo ""
|
echo ""
|
||||||
echo " ${YELLOW}镜像${NC}"
|
echo " ${YELLOW}镜像${NC}"
|
||||||
echo " ./run.sh kubernetes build 仅构建 embed 镜像"
|
echo " ./run.sh kubernetes build v1.0.1 构建 embed 镜像"
|
||||||
|
echo " ./run.sh kubernetes push v1.0.1 构建并推送到 $DOCKERHUB_IMAGE"
|
||||||
echo ""
|
echo ""
|
||||||
echo " 镜像: $KUBERNETES_IMAGE"
|
echo " 镜像仓库: $DOCKERHUB_IMAGE:<tag>"
|
||||||
echo " 命名空间: $KUBERNETES_NAMESPACE"
|
echo " 命名空间: $KUBERNETES_NAMESPACE"
|
||||||
echo " NodePort: $KUBERNETES_NODE_PORT"
|
echo " NodePort: $KUBERNETES_NODE_PORT"
|
||||||
;;
|
;;
|
||||||
@@ -1204,6 +1314,55 @@ cmd_kubernetes() {
|
|||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 统一发版:git tag + 二进制 + Docker 镜像推送 + K8s manifest
|
||||||
|
# ============================================================
|
||||||
|
cmd_release() {
|
||||||
|
local version_tag=${1:-}
|
||||||
|
local skip_tag=${2:-}
|
||||||
|
|
||||||
|
if [ -z "$version_tag" ]; then
|
||||||
|
error "用法: ./run.sh release v1.0.1"
|
||||||
|
echo " 将依次: 打 git tag → 编译二进制 → 构建镜像 → 推送 $DOCKERHUB_IMAGE → 更新 K8s manifest"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if ! looks_like_version "$version_tag"; then
|
||||||
|
error "版本号格式无效: $version_tag (示例: v1.0.1)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
banner "========== 发版 $version_tag =========="
|
||||||
|
resolve_version "$version_tag"
|
||||||
|
|
||||||
|
if [ "$skip_tag" != "--skip-tag" ]; then
|
||||||
|
if git rev-parse "$version_tag" >/dev/null 2>&1; then
|
||||||
|
warning "git tag 已存在: $version_tag(跳过创建)"
|
||||||
|
else
|
||||||
|
git tag -a "$version_tag" -m "release $version_tag"
|
||||||
|
success "已创建 git tag: $version_tag"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
build_standalone_binary "$version_tag" || exit 1
|
||||||
|
info "二进制版本:"
|
||||||
|
./"$STANDALONE_BIN" version
|
||||||
|
|
||||||
|
build_embed_image "$version_tag" 0 1 || exit 1
|
||||||
|
kubernetes_update_manifest_image "$EMBED_IMAGE"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
success "发版完成: $version_tag"
|
||||||
|
echo " 二进制: ./$STANDALONE_BIN version"
|
||||||
|
echo " 镜像: $EMBED_IMAGE"
|
||||||
|
echo " 推送: docker push $EMBED_IMAGE"
|
||||||
|
echo " Compose: ./run.sh docker up $version_tag"
|
||||||
|
echo " K8s: ./run.sh kubernetes upgrade $version_tag"
|
||||||
|
echo ""
|
||||||
|
if [ "$skip_tag" != "--skip-tag" ]; then
|
||||||
|
info "如需推送 git tag: git push origin $version_tag"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# 帮助
|
# 帮助
|
||||||
# ============================================================
|
# ============================================================
|
||||||
@@ -1218,15 +1377,12 @@ cmd_help() {
|
|||||||
echo " ./run.sh status 查看本地服务状态"
|
echo " ./run.sh status 查看本地服务状态"
|
||||||
echo " ./run.sh logs 查看实时日志"
|
echo " ./run.sh logs 查看实时日志"
|
||||||
echo ""
|
echo ""
|
||||||
echo -e " ${CYAN}Docker 容器部署${NC}"
|
echo -e " ${CYAN}Docker 容器部署 (embed 单容器)${NC}"
|
||||||
echo " ./run.sh docker up 增量构建 + 强制重建容器"
|
echo " ./run.sh docker up 构建+启动 (MySQL+Redis+AIOps)"
|
||||||
echo " ./run.sh docker up fresh 无缓存全量重建并启动"
|
echo " ./run.sh docker up v1.0.1 指定版本"
|
||||||
echo " ./run.sh docker upgrade 同 up(升级别名)"
|
echo " ./run.sh docker push v1.0.1 构建并推送到 $DOCKERHUB_IMAGE"
|
||||||
echo " ./run.sh docker down 停止并移除容器"
|
echo " ./run.sh docker down 停止容器"
|
||||||
echo " ./run.sh docker build 仅构建镜像"
|
echo " ./run.sh docker logs 查看日志"
|
||||||
echo " ./run.sh docker restart 重启容器"
|
|
||||||
echo " ./run.sh docker logs 查看容器日志"
|
|
||||||
echo " ./run.sh docker ps 查看容器状态"
|
|
||||||
echo ""
|
echo ""
|
||||||
echo -e " ${MAGENTA}Kubernetes 部署 (embed 单容器)${NC}"
|
echo -e " ${MAGENTA}Kubernetes 部署 (embed 单容器)${NC}"
|
||||||
echo " ./run.sh kubernetes deploy 构建镜像 + 全量部署到 Kubernetes"
|
echo " ./run.sh kubernetes deploy 构建镜像 + 全量部署到 Kubernetes"
|
||||||
@@ -1244,6 +1400,7 @@ cmd_help() {
|
|||||||
echo -e " ${YELLOW}编译 & 独立二进制${NC}"
|
echo -e " ${YELLOW}编译 & 独立二进制${NC}"
|
||||||
echo " ./run.sh build 编译独立二进制 ./$STANDALONE_BIN (仅根目录)"
|
echo " ./run.sh build 编译独立二进制 ./$STANDALONE_BIN (仅根目录)"
|
||||||
echo " ./run.sh build tag v1.0.1 指定版本号编译"
|
echo " ./run.sh build tag v1.0.1 指定版本号编译"
|
||||||
|
echo " ./run.sh release v1.0.1 发版:tag+二进制+镜像推送+K8s"
|
||||||
echo " ./run.sh binary upgrade 停服→清旧→重编译→后台启动(生产升级)"
|
echo " ./run.sh binary upgrade 停服→清旧→重编译→后台启动(生产升级)"
|
||||||
echo " ./run.sh binary start|stop|status 进程管理"
|
echo " ./run.sh binary start|stop|status 进程管理"
|
||||||
echo " ./run.sh binary [args] 前台启动(调试)"
|
echo " ./run.sh binary [args] 前台启动(调试)"
|
||||||
@@ -1313,6 +1470,12 @@ main() {
|
|||||||
cmd_kubernetes "$@"
|
cmd_kubernetes "$@"
|
||||||
;;
|
;;
|
||||||
|
|
||||||
|
# 统一发版
|
||||||
|
release)
|
||||||
|
shift
|
||||||
|
cmd_release "$@"
|
||||||
|
;;
|
||||||
|
|
||||||
# 帮助
|
# 帮助
|
||||||
help|--help|-h)
|
help|--help|-h)
|
||||||
cmd_help
|
cmd_help
|
||||||
|
|||||||
Reference in new issue
Block a user