chore(build): add build script
Some checks are pending
Build and Publish / manifest (push) Blocked by required conditions
Build and Publish / ci (push) Waiting to run
Build and Publish / docker (app) (push) Blocked by required conditions
Build and Publish / docker (email-worker) (push) Blocked by required conditions
Build and Publish / docker (git-hook) (push) Blocked by required conditions
Build and Publish / docker (gitserver) (push) Blocked by required conditions
Build and Publish / docker (migrate) (push) Blocked by required conditions
Build and Publish / docker (operator) (push) Blocked by required conditions
Build and Publish / docker-arm64 (app) (push) Blocked by required conditions
Build and Publish / docker-arm64 (email-worker) (push) Blocked by required conditions
Build and Publish / docker-arm64 (git-hook) (push) Blocked by required conditions
Build and Publish / docker-arm64 (gitserver) (push) Blocked by required conditions
Build and Publish / docker-arm64 (migrate) (push) Blocked by required conditions
Some checks are pending
Build and Publish / manifest (push) Blocked by required conditions
Build and Publish / ci (push) Waiting to run
Build and Publish / docker (app) (push) Blocked by required conditions
Build and Publish / docker (email-worker) (push) Blocked by required conditions
Build and Publish / docker (git-hook) (push) Blocked by required conditions
Build and Publish / docker (gitserver) (push) Blocked by required conditions
Build and Publish / docker (migrate) (push) Blocked by required conditions
Build and Publish / docker (operator) (push) Blocked by required conditions
Build and Publish / docker-arm64 (app) (push) Blocked by required conditions
Build and Publish / docker-arm64 (email-worker) (push) Blocked by required conditions
Build and Publish / docker-arm64 (git-hook) (push) Blocked by required conditions
Build and Publish / docker-arm64 (gitserver) (push) Blocked by required conditions
Build and Publish / docker-arm64 (migrate) (push) Blocked by required conditions
This commit is contained in:
parent
07ae21af81
commit
c330c23cef
109
.gitea/README.md
Normal file
109
.gitea/README.md
Normal file
@ -0,0 +1,109 @@
|
||||
# Gitea Actions 配置
|
||||
|
||||
## 目录结构
|
||||
|
||||
```
|
||||
.gitea/
|
||||
└── workflows/
|
||||
└── build.yaml # 构建流水线
|
||||
```
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 1. 启用 Gitea Actions
|
||||
|
||||
在 Gitea 管理面板中启用 Actions:
|
||||
|
||||
```ini
|
||||
[actions]
|
||||
ENABLED = true
|
||||
```
|
||||
|
||||
### 2. 注册 Runner
|
||||
|
||||
在 Gitea 仓库设置中创建 Runner,获取 Token 后配置:
|
||||
|
||||
```bash
|
||||
# Docker 部署
|
||||
docker run -d \
|
||||
--name act-runner \
|
||||
-e GITEA_INSTANCE_URL=https://git.example.com \
|
||||
-e GITEA_RUNNER_TOKEN=<your-token> \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
-v act-runner-data:/data \
|
||||
gitea/act-runner:latest
|
||||
|
||||
# 或使用 Helm (见下方)
|
||||
```
|
||||
|
||||
### 3. 添加 Secrets
|
||||
|
||||
在 Gitea 仓库设置中添加:
|
||||
|
||||
| Secret | 说明 |
|
||||
|--------|------|
|
||||
| `HARBOR_USERNAME` | Harbor 用户名 |
|
||||
| `HARBOR_PASSWORD` | Harbor 密码 |
|
||||
|
||||
## Helm 部署 Act Runner
|
||||
|
||||
```bash
|
||||
# values override
|
||||
cat > act-runner-values.yaml << 'EOF'
|
||||
actRunner:
|
||||
enabled: true
|
||||
replicaCount: 2
|
||||
capacity: 2
|
||||
labels:
|
||||
- gitea
|
||||
- docker
|
||||
resources:
|
||||
requests:
|
||||
cpu: 500m
|
||||
memory: 1Gi
|
||||
limits:
|
||||
cpu: 2000m
|
||||
memory: 4Gi
|
||||
EOF
|
||||
|
||||
helm upgrade --install act-runner ./deploy \
|
||||
-f act-runner-values.yaml \
|
||||
-n c-----code \
|
||||
--create-namespace
|
||||
```
|
||||
|
||||
## Workflow 说明
|
||||
|
||||
### build.yaml
|
||||
|
||||
| Stage | 说明 |
|
||||
|-------|------|
|
||||
| `ci` | 格式化检查、Clippy lint、单元测试 |
|
||||
| `docker` | x86_64 镜像构建并推送到 Harbor |
|
||||
| `docker-arm64` | ARM64 镜像构建 (需 ARM64 runner) |
|
||||
| `manifest` | 多架构镜像清单合并 |
|
||||
|
||||
### Runner 标签
|
||||
|
||||
| Label | 说明 |
|
||||
|-------|------|
|
||||
| `gitea` | 默认 runner |
|
||||
| `docker` | 支持 Docker-in-Docker |
|
||||
| `arm64` | ARM64 架构 runner |
|
||||
|
||||
### 触发条件
|
||||
|
||||
- Push 到 `main` 分支
|
||||
- Pull Request 到 `main` 分支
|
||||
|
||||
## 本地测试
|
||||
|
||||
使用 [nektos/act](https://github.com/nektos/act) 本地运行:
|
||||
|
||||
```bash
|
||||
# 安装
|
||||
curl -sSL https://raw.githubusercontent.com/nektos/act/master/install.sh | sh
|
||||
|
||||
# 运行 workflow
|
||||
act -W .gitea/workflows/build.yaml
|
||||
```
|
||||
42
deploy/values.user.yaml.example
Normal file
42
deploy/values.user.yaml.example
Normal file
@ -0,0 +1,42 @@
|
||||
# User overrides for Helm deployment
|
||||
# Copy to values.user.yaml and customize
|
||||
|
||||
# PostgreSQL
|
||||
database:
|
||||
existingSecret: c-----code-secrets
|
||||
secretKeys:
|
||||
url: APP_DATABASE_URL
|
||||
|
||||
# Redis
|
||||
redis:
|
||||
existingSecret: c-----code-secrets
|
||||
secretKeys:
|
||||
url: APP_REDIS_URL
|
||||
|
||||
# NATS (if using hook pool)
|
||||
nats:
|
||||
enabled: false
|
||||
url: nats://nats:4222
|
||||
|
||||
# Qdrant (if using AI embeddings)
|
||||
qdrant:
|
||||
enabled: false
|
||||
url: http://qdrant:6333
|
||||
|
||||
# App configuration
|
||||
app:
|
||||
replicaCount: 3
|
||||
ingress:
|
||||
enabled: true
|
||||
hosts:
|
||||
- host: git.example.com
|
||||
|
||||
# Gitserver persistence
|
||||
gitserver:
|
||||
persistence:
|
||||
size: 100Gi
|
||||
storageClass: fast-ssd
|
||||
|
||||
# Act Runner
|
||||
actRunner:
|
||||
enabled: false
|
||||
107
scripts/README.md
Normal file
107
scripts/README.md
Normal file
@ -0,0 +1,107 @@
|
||||
# 构建脚本
|
||||
|
||||
## 一键构建脚本
|
||||
|
||||
### build.js - 构建镜像
|
||||
|
||||
```bash
|
||||
# 构建所有镜像
|
||||
node scripts/build.js
|
||||
|
||||
# 构建指定服务
|
||||
node scripts/build.js app gitserver
|
||||
|
||||
# 指定 tag
|
||||
TAG=v1.0.0 node scripts/build.js
|
||||
|
||||
# 指定架构
|
||||
TARGET=aarch64-unknown-linux-gnu node scripts/build.js
|
||||
```
|
||||
|
||||
**环境变量:**
|
||||
|
||||
| 变量 | 默认值 | 说明 |
|
||||
|------|--------|------|
|
||||
| `REGISTRY` | `harbor.gitdata.me/gta_team` | 镜像仓库 |
|
||||
| `TAG` | `latest` | 镜像标签 |
|
||||
| `TARGET` | `x86_64-unknown-linux-gnu` | Rust 交叉编译目标 |
|
||||
|
||||
---
|
||||
|
||||
### push.js - 推送镜像
|
||||
|
||||
```bash
|
||||
# 推送所有镜像
|
||||
HARBOR_USERNAME=user HARBOR_PASSWORD=pass node scripts/push.js
|
||||
|
||||
# 推送指定服务
|
||||
HARBOR_USERNAME=user HARBOR_PASSWORD=pass TAG=sha-abc123 node scripts/push.js app
|
||||
```
|
||||
|
||||
**环境变量:**
|
||||
|
||||
| 变量 | 默认值 | 说明 |
|
||||
|------|--------|------|
|
||||
| `REGISTRY` | `harbor.gitdata.me/gta_team` | 镜像仓库 |
|
||||
| `TAG` | `latest` 或 Git SHA | 镜像标签 |
|
||||
| `HARBOR_USERNAME` | - | **必填** 仓库用户名 |
|
||||
| `HARBOR_PASSWORD` | - | **必填** 仓库密码 |
|
||||
|
||||
---
|
||||
|
||||
### deploy.js - 部署到 Kubernetes
|
||||
|
||||
```bash
|
||||
# 部署最新镜像
|
||||
node scripts/deploy.js
|
||||
|
||||
# 干跑模式(不实际部署)
|
||||
node scripts/deploy.js --dry-run
|
||||
|
||||
# 部署并运行数据库迁移
|
||||
node scripts/deploy.js --migrate
|
||||
|
||||
# 指定 tag
|
||||
TAG=sha-abc123 node scripts/deploy.js
|
||||
|
||||
# 指定命名空间
|
||||
NAMESPACE=staging node scripts/deploy.js
|
||||
```
|
||||
|
||||
**环境变量:**
|
||||
|
||||
| 变量 | 默认值 | 说明 |
|
||||
|------|--------|------|
|
||||
| `REGISTRY` | `harbor.gitdata.me/gta_team` | 镜像仓库 |
|
||||
| `TAG` | `latest` 或 Git SHA | 镜像标签 |
|
||||
| `NAMESPACE` | `c-----code` | K8s 命名空间 |
|
||||
| `RELEASE` | `c-----code` | Helm Release 名称 |
|
||||
| `KUBECONFIG` | `~/.kube/config` | Kubeconfig 路径 |
|
||||
|
||||
---
|
||||
|
||||
## 完整 CI/CD 流程
|
||||
|
||||
```bash
|
||||
# 1. 构建
|
||||
node scripts/build.js
|
||||
|
||||
# 2. 推送
|
||||
HARBOR_USERNAME=user HARBOR_PASSWORD=pass node scripts/push.js
|
||||
|
||||
# 3. 部署
|
||||
node scripts/deploy.js --migrate
|
||||
```
|
||||
|
||||
## 本地开发
|
||||
|
||||
```bash
|
||||
# 本地构建测试
|
||||
node scripts/build.js app
|
||||
|
||||
# 使用本地 tag
|
||||
TAG=dev node scripts/build.js
|
||||
|
||||
# 部署到测试环境
|
||||
NAMESPACE=test node scripts/deploy.js
|
||||
```
|
||||
69
scripts/build.js
Normal file
69
scripts/build.js
Normal file
@ -0,0 +1,69 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Build Docker images for C-----code
|
||||
*
|
||||
* Usage:
|
||||
* node scripts/build.js # Build all images
|
||||
* node scripts/build.js app # Build specific service
|
||||
* node scripts/build.js app gitserver
|
||||
*
|
||||
* Environment:
|
||||
* REGISTRY - Docker registry (default: harbor.gitdata.me/gta_team)
|
||||
* TAG - Image tag (default: latest)
|
||||
* TARGET - Rust build target (default: x86_64-unknown-linux-gnu)
|
||||
*/
|
||||
|
||||
const { execSync } = require('child_process');
|
||||
const path = require('path');
|
||||
|
||||
const REGISTRY = process.env.REGISTRY || 'harbor.gitdata.me/gta_team';
|
||||
const TAG = process.env.TAG || 'latest';
|
||||
const BUILD_TARGET = process.env.TARGET || 'x86_64-unknown-linux-gnu';
|
||||
|
||||
const SERVICES = ['app', 'gitserver', 'email-worker', 'git-hook', 'migrate', 'operator'];
|
||||
|
||||
const args = process.argv.slice(2);
|
||||
const targets = args.length > 0 ? args : SERVICES;
|
||||
|
||||
console.log(`\n=== Build Configuration ===`);
|
||||
console.log(`Registry: ${REGISTRY}`);
|
||||
console.log(`Tag: ${TAG}`);
|
||||
console.log(`Target: ${BUILD_TARGET}`);
|
||||
console.log(`Services: ${targets.join(', ')}\n`);
|
||||
|
||||
for (const service of targets) {
|
||||
if (!SERVICES.includes(service)) {
|
||||
console.error(`Unknown service: ${service}`);
|
||||
console.error(`Available: ${SERVICES.join(', ')}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const dockerfile = path.join(__dirname, '..', 'docker', `${service}.Dockerfile`);
|
||||
const image = `${REGISTRY}/${service}:${TAG}`;
|
||||
|
||||
console.log(`\n==> Building ${image}`);
|
||||
console.log(` Dockerfile: ${dockerfile}`);
|
||||
|
||||
try {
|
||||
execSync(
|
||||
`docker buildx build ` +
|
||||
`--build-arg BUILD_TARGET=${BUILD_TARGET} ` +
|
||||
`-f "${dockerfile}" ` +
|
||||
`-t "${image}" ` +
|
||||
`--load ` +
|
||||
`--progress=plain ` +
|
||||
`.`,
|
||||
{ stdio: 'inherit', cwd: path.join(__dirname, '..') }
|
||||
);
|
||||
console.log(` [OK] ${image}`);
|
||||
} catch (error) {
|
||||
console.error(` [FAIL] ${service}`);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`\n=== Build Complete ===`);
|
||||
for (const service of targets) {
|
||||
console.log(` ${REGISTRY}/${service}:${TAG}`);
|
||||
}
|
||||
console.log('');
|
||||
114
scripts/deploy.js
Normal file
114
scripts/deploy.js
Normal file
@ -0,0 +1,114 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Deploy C-----code via Helm
|
||||
*
|
||||
* Usage:
|
||||
* node scripts/deploy.js # Deploy with defaults
|
||||
* node scripts/deploy.js --dry-run # Dry run only
|
||||
* node scripts/deploy.js --migrate # Run migrations first
|
||||
*
|
||||
* Environment:
|
||||
* REGISTRY - Docker registry (default: harbor.gitdata.me/gta_team)
|
||||
* TAG - Image tag (default: latest)
|
||||
* NAMESPACE - Kubernetes namespace (default: c-----code)
|
||||
* RELEASE - Helm release name (default: c-----code)
|
||||
* KUBECONFIG - Path to kubeconfig (default: ~/.kube/config)
|
||||
*/
|
||||
|
||||
const { execSync } = require('child_process');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
|
||||
const REGISTRY = process.env.REGISTRY || 'harbor.gitdata.me/gta_team';
|
||||
const TAG = process.env.TAG || process.env.GITHUB_SHA?.substring(0, 8) || 'latest';
|
||||
const NAMESPACE = process.env.NAMESPACE || 'c-----code';
|
||||
const RELEASE = process.env.RELEASE || 'c-----code';
|
||||
const CHART_PATH = path.join(__dirname, '..', 'deploy');
|
||||
const KUBECONFIG = process.env.KUBECONFIG || path.join(process.env.HOME || process.env.USERPROFILE, '.kube', 'config');
|
||||
|
||||
const args = process.argv.slice(2);
|
||||
const isDryRun = args.includes('--dry-run');
|
||||
const runMigrate = args.includes('--migrate');
|
||||
|
||||
const SERVICES = ['app', 'gitserver', 'email-worker', 'git-hook', 'operator'];
|
||||
|
||||
// Validate kubeconfig
|
||||
if (!fs.existsSync(KUBECONFIG)) {
|
||||
console.error(`Error: kubeconfig not found at ${KUBECONFIG}`);
|
||||
console.error('Set KUBECONFIG environment variable or ensure ~/.kube/config exists');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log(`\n=== Deploy Configuration ===`);
|
||||
console.log(`Registry: ${REGISTRY}`);
|
||||
console.log(`Tag: ${TAG}`);
|
||||
console.log(`Namespace: ${NAMESPACE}`);
|
||||
console.log(`Release: ${RELEASE}`);
|
||||
console.log(`Dry Run: ${isDryRun}`);
|
||||
console.log(`Run Migrate: ${runMigrate}`);
|
||||
console.log('');
|
||||
|
||||
// Build helm values override
|
||||
const valuesFile = path.join(CHART_PATH, 'values.yaml');
|
||||
const userValuesFile = path.join(CHART_PATH, 'values.user.yaml');
|
||||
|
||||
const setValues = [
|
||||
`image.registry=${REGISTRY}`,
|
||||
`app.image.tag=${TAG}`,
|
||||
`gitserver.image.tag=${TAG}`,
|
||||
`emailWorker.image.tag=${TAG}`,
|
||||
`gitHook.image.tag=${TAG}`,
|
||||
`operator.image.tag=${TAG}`,
|
||||
];
|
||||
|
||||
if (runMigrate) {
|
||||
setValues.push('migrate.enabled=true');
|
||||
}
|
||||
|
||||
const helmArgs = [
|
||||
'upgrade', '--install', RELEASE, CHART_PATH,
|
||||
'--namespace', NAMESPACE,
|
||||
'--create-namespace',
|
||||
'-f', valuesFile,
|
||||
...(fs.existsSync(userValuesFile) ? ['-f', userValuesFile] : []),
|
||||
...setValues.flatMap(v => ['--set', v]),
|
||||
'--wait',
|
||||
'--timeout', '5m',
|
||||
];
|
||||
|
||||
if (isDryRun) {
|
||||
helmArgs.push('--dry-run');
|
||||
console.log('==> Dry run mode - no changes will be made\n');
|
||||
}
|
||||
|
||||
// Helm upgrade
|
||||
console.log(`==> Running helm upgrade`);
|
||||
console.log(` Command: helm ${helmArgs.join(' ')}\n`);
|
||||
|
||||
try {
|
||||
execSync(`helm ${helmArgs.join(' ')}`, { stdio: 'inherit', env: { ...process.env, KUBECONFIG } });
|
||||
console.log(`\n[OK] Deployment ${isDryRun ? '(dry-run) ' : ''}complete`);
|
||||
} catch (error) {
|
||||
console.error('\n[FAIL] Deployment failed');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Rollout status
|
||||
if (!isDryRun) {
|
||||
console.log('\n==> Checking rollout status');
|
||||
for (const service of SERVICES) {
|
||||
const deploymentName = `${RELEASE}-${service}`;
|
||||
console.log(` Checking ${deploymentName}...`);
|
||||
try {
|
||||
execSync(
|
||||
`kubectl rollout status deployment/${deploymentName} -n ${NAMESPACE} --timeout=120s`,
|
||||
{ stdio: 'pipe', env: { ...process.env, KUBECONFIG } }
|
||||
);
|
||||
console.log(` [OK] ${deploymentName}`);
|
||||
} catch (error) {
|
||||
console.error(` [WARN] ${deploymentName} rollout timeout or failed`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log('\n=== Deploy Complete ===\n');
|
||||
70
scripts/push.js
Normal file
70
scripts/push.js
Normal file
@ -0,0 +1,70 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Push Docker images to registry
|
||||
*
|
||||
* Usage:
|
||||
* node scripts/push.js # Push all images
|
||||
* node scripts/push.js app # Push specific service
|
||||
*
|
||||
* Environment:
|
||||
* REGISTRY - Docker registry (default: harbor.gitdata.me/gta_team)
|
||||
* TAG - Image tag (default: latest)
|
||||
* DOCKER_USER - Registry username
|
||||
* DOCKER_PASS - Registry password
|
||||
*/
|
||||
|
||||
const { execSync } = require('child_process');
|
||||
|
||||
const REGISTRY = process.env.REGISTRY || 'harbor.gitdata.me/gta_team';
|
||||
const TAG = process.env.TAG || process.env.GITHUB_SHA?.substring(0, 8) || 'latest';
|
||||
const DOCKER_USER = process.env.DOCKER_USER || process.env.HARBOR_USERNAME;
|
||||
const DOCKER_PASS = process.env.DOCKER_PASS || process.env.HARBOR_PASSWORD;
|
||||
|
||||
const SERVICES = ['app', 'gitserver', 'email-worker', 'git-hook', 'migrate', 'operator'];
|
||||
|
||||
const args = process.argv.slice(2);
|
||||
const targets = args.length > 0 ? args : SERVICES;
|
||||
|
||||
if (!DOCKER_USER || !DOCKER_PASS) {
|
||||
console.error('Error: DOCKER_USER and DOCKER_PASS environment variables are required');
|
||||
console.error('Set HARBOR_USERNAME and HARBOR_PASSWORD as alternative');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log(`\n=== Push Configuration ===`);
|
||||
console.log(`Registry: ${REGISTRY}`);
|
||||
console.log(`Tag: ${TAG}`);
|
||||
console.log(`Services: ${targets.join(', ')}\n`);
|
||||
|
||||
// Login
|
||||
console.log(`==> Logging in to ${REGISTRY}`);
|
||||
try {
|
||||
execSync(`docker login ${REGISTRY} -u "${DOCKER_USER}" -p "${DOCKER_PASS}"`, {
|
||||
stdio: 'inherit'
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Login failed');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
for (const service of targets) {
|
||||
if (!SERVICES.includes(service)) {
|
||||
console.error(`Unknown service: ${service}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const image = `${REGISTRY}/${service}:${TAG}`;
|
||||
|
||||
console.log(`\n==> Pushing ${image}`);
|
||||
|
||||
try {
|
||||
execSync(`docker push "${image}" --all-tags`, { stdio: 'inherit' });
|
||||
console.log(` [OK] ${image}`);
|
||||
} catch (error) {
|
||||
console.error(` [FAIL] ${service}`);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`\n=== Push Complete ===`);
|
||||
console.log('');
|
||||
Loading…
Reference in New Issue
Block a user