diff --git a/.gitea/workflows/build-push-harbor.yml b/.gitea/workflows/build-push-harbor.yml deleted file mode 100644 index ea40608..0000000 --- a/.gitea/workflows/build-push-harbor.yml +++ /dev/null @@ -1,150 +0,0 @@ -name: build-and-push-harbor - -on: - push: - branches: - - main - - master - - dev - - "feature/**" - workflow_dispatch: - -jobs: - docker-build-push: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: http://103.236.53.208:3000/actions/checkout@v4 - - - name: Set image tags - id: vars - run: | - echo "short_sha=${GITHUB_SHA::7}" >> "$GITHUB_OUTPUT" - echo "date_tag=$(date +%Y%m%d%H%M%S)" >> "$GITHUB_OUTPUT" - - # 调试步骤:检查 Secret 是否正确读取 (只会输出字符长度,不会泄露密码) - - name: Debug Secrets - run: | - echo "Registry: ${{ secrets.HARBOR_REGISTRY }}" - echo "User length: ${#HARBOR_USERNAME}" - echo "Pass length: ${#HARBOR_PASSWORD}" - env: - HARBOR_USERNAME: ${{ secrets.HARBOR_USERNAME }} - HARBOR_PASSWORD: ${{ secrets.HARBOR_PASSWORD }} - - - name: Login Harbor - env: - HARBOR_REGISTRY: ${{ secrets.HARBOR_REGISTRY }} - HARBOR_USERNAME: ${{ secrets.HARBOR_USERNAME }} - HARBOR_PASSWORD: ${{ secrets.HARBOR_PASSWORD }} - run: | - # 尝试登录,如果失败会打印详细信息 - echo "$HARBOR_PASSWORD" | docker login "$HARBOR_REGISTRY" -u "$HARBOR_USERNAME" --password-stdin - - - name: Build and Push Monorepo Services - env: - HARBOR_REGISTRY: ${{ secrets.HARBOR_REGISTRY }} - HARBOR_PROJECT: ${{ secrets.HARBOR_PROJECT }} - SHORT_SHA: ${{ steps.vars.outputs.short_sha }} - DATE_TAG: ${{ steps.vars.outputs.date_tag }} - shell: bash - run: | - set -euo pipefail - - # 1. 定义要遍历的微服务根目录 (根据你的项目结构) - # 你的结构是 app// - # 我们只关心 api, rpc, mq 这三种类型 - - echo "🔍 开始扫描 Go-Zero 微服务..." - - # 找到 app 下所有的 api/rpc/mq 目录 - find app -mindepth 2 -maxdepth 2 -type d \( -name "api" -o -name "rpc" -o -name "mq" \) | sort | while read -r service_dir; do - - # service_dir 举例: app/community/api - service_type=$(basename "$service_dir") # api - parent_dir=$(dirname "$service_dir") # app/community - service_name=$(basename "$parent_dir") # community - - # 2. 智能查找入口文件 (main.go 或 service_name.go) - # 在当前目录下查找含有 "package main" 的 .go 文件 - entry_file=$(grep -l "package main" "$service_dir"/*.go | head -n 1 || true) - - if [[ -z "$entry_file" ]]; then - echo "⚠️ 跳过 $service_dir: 未找到 package main 入口文件" - continue - fi - - # 3. 智能查找配置文件 (etc/*.yaml) - config_file=$(ls "$service_dir/etc/"*.yaml 2>/dev/null | head -n 1 || true) - if [[ -z "$config_file" ]]; then - echo "⚠️ 警告 $service_name-$service_type: 未找到 etc/*.yaml 配置文件,容器启动可能失败" - config_name="config.yaml" # fallback - else - config_name=$(basename "$config_file") - fi - - # 镜像名称: community-api, user-rpc 等 - image_name="${service_name}-${service_type}" - image_ref="$HARBOR_REGISTRY/$HARBOR_PROJECT/$image_name" - - echo "----------------------------------------------------" - echo "🚀 构建目标: $image_name" - echo "📂 入口文件: $entry_file" - echo "📄 配置文件: $config_name" - echo "----------------------------------------------------" - - # 4. 动态生成 Dockerfile (针对 Monorepo 优化) - # 关键点:COPY . . 把整个根目录拷进去,因为 Go-Zero 项目通常依赖 ../../common - cat < Dockerfile.tmp - FROM golang:alpine AS builder - - # 优化:使用阿里云 Alpine 源 - RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && \ - apk update --no-cache && apk add --no-cache tzdata - - WORKDIR /build - - # 优化:利用层缓存,先下载依赖 - ENV GOPROXY=https://goproxy.cn,direct - COPY go.mod go.sum ./ - RUN go mod download - - # 拷贝所有源码 (解决 common 依赖问题) - COPY . . - - # 编译 - RUN go build -ldflags="-s -w" -o /app/main $entry_file - - # 运行时镜像 - FROM scratch - - COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt - COPY --from=builder /usr/share/zoneinfo/Asia/Shanghai /usr/share/zoneinfo/Asia/Shanghai - ENV TZ=Asia/Shanghai - - WORKDIR /app - COPY --from=builder /app/main /app/main - - # 拷贝 etc 配置 - COPY $service_dir/etc /app/etc - - # 启动命令 - CMD ["./main", "-f", "etc/$config_name"] - EOF - - # 5. 执行 Docker Build - docker build -f Dockerfile.tmp -t "$image_ref:$SHORT_SHA" . - - # 打其他 Tag - docker tag "$image_ref:$SHORT_SHA" "$image_ref:$DATE_TAG" - docker tag "$image_ref:$SHORT_SHA" "$image_ref:latest" - - # 6. 推送 - echo "📤 推送镜像..." - docker push "$image_ref:$SHORT_SHA" - docker push "$image_ref:$DATE_TAG" - docker push "$image_ref:latest" - - echo "✅ $image_name 完成" - rm -f Dockerfile.tmp - done diff --git a/.gitea/workflows/cd.yaml b/.gitea/workflows/cd.yaml new file mode 100644 index 0000000..4d7ede3 --- /dev/null +++ b/.gitea/workflows/cd.yaml @@ -0,0 +1,143 @@ +name: cd + +on: + push: + branches: [main] + workflow_dispatch: + +env: + REGISTRY: registry.juwan.xhttp.zip + REPO: juwan + +jobs: + discover: + runs-on: ubuntu-latest + outputs: + targets: ${{ steps.list.outputs.targets }} + short_sha: ${{ steps.list.outputs.short_sha }} + steps: + - uses: actions/checkout@v4 + + - id: list + shell: bash + run: | + set -euo pipefail + echo "short_sha=${GITHUB_SHA::7}" >> "$GITHUB_OUTPUT" + + python3 - <<'PY' >> "$GITHUB_OUTPUT" + import json, os + NAME_OVERRIDE = { + "users": ("users", "user"), + "user_verifications": ("user_verifications", "user-verifications"), + } + STATEFULSETS = {"snowflake-rpc": "snowflake"} + targets = [] + for svc in sorted(os.listdir("app")): + svc_dir = f"app/{svc}" + if not os.path.isdir(svc_dir): + continue + for sub in sorted(os.listdir(svc_dir)): + d = f"{svc_dir}/{sub}" + if not os.path.isdir(d) or sub not in ("api","rpc","mq","adapter"): + continue + img_pre, wl_pre = NAME_OVERRIDE.get(svc, (svc, svc)) + image = f"{img_pre}-{sub}" + workload = STATEFULSETS.get(image, f"{wl_pre}-{sub}") + targets.append({"image": image, "dir": d, "workload": workload}) + print("targets=" + json.dumps(targets)) + PY + + build: + needs: discover + runs-on: ubuntu-latest + strategy: + fail-fast: false + max-parallel: 1 + matrix: + target: ${{ fromJson(needs.discover.outputs.targets) }} + steps: + - uses: actions/checkout@v4 + + - name: Setup Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ secrets.REGISTRY_USERNAME }} + password: ${{ secrets.REGISTRY_PASSWORD }} + + - name: Generate Dockerfile + shell: bash + run: | + set -euo pipefail + dir='${{ matrix.target.dir }}' + entry=$(grep -l "package main" "$dir"/*.go | head -n1) + cfg=$(basename "$(find "$dir/etc" -maxdepth 1 -name '*.yaml' | head -n1)" 2>/dev/null || echo config.yaml) + cat > Dockerfile.build < ~/.kube/config + chmod 600 ~/.kube/config + + python3 <<'PY' + import json, subprocess, os + reg = os.environ["REGISTRY"] + "/" + os.environ["REPO"] + for t in json.loads(os.environ["TARGETS"]): + img = t["image"] + wl = t["workload"] + kind = "statefulset" if wl == "snowflake" else "deployment" + ref = f"{reg}/{img}:{os.environ['SHA_TAG']}" + cmd = ["kubectl","-n","juwan","set","image",f"{kind}/{wl}",f"{img}={ref}"] + print(" ".join(cmd)) + subprocess.run(cmd, check=False) + PY