- 更新 Gitea runner 配置,支持优化的 CI/CD 环境 - 完善 Harbor HTTPS 配置和远程访问支持 - 优化 Harbor 日志配置,改用 json-file 驱动 - 添加 Docker 构建加速和代理缓存脚本 - 新增完整的文档和使用指南 - 添加 AI 开发工具集成配置 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1063 lines
26 KiB
Bash
Executable File
1063 lines
26 KiB
Bash
Executable File
#!/bin/bash
|
||
|
||
# Docker Builder - 智能构建工具
|
||
# 自动检测网络环境,选择最优构建策略,解决所有 Docker 构建问题
|
||
#
|
||
# 作者: Claude Code Assistant
|
||
# 版本: 1.0.0
|
||
# 许可: MIT
|
||
|
||
set -e
|
||
|
||
# 版本信息
|
||
VERSION="1.0.0"
|
||
SCRIPT_NAME="docker-builder"
|
||
|
||
# 默认配置
|
||
DEFAULT_DOCKERFILE="Dockerfile"
|
||
DEFAULT_TAG="latest"
|
||
DEFAULT_BUILD_CONTEXT="."
|
||
|
||
# 颜色输出
|
||
RED='\033[0;31m'
|
||
GREEN='\033[0;32m'
|
||
YELLOW='\033[1;33m'
|
||
BLUE='\033[0;34m'
|
||
PURPLE='\033[0;35m'
|
||
CYAN='\033[0;36m'
|
||
BOLD='\033[1m'
|
||
NC='\033[0m'
|
||
|
||
# 日志函数
|
||
info() { echo -e "${BLUE}ℹ️ $1${NC}"; }
|
||
success() { echo -e "${GREEN}✅ $1${NC}"; }
|
||
warning() { echo -e "${YELLOW}⚠️ $1${NC}"; }
|
||
error() { echo -e "${RED}❌ $1${NC}"; }
|
||
header() { echo -e "${PURPLE}${BOLD}🚀 $1${NC}"; }
|
||
step() { echo -e "${CYAN}▶ $1${NC}"; }
|
||
|
||
# 显示帮助信息
|
||
show_help() {
|
||
cat << EOF
|
||
${BOLD}Docker Builder - 智能构建工具 v${VERSION}${NC}
|
||
|
||
${BOLD}用法:${NC}
|
||
$0 [命令] [选项] [镜像名]
|
||
|
||
${BOLD}命令:${NC}
|
||
build 构建镜像 (默认)
|
||
init 初始化项目 Docker 配置
|
||
template 生成 Dockerfile 模板
|
||
doctor 诊断构建环境
|
||
install 安装到全局路径
|
||
update 更新工具
|
||
version 显示版本信息
|
||
help 显示帮助信息
|
||
|
||
${BOLD}选项:${NC}
|
||
-f, --file FILE Dockerfile 路径 (默认: Dockerfile)
|
||
-t, --tag TAG 镜像标签 (默认: latest)
|
||
-c, --context DIR 构建上下文目录 (默认: .)
|
||
-p, --proxy URL 强制使用代理
|
||
--no-proxy 禁用代理
|
||
--no-cache 禁用构建缓存
|
||
--push 构建后推送到 Harbor
|
||
--multi-arch 多架构构建
|
||
--strategy STRATEGY 构建策略 (auto|proxy|cache|direct|clean)
|
||
--template TYPE 模板类型 (node|python|go|java|generic)
|
||
--verbose 详细输出
|
||
--dry-run 预览命令,不执行
|
||
-q, --quiet 静默模式
|
||
-y, --yes 自动确认所有提示
|
||
|
||
${BOLD}构建策略:${NC}
|
||
auto 自动检测最优策略 (推荐)
|
||
proxy 强制使用代理透传
|
||
cache 使用本地缓存服务
|
||
direct 直接构建,清除代理配置
|
||
clean 生产环境优化构建
|
||
|
||
${BOLD}示例:${NC}
|
||
# 自动构建 (推荐)
|
||
$0 build myapp
|
||
|
||
# 使用特定策略
|
||
$0 build --strategy clean myapp
|
||
|
||
# 初始化项目
|
||
$0 init --template node
|
||
|
||
# 诊断环境
|
||
$0 doctor
|
||
|
||
# 多架构构建并推送
|
||
$0 build --multi-arch --push myapp:v1.0.0
|
||
|
||
${BOLD}全局安装:${NC}
|
||
$0 install # 安装到 /usr/local/bin/docker-builder
|
||
|
||
EOF
|
||
}
|
||
|
||
# 显示版本信息
|
||
show_version() {
|
||
echo "Docker Builder v${VERSION}"
|
||
echo "智能构建工具,解决所有 Docker 构建问题"
|
||
}
|
||
|
||
# 检测系统环境
|
||
detect_environment() {
|
||
header "检测构建环境..."
|
||
|
||
# Docker 环境
|
||
if command -v docker > /dev/null 2>&1; then
|
||
DOCKER_VERSION=$(docker --version | sed 's/.*version \(.*\),.*/\1/')
|
||
info "Docker 版本: $DOCKER_VERSION"
|
||
DOCKER_AVAILABLE=true
|
||
else
|
||
error "Docker 未安装或未启动"
|
||
return 1
|
||
fi
|
||
|
||
# BuildKit 支持
|
||
if docker buildx version > /dev/null 2>&1; then
|
||
BUILDKIT_VERSION=$(docker buildx version | head -1 | sed 's/.*\(github.com.*\)/\1/')
|
||
info "BuildKit: 可用 ($BUILDKIT_VERSION)"
|
||
BUILDKIT_AVAILABLE=true
|
||
else
|
||
warning "BuildKit: 不可用,将使用传统构建器"
|
||
BUILDKIT_AVAILABLE=false
|
||
fi
|
||
|
||
# 网络环境检测
|
||
info "检测网络环境..."
|
||
|
||
# 检测外网直连
|
||
if timeout 5 curl -s http://deb.debian.org > /dev/null 2>&1; then
|
||
info "✅ 外网直连正常"
|
||
DIRECT_CONNECT=true
|
||
else
|
||
info "❌ 外网直连异常"
|
||
DIRECT_CONNECT=false
|
||
fi
|
||
|
||
# 检测代理服务
|
||
DETECTED_PROXY=""
|
||
for port in 7890 1087 8080 8888 8889; do
|
||
if timeout 2 nc -z localhost $port 2>/dev/null; then
|
||
DETECTED_PROXY="http://127.0.0.1:$port"
|
||
info "✅ 检测到代理: $DETECTED_PROXY"
|
||
break
|
||
fi
|
||
done
|
||
|
||
# 检测 APT 缓存服务
|
||
if timeout 2 curl -s "http://localhost:3142" > /dev/null 2>&1; then
|
||
info "✅ APT 缓存服务可用: http://localhost:3142"
|
||
APT_CACHE_AVAILABLE=true
|
||
else
|
||
info "❌ APT 缓存服务不可用"
|
||
APT_CACHE_AVAILABLE=false
|
||
fi
|
||
|
||
# 检测 Harbor 服务
|
||
if timeout 5 curl -sk "https://192.168.1.83:8443/api/v2.0/health" > /dev/null 2>&1; then
|
||
info "✅ Harbor 服务可用"
|
||
HARBOR_AVAILABLE=true
|
||
else
|
||
info "❌ Harbor 服务不可用"
|
||
HARBOR_AVAILABLE=false
|
||
fi
|
||
|
||
success "环境检测完成"
|
||
return 0
|
||
}
|
||
|
||
# 选择构建策略
|
||
select_strategy() {
|
||
local strategy="$1"
|
||
|
||
if [ "$strategy" != "auto" ]; then
|
||
STRATEGY="$strategy"
|
||
return
|
||
fi
|
||
|
||
info "自动选择最优构建策略..."
|
||
|
||
# 策略优先级: clean > cache > proxy > direct
|
||
if [ "$DIRECT_CONNECT" = true ]; then
|
||
STRATEGY="clean"
|
||
info "选择策略: clean (直接构建 + 清除代理配置)"
|
||
elif [ "$APT_CACHE_AVAILABLE" = true ]; then
|
||
STRATEGY="cache"
|
||
info "选择策略: cache (使用本地缓存)"
|
||
elif [ -n "$DETECTED_PROXY" ]; then
|
||
STRATEGY="proxy"
|
||
info "选择策略: proxy (使用代理透传)"
|
||
else
|
||
STRATEGY="clean"
|
||
info "选择策略: clean (网络清理构建)"
|
||
fi
|
||
}
|
||
|
||
# 生成构建命令
|
||
generate_build_command() {
|
||
local image_name="$1"
|
||
local dockerfile="$2"
|
||
local context="$3"
|
||
local build_cmd="docker build"
|
||
|
||
# 添加 BuildKit 支持
|
||
if [ "$BUILDKIT_AVAILABLE" = true ] && [ "$NO_CACHE" != true ]; then
|
||
export DOCKER_BUILDKIT=1
|
||
build_cmd="$build_cmd --build-arg BUILDKIT_INLINE_CACHE=1"
|
||
fi
|
||
|
||
# 根据策略添加构建参数
|
||
case "$STRATEGY" in
|
||
proxy)
|
||
if [ -n "$FORCED_PROXY" ]; then
|
||
build_cmd="$build_cmd --build-arg HTTP_PROXY=$FORCED_PROXY"
|
||
build_cmd="$build_cmd --build-arg HTTPS_PROXY=$FORCED_PROXY"
|
||
build_cmd="$build_cmd --build-arg NO_PROXY=localhost,127.0.0.1,192.168.1.83"
|
||
elif [ -n "$DETECTED_PROXY" ]; then
|
||
build_cmd="$build_cmd --build-arg HTTP_PROXY=$DETECTED_PROXY"
|
||
build_cmd="$build_cmd --build-arg HTTPS_PROXY=$DETECTED_PROXY"
|
||
build_cmd="$build_cmd --build-arg NO_PROXY=localhost,127.0.0.1,192.168.1.83"
|
||
fi
|
||
;;
|
||
cache)
|
||
build_cmd="$build_cmd --build-arg APT_PROXY=http://host.docker.internal:3142"
|
||
;;
|
||
clean|direct)
|
||
build_cmd="$build_cmd --build-arg HTTP_PROXY="
|
||
build_cmd="$build_cmd --build-arg HTTPS_PROXY="
|
||
;;
|
||
esac
|
||
|
||
# 添加缓存支持 (仅在多架构或推送时使用)
|
||
if [ "$NO_CACHE" != true ] && [ "$HARBOR_AVAILABLE" = true ] && ([ "$MULTI_ARCH" = true ] || [ "$PUSH_TO_HARBOR" = true ]); then
|
||
build_cmd="$build_cmd --cache-from type=registry,ref=192.168.1.83:8443/build-cache/$image_name:buildcache"
|
||
if [ "$BUILDKIT_AVAILABLE" = true ]; then
|
||
build_cmd="$build_cmd --cache-to type=registry,ref=192.168.1.83:8443/build-cache/$image_name:buildcache,mode=max"
|
||
fi
|
||
fi
|
||
|
||
# 多架构构建
|
||
if [ "$MULTI_ARCH" = true ]; then
|
||
build_cmd="$build_cmd --platform linux/amd64,linux/arm64"
|
||
build_cmd="$build_cmd --push"
|
||
fi
|
||
|
||
# 添加标签
|
||
local full_image_name="$image_name:$TAG"
|
||
if [ "$PUSH_TO_HARBOR" = true ] && [ "$HARBOR_AVAILABLE" = true ] && [ "$MULTI_ARCH" != true ]; then
|
||
full_image_name="192.168.1.83:8443/library/$image_name:$TAG"
|
||
fi
|
||
build_cmd="$build_cmd -t $full_image_name"
|
||
|
||
# 添加 Dockerfile 和上下文
|
||
build_cmd="$build_cmd -f $dockerfile $context"
|
||
|
||
echo "$build_cmd"
|
||
}
|
||
|
||
# 执行构建
|
||
execute_build() {
|
||
local image_name="$1"
|
||
local dockerfile="$2"
|
||
local context="$3"
|
||
|
||
header "开始构建镜像..."
|
||
|
||
local build_cmd=$(generate_build_command "$image_name" "$dockerfile" "$context")
|
||
|
||
if [ "$VERBOSE" = true ] || [ "$DRY_RUN" = true ]; then
|
||
info "构建命令:"
|
||
echo "$build_cmd"
|
||
echo ""
|
||
fi
|
||
|
||
if [ "$DRY_RUN" = false ]; then
|
||
# 推送到 Harbor 前登录
|
||
if [ "$PUSH_TO_HARBOR" = true ] && [ "$HARBOR_AVAILABLE" = true ] && [ "$MULTI_ARCH" != true ]; then
|
||
info "登录 Harbor..."
|
||
echo "admin123" | docker login 192.168.1.83:8443 -u admin --password-stdin > /dev/null 2>&1
|
||
fi
|
||
|
||
if [ "$QUIET" = false ]; then
|
||
info "执行构建..."
|
||
fi
|
||
|
||
# 执行构建
|
||
if eval "$build_cmd"; then
|
||
success "构建完成: $image_name:$TAG"
|
||
|
||
# 显示镜像信息
|
||
if [ "$MULTI_ARCH" = false ]; then
|
||
local size=$(docker images "$image_name:$TAG" --format "{{.Size}}" 2>/dev/null || echo "未知")
|
||
info "镜像大小: $size"
|
||
fi
|
||
else
|
||
error "构建失败"
|
||
return 1
|
||
fi
|
||
fi
|
||
}
|
||
|
||
# 生成 Dockerfile 模板
|
||
generate_dockerfile() {
|
||
local template_type="$1"
|
||
local output_file="$2"
|
||
|
||
header "生成 Dockerfile 模板..."
|
||
|
||
case "$template_type" in
|
||
node)
|
||
generate_node_dockerfile "$output_file"
|
||
;;
|
||
python)
|
||
generate_python_dockerfile "$output_file"
|
||
;;
|
||
go)
|
||
generate_go_dockerfile "$output_file"
|
||
;;
|
||
java)
|
||
generate_java_dockerfile "$output_file"
|
||
;;
|
||
generic)
|
||
generate_generic_dockerfile "$output_file"
|
||
;;
|
||
*)
|
||
error "未知的模板类型: $template_type"
|
||
info "支持的类型: node, python, go, java, generic"
|
||
return 1
|
||
;;
|
||
esac
|
||
}
|
||
|
||
# Node.js 模板
|
||
generate_node_dockerfile() {
|
||
local output_file="$1"
|
||
cat > "$output_file" << 'EOF'
|
||
# Node.js 应用 Dockerfile - 自动优化版本
|
||
# 由 docker-builder 生成
|
||
|
||
# 构建阶段
|
||
FROM node:18-alpine AS builder
|
||
|
||
# 清除代理配置,避免网络冲突
|
||
ENV HTTP_PROXY=""
|
||
ENV HTTPS_PROXY=""
|
||
ENV http_proxy=""
|
||
ENV https_proxy=""
|
||
|
||
WORKDIR /app
|
||
|
||
# 使用国内镜像源加速
|
||
RUN npm config delete proxy && \
|
||
npm config delete https-proxy && \
|
||
npm config set registry https://registry.npmmirror.com && \
|
||
npm config set cache /tmp/.npm --global
|
||
|
||
# 复制 package 文件
|
||
COPY package*.json ./
|
||
|
||
# 安装依赖
|
||
RUN npm install --frozen-lockfile
|
||
|
||
# 复制源代码
|
||
COPY . .
|
||
|
||
# 构建应用
|
||
RUN npm run build
|
||
|
||
# 生产阶段
|
||
FROM node:18-alpine AS production
|
||
|
||
# 清除代理配置
|
||
ENV HTTP_PROXY=""
|
||
ENV HTTPS_PROXY=""
|
||
ENV http_proxy=""
|
||
ENV https_proxy=""
|
||
|
||
WORKDIR /app
|
||
|
||
# 配置 npm 使用国内镜像源
|
||
RUN npm config delete proxy && \
|
||
npm config delete https-proxy && \
|
||
npm config set registry https://registry.npmmirror.com
|
||
|
||
# 只安装运行时工具
|
||
RUN npm install -g serve
|
||
|
||
# 复制构建产物
|
||
COPY --from=builder /app/dist ./dist
|
||
COPY --from=builder /app/package.json ./
|
||
|
||
# 暴露端口
|
||
EXPOSE 3000
|
||
|
||
# 健康检查
|
||
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
|
||
CMD wget --no-verbose --tries=1 --spider http://localhost:3000 || exit 1
|
||
|
||
# 启动应用
|
||
CMD ["serve", "-s", "dist", "-l", "3000"]
|
||
EOF
|
||
success "Node.js Dockerfile 模板已生成: $output_file"
|
||
}
|
||
|
||
# Python 模板
|
||
generate_python_dockerfile() {
|
||
local output_file="$1"
|
||
cat > "$output_file" << 'EOF'
|
||
# Python 应用 Dockerfile - 自动优化版本
|
||
# 由 docker-builder 生成
|
||
|
||
FROM python:3.11-slim as base
|
||
|
||
# 清除代理配置
|
||
ENV HTTP_PROXY=""
|
||
ENV HTTPS_PROXY=""
|
||
ENV http_proxy=""
|
||
ENV https_proxy=""
|
||
|
||
# 设置工作目录
|
||
WORKDIR /app
|
||
|
||
# 使用国内 pip 镜像源
|
||
RUN pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple && \
|
||
pip config set global.trusted-host pypi.tuna.tsinghua.edu.cn
|
||
|
||
# 复制依赖文件
|
||
COPY requirements.txt .
|
||
|
||
# 安装依赖
|
||
RUN pip install --no-cache-dir -r requirements.txt
|
||
|
||
# 复制源代码
|
||
COPY . .
|
||
|
||
# 暴露端口
|
||
EXPOSE 8000
|
||
|
||
# 健康检查
|
||
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
|
||
CMD curl -f http://localhost:8000/health || exit 1
|
||
|
||
# 启动应用
|
||
CMD ["python", "app.py"]
|
||
EOF
|
||
success "Python Dockerfile 模板已生成: $output_file"
|
||
}
|
||
|
||
# Go 模板
|
||
generate_go_dockerfile() {
|
||
local output_file="$1"
|
||
cat > "$output_file" << 'EOF'
|
||
# Go 应用 Dockerfile - 自动优化版本
|
||
# 由 docker-builder 生成
|
||
|
||
# 构建阶段
|
||
FROM golang:1.21-alpine AS builder
|
||
|
||
# 清除代理配置
|
||
ENV HTTP_PROXY=""
|
||
ENV HTTPS_PROXY=""
|
||
ENV http_proxy=""
|
||
ENV https_proxy=""
|
||
|
||
WORKDIR /app
|
||
|
||
# 配置 Go 代理使用国内源
|
||
ENV GOPROXY=https://goproxy.cn,direct
|
||
ENV GOSUMDB=sum.golang.google.cn
|
||
|
||
# 复制 go mod 文件
|
||
COPY go.mod go.sum ./
|
||
|
||
# 下载依赖
|
||
RUN go mod download && go mod verify
|
||
|
||
# 复制源代码
|
||
COPY . .
|
||
|
||
# 构建应用
|
||
RUN CGO_ENABLED=0 GOOS=linux go build -o /app/server .
|
||
|
||
# 运行阶段
|
||
FROM alpine:3.18
|
||
|
||
# 清除代理配置
|
||
ENV HTTP_PROXY=""
|
||
ENV HTTPS_PROXY=""
|
||
ENV http_proxy=""
|
||
ENV https_proxy=""
|
||
|
||
# 安装 ca 证书
|
||
RUN apk --no-cache add ca-certificates
|
||
|
||
WORKDIR /root/
|
||
|
||
# 从构建阶段复制二进制文件
|
||
COPY --from=builder /app/server .
|
||
|
||
# 暴露端口
|
||
EXPOSE 8080
|
||
|
||
# 健康检查
|
||
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
|
||
CMD wget --no-verbose --tries=1 --spider http://localhost:8080/health || exit 1
|
||
|
||
# 启动应用
|
||
CMD ["./server"]
|
||
EOF
|
||
success "Go Dockerfile 模板已生成: $output_file"
|
||
}
|
||
|
||
# Java 模板
|
||
generate_java_dockerfile() {
|
||
local output_file="$1"
|
||
cat > "$output_file" << 'EOF'
|
||
# Java 应用 Dockerfile - 自动优化版本
|
||
# 由 docker-builder 生成
|
||
|
||
# 使用国内镜像源
|
||
FROM maven:3.9-openjdk-17 AS builder
|
||
|
||
# 清除代理配置
|
||
ENV HTTP_PROXY=""
|
||
ENV HTTPS_PROXY=""
|
||
ENV http_proxy=""
|
||
ENV https_proxy=""
|
||
|
||
WORKDIR /app
|
||
|
||
# 配置 Maven 使用国内镜像源
|
||
RUN mkdir -p /root/.m2 && \
|
||
echo '<?xml version="1.0" encoding="UTF-8"?>' > /root/.m2/settings.xml && \
|
||
echo '<settings>' >> /root/.m2/settings.xml && \
|
||
echo ' <mirrors>' >> /root/.m2/settings.xml && \
|
||
echo ' <mirror>' >> /root/.m2/settings.xml && \
|
||
echo ' <id>aliyun</id>' >> /root/.m2/settings.xml && \
|
||
echo ' <mirrorOf>central</mirrorOf>' >> /root/.m2/settings.xml && \
|
||
echo ' <url>https://maven.aliyun.com/repository/public</url>' >> /root/.m2/settings.xml && \
|
||
echo ' </mirror>' >> /root/.m2/settings.xml && \
|
||
echo ' </mirrors>' >> /root/.m2/settings.xml && \
|
||
echo '</settings>' >> /root/.m2/settings.xml
|
||
|
||
# 复制 pom.xml
|
||
COPY pom.xml .
|
||
|
||
# 下载依赖
|
||
RUN mvn dependency:go-offline
|
||
|
||
# 复制源代码
|
||
COPY src ./src
|
||
|
||
# 构建应用
|
||
RUN mvn clean package -DskipTests
|
||
|
||
# 运行阶段
|
||
FROM openjdk:17-jre-slim
|
||
|
||
# 清除代理配置
|
||
ENV HTTP_PROXY=""
|
||
ENV HTTPS_PROXY=""
|
||
ENV http_proxy=""
|
||
ENV https_proxy=""
|
||
|
||
WORKDIR /app
|
||
|
||
# 复制构建产物
|
||
COPY --from=builder /app/target/*.jar app.jar
|
||
|
||
# 暴露端口
|
||
EXPOSE 8080
|
||
|
||
# 健康检查
|
||
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
|
||
CMD curl -f http://localhost:8080/actuator/health || exit 1
|
||
|
||
# 启动应用
|
||
CMD ["java", "-jar", "app.jar"]
|
||
EOF
|
||
success "Java Dockerfile 模板已生成: $output_file"
|
||
}
|
||
|
||
# 通用模板
|
||
generate_generic_dockerfile() {
|
||
local output_file="$1"
|
||
cat > "$output_file" << 'EOF'
|
||
# 通用应用 Dockerfile - 自动优化版本
|
||
# 由 docker-builder 生成
|
||
|
||
FROM alpine:3.18
|
||
|
||
# 清除代理配置
|
||
ENV HTTP_PROXY=""
|
||
ENV HTTPS_PROXY=""
|
||
ENV http_proxy=""
|
||
ENV https_proxy=""
|
||
|
||
# 使用国内镜像源
|
||
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories
|
||
|
||
WORKDIR /app
|
||
|
||
# 安装基础工具
|
||
RUN apk add --no-cache ca-certificates curl
|
||
|
||
# 复制应用文件
|
||
COPY . .
|
||
|
||
# 暴露端口 (根据需要修改)
|
||
EXPOSE 8080
|
||
|
||
# 健康检查
|
||
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
|
||
CMD curl -f http://localhost:8080 || exit 1
|
||
|
||
# 启动命令 (根据需要修改)
|
||
CMD ["./start.sh"]
|
||
EOF
|
||
success "通用 Dockerfile 模板已生成: $output_file"
|
||
}
|
||
|
||
# 初始化项目
|
||
init_project() {
|
||
local template_type="$1"
|
||
local auto_confirm="$2"
|
||
|
||
header "初始化项目 Docker 配置..."
|
||
|
||
# 检测项目类型
|
||
if [ -z "$template_type" ]; then
|
||
if [ -f "package.json" ]; then
|
||
template_type="node"
|
||
info "检测到 Node.js 项目"
|
||
elif [ -f "requirements.txt" ] || [ -f "setup.py" ]; then
|
||
template_type="python"
|
||
info "检测到 Python 项目"
|
||
elif [ -f "go.mod" ]; then
|
||
template_type="go"
|
||
info "检测到 Go 项目"
|
||
elif [ -f "pom.xml" ]; then
|
||
template_type="java"
|
||
info "检测到 Java 项目"
|
||
else
|
||
template_type="generic"
|
||
info "使用通用模板"
|
||
fi
|
||
fi
|
||
|
||
# 生成 Dockerfile
|
||
local dockerfile="$DEFAULT_DOCKERFILE"
|
||
if [ -f "$dockerfile" ] && [ "$auto_confirm" != true ]; then
|
||
read -p "Dockerfile 已存在,是否覆盖? (y/N): " -n 1 -r
|
||
echo
|
||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||
info "跳过 Dockerfile 生成"
|
||
else
|
||
generate_dockerfile "$template_type" "$dockerfile"
|
||
fi
|
||
else
|
||
generate_dockerfile "$template_type" "$dockerfile"
|
||
fi
|
||
|
||
# 生成 .dockerignore
|
||
if [ ! -f ".dockerignore" ]; then
|
||
cat > .dockerignore << EOF
|
||
# Git
|
||
.git
|
||
.gitignore
|
||
|
||
# Node.js
|
||
node_modules
|
||
npm-debug.log
|
||
yarn-error.log
|
||
|
||
# Python
|
||
__pycache__
|
||
*.pyc
|
||
*.pyo
|
||
*.pyd
|
||
.venv
|
||
env/
|
||
venv/
|
||
|
||
# Go
|
||
*.exe
|
||
*.exe~
|
||
*.dll
|
||
*.so
|
||
*.dylib
|
||
*.test
|
||
*.out
|
||
|
||
# IDE
|
||
.vscode
|
||
.idea
|
||
*.swp
|
||
*.swo
|
||
|
||
# OS
|
||
.DS_Store
|
||
Thumbs.db
|
||
|
||
# Logs
|
||
logs
|
||
*.log
|
||
|
||
# Runtime
|
||
dist
|
||
build
|
||
target/
|
||
EOF
|
||
success ".dockerignore 已生成"
|
||
fi
|
||
|
||
# 生成 docker-compose.yml
|
||
if [ ! -f "docker-compose.yml" ]; then
|
||
local port=3000
|
||
case "$template_type" in
|
||
node) port=3000 ;;
|
||
python) port=8000 ;;
|
||
go) port=8080 ;;
|
||
java) port=8080 ;;
|
||
esac
|
||
|
||
cat > docker-compose.yml << EOF
|
||
version: '3.8'
|
||
|
||
services:
|
||
app:
|
||
build: .
|
||
ports:
|
||
- "${port}:${port}"
|
||
environment:
|
||
- NODE_ENV=production
|
||
restart: unless-stopped
|
||
EOF
|
||
success "docker-compose.yml 已生成"
|
||
fi
|
||
|
||
success "项目初始化完成!"
|
||
info ""
|
||
info "下一步操作:"
|
||
info " 1. 编辑 Dockerfile (如果需要)"
|
||
info " 2. 运行: docker-builder build $(basename "$PWD")"
|
||
info " 3. 启动: docker-compose up"
|
||
}
|
||
|
||
# 诊断构建环境
|
||
doctor() {
|
||
header "Docker 构建环境诊断"
|
||
echo ""
|
||
|
||
# Docker 环境
|
||
echo "🐳 Docker 环境:"
|
||
if command -v docker > /dev/null; then
|
||
echo " ✅ Docker 已安装: $(docker --version)"
|
||
if docker info > /dev/null 2>&1; then
|
||
echo " ✅ Docker 服务正常"
|
||
else
|
||
echo " ❌ Docker 服务异常"
|
||
fi
|
||
|
||
if docker buildx version > /dev/null 2>&1; then
|
||
echo " ✅ BuildKit 可用"
|
||
else
|
||
echo " ⚠️ BuildKit 不可用"
|
||
fi
|
||
else
|
||
echo " ❌ Docker 未安装"
|
||
fi
|
||
echo ""
|
||
|
||
# 网络环境
|
||
echo "🌐 网络环境:"
|
||
if timeout 5 curl -s http://deb.debian.org > /dev/null 2>&1; then
|
||
echo " ✅ 外网连接正常"
|
||
else
|
||
echo " ❌ 外网连接异常"
|
||
fi
|
||
|
||
# 代理检测
|
||
local proxy_found=false
|
||
for port in 7890 1087 8080 8888; do
|
||
if nc -z localhost $port 2>/dev/null; then
|
||
echo " ✅ 代理服务: localhost:$port"
|
||
proxy_found=true
|
||
fi
|
||
done
|
||
if [ "$proxy_found" = false ]; then
|
||
echo " ❌ 未检测到代理服务"
|
||
fi
|
||
|
||
# APT 缓存
|
||
if timeout 2 curl -s "http://localhost:3142" > /dev/null 2>&1; then
|
||
echo " ✅ APT 缓存服务可用"
|
||
else
|
||
echo " ❌ APT 缓存服务不可用"
|
||
fi
|
||
|
||
# Harbor 服务
|
||
if timeout 5 curl -sk "https://192.168.1.83:8443/api/v2.0/health" > /dev/null 2>&1; then
|
||
echo " ✅ Harbor 服务可用"
|
||
else
|
||
echo " ❌ Harbor 服务不可用"
|
||
fi
|
||
echo ""
|
||
|
||
# 项目配置
|
||
echo "📁 项目配置:"
|
||
if [ -f "Dockerfile" ]; then
|
||
echo " ✅ Dockerfile 存在"
|
||
else
|
||
echo " ❌ Dockerfile 不存在"
|
||
fi
|
||
|
||
if [ -f "package.json" ]; then
|
||
echo " ✅ Node.js 项目"
|
||
elif [ -f "requirements.txt" ]; then
|
||
echo " ✅ Python 项目"
|
||
elif [ -f "go.mod" ]; then
|
||
echo " ✅ Go 项目"
|
||
elif [ -f "pom.xml" ]; then
|
||
echo " ✅ Java 项目"
|
||
else
|
||
echo " ⚠️ 项目类型未知"
|
||
fi
|
||
|
||
if [ -f ".dockerignore" ]; then
|
||
echo " ✅ .dockerignore 存在"
|
||
else
|
||
echo " ⚠️ .dockerignore 不存在"
|
||
fi
|
||
echo ""
|
||
|
||
# 建议
|
||
echo "💡 建议:"
|
||
if ! command -v docker > /dev/null; then
|
||
echo " • 安装 Docker Desktop 或 Docker Engine"
|
||
fi
|
||
if ! docker buildx version > /dev/null 2>&1; then
|
||
echo " • 启用 BuildKit 以获得更好的构建性能"
|
||
fi
|
||
if ! timeout 5 curl -s "http://deb.debian.org" > /dev/null 2>&1; then
|
||
echo " • 检查网络连接或配置代理"
|
||
fi
|
||
if [ ! -f "Dockerfile" ]; then
|
||
echo " • 运行 'docker-builder init' 初始化项目"
|
||
fi
|
||
}
|
||
|
||
# 安装到全局
|
||
install_global() {
|
||
header "安装 docker-builder 到全局..."
|
||
|
||
local install_dir="/usr/local/bin"
|
||
local install_path="$install_dir/docker-builder"
|
||
|
||
# 检查权限
|
||
if [ ! -w "$install_dir" ]; then
|
||
error "权限不足,请使用 sudo 运行:"
|
||
echo " sudo $0 install"
|
||
return 1
|
||
fi
|
||
|
||
# 复制脚本
|
||
cp "$0" "$install_path"
|
||
chmod +x "$install_path"
|
||
|
||
success "已安装到: $install_path"
|
||
info "现在可以在任何位置使用 'docker-builder' 命令"
|
||
|
||
# 验证安装
|
||
if command -v docker-builder > /dev/null; then
|
||
info "安装验证成功: $(docker-builder --version)"
|
||
else
|
||
warning "请确保 $install_dir 在 PATH 中"
|
||
fi
|
||
}
|
||
|
||
# 更新工具
|
||
update_tool() {
|
||
header "更新 docker-builder..."
|
||
|
||
local script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
local script_path="$script_dir/$(basename "$0")"
|
||
|
||
if [ -f "$script_path" ]; then
|
||
echo "当前版本: $VERSION"
|
||
echo "请从源码仓库更新此脚本"
|
||
else
|
||
error "无法找到脚本文件"
|
||
fi
|
||
}
|
||
|
||
# 主函数
|
||
main() {
|
||
# 默认值
|
||
COMMAND="build"
|
||
DOCKERFILE="$DEFAULT_DOCKERFILE"
|
||
TAG="$DEFAULT_TAG"
|
||
CONTEXT="$DEFAULT_BUILD_CONTEXT"
|
||
STRATEGY="auto"
|
||
TEMPLATE_TYPE=""
|
||
FORCED_PROXY=""
|
||
NO_CACHE=false
|
||
PUSH_TO_HARBOR=false
|
||
MULTI_ARCH=false
|
||
VERBOSE=false
|
||
DRY_RUN=false
|
||
QUIET=false
|
||
AUTO_CONFIRM=false
|
||
|
||
# 解析命令行参数
|
||
while [[ $# -gt 0 ]]; do
|
||
case $1 in
|
||
build|init|template|doctor|install|update|version|help)
|
||
COMMAND="$1"
|
||
shift
|
||
;;
|
||
-f|--file)
|
||
DOCKERFILE="$2"
|
||
shift 2
|
||
;;
|
||
-t|--tag)
|
||
TAG="$2"
|
||
shift 2
|
||
;;
|
||
-c|--context)
|
||
CONTEXT="$2"
|
||
shift 2
|
||
;;
|
||
-p|--proxy)
|
||
FORCED_PROXY="$2"
|
||
shift 2
|
||
;;
|
||
--no-proxy)
|
||
STRATEGY="clean"
|
||
shift
|
||
;;
|
||
--no-cache)
|
||
NO_CACHE=true
|
||
shift
|
||
;;
|
||
--push)
|
||
PUSH_TO_HARBOR=true
|
||
shift
|
||
;;
|
||
--multi-arch)
|
||
MULTI_ARCH=true
|
||
shift
|
||
;;
|
||
--strategy)
|
||
STRATEGY="$2"
|
||
shift 2
|
||
;;
|
||
--template)
|
||
TEMPLATE_TYPE="$2"
|
||
shift 2
|
||
;;
|
||
--verbose)
|
||
VERBOSE=true
|
||
shift
|
||
;;
|
||
--dry-run)
|
||
DRY_RUN=true
|
||
shift
|
||
;;
|
||
-q|--quiet)
|
||
QUIET=true
|
||
shift
|
||
;;
|
||
-y|--yes)
|
||
AUTO_CONFIRM=true
|
||
shift
|
||
;;
|
||
-h|--help)
|
||
show_help
|
||
exit 0
|
||
;;
|
||
--version)
|
||
show_version
|
||
exit 0
|
||
;;
|
||
-*)
|
||
error "未知选项: $1"
|
||
show_help
|
||
exit 1
|
||
;;
|
||
*)
|
||
# 位置参数
|
||
if [ -z "$IMAGE_NAME" ]; then
|
||
IMAGE_NAME="$1"
|
||
elif [ -z "$TAG" ] && [ "$TAG" = "$DEFAULT_TAG" ]; then
|
||
TAG="$1"
|
||
fi
|
||
shift
|
||
;;
|
||
esac
|
||
done
|
||
|
||
# 执行命令
|
||
case "$COMMAND" in
|
||
build)
|
||
if [ -z "$IMAGE_NAME" ]; then
|
||
error "请指定镜像名称"
|
||
info "用法: $0 build <镜像名>"
|
||
exit 1
|
||
fi
|
||
|
||
if [ ! -f "$DOCKERFILE" ]; then
|
||
error "Dockerfile 不存在: $DOCKERFILE"
|
||
info "运行 'docker-builder init' 初始化项目"
|
||
exit 1
|
||
fi
|
||
|
||
detect_environment
|
||
select_strategy "$STRATEGY"
|
||
execute_build "$IMAGE_NAME" "$DOCKERFILE" "$CONTEXT"
|
||
;;
|
||
init)
|
||
init_project "$TEMPLATE_TYPE" "$AUTO_CONFIRM"
|
||
;;
|
||
template)
|
||
if [ -z "$TEMPLATE_TYPE" ]; then
|
||
error "请指定模板类型"
|
||
info "支持类型: node, python, go, java, generic"
|
||
exit 1
|
||
fi
|
||
generate_dockerfile "$TEMPLATE_TYPE" "$DOCKERFILE"
|
||
;;
|
||
doctor)
|
||
doctor
|
||
;;
|
||
install)
|
||
install_global
|
||
;;
|
||
update)
|
||
update_tool
|
||
;;
|
||
version)
|
||
show_version
|
||
;;
|
||
help)
|
||
show_help
|
||
;;
|
||
*)
|
||
error "未知命令: $COMMAND"
|
||
show_help
|
||
exit 1
|
||
;;
|
||
esac
|
||
}
|
||
|
||
# 检查是否直接执行
|
||
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
||
main "$@"
|
||
fi |