chore(project): Initialize project basic configuration and deployment template
Some checks reported errors
continuous-integration/drone/push Build encountered an error
Some checks reported errors
continuous-integration/drone/push Build encountered an error
This commit is contained in:
parent
c330c23cef
commit
88f58a65c0
221
.drone.yml
Normal file
221
.drone.yml
Normal file
@ -0,0 +1,221 @@
|
||||
---
|
||||
# =============================================================================
|
||||
# Drone CI Pipeline
|
||||
# =============================================================================
|
||||
kind: pipeline
|
||||
type: kubernetes
|
||||
name: default
|
||||
|
||||
trigger:
|
||||
event:
|
||||
- push
|
||||
- tag
|
||||
branch:
|
||||
- main
|
||||
|
||||
environment:
|
||||
REGISTRY: harbor.gitdata.me/gta_team
|
||||
CARGO_TERM_COLOR: always
|
||||
BUILD_TARGET: x86_64-unknown-linux-gnu
|
||||
|
||||
steps:
|
||||
# =============================================================================
|
||||
# Clone
|
||||
# =============================================================================
|
||||
- name: clone
|
||||
image: bitnami/git:latest
|
||||
commands:
|
||||
- |
|
||||
if [ -n "${DRONE_TAG}" ]; then
|
||||
git checkout ${DRONE_TAG}
|
||||
fi
|
||||
|
||||
# =============================================================================
|
||||
# Stage 1: Rust – fmt + clippy + test
|
||||
# =============================================================================
|
||||
- name: rust-fmt
|
||||
image: rust:1.94
|
||||
commands:
|
||||
- cargo fmt --all -- --check
|
||||
|
||||
- name: rust-clippy
|
||||
image: rust:1.94
|
||||
commands:
|
||||
- apt-get update && apt-get install -y --no-install-recommends \
|
||||
pkg-config libssl-dev libclang-dev libgit2-dev zlib1g-dev
|
||||
- rustup component add clippy
|
||||
- cargo clippy --workspace --all-targets -- -D warnings
|
||||
|
||||
- name: rust-test
|
||||
image: rust:1.94
|
||||
commands:
|
||||
- apt-get update && apt-get install -y --no-install-recommends \
|
||||
pkg-config libssl-dev libclang-dev libgit2-dev zlib1g-dev
|
||||
- cargo test --workspace --all-features
|
||||
|
||||
# =============================================================================
|
||||
# Stage 2: Frontend – lint + typecheck + build
|
||||
# =============================================================================
|
||||
- name: frontend-deps
|
||||
image: node:22-alpine
|
||||
commands:
|
||||
- corepack enable
|
||||
- corepack prepare pnpm@10 --activate
|
||||
- pnpm install --frozen-lockfile
|
||||
|
||||
- name: frontend-lint
|
||||
image: node:22-alpine
|
||||
commands:
|
||||
- pnpm lint
|
||||
depends_on: [ frontend-deps ]
|
||||
|
||||
- name: frontend-typecheck
|
||||
image: node:22-alpine
|
||||
commands:
|
||||
- pnpm tsc -b --noEmit
|
||||
depends_on: [ frontend-lint ]
|
||||
|
||||
- name: frontend-build
|
||||
image: node:22-alpine
|
||||
commands:
|
||||
- pnpm build
|
||||
depends_on: [ frontend-typecheck ]
|
||||
|
||||
# =============================================================================
|
||||
# Stage 3: Docker build & push
|
||||
# =============================================================================
|
||||
- name: docker-login
|
||||
image: docker:latest
|
||||
commands:
|
||||
- docker login ${REGISTRY} --username ${DRONE_SECRET_DOCKER_USERNAME} --password-stdin <<< ${DRONE_SECRET_DOCKER_PASSWORD}
|
||||
when:
|
||||
status: [ success ]
|
||||
|
||||
- name: docker-build-and-push
|
||||
image: docker:latest
|
||||
environment:
|
||||
DOCKER_BUILDKIT: "1"
|
||||
commands:
|
||||
- |
|
||||
TAG="${DRONE_TAG:-${DRONE_COMMIT_SHA:0:8}}"
|
||||
echo "==> Building images with tag: ${TAG}"
|
||||
docker build --build-arg BUILD_TARGET=${BUILD_TARGET} -f docker/app.Dockerfile -t ${REGISTRY}/app:${TAG} .
|
||||
docker build --build-arg BUILD_TARGET=${BUILD_TARGET} -f docker/gitserver.Dockerfile -t ${REGISTRY}/gitserver:${TAG} .
|
||||
docker build --build-arg BUILD_TARGET=${BUILD_TARGET} -f docker/email-worker.Dockerfile -t ${REGISTRY}/email-worker:${TAG} .
|
||||
docker build --build-arg BUILD_TARGET=${BUILD_TARGET} -f docker/git-hook.Dockerfile -t ${REGISTRY}/git-hook:${TAG} .
|
||||
docker build --build-arg BUILD_TARGET=${BUILD_TARGET} -f docker/migrate.Dockerfile -t ${REGISTRY}/migrate:${TAG} .
|
||||
docker build --build-arg BUILD_TARGET=${BUILD_TARGET} -f docker/operator.Dockerfile -t ${REGISTRY}/operator:${TAG} .
|
||||
docker build -f docker/static.Dockerfile -t ${REGISTRY}/static:${TAG} .
|
||||
docker build -f docker/frontend.Dockerfile -t ${REGISTRY}/frontend:${TAG} .
|
||||
echo "==> Pushing images"
|
||||
for svc in app gitserver email-worker git-hook migrate operator static frontend; do
|
||||
docker push ${REGISTRY}/${svc}:${TAG}
|
||||
done
|
||||
echo "==> Tagging as latest"
|
||||
for svc in app gitserver email-worker git-hook migrate operator static frontend; do
|
||||
docker tag ${REGISTRY}/${svc}:${TAG} ${REGISTRY}/${svc}:latest
|
||||
docker push ${REGISTRY}/${svc}:latest
|
||||
done
|
||||
echo "==> All images pushed"
|
||||
depends_on: [ docker-login, frontend-build ]
|
||||
settings:
|
||||
privileged: true
|
||||
when:
|
||||
status: [ success ]
|
||||
|
||||
# =============================================================================
|
||||
# Stage 4: Deploy to Kubernetes
|
||||
# =============================================================================
|
||||
- name: prepare-kubeconfig
|
||||
image: alpine:latest
|
||||
commands:
|
||||
- apk add --no-cache kubectl
|
||||
- mkdir -p ~/.kube
|
||||
- echo "${KUBECONFIG}" | base64 -d > ~/.kube/config
|
||||
- chmod 600 ~/.kube/config
|
||||
|
||||
- name: create-namespace
|
||||
image: bitnami/kubectl:latest
|
||||
commands:
|
||||
- kubectl create namespace gitdataai --dry-run=client -o yaml | kubectl apply -f -
|
||||
depends_on: [ prepare-kubeconfig ]
|
||||
when:
|
||||
branch: [ main ]
|
||||
|
||||
- name: deploy-configmap
|
||||
image: bitnami/kubectl:latest
|
||||
commands:
|
||||
- kubectl apply -f deploy/configmap.yaml
|
||||
depends_on: [ create-namespace ]
|
||||
when:
|
||||
branch: [ main ]
|
||||
|
||||
- name: helm-deploy
|
||||
image: alpine/helm:latest
|
||||
commands:
|
||||
- apk add --no-cache curl kubectl
|
||||
- curl -fsSL -o /tmp/helm.tar.gz https://get.helm.sh/helm-v3.15.0-linux-amd64.tar.gz
|
||||
- tar -xzf /tmp/helm.tar.gz -C /tmp
|
||||
- mv /tmp/linux-amd64/helm /usr/local/bin/helm && chmod +x /usr/local/bin/helm
|
||||
- |
|
||||
TAG="${DRONE_TAG:-${DRONE_COMMIT_SHA:0:8}}"
|
||||
helm upgrade --install gitdata deploy/ \
|
||||
--namespace gitdataai \
|
||||
-f deploy/values.yaml \
|
||||
-f deploy/secrets.yaml \
|
||||
--set image.registry=${REGISTRY} \
|
||||
--set app.image.tag=${TAG} \
|
||||
--set gitserver.image.tag=${TAG} \
|
||||
--set emailWorker.image.tag=${TAG} \
|
||||
--set gitHook.image.tag=${TAG} \
|
||||
--set operator.image.tag=${TAG} \
|
||||
--set static.image.tag=${TAG} \
|
||||
--set frontend.image.tag=${TAG} \
|
||||
--wait \
|
||||
--timeout 5m \
|
||||
--atomic
|
||||
depends_on: [ deploy-configmap ]
|
||||
when:
|
||||
status: [ success ]
|
||||
branch: [ main ]
|
||||
|
||||
- name: verify-rollout
|
||||
image: bitnami/kubectl:latest
|
||||
commands:
|
||||
- kubectl rollout status deployment/gitdata-frontend -n gitdataai --timeout=300s
|
||||
- kubectl rollout status deployment/gitdata-app -n gitdataai --timeout=300s
|
||||
- kubectl rollout status deployment/gitdata-gitserver -n gitdataai --timeout=300s
|
||||
- kubectl rollout status deployment/gitdata-email-worker -n gitdataai --timeout=300s
|
||||
- kubectl rollout status deployment/gitdata-git-hook -n gitdataai --timeout=300s
|
||||
depends_on: [ helm-deploy ]
|
||||
when:
|
||||
status: [ success ]
|
||||
branch: [ main ]
|
||||
|
||||
# =============================================================================
|
||||
# Secrets (register via drone CLI)
|
||||
#
|
||||
# # Harbor username for docker login
|
||||
# drone secret add \
|
||||
# --repository <org/repo> \
|
||||
# --name drone_secret_docker_username \
|
||||
# --data <harbor-username>
|
||||
#
|
||||
# # Harbor password for docker login
|
||||
# drone secret add \
|
||||
# --repository <org/repo> \
|
||||
# --name drone_secret_docker_password \
|
||||
# --data <harbor-password>
|
||||
#
|
||||
# # kubeconfig (base64 encoded)
|
||||
# drone secret add \
|
||||
# --repository <org/repo> \
|
||||
# --name kubeconfig \
|
||||
# --data "$(cat ~/.kube/config | base64 -w 0)"
|
||||
#
|
||||
# # Local exec (for testing):
|
||||
# drone exec --trusted \
|
||||
# --secret=DRONE_SECRET_DOCKER_USERNAME=<username> \
|
||||
# --secret=DRONE_SECRET_DOCKER_PASSWORD=<password> \
|
||||
# --secret=KUBECONFIG=$(base64 -w 0 ~/.kube/config)
|
||||
# =============================================================================
|
||||
109
.gitea/README.md
109
.gitea/README.md
@ -1,109 +0,0 @@
|
||||
# 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
|
||||
```
|
||||
@ -1,159 +0,0 @@
|
||||
name: Build and Publish
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
|
||||
env:
|
||||
REGISTRY: harbor.gitdata.me/gta_team
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
jobs:
|
||||
# ---- Lint & Test ----
|
||||
ci:
|
||||
runs-on: gitea
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Rust
|
||||
uses: dtolnay/rust-action@stable
|
||||
with:
|
||||
toolchain: 1.94
|
||||
|
||||
- name: Cache Cargo
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry
|
||||
~/.cargo/git
|
||||
target
|
||||
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
|
||||
|
||||
- name: Check formatting
|
||||
run: cargo fmt --check
|
||||
|
||||
- name: Clippy
|
||||
run: cargo clippy --workspace --all-targets -- -D warnings
|
||||
|
||||
- name: Test
|
||||
run: cargo test --workspace -- --test-threads=4
|
||||
|
||||
# ---- Docker Build (x86_64) ----
|
||||
docker:
|
||||
needs: ci
|
||||
if: github.event_name == 'push'
|
||||
runs-on: gitea
|
||||
strategy:
|
||||
matrix:
|
||||
service:
|
||||
- app
|
||||
- gitserver
|
||||
- email-worker
|
||||
- git-hook
|
||||
- migrate
|
||||
- operator
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to Harbor
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: harbor.gitdata.me
|
||||
username: ${{ secrets.HARBOR_USERNAME }}
|
||||
password: ${{ secrets.HARBOR_PASSWORD }}
|
||||
|
||||
- name: Extract metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ matrix.service }}
|
||||
tags: |
|
||||
type=sha,prefix=,format={{sha}}
|
||||
type=raw,value=latest
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
file: docker/${{ matrix.service }}.Dockerfile
|
||||
platforms: linux/amd64
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
build-args: |
|
||||
BUILD_TARGET=x86_64-unknown-linux-gnu
|
||||
|
||||
# ---- ARM64 Build ----
|
||||
docker-arm64:
|
||||
needs: ci
|
||||
if: github.event_name == 'push'
|
||||
runs-on: gitea-arm64
|
||||
strategy:
|
||||
matrix:
|
||||
service:
|
||||
- app
|
||||
- gitserver
|
||||
- email-worker
|
||||
- git-hook
|
||||
- migrate
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to Harbor
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: harbor.gitdata.me
|
||||
username: ${{ secrets.HARBOR_USERNAME }}
|
||||
password: ${{ secrets.HARBOR_PASSWORD }}
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
file: docker/${{ matrix.service }}.Dockerfile
|
||||
platforms: linux/arm64
|
||||
push: true
|
||||
tags: |
|
||||
${{ env.REGISTRY }}/${{ matrix.service }}:latest-arm64
|
||||
${{ env.REGISTRY }}/${{ matrix.service }}:sha-${{ github.sha }}
|
||||
build-args: |
|
||||
BUILD_TARGET=aarch64-unknown-linux-gnu
|
||||
|
||||
# ---- Publish Manifest (multi-arch) ----
|
||||
manifest:
|
||||
needs: [docker, docker-arm64]
|
||||
if: github.event_name == 'push'
|
||||
runs-on: gitea
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Login to Harbor
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: harbor.gitdata.me
|
||||
username: ${{ secrets.HARBOR_USERNAME }}
|
||||
password: ${{ secrets.HARBOR_PASSWORD }}
|
||||
|
||||
- name: Create and push manifest
|
||||
run: |
|
||||
for service in app gitserver email-worker git-hook migrate; do
|
||||
docker manifest create ${{ env.REGISTRY }}/$service:latest \
|
||||
${{ env.REGISTRY }}/$service:latest \
|
||||
${{ env.REGISTRY }}/$service:latest-arm64
|
||||
docker manifest push ${{ env.REGISTRY }}/$service:latest
|
||||
done
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@ -7,6 +7,7 @@ node_modules
|
||||
.env
|
||||
.env.local
|
||||
dist
|
||||
deploy/secrets.yaml
|
||||
.codex
|
||||
.qwen
|
||||
.opencode
|
||||
|
||||
1
.idea/code.iml
generated
1
.idea/code.iml
generated
@ -16,6 +16,7 @@
|
||||
<sourceFolder url="file://$MODULE_DIR$/apps/gitserver/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/apps/operator/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/libs/agent-tool-derive/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/apps/static/src" isTestSource="false" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
|
||||
170
Cargo.lock
generated
170
Cargo.lock
generated
@ -75,6 +75,29 @@ dependencies = [
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "actix-files"
|
||||
version = "0.6.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df8c4f30e3272d7c345f88ae0aac3848507ef5ba871f9cc2a41c8085a0f0523b"
|
||||
dependencies = [
|
||||
"actix-http",
|
||||
"actix-service",
|
||||
"actix-utils",
|
||||
"actix-web",
|
||||
"bitflags",
|
||||
"bytes",
|
||||
"derive_more",
|
||||
"futures-core",
|
||||
"http-range",
|
||||
"log",
|
||||
"mime",
|
||||
"mime_guess",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"v_htmlescape",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "actix-http"
|
||||
version = "3.12.0"
|
||||
@ -2269,6 +2292,29 @@ dependencies = [
|
||||
"syn 2.0.117",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_filter"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32e90c2accc4b07a8456ea0debdc2e7587bdd890680d71173a15d4ae604f6eef"
|
||||
dependencies = [
|
||||
"log",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.11.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0621c04f2196ac3f488dd583365b9c09be011a4ab8b9f37248ffcc8f6198b56a"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"env_filter",
|
||||
"jiff",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "equator"
|
||||
version = "0.4.2"
|
||||
@ -3239,6 +3285,12 @@ dependencies = [
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http-range"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21dec9db110f5f872ed9699c3ecf50cf16f423502706ba5c72462e28d3157573"
|
||||
|
||||
[[package]]
|
||||
name = "httparse"
|
||||
version = "1.10.1"
|
||||
@ -3707,6 +3759,30 @@ version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
|
||||
|
||||
[[package]]
|
||||
name = "jiff"
|
||||
version = "0.2.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a3546dc96b6d42c5f24902af9e2538e82e39ad350b0c766eb3fbf2d8f3d8359"
|
||||
dependencies = [
|
||||
"jiff-static",
|
||||
"log",
|
||||
"portable-atomic",
|
||||
"portable-atomic-util",
|
||||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jiff-static"
|
||||
version = "0.2.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2a8c8b344124222efd714b73bb41f8b5120b27a7cc1c75593a6ff768d9d05aa4"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.117",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jobserver"
|
||||
version = "0.1.34"
|
||||
@ -4373,6 +4449,18 @@ dependencies = [
|
||||
"unicase",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mime_guess2"
|
||||
version = "2.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1706dc14a2e140dec0a7a07109d9a3d5890b81e85bd6c60b906b249a77adf0ca"
|
||||
dependencies = [
|
||||
"mime",
|
||||
"phf",
|
||||
"phf_shared",
|
||||
"unicase",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "minimal-lexical"
|
||||
version = "0.2.1"
|
||||
@ -4997,6 +5085,50 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf"
|
||||
version = "0.11.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078"
|
||||
dependencies = [
|
||||
"phf_macros",
|
||||
"phf_shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_generator"
|
||||
version = "0.11.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d"
|
||||
dependencies = [
|
||||
"phf_shared",
|
||||
"rand 0.8.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_macros"
|
||||
version = "0.11.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216"
|
||||
dependencies = [
|
||||
"phf_generator",
|
||||
"phf_shared",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.117",
|
||||
"unicase",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_shared"
|
||||
version = "0.11.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5"
|
||||
dependencies = [
|
||||
"siphasher",
|
||||
"unicase",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project"
|
||||
version = "1.1.11"
|
||||
@ -5153,6 +5285,15 @@ version = "1.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49"
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic-util"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "091397be61a01d4be58e7841595bd4bfedb15f1cd54977d79b8271e94ed799a3"
|
||||
dependencies = [
|
||||
"portable-atomic",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "potential_utf"
|
||||
version = "0.1.4"
|
||||
@ -6795,6 +6936,12 @@ version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e"
|
||||
|
||||
[[package]]
|
||||
name = "siphasher"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e"
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.12"
|
||||
@ -7144,6 +7291,23 @@ version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
|
||||
|
||||
[[package]]
|
||||
name = "static-server"
|
||||
version = "0.2.9"
|
||||
dependencies = [
|
||||
"actix-cors",
|
||||
"actix-files",
|
||||
"actix-web",
|
||||
"anyhow",
|
||||
"env_logger",
|
||||
"mime",
|
||||
"mime_guess2",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"slog",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "static_assertions"
|
||||
version = "1.1.0"
|
||||
@ -7909,6 +8073,12 @@ dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "v_htmlescape"
|
||||
version = "0.15.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e8257fbc510f0a46eb602c10215901938b5c2a7d5e70fc11483b1d3c9b5b18c"
|
||||
|
||||
[[package]]
|
||||
name = "valuable"
|
||||
version = "0.1.1"
|
||||
|
||||
@ -23,6 +23,7 @@ members = [
|
||||
"apps/gitserver",
|
||||
"apps/email",
|
||||
"apps/operator",
|
||||
"apps/static",
|
||||
]
|
||||
|
||||
resolver = "3"
|
||||
|
||||
22
apps/static/Cargo.toml
Normal file
22
apps/static/Cargo.toml
Normal file
@ -0,0 +1,22 @@
|
||||
[package]
|
||||
name = "static-server"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
[dependencies]
|
||||
actix-web = { workspace = true }
|
||||
actix-files = { workspace = true }
|
||||
actix-cors = { workspace = true }
|
||||
tokio = { workspace = true, features = ["full"] }
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
mime = { workspace = true }
|
||||
mime_guess2 = { workspace = true }
|
||||
slog = { workspace = true }
|
||||
anyhow = { workspace = true }
|
||||
env_logger = { workspace = true }
|
||||
|
||||
[profile.release]
|
||||
strip = true
|
||||
lto = "thin"
|
||||
opt-level = 3
|
||||
110
apps/static/src/main.rs
Normal file
110
apps/static/src/main.rs
Normal file
@ -0,0 +1,110 @@
|
||||
use actix_cors::Cors;
|
||||
use actix_files::Files;
|
||||
use actix_web::{http::header, middleware::Logger, web, App, HttpResponse, HttpServer};
|
||||
use std::path::PathBuf;
|
||||
|
||||
/// Static file server for avatar, blob, and other static files
|
||||
/// Serves files from /data/{type} directories
|
||||
|
||||
#[derive(Clone)]
|
||||
struct StaticConfig {
|
||||
root: PathBuf,
|
||||
cors_enabled: bool,
|
||||
}
|
||||
|
||||
impl StaticConfig {
|
||||
fn from_env() -> Self {
|
||||
let root = std::env::var("STATIC_ROOT").unwrap_or_else(|_| "/data".to_string());
|
||||
let cors = std::env::var("STATIC_CORS").unwrap_or_else(|_| "true".to_string());
|
||||
|
||||
Self {
|
||||
root: PathBuf::from(root),
|
||||
cors_enabled: cors == "true" || cors == "1",
|
||||
}
|
||||
}
|
||||
|
||||
fn ensure_dir(&self, name: &str) -> PathBuf {
|
||||
let dir = self.root.join(name);
|
||||
if !dir.exists() {
|
||||
std::fs::create_dir_all(&dir).ok();
|
||||
}
|
||||
dir
|
||||
}
|
||||
}
|
||||
|
||||
async fn health() -> HttpResponse {
|
||||
HttpResponse::Ok().json(serde_json::json!({
|
||||
"status": "ok",
|
||||
"service": "static-server"
|
||||
}))
|
||||
}
|
||||
|
||||
#[actix_web::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
|
||||
|
||||
let cfg = StaticConfig::from_env();
|
||||
let bind = std::env::var("STATIC_BIND").unwrap_or_else(|_| "0.0.0.0:8081".to_string());
|
||||
|
||||
println!("Static file server starting...");
|
||||
println!(" Root: {:?}", cfg.root);
|
||||
println!(" Bind: {}", bind);
|
||||
println!(" CORS: {}", if cfg.cors_enabled { "enabled" } else { "disabled" });
|
||||
|
||||
// Ensure all directories exist
|
||||
for name in ["avatar", "blob", "media", "static"] {
|
||||
let dir = cfg.ensure_dir(name);
|
||||
println!(" {} dir: {:?}", name, dir);
|
||||
}
|
||||
|
||||
let root = cfg.root.clone();
|
||||
let cors_enabled = cfg.cors_enabled;
|
||||
|
||||
HttpServer::new(move || {
|
||||
let root = root.clone();
|
||||
|
||||
let cors = if cors_enabled {
|
||||
Cors::default()
|
||||
.allow_any_origin()
|
||||
.allowed_methods(vec!["GET", "HEAD", "OPTIONS"])
|
||||
.allowed_headers(vec![
|
||||
header::AUTHORIZATION,
|
||||
header::ACCEPT,
|
||||
header::CONTENT_TYPE,
|
||||
])
|
||||
.max_age(3600)
|
||||
} else {
|
||||
Cors::permissive()
|
||||
};
|
||||
|
||||
App::new()
|
||||
.wrap(cors)
|
||||
.wrap(Logger::default())
|
||||
.route("/health", web::get().to(health))
|
||||
.service(
|
||||
Files::new("/avatar", root.join("avatar"))
|
||||
.prefer_utf8(true)
|
||||
.index_file("index.html"),
|
||||
)
|
||||
.service(
|
||||
Files::new("/blob", root.join("blob"))
|
||||
.prefer_utf8(true)
|
||||
.index_file("index.html"),
|
||||
)
|
||||
.service(
|
||||
Files::new("/media", root.join("media"))
|
||||
.prefer_utf8(true)
|
||||
.index_file("index.html"),
|
||||
)
|
||||
.service(
|
||||
Files::new("/static", root.join("static"))
|
||||
.prefer_utf8(true)
|
||||
.index_file("index.html"),
|
||||
)
|
||||
})
|
||||
.bind(&bind)?
|
||||
.run()
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
apiVersion: v2
|
||||
name: c-----code
|
||||
name: gitdata
|
||||
description: Self-hosted GitHub + Slack alternative platform
|
||||
type: application
|
||||
version: 0.1.0
|
||||
@ -9,5 +9,6 @@ keywords:
|
||||
- collaboration
|
||||
- self-hosted
|
||||
maintainers:
|
||||
- name: C-----code Team
|
||||
- name: gitdata Team
|
||||
email: team@c.dev
|
||||
|
||||
|
||||
66
deploy/configmap.yaml
Normal file
66
deploy/configmap.yaml
Normal file
@ -0,0 +1,66 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: gitdata-config
|
||||
namespace: gitdataai
|
||||
labels:
|
||||
app.kubernetes.io/name: gitdata
|
||||
app.kubernetes.io/instance: gitdata
|
||||
app.kubernetes.io/version: "0.1.0"
|
||||
data:
|
||||
# App Info
|
||||
APP_NAME: "gitdata"
|
||||
APP_VERSION: "0.1.0"
|
||||
APP_STATIC_DOMAIN: "https://static.gitdata.ai"
|
||||
APP_MEDIA_DOMAIN: "https://static.gitdata.ai"
|
||||
APP_GIT_HTTP_DOMAIN: "https://git.gitdata.ai"
|
||||
APP_AVATAR_PATH: "/data/avatar"
|
||||
APP_REPOS_ROOT: "/data/repos"
|
||||
APP_DATABASE_URL: "postgresql://gitdataai:gitdataai123@cnpg-cluster-rw.cnpg:5432/gitdataai?sslmode=disable"
|
||||
APP_DATABASE_MAX_CONNECTIONS: "100"
|
||||
APP_DATABASE_MIN_CONNECTIONS: "5"
|
||||
APP_DATABASE_IDLE_TIMEOUT: "600"
|
||||
APP_DATABASE_MAX_LIFETIME: "3600"
|
||||
APP_DATABASE_CONNECTION_TIMEOUT: "30"
|
||||
APP_DATABASE_SCHEMA_SEARCH_PATH: "public"
|
||||
APP_DATABASE_HEALTH_CHECK_INTERVAL: "30"
|
||||
APP_DATABASE_RETRY_ATTEMPTS: "3"
|
||||
APP_DATABASE_RETRY_DELAY: "1"
|
||||
APP_REDIS_URL: "redis://default:redis123@valkey-cluster.valkey-cluster.svc.cluster.local:6379"
|
||||
APP_REDIS_POOL_SIZE: "16"
|
||||
APP_REDIS_CONNECT_TIMEOUT: "5"
|
||||
APP_REDIS_ACQUIRE_TIMEOUT: "1"
|
||||
NATS_URL: "nats://nats-client.nats.svc.cluster.local:4222"
|
||||
HOOK_POOL_MAX_CONCURRENT: "100"
|
||||
HOOK_POOL_CPU_THRESHOLD: "80"
|
||||
HOOK_POOL_REDIS_LIST_PREFIX: "{hook}"
|
||||
HOOK_POOL_REDIS_LOG_CHANNEL: "hook:logs"
|
||||
HOOK_POOL_REDIS_BLOCK_TIMEOUT: "5"
|
||||
HOOK_POOL_REDIS_MAX_RETRIES: "3"
|
||||
APP_LOG_LEVEL: "info"
|
||||
APP_LOG_FORMAT: "json"
|
||||
APP_LOG_FILE_ENABLED: "false"
|
||||
APP_LOG_FILE_PATH: "/var/log/gitdata/app.log"
|
||||
APP_LOG_FILE_ROTATION: "daily"
|
||||
APP_LOG_FILE_MAX_FILES: "7"
|
||||
APP_LOG_FILE_MAX_SIZE: "100"
|
||||
APP_OTEL_ENABLED: "false"
|
||||
APP_OTEL_ENDPOINT: ""
|
||||
APP_OTEL_SERVICE_NAME: "gitdata"
|
||||
APP_OTEL_SERVICE_VERSION: "0.1.0"
|
||||
APP_SMTP_HOST: "smtp.exmail.qq.com"
|
||||
APP_SMTP_PORT: "465"
|
||||
APP_SMTP_USERNAME: "gitdata-bot@gitdata.ai"
|
||||
APP_SMTP_PASSWORD: "Dha88YLtNicGUj4G"
|
||||
APP_SMTP_FROM: "gitdata-bot@gitdata.ai"
|
||||
APP_SMTP_TLS: "true"
|
||||
APP_SMTP_TIMEOUT: "30"
|
||||
APP_SSH_DOMAIN: "git.gitdata.ai"
|
||||
APP_SSH_PORT: "22"
|
||||
APP_AI_BASIC_URL: "https://axonhub.gitdata.me/v1"
|
||||
APP_AI_API_KEY: "ah-629e2cfb5a58f6b7053cd890c6bd6c0de4537fa2f816ccc984090d022a50262e"
|
||||
APP_EMBED_MODEL_BASE_URL: "https://api.siliconflow.cn/v1"
|
||||
APP_EMBED_MODEL_API_KEY: "sk-xzehcnpedeijpgyiitcalzhlcdrmyujezubudvpacukyvzmo"
|
||||
APP_EMBED_MODEL_NAME: "BAAI/bge-m3"
|
||||
APP_EMBED_MODEL_DIMENSIONS: "1024"
|
||||
APP_QDRANT_URL: "http://qdrant.qdrant.svc.cluster.local:6333"
|
||||
71
deploy/secrets.yaml.example
Normal file
71
deploy/secrets.yaml.example
Normal file
@ -0,0 +1,71 @@
|
||||
# =============================================================================
|
||||
# Secrets Configuration - 示例文件 (外部 Secret Manager)
|
||||
# =============================================================================
|
||||
# 生产环境使用 External Secrets Operator (ESO) 从 Vault/AWS SM/Azure KeyVault 同步
|
||||
# https://external-secrets.io/
|
||||
#
|
||||
# 密钥管理器需要预先配置 SecretStore,例如 Vault:
|
||||
# apiVersion: external-secrets.io/v1beta1
|
||||
# kind: SecretStore
|
||||
# metadata:
|
||||
# name: vault-backend
|
||||
# namespace: gitdataai
|
||||
# spec:
|
||||
# vault:
|
||||
# server: "https://vault.example.com"
|
||||
# pathPrefix: /secret
|
||||
# auth:
|
||||
# kubernetes:
|
||||
# mountPath: kubernetes
|
||||
# role: gitdata
|
||||
#
|
||||
# 密钥路径约定:
|
||||
# gitdata/database → { url: "postgresql://..." }
|
||||
# gitdata/redis → { url: "redis://..." }
|
||||
# gitdata/qdrant → { apiKey: "..." }
|
||||
# =============================================================================
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# External Secrets 配置
|
||||
# -----------------------------------------------------------------------------
|
||||
externalSecrets:
|
||||
# SecretStore / ClusterSecretStore 名称 (集群预先配置)
|
||||
storeName: "vault-backend"
|
||||
storeKind: "SecretStore" # 或 ClusterSecretStore (跨 namespace)
|
||||
|
||||
# Vault 密钥路径
|
||||
databaseKey: "gitdata/database"
|
||||
redisKey: "gitdata/redis"
|
||||
qdrantKey: "gitdata/qdrant"
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Secret 名称 (与 ExternalSecret target.name 对应)
|
||||
# -----------------------------------------------------------------------------
|
||||
database:
|
||||
existingSecret: "gitdata-database-secret"
|
||||
secretKeys:
|
||||
url: APP_DATABASE_URL
|
||||
|
||||
redis:
|
||||
existingSecret: "gitdata-redis-secret"
|
||||
secretKeys:
|
||||
url: APP_REDIS_URL
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Qdrant (启用 AI 功能时需要)
|
||||
# -----------------------------------------------------------------------------
|
||||
qdrant:
|
||||
enabled: true
|
||||
url: "http://qdrant.qdrant.svc.cluster.local:6333"
|
||||
existingSecret: "gitdata-qdrant-secret"
|
||||
secretKeys:
|
||||
apiKey: APP_QDRANT_API_KEY
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 本地开发 / CI/CD 快速部署 (secrets.create: true)
|
||||
# 生产环境请使用 externalSecrets 配置
|
||||
# -----------------------------------------------------------------------------
|
||||
# secrets:
|
||||
# create: true
|
||||
# databaseUrl: "postgresql://..."
|
||||
# redisUrl: "redis://..."
|
||||
@ -26,7 +26,7 @@
|
||||
Or set .Values.secrets in values.yaml.
|
||||
|
||||
🔄 To run database migrations:
|
||||
helm upgrade {{ .Release.Name }} ./c-----code -n {{ .Release.Namespace }} \
|
||||
helm upgrade {{ .Release.Name }} ./gitdata -n {{ .Release.Namespace }} \
|
||||
--set migrate.enabled=true
|
||||
|
||||
📖 Useful commands:
|
||||
|
||||
@ -2,29 +2,29 @@
|
||||
Common helpers
|
||||
============================================================================= */}}
|
||||
|
||||
{{- define "c-----code.fullname" -}}
|
||||
{{- define "gitdata.fullname" -}}
|
||||
{{- .Release.Name -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- define "c-----code.namespace" -}}
|
||||
{{- define "gitdata.namespace" -}}
|
||||
{{- .Values.namespace | default .Release.Namespace -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- define "c-----code.image" -}}
|
||||
{{- define "gitdata.image" -}}
|
||||
{{- $registry := .Values.image.registry -}}
|
||||
{{- $pullPolicy := .Values.image.pullPolicy -}}
|
||||
{{- printf "%s/%s:%s" $registry .image.repository .image.tag -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/* Inject image pull policy into sub-chart image dict */}}
|
||||
{{- define "c-----code.mergeImage" -}}
|
||||
{{- define "gitdata.mergeImage" -}}
|
||||
{{- $merged := dict "pullPolicy" $.Values.image.pullPolicy -}}
|
||||
{{- $merged = merge $merged .image -}}
|
||||
{{- printf "%s/%s:%s" $.Values.image.registry $merged.repository $merged.tag -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/* Build a key-value env var list, optionally reading from a Secret */}}
|
||||
{{- define "c-----code.envFromSecret" -}}
|
||||
{{- define "gitdata.envFromSecret" -}}
|
||||
{{- $secretName := .existingSecret -}}
|
||||
{{- $keys := .secretKeys -}}
|
||||
{{- $result := list -}}
|
||||
@ -36,7 +36,7 @@
|
||||
{{- end -}}
|
||||
|
||||
{{/* Merge two env lists (extra env over auto-injected) */}}
|
||||
{{- define "c-----code.mergeEnv" -}}
|
||||
{{- define "gitdata.mergeEnv" -}}
|
||||
{{- $auto := .auto -}}
|
||||
{{- $extra := .extra | default list -}}
|
||||
{{- $merged := append $auto $extra | toJson | fromJson -}}
|
||||
|
||||
@ -1,158 +0,0 @@
|
||||
{{- if .Values.actRunner.enabled -}}
|
||||
{{- $fullName := include "c-----code.fullname" . -}}
|
||||
{{- $ns := include "c-----code.namespace" . -}}
|
||||
{{- $runner := .Values.actRunner -}}
|
||||
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ $fullName }}-act-runner
|
||||
namespace: {{ $ns }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ $fullName }}-act-runner
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion }}
|
||||
spec:
|
||||
replicas: {{ $runner.replicaCount }}
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: {{ $fullName }}-act-runner
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ $fullName }}-act-runner
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
spec:
|
||||
serviceAccountName: {{ $fullName }}-act-runner
|
||||
containers:
|
||||
- name: runner
|
||||
image: "{{ .Values.image.registry }}/act-runner:{{ $runner.image.tag }}"
|
||||
imagePullPolicy: {{ $runner.image.pullPolicy | default .Values.image.pullPolicy }}
|
||||
args:
|
||||
- --config
|
||||
- /runner/config.yaml
|
||||
- --replaces-self
|
||||
env:
|
||||
- name: CONFIG_FILE
|
||||
value: /runner/config.yaml
|
||||
{{- if .Values.nats.enabled }}
|
||||
- name: HOOK_POOL_REDIS_LIST_PREFIX
|
||||
value: "{hook}"
|
||||
- name: HOOK_POOL_REDIS_LOG_CHANNEL
|
||||
value: "hook:logs"
|
||||
{{- end }}
|
||||
{{- range $runner.env }}
|
||||
- name: {{ .name }}
|
||||
value: {{ .value | quote }}
|
||||
{{- end }}
|
||||
volumeMounts:
|
||||
- name: runner-config
|
||||
mountPath: /runner
|
||||
readOnly: true
|
||||
- name: docker-socket
|
||||
mountPath: /var/run/docker.sock
|
||||
resources:
|
||||
{{- toYaml $runner.resources | nindent 10 }}
|
||||
volumes:
|
||||
- name: runner-config
|
||||
configMap:
|
||||
name: {{ $fullName }}-act-runner-config
|
||||
- name: docker-socket
|
||||
hostPath:
|
||||
path: /var/run/docker.sock
|
||||
type: Socket
|
||||
{{- with $runner.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with $runner.affinity }}
|
||||
affinity:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with $runner.tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: {{ $fullName }}-act-runner-config
|
||||
namespace: {{ $ns }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ $fullName }}-act-runner
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
data:
|
||||
config.yaml: |
|
||||
# Act Runner Configuration
|
||||
# Generated by Helm values
|
||||
log:
|
||||
level: {{ $runner.logLevel | default "info" }}
|
||||
runner:
|
||||
capacity: {{ $runner.capacity | default 2 }}
|
||||
labels:
|
||||
{{- range $runner.labels }}
|
||||
- {{ . }}
|
||||
{{- end }}
|
||||
cache:
|
||||
{{- if $runner.cache.enabled }}
|
||||
enabled: true
|
||||
dir: {{ $runner.cache.dir | default "/tmp/actions-cache" }}
|
||||
{{- else }}
|
||||
enabled: false
|
||||
{{- end }}
|
||||
docker:
|
||||
host: unix:///var/run/docker.sock
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: {{ $fullName }}-act-runner
|
||||
namespace: {{ $ns }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ $fullName }}-act-runner
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: {{ $fullName }}-act-runner
|
||||
namespace: {{ $ns }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ $fullName }}-act-runner
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["pods", "pods/log"]
|
||||
verbs: ["get", "list", "watch"]
|
||||
- apiGroups: [""]
|
||||
resources: ["secrets"]
|
||||
verbs: ["get", "list"]
|
||||
- apiGroups: [""]
|
||||
resources: ["configmaps"]
|
||||
verbs: ["get", "list", "create", "update", "patch"]
|
||||
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: {{ $fullName }}-act-runner
|
||||
namespace: {{ $ns }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ $fullName }}-act-runner
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: {{ $fullName }}-act-runner
|
||||
namespace: {{ $ns }}
|
||||
roleRef:
|
||||
kind: Role
|
||||
name: {{ $fullName }}-act-runner
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
|
||||
{{- end }}
|
||||
@ -2,24 +2,25 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ include "c-----code.fullname" . }}-app
|
||||
namespace: {{ include "c-----code.namespace" . }}
|
||||
name: {{ include "gitdata.fullname" . }}-app
|
||||
namespace: {{ include "gitdata.namespace" . }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ include "c-----code.fullname" . }}-app
|
||||
app.kubernetes.io/name: {{ include "gitdata.fullname" . }}-app
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion }}
|
||||
spec:
|
||||
replicas: {{ .Values.app.replicaCount }}
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: {{ include "c-----code.fullname" . }}-app
|
||||
app.kubernetes.io/name: {{ include "gitdata.fullname" . }}-app
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ include "c-----code.fullname" . }}-app
|
||||
app.kubernetes.io/name: {{ include "gitdata.fullname" . }}-app
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
spec:
|
||||
terminationGracePeriodSeconds: 30
|
||||
containers:
|
||||
- name: app
|
||||
image: "{{ .Values.image.registry }}/{{ .Values.app.image.repository }}:{{ .Values.app.image.tag }}"
|
||||
@ -31,34 +32,52 @@ spec:
|
||||
env:
|
||||
- name: APP_DATABASE_URL
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.database.existingSecret | default (printf "%s-secrets" (include "c-----code.fullname" .)) }}
|
||||
key: {{ .Values.database.secretKeys.url }}
|
||||
configMapKeyRef:
|
||||
name: {{ include "gitdata.fullname" . }}-config
|
||||
key: APP_DATABASE_URL
|
||||
optional: true
|
||||
- name: APP_REDIS_URL
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.redis.existingSecret | default (printf "%s-secrets" (include "c-----code.fullname" .)) }}
|
||||
key: {{ .Values.redis.secretKeys.url }}
|
||||
configMapKeyRef:
|
||||
name: {{ include "gitdata.fullname" . }}-config
|
||||
key: APP_REDIS_URL
|
||||
optional: true
|
||||
- name: NATS_URL
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: {{ include "gitdata.fullname" . }}-config
|
||||
key: NATS_URL
|
||||
optional: true
|
||||
{{- if .Values.nats.enabled }}
|
||||
- name: HOOK_POOL_REDIS_LIST_PREFIX
|
||||
value: "{hook}"
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: {{ include "gitdata.fullname" . }}-config
|
||||
key: HOOK_POOL_REDIS_LIST_PREFIX
|
||||
optional: true
|
||||
- name: HOOK_POOL_REDIS_LOG_CHANNEL
|
||||
value: "hook:logs"
|
||||
{{- end }}
|
||||
{{- if .Values.qdrant.enabled }}
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: {{ include "gitdata.fullname" . }}-config
|
||||
key: HOOK_POOL_REDIS_LOG_CHANNEL
|
||||
optional: true
|
||||
- name: APP_QDRANT_URL
|
||||
value: {{ .Values.qdrant.url }}
|
||||
{{- if and .Values.qdrant.existingSecret .Values.qdrant.secretKeys.apiKey }}
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: {{ include "gitdata.fullname" . }}-config
|
||||
key: APP_QDRANT_URL
|
||||
optional: true
|
||||
- name: APP_QDRANT_API_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.qdrant.existingSecret }}
|
||||
key: {{ .Values.qdrant.secretKeys.apiKey }}
|
||||
configMapKeyRef:
|
||||
name: {{ include "gitdata.fullname" . }}-config
|
||||
key: APP_QDRANT_API_KEY
|
||||
optional: true
|
||||
- name: APP_AVATAR_PATH
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: {{ include "gitdata.fullname" . }}-config
|
||||
key: APP_AVATAR_PATH
|
||||
optional: true
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- range .Values.app.env }}
|
||||
- name: {{ .name }}
|
||||
value: {{ .value | quote }}
|
||||
@ -75,8 +94,28 @@ spec:
|
||||
port: {{ .Values.app.readinessProbe.port }}
|
||||
initialDelaySeconds: {{ .Values.app.readinessProbe.initialDelaySeconds }}
|
||||
periodSeconds: {{ .Values.app.readinessProbe.periodSeconds }}
|
||||
{{- if .Values.app.startupProbe }}
|
||||
startupProbe:
|
||||
httpGet:
|
||||
path: {{ .Values.app.startupProbe.path }}
|
||||
port: {{ .Values.app.startupProbe.port }}
|
||||
initialDelaySeconds: {{ .Values.app.startupProbe.initialDelaySeconds | default 0 }}
|
||||
periodSeconds: {{ .Values.app.startupProbe.periodSeconds }}
|
||||
failureThreshold: {{ .Values.app.startupProbe.failureThreshold }}
|
||||
{{- end }}
|
||||
resources:
|
||||
{{- toYaml .Values.app.resources | nindent 10 }}
|
||||
{{- if .Values.storage.enabled }}
|
||||
volumeMounts:
|
||||
- name: shared-data
|
||||
mountPath: /data
|
||||
{{- end }}
|
||||
{{- if .Values.storage.enabled }}
|
||||
volumes:
|
||||
- name: shared-data
|
||||
persistentVolumeClaim:
|
||||
claimName: {{ include "gitdata.fullname" . }}-shared-data
|
||||
{{- end }}
|
||||
{{- with .Values.app.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
@ -93,10 +132,10 @@ spec:
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ include "c-----code.fullname" . }}-app
|
||||
namespace: {{ include "c-----code.namespace" . }}
|
||||
name: {{ include "gitdata.fullname" . }}-app
|
||||
namespace: {{ include "gitdata.namespace" . }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ include "c-----code.fullname" . }}-app
|
||||
app.kubernetes.io/name: {{ include "gitdata.fullname" . }}-app
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
spec:
|
||||
type: {{ .Values.app.service.type }}
|
||||
@ -106,6 +145,6 @@ spec:
|
||||
protocol: TCP
|
||||
name: http
|
||||
selector:
|
||||
app.kubernetes.io/name: {{ include "c-----code.fullname" . }}-app
|
||||
app.kubernetes.io/name: {{ include "gitdata.fullname" . }}-app
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
{{- end }}
|
||||
|
||||
@ -1,15 +1,51 @@
|
||||
{{- /* Application configuration - non-sensitive values */ -}}
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: {{ include "c-----code.fullname" . }}-config
|
||||
namespace: {{ include "c-----code.namespace" . }}
|
||||
name: {{ include "gitdata.fullname" . }}-config
|
||||
namespace: {{ include "gitdata.namespace" . }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ .Chart.Name }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion }}
|
||||
data:
|
||||
{{- if .Values.app.config }}
|
||||
{{- range $key, $value := .Values.app.config }}
|
||||
{{ $key }}: {{ $value | quote }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
APP_NAME: {{ .Values.app.name | default "gitdata" | quote }}
|
||||
APP_VERSION: {{ .Chart.AppVersion | quote }}
|
||||
APP_STATIC_DOMAIN: {{ .Values.config.staticDomain | default "" | quote }}
|
||||
APP_MEDIA_DOMAIN: {{ .Values.config.mediaDomain | default "" | quote }}
|
||||
APP_GIT_HTTP_DOMAIN: {{ .Values.config.gitHttpDomain | default "" | quote }}
|
||||
APP_AVATAR_PATH: {{ .Values.config.avatarPath | default "/data/avatar" | quote }}
|
||||
APP_REPOS_ROOT: {{ .Values.config.reposRoot | default "/data/repos" | quote }}
|
||||
APP_LOG_LEVEL: {{ .Values.config.logLevel | default "info" | quote }}
|
||||
APP_LOG_FORMAT: {{ .Values.config.logFormat | default "json" | quote }}
|
||||
APP_LOG_FILE_ENABLED: {{ .Values.config.logFileEnabled | default "false" | quote }}
|
||||
APP_LOG_FILE_PATH: {{ .Values.config.logFilePath | default "/var/log/gitdata/app.log" | quote }}
|
||||
APP_LOG_FILE_ROTATION: {{ .Values.config.logFileRotation | default "daily" | quote }}
|
||||
APP_LOG_FILE_MAX_FILES: {{ .Values.config.logFileMaxFiles | default "7" | quote }}
|
||||
APP_LOG_FILE_MAX_SIZE: {{ .Values.config.logFileMaxSize | default "100" | quote }}
|
||||
APP_OTEL_ENABLED: {{ .Values.config.otelEnabled | default "false" | quote }}
|
||||
APP_OTEL_ENDPOINT: {{ .Values.config.otelEndpoint | default "" | quote }}
|
||||
APP_OTEL_SERVICE_NAME: {{ .Values.config.otelServiceName | default "gitdata" | quote }}
|
||||
APP_OTEL_SERVICE_VERSION: {{ .Chart.AppVersion | quote }}
|
||||
APP_DATABASE_MAX_CONNECTIONS: {{ .Values.config.databaseMaxConnections | default "100" | quote }}
|
||||
APP_DATABASE_MIN_CONNECTIONS: {{ .Values.config.databaseMinConnections | default "5" | quote }}
|
||||
APP_DATABASE_IDLE_TIMEOUT: {{ .Values.config.databaseIdleTimeout | default "600" | quote }}
|
||||
APP_DATABASE_MAX_LIFETIME: {{ .Values.config.databaseMaxLifetime | default "3600" | quote }}
|
||||
APP_DATABASE_CONNECTION_TIMEOUT: {{ .Values.config.databaseConnectionTimeout | default "30" | quote }}
|
||||
APP_DATABASE_SCHEMA_SEARCH_PATH: {{ .Values.config.databaseSchemaSearchPath | default "public" | quote }}
|
||||
APP_DATABASE_HEALTH_CHECK_INTERVAL: {{ .Values.config.databaseHealthCheckInterval | default "30" | quote }}
|
||||
APP_DATABASE_RETRY_ATTEMPTS: {{ .Values.config.databaseRetryAttempts | default "3" | quote }}
|
||||
APP_DATABASE_RETRY_DELAY: {{ .Values.config.databaseRetryDelay | default "1" | quote }}
|
||||
APP_REDIS_POOL_SIZE: {{ .Values.config.redisPoolSize | default "16" | quote }}
|
||||
APP_REDIS_CONNECT_TIMEOUT: {{ .Values.config.redisConnectTimeout | default "5" | quote }}
|
||||
APP_REDIS_ACQUIRE_TIMEOUT: {{ .Values.config.redisAcquireTimeout | default "1" | quote }}
|
||||
HOOK_POOL_MAX_CONCURRENT: {{ .Values.config.hookPoolMaxConcurrent | default "100" | quote }}
|
||||
HOOK_POOL_CPU_THRESHOLD: {{ .Values.config.hookPoolCpuThreshold | default "80" | quote }}
|
||||
HOOK_POOL_REDIS_LIST_PREFIX: {{ .Values.config.hookPoolRedisListPrefix | default "{hook}" | quote }}
|
||||
HOOK_POOL_REDIS_LOG_CHANNEL: {{ .Values.config.hookPoolRedisLogChannel | default "hook:logs" | quote }}
|
||||
HOOK_POOL_REDIS_BLOCK_TIMEOUT: {{ .Values.config.hookPoolRedisBlockTimeout | default "5" | quote }}
|
||||
HOOK_POOL_REDIS_MAX_RETRIES: {{ .Values.config.hookPoolRedisMaxRetries | default "3" | quote }}
|
||||
APP_SMTP_PORT: {{ .Values.config.smtpPort | default "587" | quote }}
|
||||
APP_SMTP_TLS: {{ .Values.config.smtpTls | default "true" | quote }}
|
||||
APP_SMTP_TIMEOUT: {{ .Values.config.smtpTimeout | default "30" | quote }}
|
||||
APP_SSH_PORT: {{ .Values.config.sshPort | default "22" | quote }}
|
||||
|
||||
@ -2,22 +2,22 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ include "c-----code.fullname" . }}-email-worker
|
||||
namespace: {{ include "c-----code.namespace" . }}
|
||||
name: {{ include "gitdata.fullname" . }}-email-worker
|
||||
namespace: {{ include "gitdata.namespace" . }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ include "c-----code.fullname" . }}-email-worker
|
||||
app.kubernetes.io/name: {{ include "gitdata.fullname" . }}-email-worker
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion }}
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: {{ include "c-----code.fullname" . }}-email-worker
|
||||
app.kubernetes.io/name: {{ include "gitdata.fullname" . }}-email-worker
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ include "c-----code.fullname" . }}-email-worker
|
||||
app.kubernetes.io/name: {{ include "gitdata.fullname" . }}-email-worker
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
spec:
|
||||
containers:
|
||||
@ -27,15 +27,15 @@ spec:
|
||||
env:
|
||||
- name: APP_DATABASE_URL
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.database.existingSecret | default (printf "%s-secrets" (include "c-----code.fullname" .)) }}
|
||||
key: {{ .Values.database.secretKeys.url }}
|
||||
configMapKeyRef:
|
||||
name: {{ include "gitdata.fullname" . }}-config
|
||||
key: APP_DATABASE_URL
|
||||
optional: true
|
||||
- name: APP_REDIS_URL
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.redis.existingSecret | default (printf "%s-secrets" (include "c-----code.fullname" .)) }}
|
||||
key: {{ .Values.redis.secretKeys.url }}
|
||||
configMapKeyRef:
|
||||
name: {{ include "gitdata.fullname" . }}-config
|
||||
key: APP_REDIS_URL
|
||||
optional: true
|
||||
{{- range .Values.emailWorker.env }}
|
||||
- name: {{ .name }}
|
||||
@ -43,6 +43,30 @@ spec:
|
||||
{{- end }}
|
||||
resources:
|
||||
{{- toYaml .Values.emailWorker.resources | nindent 10 }}
|
||||
{{- if .Values.emailWorker.livenessProbe }}
|
||||
livenessProbe:
|
||||
exec:
|
||||
command:
|
||||
{{- range .Values.emailWorker.livenessProbe.exec.command }}
|
||||
- {{ . | quote }}
|
||||
{{- end }}
|
||||
initialDelaySeconds: {{ .Values.emailWorker.livenessProbe.initialDelaySeconds }}
|
||||
periodSeconds: {{ .Values.emailWorker.livenessProbe.periodSeconds }}
|
||||
timeoutSeconds: {{ .Values.emailWorker.livenessProbe.timeoutSeconds }}
|
||||
failureThreshold: {{ .Values.emailWorker.livenessProbe.failureThreshold }}
|
||||
{{- end }}
|
||||
{{- if .Values.emailWorker.readinessProbe }}
|
||||
readinessProbe:
|
||||
exec:
|
||||
command:
|
||||
{{- range .Values.emailWorker.readinessProbe.exec.command }}
|
||||
- {{ . | quote }}
|
||||
{{- end }}
|
||||
initialDelaySeconds: {{ .Values.emailWorker.readinessProbe.initialDelaySeconds }}
|
||||
periodSeconds: {{ .Values.emailWorker.readinessProbe.periodSeconds }}
|
||||
timeoutSeconds: {{ .Values.emailWorker.readinessProbe.timeoutSeconds }}
|
||||
failureThreshold: {{ .Values.emailWorker.readinessProbe.failureThreshold }}
|
||||
{{- end }}
|
||||
{{- with .Values.emailWorker.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
@ -55,4 +79,10 @@ spec:
|
||||
tolerations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- if .Values.storage.enabled }}
|
||||
volumes:
|
||||
- name: shared-data
|
||||
persistentVolumeClaim:
|
||||
claimName: {{ include "gitdata.fullname" . }}-shared-data
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
76
deploy/templates/external-secrets.yaml
Normal file
76
deploy/templates/external-secrets.yaml
Normal file
@ -0,0 +1,76 @@
|
||||
{{- /*
|
||||
External Secrets - 从外部 Secret Manager 同步密钥
|
||||
需要集群安装: External Secrets Operator (ESO)
|
||||
https://external-secrets.io/
|
||||
*/ -}}
|
||||
|
||||
{{- $ns := include "gitdata.namespace" . -}}
|
||||
|
||||
{{- /* Database Secret */ -}}
|
||||
{{- if .Values.database.existingSecret -}}
|
||||
---
|
||||
apiVersion: external-secrets.io/v1beta1
|
||||
kind: ExternalSecret
|
||||
metadata:
|
||||
name: {{ .Values.database.existingSecret }}
|
||||
namespace: {{ $ns }}
|
||||
spec:
|
||||
refreshInterval: 1h
|
||||
secretStoreRef:
|
||||
name: {{ .Values.externalSecrets.storeName | default "vault-backend" }}
|
||||
kind: {{ .Values.externalSecrets.storeKind | default "SecretStore" }}
|
||||
target:
|
||||
name: {{ .Values.database.existingSecret }}
|
||||
creationPolicy: Owner
|
||||
data:
|
||||
- secretKey: {{ .Values.database.secretKeys.url }}
|
||||
remoteRef:
|
||||
key: {{ .Values.externalSecrets.databaseKey | default "gitdata/database" }}
|
||||
property: url
|
||||
{{- end }}
|
||||
|
||||
{{- /* Redis Secret */ -}}
|
||||
{{- if .Values.redis.existingSecret -}}
|
||||
---
|
||||
apiVersion: external-secrets.io/v1beta1
|
||||
kind: ExternalSecret
|
||||
metadata:
|
||||
name: {{ .Values.redis.existingSecret }}
|
||||
namespace: {{ $ns }}
|
||||
spec:
|
||||
refreshInterval: 1h
|
||||
secretStoreRef:
|
||||
name: {{ .Values.externalSecrets.storeName | default "vault-backend" }}
|
||||
kind: {{ .Values.externalSecrets.storeKind | default "SecretStore" }}
|
||||
target:
|
||||
name: {{ .Values.redis.existingSecret }}
|
||||
creationPolicy: Owner
|
||||
data:
|
||||
- secretKey: {{ .Values.redis.secretKeys.url }}
|
||||
remoteRef:
|
||||
key: {{ .Values.externalSecrets.redisKey | default "gitdata/redis" }}
|
||||
property: url
|
||||
{{- end }}
|
||||
|
||||
{{- /* Qdrant Secret */ -}}
|
||||
{{- if and .Values.qdrant.enabled .Values.qdrant.existingSecret -}}
|
||||
---
|
||||
apiVersion: external-secrets.io/v1beta1
|
||||
kind: ExternalSecret
|
||||
metadata:
|
||||
name: {{ .Values.qdrant.existingSecret }}
|
||||
namespace: {{ $ns }}
|
||||
spec:
|
||||
refreshInterval: 1h
|
||||
secretStoreRef:
|
||||
name: {{ .Values.externalSecrets.storeName | default "vault-backend" }}
|
||||
kind: {{ .Values.externalSecrets.storeKind | default "SecretStore" }}
|
||||
target:
|
||||
name: {{ .Values.qdrant.existingSecret }}
|
||||
creationPolicy: Owner
|
||||
data:
|
||||
- secretKey: {{ .Values.qdrant.secretKeys.apiKey }}
|
||||
remoteRef:
|
||||
key: {{ .Values.externalSecrets.qdrantKey | default "gitdata/qdrant" }}
|
||||
property: apiKey
|
||||
{{- end }}
|
||||
82
deploy/templates/frontend-deployment.yaml
Normal file
82
deploy/templates/frontend-deployment.yaml
Normal file
@ -0,0 +1,82 @@
|
||||
{{- if .Values.frontend.enabled -}}
|
||||
{{- $fullName := include "gitdata.fullname" . -}}
|
||||
{{- $ns := include "gitdata.namespace" . -}}
|
||||
{{- $svc := .Values.frontend -}}
|
||||
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ $fullName }}-frontend
|
||||
namespace: {{ $ns }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ $fullName }}-frontend
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion }}
|
||||
spec:
|
||||
replicas: {{ $svc.replicaCount }}
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: {{ $fullName }}-frontend
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ $fullName }}-frontend
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
spec:
|
||||
containers:
|
||||
- name: frontend
|
||||
image: "{{ $.Values.image.registry }}/{{ $svc.image.repository }}:{{ $svc.image.tag }}"
|
||||
imagePullPolicy: {{ $svc.image.pullPolicy | default $.Values.image.pullPolicy }}
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 80
|
||||
protocol: TCP
|
||||
resources:
|
||||
{{- toYaml $svc.resources | nindent 10 }}
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: 80
|
||||
initialDelaySeconds: {{ $svc.livenessProbe.initialDelaySeconds }}
|
||||
periodSeconds: {{ $svc.livenessProbe.periodSeconds }}
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: 80
|
||||
initialDelaySeconds: {{ $svc.readinessProbe.initialDelaySeconds }}
|
||||
periodSeconds: {{ $svc.readinessProbe.periodSeconds }}
|
||||
{{- with $svc.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with $svc.affinity }}
|
||||
affinity:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with $svc.tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ $fullName }}-frontend
|
||||
namespace: {{ $ns }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ $fullName }}-frontend
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
spec:
|
||||
type: {{ $svc.service.type }}
|
||||
ports:
|
||||
- name: http
|
||||
port: 80
|
||||
targetPort: 80
|
||||
protocol: TCP
|
||||
selector:
|
||||
app.kubernetes.io/name: {{ $fullName }}-frontend
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
{{- end }}
|
||||
61
deploy/templates/frontend-ingress.yaml
Normal file
61
deploy/templates/frontend-ingress.yaml
Normal file
@ -0,0 +1,61 @@
|
||||
{{- if .Values.frontend.ingress.enabled -}}
|
||||
{{- $fullName := include "gitdata.fullname" . -}}
|
||||
{{- $ns := include "gitdata.namespace" . -}}
|
||||
{{- $ing := .Values.frontend.ingress -}}
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: {{ $fullName }}-frontend
|
||||
namespace: {{ $ns }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ $fullName }}-frontend
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: {{ $ing.clusterIssuer | default "cloudflare-acme-cluster-issuer" }}
|
||||
{{- if $ing.annotations }}
|
||||
{{ toYaml $ing.annotations | indent 4 }}
|
||||
{{- end }}
|
||||
{{- if not (hasKey ($ing.annotations | default dict) "nginx.ingress.kubernetes.io/proxy-body-size") }}
|
||||
{{- if or (not $ing.className) (eq $ing.className "nginx") (contains "nginx" $ing.className) }}
|
||||
nginx.ingress.kubernetes.io/proxy-body-size: "0"
|
||||
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
|
||||
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- if $ing.className }}
|
||||
ingressClassName: {{ $ing.className }}
|
||||
{{- end }}
|
||||
{{- if $ing.tls }}
|
||||
tls:
|
||||
{{- range $ing.tls }}
|
||||
- hosts:
|
||||
{{- range .hosts }}
|
||||
- {{ . | quote }}
|
||||
{{- end }}
|
||||
secretName: {{ .secretName }}
|
||||
{{- end }}
|
||||
{{- else }}
|
||||
tls:
|
||||
{{- range $ing.hosts }}
|
||||
- hosts:
|
||||
- {{ .host | quote }}
|
||||
secretName: {{ $fullName }}-frontend-tls
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
rules:
|
||||
{{- range $ing.hosts }}
|
||||
- host: {{ .host | quote }}
|
||||
http:
|
||||
paths:
|
||||
{{- range .paths }}
|
||||
- path: {{ .path }}
|
||||
pathType: {{ .pathType | default "Prefix" }}
|
||||
backend:
|
||||
service:
|
||||
name: {{ $fullName }}-frontend
|
||||
port:
|
||||
number: 80
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@ -2,22 +2,22 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ include "c-----code.fullname" . }}-git-hook
|
||||
namespace: {{ include "c-----code.namespace" . }}
|
||||
name: {{ include "gitdata.fullname" . }}-git-hook
|
||||
namespace: {{ include "gitdata.namespace" . }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ include "c-----code.fullname" . }}-git-hook
|
||||
app.kubernetes.io/name: {{ include "gitdata.fullname" . }}-git-hook
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion }}
|
||||
spec:
|
||||
replicas: {{ .Values.gitHook.replicaCount | default 2 }}
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: {{ include "c-----code.fullname" . }}-git-hook
|
||||
app.kubernetes.io/name: {{ include "gitdata.fullname" . }}-git-hook
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ include "c-----code.fullname" . }}-git-hook
|
||||
app.kubernetes.io/name: {{ include "gitdata.fullname" . }}-git-hook
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
spec:
|
||||
containers:
|
||||
@ -27,28 +27,58 @@ spec:
|
||||
env:
|
||||
- name: APP_DATABASE_URL
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.database.existingSecret | default (printf "%s-secrets" (include "c-----code.fullname" .)) }}
|
||||
key: {{ .Values.database.secretKeys.url }}
|
||||
configMapKeyRef:
|
||||
name: {{ include "gitdata.fullname" . }}-config
|
||||
key: APP_DATABASE_URL
|
||||
optional: true
|
||||
- name: APP_REDIS_URL
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.redis.existingSecret | default (printf "%s-secrets" (include "c-----code.fullname" .)) }}
|
||||
key: {{ .Values.redis.secretKeys.url }}
|
||||
configMapKeyRef:
|
||||
name: {{ include "gitdata.fullname" . }}-config
|
||||
key: APP_REDIS_URL
|
||||
optional: true
|
||||
{{- if .Values.nats.enabled }}
|
||||
- name: HOOK_POOL_REDIS_LIST_PREFIX
|
||||
value: "{hook}"
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: {{ include "gitdata.fullname" . }}-config
|
||||
key: HOOK_POOL_REDIS_LIST_PREFIX
|
||||
optional: true
|
||||
- name: HOOK_POOL_REDIS_LOG_CHANNEL
|
||||
value: "hook:logs"
|
||||
{{- end }}
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: {{ include "gitdata.fullname" . }}-config
|
||||
key: HOOK_POOL_REDIS_LOG_CHANNEL
|
||||
optional: true
|
||||
{{- range .Values.gitHook.env }}
|
||||
- name: {{ .name }}
|
||||
value: {{ .value | quote }}
|
||||
{{- end }}
|
||||
resources:
|
||||
{{- toYaml .Values.gitHook.resources | nindent 10 }}
|
||||
{{- if .Values.gitHook.livenessProbe }}
|
||||
livenessProbe:
|
||||
exec:
|
||||
command:
|
||||
{{- range .Values.gitHook.livenessProbe.exec.command }}
|
||||
- {{ . | quote }}
|
||||
{{- end }}
|
||||
initialDelaySeconds: {{ .Values.gitHook.livenessProbe.initialDelaySeconds }}
|
||||
periodSeconds: {{ .Values.gitHook.livenessProbe.periodSeconds }}
|
||||
timeoutSeconds: {{ .Values.gitHook.livenessProbe.timeoutSeconds }}
|
||||
failureThreshold: {{ .Values.gitHook.livenessProbe.failureThreshold }}
|
||||
{{- end }}
|
||||
{{- if .Values.gitHook.readinessProbe }}
|
||||
readinessProbe:
|
||||
exec:
|
||||
command:
|
||||
{{- range .Values.gitHook.readinessProbe.exec.command }}
|
||||
- {{ . | quote }}
|
||||
{{- end }}
|
||||
initialDelaySeconds: {{ .Values.gitHook.readinessProbe.initialDelaySeconds }}
|
||||
periodSeconds: {{ .Values.gitHook.readinessProbe.periodSeconds }}
|
||||
timeoutSeconds: {{ .Values.gitHook.readinessProbe.timeoutSeconds }}
|
||||
failureThreshold: {{ .Values.gitHook.readinessProbe.failureThreshold }}
|
||||
{{- end }}
|
||||
{{- with .Values.gitHook.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
@ -61,4 +91,10 @@ spec:
|
||||
tolerations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- if .Values.storage.enabled }}
|
||||
volumes:
|
||||
- name: shared-data
|
||||
persistentVolumeClaim:
|
||||
claimName: {{ include "gitdata.fullname" . }}-shared-data
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
@ -1,29 +1,9 @@
|
||||
{{- if .Values.gitserver.enabled -}}
|
||||
{{- $fullName := include "c-----code.fullname" . -}}
|
||||
{{- $ns := include "c-----code.namespace" . -}}
|
||||
{{- $fullName := include "gitdata.fullname" . -}}
|
||||
{{- $ns := include "gitdata.namespace" . -}}
|
||||
{{- $svc := .Values.gitserver -}}
|
||||
|
||||
{{/* PersistentVolumeClaim for git repositories */}}
|
||||
{{- if $svc.persistence.enabled }}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: {{ $fullName }}-repos
|
||||
namespace: {{ $ns }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ $fullName }}-gitserver
|
||||
app.kubernetes.io/instance: {{ $.Release.Name }}
|
||||
spec:
|
||||
accessModes:
|
||||
- {{ $svc.persistence.accessMode | default "ReadWriteOnce" }}
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ $svc.persistence.size }}
|
||||
{{- if $svc.persistence.storageClass }}
|
||||
storageClassName: {{ $svc.persistence.storageClass }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{/* Uses shared PVC defined in storage.yaml */}}
|
||||
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
@ -56,47 +36,70 @@ spec:
|
||||
containerPort: {{ $svc.service.http.port }}
|
||||
protocol: TCP
|
||||
- name: ssh
|
||||
containerPort: {{ $svc.ssh.port }}
|
||||
containerPort: {{ $svc.service.ssh.port }}
|
||||
protocol: TCP
|
||||
env:
|
||||
- name: APP_REPOS_ROOT
|
||||
value: /data/repos
|
||||
- name: APP_DATABASE_URL
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ $.Values.database.existingSecret | default (printf "%s-secrets" $fullName) }}
|
||||
key: {{ $.Values.database.secretKeys.url }}
|
||||
configMapKeyRef:
|
||||
name: {{ $fullName }}-config
|
||||
key: APP_DATABASE_URL
|
||||
optional: true
|
||||
- name: APP_REDIS_URL
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ $.Values.redis.existingSecret | default (printf "%s-secrets" $fullName) }}
|
||||
key: {{ $.Values.redis.secretKeys.url }}
|
||||
configMapKeyRef:
|
||||
name: {{ $fullName }}-config
|
||||
key: APP_REDIS_URL
|
||||
optional: true
|
||||
{{- if $svc.ssh.domain }}
|
||||
- name: APP_SSH_DOMAIN
|
||||
value: {{ $svc.ssh.domain }}
|
||||
{{- end }}
|
||||
{{- if $svc.ssh.port }}
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: {{ $fullName }}-config
|
||||
key: APP_SSH_DOMAIN
|
||||
optional: true
|
||||
- name: APP_SSH_PORT
|
||||
value: {{ $svc.ssh.port | quote }}
|
||||
{{- end }}
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: {{ $fullName }}-config
|
||||
key: APP_SSH_PORT
|
||||
optional: true
|
||||
{{- range $svc.env }}
|
||||
- name: {{ .name }}
|
||||
value: {{ .value | quote }}
|
||||
{{- end }}
|
||||
resources:
|
||||
{{- toYaml $svc.resources | nindent 10 }}
|
||||
{{- if $svc.livenessProbe }}
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
port: {{ $svc.livenessProbe.tcpSocket.port }}
|
||||
initialDelaySeconds: {{ $svc.livenessProbe.initialDelaySeconds }}
|
||||
periodSeconds: {{ $svc.livenessProbe.periodSeconds }}
|
||||
timeoutSeconds: {{ $svc.livenessProbe.timeoutSeconds }}
|
||||
failureThreshold: {{ $svc.livenessProbe.failureThreshold }}
|
||||
{{- end }}
|
||||
{{- if $svc.readinessProbe }}
|
||||
readinessProbe:
|
||||
tcpSocket:
|
||||
port: {{ $svc.readinessProbe.tcpSocket.port }}
|
||||
initialDelaySeconds: {{ $svc.readinessProbe.initialDelaySeconds }}
|
||||
periodSeconds: {{ $svc.readinessProbe.periodSeconds }}
|
||||
timeoutSeconds: {{ $svc.readinessProbe.timeoutSeconds }}
|
||||
failureThreshold: {{ $svc.readinessProbe.failureThreshold }}
|
||||
{{- end }}
|
||||
volumeMounts:
|
||||
{{- if $svc.persistence.enabled }}
|
||||
- name: repos
|
||||
{{- if and $svc.persistence.enabled $.Values.storage.enabled }}
|
||||
- name: shared-data
|
||||
mountPath: /data/repos
|
||||
subPath: repos/
|
||||
{{- end }}
|
||||
volumes:
|
||||
{{- if $svc.persistence.enabled }}
|
||||
- name: repos
|
||||
{{- if and $svc.persistence.enabled $.Values.storage.enabled }}
|
||||
- name: shared-data
|
||||
persistentVolumeClaim:
|
||||
claimName: {{ $fullName }}-repos
|
||||
claimName: {{ $fullName }}-shared-data
|
||||
{{- end }}
|
||||
{{- with $svc.nodeSelector }}
|
||||
nodeSelector:
|
||||
@ -142,19 +145,40 @@ metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ $fullName }}-gitserver
|
||||
app.kubernetes.io/instance: {{ $.Release.Name }}
|
||||
{{- if $svc.service.ssh.loadBalancerSourceRanges }}
|
||||
annotations:
|
||||
metallb.universe.tf/loadBalancerIPs: {{ $svc.service.ssh.loadBalancerIP | default "" }}
|
||||
{{- end }}
|
||||
spec:
|
||||
type: {{ $svc.service.ssh.type }}
|
||||
{{- if eq $svc.service.ssh.type "NodePort" }}
|
||||
{{- if eq $svc.service.ssh.type "LoadBalancer" }}
|
||||
ports:
|
||||
- name: ssh
|
||||
port: {{ $svc.ssh.port }}
|
||||
port: {{ $svc.service.ssh.port }}
|
||||
targetPort: ssh
|
||||
nodePort: {{ $svc.service.ssh.nodePort }}
|
||||
protocol: TCP
|
||||
{{- if $svc.service.ssh.loadBalancerIP }}
|
||||
loadBalancerIP: {{ $svc.service.ssh.loadBalancerIP }}
|
||||
{{- end }}
|
||||
{{- if $svc.service.ssh.loadBalancerSourceRanges }}
|
||||
loadBalancerSourceRanges:
|
||||
{{- range $svc.service.ssh.loadBalancerSourceRanges }}
|
||||
- {{ . }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- else if eq $svc.service.ssh.type "NodePort" }}
|
||||
ports:
|
||||
- name: ssh
|
||||
port: {{ $svc.service.ssh.port }}
|
||||
targetPort: ssh
|
||||
nodePort: {{ $svc.service.ssh.nodePort | default 30222 }}
|
||||
protocol: TCP
|
||||
{{- else }}
|
||||
ports:
|
||||
- name: ssh
|
||||
port: {{ $svc.ssh.port }}
|
||||
port: {{ $svc.service.ssh.port }}
|
||||
targetPort: ssh
|
||||
protocol: TCP
|
||||
{{- end }}
|
||||
selector:
|
||||
app.kubernetes.io/name: {{ $fullName }}-gitserver
|
||||
|
||||
61
deploy/templates/gitserver-ingress.yaml
Normal file
61
deploy/templates/gitserver-ingress.yaml
Normal file
@ -0,0 +1,61 @@
|
||||
{{- if .Values.gitserver.ingress.enabled -}}
|
||||
{{- $fullName := include "gitdata.fullname" . -}}
|
||||
{{- $ns := include "gitdata.namespace" . -}}
|
||||
{{- $ing := .Values.gitserver.ingress -}}
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: {{ $fullName }}-gitserver-http
|
||||
namespace: {{ $ns }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ $fullName }}-gitserver
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: {{ $ing.clusterIssuer | default "cloudflare-acme-cluster-issuer" }}
|
||||
{{- if $ing.annotations }}
|
||||
{{ toYaml $ing.annotations | indent 4 }}
|
||||
{{- end }}
|
||||
{{- if not (hasKey ($ing.annotations | default dict) "nginx.ingress.kubernetes.io/proxy-body-size") }}
|
||||
{{- if or (not $ing.className) (eq $ing.className "nginx") (contains "nginx" $ing.className) }}
|
||||
nginx.ingress.kubernetes.io/proxy-body-size: "0"
|
||||
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
|
||||
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- if $ing.className }}
|
||||
ingressClassName: {{ $ing.className }}
|
||||
{{- end }}
|
||||
{{- if $ing.tls }}
|
||||
tls:
|
||||
{{- range $ing.tls }}
|
||||
- hosts:
|
||||
{{- range .hosts }}
|
||||
- {{ . | quote }}
|
||||
{{- end }}
|
||||
secretName: {{ .secretName }}
|
||||
{{- end }}
|
||||
{{- else }}
|
||||
tls:
|
||||
{{- range $ing.hosts }}
|
||||
- hosts:
|
||||
- {{ .host | quote }}
|
||||
secretName: {{ $fullName }}-gitserver-tls
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
rules:
|
||||
{{- range $ing.hosts }}
|
||||
- host: {{ .host | quote }}
|
||||
http:
|
||||
paths:
|
||||
{{- range .paths }}
|
||||
- path: {{ .path }}
|
||||
pathType: {{ .pathType | default "Prefix" }}
|
||||
backend:
|
||||
service:
|
||||
name: {{ $fullName }}-gitserver-http
|
||||
port:
|
||||
number: {{ $.Values.gitserver.service.http.port }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@ -1,46 +1,61 @@
|
||||
{{- if .Values.app.ingress.enabled -}}
|
||||
{{- $svcName := printf "%s-app" (include "c-----code.fullname" .) -}}
|
||||
{{- $ns := include "c-----code.namespace" . -}}
|
||||
{{- $svcName := printf "%s-app" (include "gitdata.fullname" .) -}}
|
||||
{{- $ns := include "gitdata.namespace" . -}}
|
||||
{{- $ing := .Values.app.ingress -}}
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: {{ include "c-----code.fullname" . }}-ingress
|
||||
name: {{ include "gitdata.fullname" . }}-ingress
|
||||
namespace: {{ $ns }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ include "c-----code.fullname" . }}-app
|
||||
app.kubernetes.io/name: {{ include "gitdata.fullname" . }}-app
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
{{- with $ing.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- if $ing.className }}
|
||||
ingressClassName: {{ $ing.className }}
|
||||
{{- end }}
|
||||
{{- if $ing.tls }}
|
||||
tls:
|
||||
{{- range $ing.tls }}
|
||||
- hosts:
|
||||
{{- range .hosts }}
|
||||
- {{ . | quote }}
|
||||
{{- end }}
|
||||
secretName: {{ .secretName }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
rules:
|
||||
{{- range $ing.hosts }}
|
||||
- host: {{ .host | quote }}
|
||||
http:
|
||||
paths:
|
||||
{{- range .paths }}
|
||||
- path: {{ .path }}
|
||||
pathType: {{ .pathType | default "Prefix" }}
|
||||
backend:
|
||||
service:
|
||||
name: {{ $svcName }}
|
||||
port:
|
||||
number: {{ $.Values.app.service.port }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
cert-manager.io/cluster-issuer: {{ $ing.clusterIssuer | default "cloudflare-acme-cluster-issuer" }}
|
||||
{{- if $ing.annotations }}
|
||||
{{ toYaml $ing.annotations | indent 4 }}
|
||||
{{- end }}
|
||||
{{- if not (hasKey ($ing.annotations | default dict) "nginx.ingress.kubernetes.io/proxy-body-size") }}
|
||||
{{- if or (not $ing.className) (eq $ing.className "nginx") (contains "nginx" $ing.className) }}
|
||||
nginx.ingress.kubernetes.io/proxy-body-size: "0"
|
||||
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
|
||||
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- if $ing.className }}
|
||||
ingressClassName: {{ $ing.className }}
|
||||
{{- end }}
|
||||
{{- if $ing.tls }}
|
||||
tls:
|
||||
{{- range $ing.tls }}
|
||||
- hosts:
|
||||
{{- range .hosts }}
|
||||
- {{ . | quote }}
|
||||
{{- end }}
|
||||
secretName: {{ .secretName }}
|
||||
{{- end }}
|
||||
{{- else }}
|
||||
tls:
|
||||
{{- range $ing.hosts }}
|
||||
- hosts:
|
||||
- {{ .host | quote }}
|
||||
secretName: {{ include "gitdata.fullname" $ }}-app-tls
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
rules:
|
||||
{{- range $ing.hosts }}
|
||||
- host: {{ .host | quote }}
|
||||
http:
|
||||
paths:
|
||||
{{- range .paths }}
|
||||
- path: {{ .path }}
|
||||
pathType: {{ .pathType | default "Prefix" }}
|
||||
backend:
|
||||
service:
|
||||
name: {{ $svcName }}
|
||||
port:
|
||||
number: {{ $.Values.app.service.port }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
@ -2,10 +2,10 @@
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: {{ include "c-----code.fullname" . }}-migrate
|
||||
namespace: {{ include "c-----code.namespace" . }}
|
||||
name: {{ include "gitdata.fullname" . }}-migrate
|
||||
namespace: {{ include "gitdata.namespace" . }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ include "c-----code.fullname" . }}-migrate
|
||||
app.kubernetes.io/name: {{ include "gitdata.fullname" . }}-migrate
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion }}
|
||||
helm.sh/hook: post-install,post-upgrade
|
||||
@ -15,7 +15,7 @@ spec:
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ include "c-----code.fullname" . }}-migrate
|
||||
app.kubernetes.io/name: {{ include "gitdata.fullname" . }}-migrate
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
spec:
|
||||
restartPolicy: OnFailure
|
||||
@ -32,9 +32,9 @@ spec:
|
||||
env:
|
||||
- name: APP_DATABASE_URL
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.database.existingSecret | default (printf "%s-secrets" (include "c-----code.fullname" .)) }}
|
||||
key: {{ .Values.database.secretKeys.url }}
|
||||
configMapKeyRef:
|
||||
name: {{ include "gitdata.fullname" . }}-config
|
||||
key: APP_DATABASE_URL
|
||||
{{- range .Values.migrate.env }}
|
||||
- name: {{ .name }}
|
||||
value: {{ .value | quote }}
|
||||
|
||||
10
deploy/templates/namespace.yaml
Normal file
10
deploy/templates/namespace.yaml
Normal file
@ -0,0 +1,10 @@
|
||||
{{- /* Unified namespace declaration */ -}}
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: {{ include "gitdata.namespace" . }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ include "gitdata.fullname" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
annotations:
|
||||
helm.sh/resource-policy: keep
|
||||
@ -2,31 +2,53 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ include "c-----code.fullname" . }}-operator
|
||||
namespace: {{ include "c-----code.namespace" . }}
|
||||
name: {{ include "gitdata.fullname" . }}-operator
|
||||
namespace: {{ include "gitdata.namespace" . }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ include "c-----code.fullname" . }}-operator
|
||||
app.kubernetes.io/name: {{ include "gitdata.fullname" . }}-operator
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion }}
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: {{ include "c-----code.fullname" . }}-operator
|
||||
app.kubernetes.io/name: {{ include "gitdata.fullname" . }}-operator
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ include "c-----code.fullname" . }}-operator
|
||||
app.kubernetes.io/name: {{ include "gitdata.fullname" . }}-operator
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
spec:
|
||||
serviceAccountName: {{ include "c-----code.fullname" . }}-operator
|
||||
serviceAccountName: {{ include "gitdata.fullname" . }}-operator
|
||||
terminationGracePeriodSeconds: 10
|
||||
volumes:
|
||||
- name: tmp
|
||||
emptyDir: {}
|
||||
containers:
|
||||
- name: operator
|
||||
image: "{{ .Values.image.registry }}/{{ .Values.operator.image.repository }}:{{ .Values.operator.image.tag }}"
|
||||
imagePullPolicy: {{ .Values.operator.image.pullPolicy | default .Values.image.pullPolicy }}
|
||||
env:
|
||||
- name: OPERATOR_IMAGE_PREFIX
|
||||
value: {{ .Values.operator.imagePrefix | default (printf "%s/" (include "gitdata.fullname" .)) | quote }}
|
||||
- name: OPERATOR_LOG_LEVEL
|
||||
value: {{ .Values.operator.logLevel | default "info" | quote }}
|
||||
- name: POD_NAMESPACE
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.namespace
|
||||
resources:
|
||||
{{- toYaml .Values.operator.resources | nindent 10 }}
|
||||
volumeMounts:
|
||||
- name: tmp
|
||||
mountPath: /tmp
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
readOnlyRootFilesystem: true
|
||||
capabilities:
|
||||
drop:
|
||||
- ALL
|
||||
{{- with .Values.operator.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
@ -44,9 +66,51 @@ spec:
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: {{ include "c-----code.fullname" . }}-operator
|
||||
namespace: {{ include "c-----code.namespace" . }}
|
||||
name: {{ include "gitdata.fullname" . }}-operator
|
||||
namespace: {{ include "gitdata.namespace" . }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ include "c-----code.fullname" . }}-operator
|
||||
app.kubernetes.io/name: {{ include "gitdata.fullname" . }}-operator
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: {{ include "gitdata.fullname" . }}-operator
|
||||
namespace: {{ include "gitdata.namespace" . }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ include "gitdata.fullname" . }}-operator
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
rules:
|
||||
- apiGroups: ["code.dev"]
|
||||
resources: ["apps", "gitservers", "emailworkers", "githooks", "migrates"]
|
||||
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
|
||||
- apiGroups: ["code.dev"]
|
||||
resources: ["apps/status", "gitservers/status", "emailworkers/status", "githooks/status", "migrates/status"]
|
||||
verbs: ["get", "patch", "update"]
|
||||
- apiGroups: ["apps"]
|
||||
resources: ["deployments"]
|
||||
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
|
||||
- apiGroups: [""]
|
||||
resources: ["services", "persistentvolumeclaims", "configmaps", "secrets"]
|
||||
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
|
||||
- apiGroups: ["batch"]
|
||||
resources: ["jobs"]
|
||||
verbs: ["get", "list", "watch", "create", "update", "patch", "delete", "deletecollection"]
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: {{ include "gitdata.fullname" . }}-operator
|
||||
namespace: {{ include "gitdata.namespace" . }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ include "gitdata.fullname" . }}-operator
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: {{ include "gitdata.fullname" . }}-operator
|
||||
namespace: {{ include "gitdata.namespace" . }}
|
||||
roleRef:
|
||||
kind: Role
|
||||
name: {{ include "gitdata.fullname" . }}-operator
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
{{- end }}
|
||||
|
||||
48
deploy/templates/pdb.yaml
Normal file
48
deploy/templates/pdb.yaml
Normal file
@ -0,0 +1,48 @@
|
||||
{{- /* PodDisruptionBudgets for high-availability services */ -}}
|
||||
|
||||
{{- if and .Values.app.enabled .Values.app.pdb.enabled -}}
|
||||
apiVersion: policy/v1
|
||||
kind: PodDisruptionBudget
|
||||
metadata:
|
||||
name: {{ include "gitdata.fullname" . }}-app
|
||||
namespace: {{ include "gitdata.namespace" . }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ include "gitdata.fullname" . }}-app
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
spec:
|
||||
{{- if .Values.app.pdb.minAvailable }}
|
||||
minAvailable: {{ .Values.app.pdb.minAvailable }}
|
||||
{{- else if .Values.app.pdb.maxUnavailable }}
|
||||
maxUnavailable: {{ .Values.app.pdb.maxUnavailable }}
|
||||
{{- else }}
|
||||
minAvailable: 1
|
||||
{{- end }}
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: {{ include "gitdata.fullname" . }}-app
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
{{- end }}
|
||||
|
||||
{{- if and .Values.gitHook.enabled .Values.gitHook.pdb.enabled -}}
|
||||
---
|
||||
apiVersion: policy/v1
|
||||
kind: PodDisruptionBudget
|
||||
metadata:
|
||||
name: {{ include "gitdata.fullname" . }}-git-hook
|
||||
namespace: {{ include "gitdata.namespace" . }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ include "gitdata.fullname" . }}-git-hook
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
spec:
|
||||
{{- if .Values.gitHook.pdb.minAvailable }}
|
||||
minAvailable: {{ .Values.gitHook.pdb.minAvailable }}
|
||||
{{- else if .Values.gitHook.pdb.maxUnavailable }}
|
||||
maxUnavailable: {{ .Values.gitHook.pdb.maxUnavailable }}
|
||||
{{- else }}
|
||||
minAvailable: 1
|
||||
{{- end }}
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: {{ include "gitdata.fullname" . }}-git-hook
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
{{- end }}
|
||||
@ -1,17 +1,63 @@
|
||||
{{- /* Template for bootstrap secrets – replace with external secret manager in prod */ -}}
|
||||
{{- if .Values.secrets }}
|
||||
{{- /*
|
||||
Bootstrap secrets for development only.
|
||||
In production, use an external secret manager (Vault, SealedSecrets, External Secrets).
|
||||
*/ -}}
|
||||
|
||||
{{- /*
|
||||
Bootstrap secrets for development only.
|
||||
In production, use an external secret manager (Vault, SealedSecrets, External Secrets).
|
||||
*/ -}}
|
||||
|
||||
{{- $secrets := .Values.secrets | default dict -}}
|
||||
{{- if $secrets.create -}}
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: {{ include "c-----code.fullname" . }}-secrets
|
||||
namespace: {{ include "c-----code.namespace" . }}
|
||||
name: {{ include "gitdata.fullname" . }}-secrets
|
||||
namespace: {{ include "gitdata.namespace" . }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ .Chart.Name }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion }}
|
||||
annotations:
|
||||
"helm.sh/resource-policy": keep
|
||||
type: Opaque
|
||||
stringData:
|
||||
{{- range $key, $value := .Values.secrets }}
|
||||
{{- if $secrets.databaseUrl }}
|
||||
APP_DATABASE_URL: {{ $secrets.databaseUrl | quote }}
|
||||
{{- end }}
|
||||
{{- if $secrets.redisUrl }}
|
||||
APP_REDIS_URL: {{ $secrets.redisUrl | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.nats.enabled }}
|
||||
NATS_URL: {{ .Values.nats.url | quote }}
|
||||
{{- end }}
|
||||
{{- if $secrets.aiApiKey }}
|
||||
APP_AI_BASIC_URL: {{ $secrets.aiBasicUrl | quote }}
|
||||
APP_AI_API_KEY: {{ $secrets.aiApiKey | quote }}
|
||||
{{- end }}
|
||||
{{- if $secrets.embedApiKey }}
|
||||
APP_EMBED_MODEL_BASE_URL: {{ $secrets.embedBasicUrl | quote }}
|
||||
APP_EMBED_MODEL_API_KEY: {{ $secrets.embedApiKey | quote }}
|
||||
APP_EMBED_MODEL_NAME: {{ $secrets.embedModelName | quote }}
|
||||
{{- end }}
|
||||
{{- if and .Values.qdrant.enabled .Values.qdrant.url }}
|
||||
APP_QDRANT_URL: {{ .Values.qdrant.url | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.qdrant.apiKey }}
|
||||
APP_QDRANT_API_KEY: {{ .Values.qdrant.apiKey | quote }}
|
||||
{{- end }}
|
||||
{{- if $secrets.smtpHost }}
|
||||
APP_SMTP_HOST: {{ $secrets.smtpHost | quote }}
|
||||
APP_SMTP_PORT: {{ $secrets.smtpPort | default "587" | quote }}
|
||||
APP_SMTP_USERNAME: {{ $secrets.smtpUsername | quote }}
|
||||
APP_SMTP_PASSWORD: {{ $secrets.smtpPassword | quote }}
|
||||
APP_SMTP_FROM: {{ $secrets.smtpFrom | default $secrets.smtpUsername | quote }}
|
||||
APP_SMTP_TLS: {{ $secrets.smtpTls | default "true" | quote }}
|
||||
{{- end }}
|
||||
{{- if $secrets.sshDomain }}
|
||||
APP_SSH_DOMAIN: {{ $secrets.sshDomain | quote }}
|
||||
{{- end }}
|
||||
{{- range $key, $value := $secrets.extra | default dict }}
|
||||
{{ $key }}: {{ $value | quote }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
112
deploy/templates/static-deployment.yaml
Normal file
112
deploy/templates/static-deployment.yaml
Normal file
@ -0,0 +1,112 @@
|
||||
{{- if .Values.static.enabled -}}
|
||||
{{- $fullName := include "gitdata.fullname" . -}}
|
||||
{{- $ns := include "gitdata.namespace" . -}}
|
||||
{{- $svc := .Values.static -}}
|
||||
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ $fullName }}-static
|
||||
namespace: {{ $ns }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ $fullName }}-static
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion }}
|
||||
spec:
|
||||
replicas: {{ $svc.replicaCount }}
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: {{ $fullName }}-static
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ $fullName }}-static
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
spec:
|
||||
containers:
|
||||
- name: static
|
||||
image: "{{ $.Values.image.registry }}/{{ $svc.image.repository }}:{{ $svc.image.tag }}"
|
||||
imagePullPolicy: {{ $svc.image.pullPolicy | default $.Values.image.pullPolicy }}
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: {{ $svc.service.port }}
|
||||
protocol: TCP
|
||||
env:
|
||||
- name: STATIC_ROOT
|
||||
value: /data
|
||||
- name: STATIC_BIND
|
||||
value: {{ printf "0.0.0.0:%s" (print $svc.service.port) }}
|
||||
- name: STATIC_CORS
|
||||
value: {{ $svc.cors | default "true" | quote }}
|
||||
{{- if $svc.logLevel }}
|
||||
- name: STATIC_LOG_LEVEL
|
||||
value: {{ $svc.logLevel }}
|
||||
{{- end }}
|
||||
{{- range $svc.env }}
|
||||
- name: {{ .name }}
|
||||
value: {{ .value | quote }}
|
||||
{{- end }}
|
||||
resources:
|
||||
{{- toYaml $svc.resources | nindent 10 }}
|
||||
{{- if $svc.livenessProbe }}
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: {{ $svc.service.port }}
|
||||
initialDelaySeconds: {{ $svc.livenessProbe.initialDelaySeconds }}
|
||||
periodSeconds: {{ $svc.livenessProbe.periodSeconds }}
|
||||
timeoutSeconds: {{ $svc.livenessProbe.timeoutSeconds }}
|
||||
failureThreshold: {{ $svc.livenessProbe.failureThreshold }}
|
||||
{{- end }}
|
||||
{{- if $svc.readinessProbe }}
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: {{ $svc.service.port }}
|
||||
initialDelaySeconds: {{ $svc.readinessProbe.initialDelaySeconds }}
|
||||
periodSeconds: {{ $svc.readinessProbe.periodSeconds }}
|
||||
timeoutSeconds: {{ $svc.readinessProbe.timeoutSeconds }}
|
||||
failureThreshold: {{ $svc.readinessProbe.failureThreshold }}
|
||||
{{- end }}
|
||||
volumeMounts:
|
||||
- name: shared-data
|
||||
mountPath: /data
|
||||
volumes:
|
||||
- name: shared-data
|
||||
persistentVolumeClaim:
|
||||
claimName: {{ $fullName }}-shared-data
|
||||
{{- with $svc.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with $svc.affinity }}
|
||||
affinity:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with $svc.tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ $fullName }}-static
|
||||
namespace: {{ $ns }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ $fullName }}-static
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
spec:
|
||||
type: {{ $svc.service.type }}
|
||||
ports:
|
||||
- name: http
|
||||
port: {{ $svc.service.port }}
|
||||
targetPort: http
|
||||
protocol: TCP
|
||||
selector:
|
||||
app.kubernetes.io/name: {{ $fullName }}-static
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
{{- end }}
|
||||
61
deploy/templates/static-ingress.yaml
Normal file
61
deploy/templates/static-ingress.yaml
Normal file
@ -0,0 +1,61 @@
|
||||
{{- if .Values.static.ingress.enabled -}}
|
||||
{{- $fullName := include "gitdata.fullname" . -}}
|
||||
{{- $ns := include "gitdata.namespace" . -}}
|
||||
{{- $ing := .Values.static.ingress -}}
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: {{ $fullName }}-static
|
||||
namespace: {{ $ns }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ $fullName }}-static
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: {{ $ing.clusterIssuer | default "cloudflare-acme-cluster-issuer" }}
|
||||
{{- if $ing.annotations }}
|
||||
{{ toYaml $ing.annotations | indent 4 }}
|
||||
{{- end }}
|
||||
{{- if not (hasKey ($ing.annotations | default dict) "nginx.ingress.kubernetes.io/proxy-body-size") }}
|
||||
{{- if or (not $ing.className) (eq $ing.className "nginx") (contains "nginx" $ing.className) }}
|
||||
nginx.ingress.kubernetes.io/proxy-body-size: "0"
|
||||
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
|
||||
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- if $ing.className }}
|
||||
ingressClassName: {{ $ing.className }}
|
||||
{{- end }}
|
||||
{{- if $ing.tls }}
|
||||
tls:
|
||||
{{- range $ing.tls }}
|
||||
- hosts:
|
||||
{{- range .hosts }}
|
||||
- {{ . | quote }}
|
||||
{{- end }}
|
||||
secretName: {{ .secretName }}
|
||||
{{- end }}
|
||||
{{- else }}
|
||||
tls:
|
||||
{{- range $ing.hosts }}
|
||||
- hosts:
|
||||
- {{ .host | quote }}
|
||||
secretName: {{ $fullName }}-static-tls
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
rules:
|
||||
{{- range $ing.hosts }}
|
||||
- host: {{ .host | quote }}
|
||||
http:
|
||||
paths:
|
||||
{{- range .paths }}
|
||||
- path: {{ .path }}
|
||||
pathType: {{ .pathType | default "Prefix" }}
|
||||
backend:
|
||||
service:
|
||||
name: {{ $fullName }}-static
|
||||
port:
|
||||
number: {{ $.Values.static.service.port }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
18
deploy/templates/storage.yaml
Normal file
18
deploy/templates/storage.yaml
Normal file
@ -0,0 +1,18 @@
|
||||
{{- /* Global shared PVC for all components */ -}}
|
||||
{{- if .Values.storage.enabled -}}
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: {{ include "gitdata.fullname" . }}-shared-data
|
||||
namespace: {{ include "gitdata.namespace" . }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ include "gitdata.fullname" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
spec:
|
||||
accessModes:
|
||||
- {{ .Values.storage.accessMode | default "ReadWriteMany" }}
|
||||
storageClassName: {{ .Values.storage.storageClass }}
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .Values.storage.size }}
|
||||
{{- end }}
|
||||
@ -3,13 +3,13 @@
|
||||
|
||||
# PostgreSQL
|
||||
database:
|
||||
existingSecret: c-----code-secrets
|
||||
existingSecret: gitdata-secrets
|
||||
secretKeys:
|
||||
url: APP_DATABASE_URL
|
||||
|
||||
# Redis
|
||||
redis:
|
||||
existingSecret: c-----code-secrets
|
||||
existingSecret: gitdata-secrets
|
||||
secretKeys:
|
||||
url: APP_REDIS_URL
|
||||
|
||||
@ -31,12 +31,15 @@ app:
|
||||
hosts:
|
||||
- host: git.example.com
|
||||
|
||||
# Gitserver persistence
|
||||
# Gitserver
|
||||
gitserver:
|
||||
persistence:
|
||||
size: 100Gi
|
||||
storageClass: fast-ssd
|
||||
|
||||
# Act Runner
|
||||
actRunner:
|
||||
enabled: false
|
||||
ingress:
|
||||
enabled: true
|
||||
hosts:
|
||||
- host: git-http.example.com
|
||||
annotations:
|
||||
# Override default proxy-body-size if needed
|
||||
# nginx.ingress.kubernetes.io/proxy-body-size: "0" # 0 = unlimited
|
||||
|
||||
@ -1,16 +1,104 @@
|
||||
# =============================================================================
|
||||
# Global / common settings
|
||||
# =============================================================================
|
||||
namespace: c-----code
|
||||
releaseName: c-----code
|
||||
namespace: gitdataai
|
||||
releaseName: gitdata
|
||||
|
||||
image:
|
||||
registry: harbor.gitdata.me/gta_team
|
||||
pullPolicy: IfNotPresent
|
||||
|
||||
# PostgreSQL (required) – set connection string via secret or values
|
||||
# =============================================================================
|
||||
# Cert-Manager Configuration (集群已安装 cert-manager)
|
||||
# =============================================================================
|
||||
certManager:
|
||||
enabled: true
|
||||
clusterIssuerName: cloudflare-acme-cluster-issuer # 引用集群已有的 ClusterIssuer
|
||||
|
||||
# =============================================================================
|
||||
# External Secrets Configuration (需要集群安装 ESO)
|
||||
# =============================================================================
|
||||
externalSecrets:
|
||||
storeName: "vault-backend"
|
||||
storeKind: "SecretStore"
|
||||
databaseKey: "gitdata/database"
|
||||
redisKey: "gitdata/redis"
|
||||
qdrantKey: "gitdata/qdrant"
|
||||
|
||||
# =============================================================================
|
||||
# Shared persistent storage (aliyun-nfs)
|
||||
# =============================================================================
|
||||
storage:
|
||||
enabled: true
|
||||
storageClass: aliyun-nfs
|
||||
size: 20Ti
|
||||
accessMode: ReadWriteMany # NFS supports multiple readers/writers
|
||||
|
||||
# =============================================================================
|
||||
# Application config (non-sensitive, shared via ConfigMap)
|
||||
# =============================================================================
|
||||
config:
|
||||
# App info
|
||||
name: gitdata
|
||||
|
||||
# Domain configuration
|
||||
staticDomain: "https://static.gitdata.ai"
|
||||
mediaDomain: ""
|
||||
gitHttpDomain: "https://git.gitdata.ai"
|
||||
|
||||
# Storage paths
|
||||
avatarPath: /data/avatar
|
||||
reposRoot: /data/repos
|
||||
|
||||
# Logging
|
||||
logLevel: info
|
||||
logFormat: json
|
||||
logFileEnabled: "false"
|
||||
logFilePath: /var/log/gitdata/app.log
|
||||
logFileRotation: daily
|
||||
logFileMaxFiles: "7"
|
||||
logFileMaxSize: "100"
|
||||
|
||||
# OpenTelemetry
|
||||
otelEnabled: "false"
|
||||
otelEndpoint: ""
|
||||
otelServiceName: gitdata
|
||||
|
||||
# Database pool tuning
|
||||
databaseMaxConnections: "100"
|
||||
databaseMinConnections: "5"
|
||||
databaseIdleTimeout: "600"
|
||||
databaseMaxLifetime: "3600"
|
||||
databaseConnectionTimeout: "30"
|
||||
databaseSchemaSearchPath: public
|
||||
databaseHealthCheckInterval: "30"
|
||||
databaseRetryAttempts: "3"
|
||||
databaseRetryDelay: "1"
|
||||
|
||||
# Redis tuning
|
||||
redisPoolSize: "16"
|
||||
redisConnectTimeout: "5"
|
||||
redisAcquireTimeout: "1"
|
||||
|
||||
# Hook pool
|
||||
hookPoolMaxConcurrent: "100"
|
||||
hookPoolCpuThreshold: "80"
|
||||
hookPoolRedisListPrefix: "{hook}"
|
||||
hookPoolRedisLogChannel: hook:logs
|
||||
hookPoolRedisBlockTimeout: "5"
|
||||
hookPoolRedisMaxRetries: "3"
|
||||
|
||||
# SSH
|
||||
sshPort: "22"
|
||||
|
||||
# SMTP (non-sensitive defaults)
|
||||
smtpPort: "465"
|
||||
smtpTls: "true"
|
||||
smtpTimeout: "30"
|
||||
|
||||
# PostgreSQL (required)
|
||||
database:
|
||||
existingSecret: ""
|
||||
existingSecret: "" # 留空则使用默认名 {release-name}-secrets
|
||||
secretKeys:
|
||||
url: APP_DATABASE_URL
|
||||
|
||||
@ -20,19 +108,64 @@ redis:
|
||||
secretKeys:
|
||||
url: APP_REDIS_URL
|
||||
|
||||
# NATS (optional – required only if HOOK_POOL is enabled)
|
||||
# NATS (optional)
|
||||
nats:
|
||||
enabled: false
|
||||
url: nats://nats:4222
|
||||
enabled: true
|
||||
url: "nats://nats-client.nats.svc.cluster.local:4222"
|
||||
|
||||
# Qdrant (optional – required only if AI embeddings are used)
|
||||
# Qdrant (optional)
|
||||
qdrant:
|
||||
enabled: false
|
||||
url: http://qdrant:6333
|
||||
enabled: true
|
||||
url: "http://qdrant.qdrant.svc.cluster.local:6333"
|
||||
existingSecret: ""
|
||||
secretKeys:
|
||||
apiKey: APP_QDRANT_API_KEY
|
||||
|
||||
# =============================================================================
|
||||
# Frontend - React SPA
|
||||
# =============================================================================
|
||||
frontend:
|
||||
enabled: true
|
||||
replicaCount: 2
|
||||
|
||||
image:
|
||||
repository: frontend
|
||||
tag: latest
|
||||
|
||||
service:
|
||||
type: ClusterIP
|
||||
|
||||
ingress:
|
||||
enabled: true
|
||||
className: nginx
|
||||
annotations: {}
|
||||
hosts:
|
||||
- host: gitdata.ai
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
tls: []
|
||||
|
||||
resources:
|
||||
requests:
|
||||
cpu: 50m
|
||||
memory: 64Mi
|
||||
limits:
|
||||
cpu: 200m
|
||||
memory: 256Mi
|
||||
|
||||
livenessProbe:
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
|
||||
readinessProbe:
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 5
|
||||
|
||||
nodeSelector: {}
|
||||
tolerations: []
|
||||
affinity: {}
|
||||
|
||||
# =============================================================================
|
||||
# App – main web/API service
|
||||
# =============================================================================
|
||||
@ -44,19 +177,26 @@ app:
|
||||
repository: app
|
||||
tag: latest
|
||||
|
||||
# Pod disruption budget
|
||||
pdb:
|
||||
enabled: true
|
||||
minAvailable: 2 # Keep at least 2 pods available during disruptions
|
||||
|
||||
service:
|
||||
type: ClusterIP
|
||||
port: 8080
|
||||
|
||||
ingress:
|
||||
enabled: false
|
||||
className: cilium # Cilium Ingress (or envoy for EnvoyGateway)
|
||||
enabled: true
|
||||
className: nginx
|
||||
annotations: {}
|
||||
hosts:
|
||||
- host: c-----.local
|
||||
- host: gitdata.ai
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
- path: /api
|
||||
pathType: Prefix
|
||||
tls: []
|
||||
|
||||
resources:
|
||||
@ -79,13 +219,76 @@ app:
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 5
|
||||
|
||||
# Extra env vars (merge with auto-injected ones)
|
||||
startupProbe:
|
||||
path: /health
|
||||
port: 8080
|
||||
initialDelaySeconds: 0
|
||||
periodSeconds: 10
|
||||
failureThreshold: 30 # Allow up to 5 minutes for slow starts
|
||||
|
||||
env: []
|
||||
|
||||
nodeSelector: {}
|
||||
tolerations: []
|
||||
affinity: {}
|
||||
|
||||
# =============================================================================
|
||||
# Static server - avatar, blob, media files
|
||||
# =============================================================================
|
||||
static:
|
||||
enabled: true
|
||||
replicaCount: 2
|
||||
|
||||
image:
|
||||
repository: static
|
||||
tag: latest
|
||||
|
||||
service:
|
||||
type: ClusterIP
|
||||
port: 8081
|
||||
|
||||
ingress:
|
||||
enabled: true
|
||||
className: nginx
|
||||
annotations: {}
|
||||
hosts:
|
||||
- host: static.gitdata.ai
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
|
||||
cors: true
|
||||
logLevel: info
|
||||
|
||||
resources:
|
||||
requests:
|
||||
cpu: 50m
|
||||
memory: 64Mi
|
||||
limits:
|
||||
cpu: 200m
|
||||
memory: 256Mi
|
||||
|
||||
livenessProbe:
|
||||
path: /health
|
||||
port: 8081
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 3
|
||||
failureThreshold: 3
|
||||
|
||||
readinessProbe:
|
||||
path: /health
|
||||
port: 8081
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 5
|
||||
timeoutSeconds: 3
|
||||
failureThreshold: 3
|
||||
|
||||
env: []
|
||||
nodeSelector: {}
|
||||
tolerations: []
|
||||
affinity: {}
|
||||
|
||||
# =============================================================================
|
||||
# Gitserver – git daemon / SSH + HTTP server
|
||||
# =============================================================================
|
||||
@ -102,8 +305,11 @@ gitserver:
|
||||
type: ClusterIP
|
||||
port: 8022
|
||||
ssh:
|
||||
type: NodePort
|
||||
nodePort: 30222
|
||||
type: LoadBalancer
|
||||
port: 22
|
||||
domain: ""
|
||||
loadBalancerIP: ""
|
||||
loadBalancerSourceRanges: []
|
||||
|
||||
resources:
|
||||
requests:
|
||||
@ -113,16 +319,38 @@ gitserver:
|
||||
cpu: 500m
|
||||
memory: 512Mi
|
||||
|
||||
# Storage for git repos
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
port: 8022
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 15
|
||||
timeoutSeconds: 5
|
||||
failureThreshold: 3
|
||||
|
||||
readinessProbe:
|
||||
tcpSocket:
|
||||
port: 8022
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 3
|
||||
failureThreshold: 3
|
||||
|
||||
persistence:
|
||||
enabled: true
|
||||
storageClass: ""
|
||||
size: 50Gi
|
||||
accessMode: ReadWriteOnce
|
||||
|
||||
ssh:
|
||||
domain: ""
|
||||
port: 22
|
||||
ingress:
|
||||
enabled: true
|
||||
className: nginx
|
||||
annotations: {}
|
||||
hosts:
|
||||
- host: git.gitdata.ai
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
tls: []
|
||||
|
||||
env: []
|
||||
|
||||
@ -140,6 +368,28 @@ emailWorker:
|
||||
repository: email-worker
|
||||
tag: latest
|
||||
|
||||
livenessProbe:
|
||||
exec:
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- "pgrep email-worker || exit 1"
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 30
|
||||
timeoutSeconds: 5
|
||||
failureThreshold: 3
|
||||
|
||||
readinessProbe:
|
||||
exec:
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- "pgrep email-worker || exit 1"
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 15
|
||||
timeoutSeconds: 3
|
||||
failureThreshold: 3
|
||||
|
||||
resources:
|
||||
requests:
|
||||
cpu: 50m
|
||||
@ -166,6 +416,32 @@ gitHook:
|
||||
|
||||
replicaCount: 2
|
||||
|
||||
pdb:
|
||||
enabled: true
|
||||
minAvailable: 1
|
||||
|
||||
livenessProbe:
|
||||
exec:
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- "pgrep git-hook || exit 1"
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 15
|
||||
timeoutSeconds: 5
|
||||
failureThreshold: 3
|
||||
|
||||
readinessProbe:
|
||||
exec:
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- "pgrep git-hook || exit 1"
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 3
|
||||
failureThreshold: 3
|
||||
|
||||
resources:
|
||||
requests:
|
||||
cpu: 50m
|
||||
@ -196,15 +472,18 @@ migrate:
|
||||
env: []
|
||||
|
||||
# =============================================================================
|
||||
# Operator – Kubernetes operator (manages custom App/GitServer CRDs)
|
||||
# Operator – Kubernetes operator
|
||||
# =============================================================================
|
||||
operator:
|
||||
enabled: false # Enable only if running the custom operator
|
||||
enabled: false
|
||||
|
||||
image:
|
||||
repository: operator
|
||||
tag: latest
|
||||
|
||||
imagePrefix: ""
|
||||
logLevel: info
|
||||
|
||||
resources:
|
||||
requests:
|
||||
cpu: 50m
|
||||
@ -216,47 +495,3 @@ operator:
|
||||
nodeSelector: {}
|
||||
tolerations: []
|
||||
affinity: {}
|
||||
|
||||
# =============================================================================
|
||||
# Act Runner – Gitea Actions self-hosted runner
|
||||
# =============================================================================
|
||||
actRunner:
|
||||
enabled: false
|
||||
|
||||
image:
|
||||
repository: act-runner
|
||||
tag: latest
|
||||
|
||||
replicaCount: 2
|
||||
|
||||
# Concurrency per runner instance
|
||||
capacity: 2
|
||||
|
||||
# Runner labels (must match workflow `runs-on`)
|
||||
labels:
|
||||
- gitea
|
||||
- docker
|
||||
|
||||
logLevel: info
|
||||
|
||||
cache:
|
||||
enabled: true
|
||||
dir: /tmp/actions-cache
|
||||
|
||||
resources:
|
||||
requests:
|
||||
cpu: 500m
|
||||
memory: 1Gi
|
||||
limits:
|
||||
cpu: 2000m
|
||||
memory: 4Gi
|
||||
|
||||
env: []
|
||||
|
||||
nodeSelector: {}
|
||||
tolerations:
|
||||
- key: "runner"
|
||||
operator: "Equal"
|
||||
value: "true"
|
||||
effect: "NoSchedule"
|
||||
affinity: {}
|
||||
|
||||
50
docker/frontend.Dockerfile
Normal file
50
docker/frontend.Dockerfile
Normal file
@ -0,0 +1,50 @@
|
||||
# ---- Stage 1: Build ----
|
||||
FROM node:22-alpine AS builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Copy package files
|
||||
COPY package.json pnpm-lock.yaml ./
|
||||
RUN corepack enable && corepack prepare pnpm@10 --activate
|
||||
|
||||
# Install dependencies
|
||||
RUN pnpm install --frozen-lockfile
|
||||
|
||||
# Copy source
|
||||
COPY . .
|
||||
|
||||
# Build
|
||||
RUN pnpm build
|
||||
|
||||
# ---- Stage 2: Serve with nginx ----
|
||||
FROM nginx:alpine AS runtime
|
||||
|
||||
# Copy built assets
|
||||
COPY --from=builder /app/dist /usr/share/nginx/html
|
||||
|
||||
# nginx configuration for SPA
|
||||
RUN echo 'server { \
|
||||
listen 80; \
|
||||
server_name _; \
|
||||
root /usr/share/nginx/html; \
|
||||
index index.html; \
|
||||
location / { \
|
||||
try_files $uri $uri/ /index.html; \
|
||||
} \
|
||||
location /api/ { \
|
||||
proxy_pass http://app:8080/api/; \
|
||||
proxy_set_header Host $host; \
|
||||
proxy_set_header X-Real-IP $remote_addr; \
|
||||
} \
|
||||
location /ws/ { \
|
||||
proxy_pass http://app:8080/ws/; \
|
||||
proxy_http_version 1.1; \
|
||||
proxy_set_header Upgrade $http_upgrade; \
|
||||
proxy_set_header Connection "upgrade"; \
|
||||
proxy_set_header Host $host; \
|
||||
} \
|
||||
}' > /etc/nginx/conf.d/default.conf
|
||||
|
||||
EXPOSE 80
|
||||
|
||||
ENTRYPOINT ["nginx", "-g", "daemon off;"]
|
||||
41
docker/static.Dockerfile
Normal file
41
docker/static.Dockerfile
Normal file
@ -0,0 +1,41 @@
|
||||
# ---- Stage 1: Build ----
|
||||
FROM rust:1.94-bookworm AS builder
|
||||
|
||||
ARG BUILD_TARGET=x86_64-unknown-linux-gnu
|
||||
ENV TARGET=${BUILD_TARGET}
|
||||
|
||||
WORKDIR /build
|
||||
|
||||
# Copy workspace manifests
|
||||
COPY Cargo.toml Cargo.lock ./
|
||||
COPY libs/ libs/
|
||||
COPY apps/static/ apps/static/
|
||||
|
||||
# Pre-build dependencies only
|
||||
RUN cargo fetch
|
||||
|
||||
# Build the binary
|
||||
RUN --mount=type=cache,target=/usr/local/cargo/registry \
|
||||
--mount=type=cache,target=/usr/local/cargo/git \
|
||||
--mount=type=cache,target=target \
|
||||
cargo build --release --package static-server --target ${TARGET}
|
||||
|
||||
# ---- Stage 2: Runtime ----
|
||||
FROM debian:bookworm-slim AS runtime
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
ca-certificates \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
WORKDIR /app
|
||||
COPY --from=builder /build/target/${TARGET}/release/static-server /app/static-server
|
||||
|
||||
ENV RUST_LOG=info
|
||||
ENV STATIC_LOG_LEVEL=info
|
||||
ENV STATIC_BIND=0.0.0.0:8081
|
||||
ENV STATIC_ROOT=/data
|
||||
ENV STATIC_CORS=true
|
||||
|
||||
EXPOSE 8081
|
||||
|
||||
ENTRYPOINT ["/app/static-server"]
|
||||
@ -20,11 +20,11 @@ TARGET=aarch64-unknown-linux-gnu node scripts/build.js
|
||||
|
||||
**环境变量:**
|
||||
|
||||
| 变量 | 默认值 | 说明 |
|
||||
|------|--------|------|
|
||||
| `REGISTRY` | `harbor.gitdata.me/gta_team` | 镜像仓库 |
|
||||
| `TAG` | `latest` | 镜像标签 |
|
||||
| `TARGET` | `x86_64-unknown-linux-gnu` | Rust 交叉编译目标 |
|
||||
| 变量 | 默认值 | 说明 |
|
||||
|------------|------------------------------|-------------|
|
||||
| `REGISTRY` | `harbor.gitdata.me/gta_team` | 镜像仓库 |
|
||||
| `TAG` | `latest` | 镜像标签 |
|
||||
| `TARGET` | `x86_64-unknown-linux-gnu` | Rust 交叉编译目标 |
|
||||
|
||||
---
|
||||
|
||||
@ -40,12 +40,12 @@ HARBOR_USERNAME=user HARBOR_PASSWORD=pass TAG=sha-abc123 node scripts/push.js ap
|
||||
|
||||
**环境变量:**
|
||||
|
||||
| 变量 | 默认值 | 说明 |
|
||||
|------|--------|------|
|
||||
| `REGISTRY` | `harbor.gitdata.me/gta_team` | 镜像仓库 |
|
||||
| `TAG` | `latest` 或 Git SHA | 镜像标签 |
|
||||
| `HARBOR_USERNAME` | - | **必填** 仓库用户名 |
|
||||
| `HARBOR_PASSWORD` | - | **必填** 仓库密码 |
|
||||
| 变量 | 默认值 | 说明 |
|
||||
|-------------------|------------------------------|--------------|
|
||||
| `REGISTRY` | `harbor.gitdata.me/gta_team` | 镜像仓库 |
|
||||
| `TAG` | `latest` 或 Git SHA | 镜像标签 |
|
||||
| `HARBOR_USERNAME` | - | **必填** 仓库用户名 |
|
||||
| `HARBOR_PASSWORD` | - | **必填** 仓库密码 |
|
||||
|
||||
---
|
||||
|
||||
@ -70,13 +70,13 @@ 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 路径 |
|
||||
| 变量 | 默认值 | 说明 |
|
||||
|--------------|------------------------------|-----------------|
|
||||
| `REGISTRY` | `harbor.gitdata.me/gta_team` | 镜像仓库 |
|
||||
| `TAG` | `latest` 或 Git SHA | 镜像标签 |
|
||||
| `NAMESPACE` | `gitdata` | K8s 命名空间 |
|
||||
| `RELEASE` | `gitdata` | Helm Release 名称 |
|
||||
| `KUBECONFIG` | `~/.kube/config` | Kubeconfig 路径 |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@ -20,7 +20,7 @@ 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 SERVICES = ['app', 'gitserver', 'email-worker', 'git-hook', 'migrate', 'operator', 'static', 'frontend'];
|
||||
|
||||
const args = process.argv.slice(2);
|
||||
const targets = args.length > 0 ? args : SERVICES;
|
||||
|
||||
@ -10,19 +10,19 @@
|
||||
* 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)
|
||||
* NAMESPACE - Kubernetes namespace (default: gitdata)
|
||||
* RELEASE - Helm release name (default: gitdata)
|
||||
* KUBECONFIG - Path to kubeconfig (default: ~/.kube/config)
|
||||
*/
|
||||
|
||||
const { execSync } = require('child_process');
|
||||
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 NAMESPACE = process.env.NAMESPACE || 'gitdata';
|
||||
const RELEASE = process.env.RELEASE || 'gitdata';
|
||||
const CHART_PATH = path.join(__dirname, '..', 'deploy');
|
||||
const KUBECONFIG = process.env.KUBECONFIG || path.join(process.env.HOME || process.env.USERPROFILE, '.kube', 'config');
|
||||
|
||||
@ -34,9 +34,9 @@ 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.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 ===`);
|
||||
@ -53,32 +53,32 @@ 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}`,
|
||||
`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');
|
||||
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',
|
||||
'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');
|
||||
helmArgs.push('--dry-run');
|
||||
console.log('==> Dry run mode - no changes will be made\n');
|
||||
}
|
||||
|
||||
// Helm upgrade
|
||||
@ -86,29 +86,29 @@ 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`);
|
||||
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);
|
||||
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==> 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');
|
||||
|
||||
Loading…
Reference in New Issue
Block a user