From cd80375cc51f2f972c3e30af111b770ab10faee9 Mon Sep 17 00:00:00 2001 From: tone Date: Sat, 27 Dec 2025 14:26:20 +0800 Subject: [PATCH] chore: .. --- .gitea/workflows/deploy.yml | 111 ++++++++++++++++++++++++++++++++---- 1 file changed, 101 insertions(+), 10 deletions(-) diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index 6b92465..6b28234 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -54,13 +54,56 @@ jobs: -t localhost:5000/frontend:${IMAGE_TAG} . docker push localhost:5000/frontend:${IMAGE_TAG} - - name: Run database migrations with Kubernetes Job + - name: Run database migrations with Node.js Job run: | cd /workspace/tone/tonePage/apps/deploy - echo "Running database migrations using backend image: localhost:5000/backend:${IMAGE_TAG}" + echo "Running database migrations using Node.js image and backend content." - JOB_NAME="backend-migrate-$(echo ${IMAGE_TAG} | cut -c1-8)-$(date +%s)" + # 生成一个唯一的 Job 名称,避免冲突 + JOB_NAME="node-migrate-$(echo ${IMAGE_TAG} | cut -c1-8)-$(date +%s)" + # 从后端镜像中提取编译后的代码 (dist) 和 package.json + # 创建一个临时容器来复制文件 + TEMP_CONTAINER_NAME="temp-extract-${IMAGE_TAG}" + docker create --name $TEMP_CONTAINER_NAME localhost:5000/backend:${IMAGE_TAG} /bin/true + + # 创建临时目录 + TEMP_DIR=$(mktemp -d) + echo "Using temporary directory: $TEMP_DIR" + + # 复制 package.json 和 dist 目录 + docker cp $TEMP_CONTAINER_NAME:/app/package.json $TEMP_DIR/ + docker cp $TEMP_CONTAINER_NAME:/app/dist $TEMP_DIR/ + + # 清理临时容器 + docker rm -v $TEMP_CONTAINER_NAME > /dev/null + + # 创建一个 ConfigMap 来存储迁移文件内容 + # 将 dist 目录打包成 tar 并 base64 编码 + cd $TEMP_DIR + tar czf dist.tar.gz dist + DIST_TAR_B64=$(base64 -w 0 dist.tar.gz) + # 也获取 package.json 内容 + PKG_JSON_B64=$(base64 -w 0 package.json) + + # 创建一个临时的 ConfigMap YAML 文件 + cat << EOF > /tmp/migration-cm-${IMAGE_TAG}.yaml + apiVersion: v1 + kind: ConfigMap + metadata: + name: migration-files-$JOB_NAME + namespace: default + data: + dist.tar.gz.b64: | + $DIST_TAR_B64 + package.json.b64: | + $PKG_JSON_B64 + EOF + + # 应用 ConfigMap + kubectl apply -f /tmp/migration-cm-${IMAGE_TAG}.yaml + + # 创建一个临时的 Job YAML 文件 cat << EOF > /tmp/migration-job-${IMAGE_TAG}.yaml apiVersion: batch/v1 kind: Job @@ -71,10 +114,44 @@ jobs: template: spec: restartPolicy: Never + initContainers: + # Init container to decode and extract the files from ConfigMap + - name: setup-migration + image: busybox:1.35 + command: ['sh', '-c'] + args: + - | + echo "Decoding package.json and dist archive..." + echo "\$PKG_JSON_B64" | base64 -d > /app/package.json + echo "\$DIST_TAR_B64" | base64 -d > /app/dist.tar.gz + echo "Extracting dist archive..." + cd /app && tar xzf dist.tar.gz + echo "Listing /app contents:" + ls -la /app + env: + - name: PKG_JSON_B64 + valueFrom: + configMapKeyRef: + name: migration-files-$JOB_NAME + key: package.json.b64 + - name: DIST_TAR_B64 + valueFrom: + configMapKeyRef: + name: migration-files-$JOB_NAME + key: dist.tar.gz.b64 + volumeMounts: + - name: shared-data + mountPath: /app containers: - name: migrator - image: localhost:5000/backend:${IMAGE_TAG} - command: ["pnpm", "run", "migration:run"] + image: node:22-alpine # 使用包含 Node.js 和 npm 的标准镜像 + command: ["/bin/sh", "-c"] + args: + - | + echo "Installing dependencies..." + npm ci --only=production + echo "Running database migration..." + npx typeorm migration:run -d dist/data-source.js env: - name: NODE_ENV value: "production" @@ -86,6 +163,7 @@ jobs: value: "tone_page" - name: DATABASE_USERNAME value: "tone_page" + # 从 Secret 中获取敏感信息 - name: DATABASE_PASSWORD valueFrom: secretKeyRef: @@ -128,34 +206,47 @@ jobs: secretKeyRef: name: backend-secret key: WEBAUTHN_RP_NAME - backoffLimit: 3 + volumeMounts: + - name: shared-data + mountPath: /app + workingDir: /app + volumes: + - name: shared-data + emptyDir: {} + backoffLimit: 1 # 如果 Job 失败,只重试 1 次 EOF + # 应用 Job 配置 kubectl apply -f /tmp/migration-job-${IMAGE_TAG}.yaml echo "Waiting for job $JOB_NAME to complete..." - kubectl wait --for=condition=complete job/$JOB_NAME --timeout=30s + # 等待 Job 完成,最多等待 5 分钟 (300秒) + kubectl wait --for=condition=complete job/$JOB_NAME --timeout=300s + # 检查 Job 是否成功 FAILED_COUNT=$(kubectl get job $JOB_NAME -o jsonpath='{.status.failed}' 2>/dev/null || echo "null") if [ "$FAILED_COUNT" = "null" ] || [ "$FAILED_COUNT" -eq 0 ]; then echo "Migration job $JOB_NAME completed successfully." else echo "Migration job $JOB_NAME failed. Failed pod count: $FAILED_COUNT" - # 打印 Job 的详细状态和日志以便调试 kubectl describe job $JOB_NAME echo "Logs from the failed pod:" - # 获取失败的 Pod 名称并打印其日志 FAILED_POD_NAME=$(kubectl get pods --selector=job-name=$JOB_NAME --field-selector=status.phase=Failed -o jsonpath='{.items[0].metadata.name}') if [ ! -z "$FAILED_POD_NAME" ]; then - kubectl logs $FAILED_POD_NAME + kubectl logs $FAILED_POD_NAME -c migrator + kubectl logs $FAILED_POD_NAME -c setup-migration # Also check init container logs else echo "Could not find the failed pod name." fi exit 1 fi + # 清理临时资源 (可选) kubectl delete job $JOB_NAME + kubectl delete configmap migration-files-$JOB_NAME rm /tmp/migration-job-${IMAGE_TAG}.yaml + rm /tmp/migration-cm-${IMAGE_TAG}.yaml + rm -rf $TEMP_DIR echo "Database migrations completed successfully."