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
|
||||||
.env.local
|
.env.local
|
||||||
dist
|
dist
|
||||||
|
deploy/secrets.yaml
|
||||||
.codex
|
.codex
|
||||||
.qwen
|
.qwen
|
||||||
.opencode
|
.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/gitserver/src" isTestSource="false" />
|
||||||
<sourceFolder url="file://$MODULE_DIR$/apps/operator/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$/libs/agent-tool-derive/src" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/apps/static/src" isTestSource="false" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||||
</content>
|
</content>
|
||||||
<orderEntry type="inheritedJdk" />
|
<orderEntry type="inheritedJdk" />
|
||||||
|
|||||||
170
Cargo.lock
generated
170
Cargo.lock
generated
@ -75,6 +75,29 @@ dependencies = [
|
|||||||
"smallvec",
|
"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]]
|
[[package]]
|
||||||
name = "actix-http"
|
name = "actix-http"
|
||||||
version = "3.12.0"
|
version = "3.12.0"
|
||||||
@ -2269,6 +2292,29 @@ dependencies = [
|
|||||||
"syn 2.0.117",
|
"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]]
|
[[package]]
|
||||||
name = "equator"
|
name = "equator"
|
||||||
version = "0.4.2"
|
version = "0.4.2"
|
||||||
@ -3239,6 +3285,12 @@ dependencies = [
|
|||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "http-range"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "21dec9db110f5f872ed9699c3ecf50cf16f423502706ba5c72462e28d3157573"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "httparse"
|
name = "httparse"
|
||||||
version = "1.10.1"
|
version = "1.10.1"
|
||||||
@ -3707,6 +3759,30 @@ version = "1.0.18"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
|
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]]
|
[[package]]
|
||||||
name = "jobserver"
|
name = "jobserver"
|
||||||
version = "0.1.34"
|
version = "0.1.34"
|
||||||
@ -4373,6 +4449,18 @@ dependencies = [
|
|||||||
"unicase",
|
"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]]
|
[[package]]
|
||||||
name = "minimal-lexical"
|
name = "minimal-lexical"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
@ -4997,6 +5085,50 @@ dependencies = [
|
|||||||
"serde",
|
"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]]
|
[[package]]
|
||||||
name = "pin-project"
|
name = "pin-project"
|
||||||
version = "1.1.11"
|
version = "1.1.11"
|
||||||
@ -5153,6 +5285,15 @@ version = "1.13.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49"
|
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]]
|
[[package]]
|
||||||
name = "potential_utf"
|
name = "potential_utf"
|
||||||
version = "0.1.4"
|
version = "0.1.4"
|
||||||
@ -6795,6 +6936,12 @@ version = "0.1.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e"
|
checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "siphasher"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "slab"
|
name = "slab"
|
||||||
version = "0.4.12"
|
version = "0.4.12"
|
||||||
@ -7144,6 +7291,23 @@ version = "1.2.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
|
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]]
|
[[package]]
|
||||||
name = "static_assertions"
|
name = "static_assertions"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
@ -7909,6 +8073,12 @@ dependencies = [
|
|||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "v_htmlescape"
|
||||||
|
version = "0.15.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4e8257fbc510f0a46eb602c10215901938b5c2a7d5e70fc11483b1d3c9b5b18c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "valuable"
|
name = "valuable"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
|
|||||||
@ -23,6 +23,7 @@ members = [
|
|||||||
"apps/gitserver",
|
"apps/gitserver",
|
||||||
"apps/email",
|
"apps/email",
|
||||||
"apps/operator",
|
"apps/operator",
|
||||||
|
"apps/static",
|
||||||
]
|
]
|
||||||
|
|
||||||
resolver = "3"
|
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
|
apiVersion: v2
|
||||||
name: c-----code
|
name: gitdata
|
||||||
description: Self-hosted GitHub + Slack alternative platform
|
description: Self-hosted GitHub + Slack alternative platform
|
||||||
type: application
|
type: application
|
||||||
version: 0.1.0
|
version: 0.1.0
|
||||||
@ -9,5 +9,6 @@ keywords:
|
|||||||
- collaboration
|
- collaboration
|
||||||
- self-hosted
|
- self-hosted
|
||||||
maintainers:
|
maintainers:
|
||||||
- name: C-----code Team
|
- name: gitdata Team
|
||||||
email: team@c.dev
|
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.
|
Or set .Values.secrets in values.yaml.
|
||||||
|
|
||||||
🔄 To run database migrations:
|
🔄 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
|
--set migrate.enabled=true
|
||||||
|
|
||||||
📖 Useful commands:
|
📖 Useful commands:
|
||||||
|
|||||||
@ -2,29 +2,29 @@
|
|||||||
Common helpers
|
Common helpers
|
||||||
============================================================================= */}}
|
============================================================================= */}}
|
||||||
|
|
||||||
{{- define "c-----code.fullname" -}}
|
{{- define "gitdata.fullname" -}}
|
||||||
{{- .Release.Name -}}
|
{{- .Release.Name -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{- define "c-----code.namespace" -}}
|
{{- define "gitdata.namespace" -}}
|
||||||
{{- .Values.namespace | default .Release.Namespace -}}
|
{{- .Values.namespace | default .Release.Namespace -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{- define "c-----code.image" -}}
|
{{- define "gitdata.image" -}}
|
||||||
{{- $registry := .Values.image.registry -}}
|
{{- $registry := .Values.image.registry -}}
|
||||||
{{- $pullPolicy := .Values.image.pullPolicy -}}
|
{{- $pullPolicy := .Values.image.pullPolicy -}}
|
||||||
{{- printf "%s/%s:%s" $registry .image.repository .image.tag -}}
|
{{- printf "%s/%s:%s" $registry .image.repository .image.tag -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{/* Inject image pull policy into sub-chart image dict */}}
|
{{/* Inject image pull policy into sub-chart image dict */}}
|
||||||
{{- define "c-----code.mergeImage" -}}
|
{{- define "gitdata.mergeImage" -}}
|
||||||
{{- $merged := dict "pullPolicy" $.Values.image.pullPolicy -}}
|
{{- $merged := dict "pullPolicy" $.Values.image.pullPolicy -}}
|
||||||
{{- $merged = merge $merged .image -}}
|
{{- $merged = merge $merged .image -}}
|
||||||
{{- printf "%s/%s:%s" $.Values.image.registry $merged.repository $merged.tag -}}
|
{{- printf "%s/%s:%s" $.Values.image.registry $merged.repository $merged.tag -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{/* Build a key-value env var list, optionally reading from a Secret */}}
|
{{/* Build a key-value env var list, optionally reading from a Secret */}}
|
||||||
{{- define "c-----code.envFromSecret" -}}
|
{{- define "gitdata.envFromSecret" -}}
|
||||||
{{- $secretName := .existingSecret -}}
|
{{- $secretName := .existingSecret -}}
|
||||||
{{- $keys := .secretKeys -}}
|
{{- $keys := .secretKeys -}}
|
||||||
{{- $result := list -}}
|
{{- $result := list -}}
|
||||||
@ -36,7 +36,7 @@
|
|||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{/* Merge two env lists (extra env over auto-injected) */}}
|
{{/* Merge two env lists (extra env over auto-injected) */}}
|
||||||
{{- define "c-----code.mergeEnv" -}}
|
{{- define "gitdata.mergeEnv" -}}
|
||||||
{{- $auto := .auto -}}
|
{{- $auto := .auto -}}
|
||||||
{{- $extra := .extra | default list -}}
|
{{- $extra := .extra | default list -}}
|
||||||
{{- $merged := append $auto $extra | toJson | fromJson -}}
|
{{- $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
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
name: {{ include "c-----code.fullname" . }}-app
|
name: {{ include "gitdata.fullname" . }}-app
|
||||||
namespace: {{ include "c-----code.namespace" . }}
|
namespace: {{ include "gitdata.namespace" . }}
|
||||||
labels:
|
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/instance: {{ .Release.Name }}
|
||||||
app.kubernetes.io/version: {{ .Chart.AppVersion }}
|
app.kubernetes.io/version: {{ .Chart.AppVersion }}
|
||||||
spec:
|
spec:
|
||||||
replicas: {{ .Values.app.replicaCount }}
|
replicas: {{ .Values.app.replicaCount }}
|
||||||
selector:
|
selector:
|
||||||
matchLabels:
|
matchLabels:
|
||||||
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/instance: {{ .Release.Name }}
|
||||||
template:
|
template:
|
||||||
metadata:
|
metadata:
|
||||||
labels:
|
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/instance: {{ .Release.Name }}
|
||||||
spec:
|
spec:
|
||||||
|
terminationGracePeriodSeconds: 30
|
||||||
containers:
|
containers:
|
||||||
- name: app
|
- name: app
|
||||||
image: "{{ .Values.image.registry }}/{{ .Values.app.image.repository }}:{{ .Values.app.image.tag }}"
|
image: "{{ .Values.image.registry }}/{{ .Values.app.image.repository }}:{{ .Values.app.image.tag }}"
|
||||||
@ -31,34 +32,52 @@ spec:
|
|||||||
env:
|
env:
|
||||||
- name: APP_DATABASE_URL
|
- name: APP_DATABASE_URL
|
||||||
valueFrom:
|
valueFrom:
|
||||||
secretKeyRef:
|
configMapKeyRef:
|
||||||
name: {{ .Values.database.existingSecret | default (printf "%s-secrets" (include "c-----code.fullname" .)) }}
|
name: {{ include "gitdata.fullname" . }}-config
|
||||||
key: {{ .Values.database.secretKeys.url }}
|
key: APP_DATABASE_URL
|
||||||
optional: true
|
optional: true
|
||||||
- name: APP_REDIS_URL
|
- name: APP_REDIS_URL
|
||||||
valueFrom:
|
valueFrom:
|
||||||
secretKeyRef:
|
configMapKeyRef:
|
||||||
name: {{ .Values.redis.existingSecret | default (printf "%s-secrets" (include "c-----code.fullname" .)) }}
|
name: {{ include "gitdata.fullname" . }}-config
|
||||||
key: {{ .Values.redis.secretKeys.url }}
|
key: APP_REDIS_URL
|
||||||
|
optional: true
|
||||||
|
- name: NATS_URL
|
||||||
|
valueFrom:
|
||||||
|
configMapKeyRef:
|
||||||
|
name: {{ include "gitdata.fullname" . }}-config
|
||||||
|
key: NATS_URL
|
||||||
optional: true
|
optional: true
|
||||||
{{- if .Values.nats.enabled }}
|
|
||||||
- name: HOOK_POOL_REDIS_LIST_PREFIX
|
- 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
|
- name: HOOK_POOL_REDIS_LOG_CHANNEL
|
||||||
value: "hook:logs"
|
valueFrom:
|
||||||
{{- end }}
|
configMapKeyRef:
|
||||||
{{- if .Values.qdrant.enabled }}
|
name: {{ include "gitdata.fullname" . }}-config
|
||||||
|
key: HOOK_POOL_REDIS_LOG_CHANNEL
|
||||||
|
optional: true
|
||||||
- name: APP_QDRANT_URL
|
- name: APP_QDRANT_URL
|
||||||
value: {{ .Values.qdrant.url }}
|
valueFrom:
|
||||||
{{- if and .Values.qdrant.existingSecret .Values.qdrant.secretKeys.apiKey }}
|
configMapKeyRef:
|
||||||
|
name: {{ include "gitdata.fullname" . }}-config
|
||||||
|
key: APP_QDRANT_URL
|
||||||
|
optional: true
|
||||||
- name: APP_QDRANT_API_KEY
|
- name: APP_QDRANT_API_KEY
|
||||||
valueFrom:
|
valueFrom:
|
||||||
secretKeyRef:
|
configMapKeyRef:
|
||||||
name: {{ .Values.qdrant.existingSecret }}
|
name: {{ include "gitdata.fullname" . }}-config
|
||||||
key: {{ .Values.qdrant.secretKeys.apiKey }}
|
key: APP_QDRANT_API_KEY
|
||||||
|
optional: true
|
||||||
|
- name: APP_AVATAR_PATH
|
||||||
|
valueFrom:
|
||||||
|
configMapKeyRef:
|
||||||
|
name: {{ include "gitdata.fullname" . }}-config
|
||||||
|
key: APP_AVATAR_PATH
|
||||||
optional: true
|
optional: true
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- range .Values.app.env }}
|
{{- range .Values.app.env }}
|
||||||
- name: {{ .name }}
|
- name: {{ .name }}
|
||||||
value: {{ .value | quote }}
|
value: {{ .value | quote }}
|
||||||
@ -75,8 +94,28 @@ spec:
|
|||||||
port: {{ .Values.app.readinessProbe.port }}
|
port: {{ .Values.app.readinessProbe.port }}
|
||||||
initialDelaySeconds: {{ .Values.app.readinessProbe.initialDelaySeconds }}
|
initialDelaySeconds: {{ .Values.app.readinessProbe.initialDelaySeconds }}
|
||||||
periodSeconds: {{ .Values.app.readinessProbe.periodSeconds }}
|
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:
|
resources:
|
||||||
{{- toYaml .Values.app.resources | nindent 10 }}
|
{{- 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 }}
|
{{- with .Values.app.nodeSelector }}
|
||||||
nodeSelector:
|
nodeSelector:
|
||||||
{{- toYaml . | nindent 8 }}
|
{{- toYaml . | nindent 8 }}
|
||||||
@ -93,10 +132,10 @@ spec:
|
|||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Service
|
kind: Service
|
||||||
metadata:
|
metadata:
|
||||||
name: {{ include "c-----code.fullname" . }}-app
|
name: {{ include "gitdata.fullname" . }}-app
|
||||||
namespace: {{ include "c-----code.namespace" . }}
|
namespace: {{ include "gitdata.namespace" . }}
|
||||||
labels:
|
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/instance: {{ .Release.Name }}
|
||||||
spec:
|
spec:
|
||||||
type: {{ .Values.app.service.type }}
|
type: {{ .Values.app.service.type }}
|
||||||
@ -106,6 +145,6 @@ spec:
|
|||||||
protocol: TCP
|
protocol: TCP
|
||||||
name: http
|
name: http
|
||||||
selector:
|
selector:
|
||||||
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/instance: {{ .Release.Name }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|||||||
@ -1,15 +1,51 @@
|
|||||||
|
{{- /* Application configuration - non-sensitive values */ -}}
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: ConfigMap
|
kind: ConfigMap
|
||||||
metadata:
|
metadata:
|
||||||
name: {{ include "c-----code.fullname" . }}-config
|
name: {{ include "gitdata.fullname" . }}-config
|
||||||
namespace: {{ include "c-----code.namespace" . }}
|
namespace: {{ include "gitdata.namespace" . }}
|
||||||
labels:
|
labels:
|
||||||
app.kubernetes.io/name: {{ .Chart.Name }}
|
app.kubernetes.io/name: {{ .Chart.Name }}
|
||||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||||
app.kubernetes.io/version: {{ .Chart.AppVersion }}
|
app.kubernetes.io/version: {{ .Chart.AppVersion }}
|
||||||
data:
|
data:
|
||||||
{{- if .Values.app.config }}
|
APP_NAME: {{ .Values.app.name | default "gitdata" | quote }}
|
||||||
{{- range $key, $value := .Values.app.config }}
|
APP_VERSION: {{ .Chart.AppVersion | quote }}
|
||||||
{{ $key }}: {{ $value | quote }}
|
APP_STATIC_DOMAIN: {{ .Values.config.staticDomain | default "" | quote }}
|
||||||
{{- end }}
|
APP_MEDIA_DOMAIN: {{ .Values.config.mediaDomain | default "" | quote }}
|
||||||
{{- end }}
|
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
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
name: {{ include "c-----code.fullname" . }}-email-worker
|
name: {{ include "gitdata.fullname" . }}-email-worker
|
||||||
namespace: {{ include "c-----code.namespace" . }}
|
namespace: {{ include "gitdata.namespace" . }}
|
||||||
labels:
|
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/instance: {{ .Release.Name }}
|
||||||
app.kubernetes.io/version: {{ .Chart.AppVersion }}
|
app.kubernetes.io/version: {{ .Chart.AppVersion }}
|
||||||
spec:
|
spec:
|
||||||
replicas: 1
|
replicas: 1
|
||||||
selector:
|
selector:
|
||||||
matchLabels:
|
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 }}
|
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||||
template:
|
template:
|
||||||
metadata:
|
metadata:
|
||||||
labels:
|
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/instance: {{ .Release.Name }}
|
||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
@ -27,15 +27,15 @@ spec:
|
|||||||
env:
|
env:
|
||||||
- name: APP_DATABASE_URL
|
- name: APP_DATABASE_URL
|
||||||
valueFrom:
|
valueFrom:
|
||||||
secretKeyRef:
|
configMapKeyRef:
|
||||||
name: {{ .Values.database.existingSecret | default (printf "%s-secrets" (include "c-----code.fullname" .)) }}
|
name: {{ include "gitdata.fullname" . }}-config
|
||||||
key: {{ .Values.database.secretKeys.url }}
|
key: APP_DATABASE_URL
|
||||||
optional: true
|
optional: true
|
||||||
- name: APP_REDIS_URL
|
- name: APP_REDIS_URL
|
||||||
valueFrom:
|
valueFrom:
|
||||||
secretKeyRef:
|
configMapKeyRef:
|
||||||
name: {{ .Values.redis.existingSecret | default (printf "%s-secrets" (include "c-----code.fullname" .)) }}
|
name: {{ include "gitdata.fullname" . }}-config
|
||||||
key: {{ .Values.redis.secretKeys.url }}
|
key: APP_REDIS_URL
|
||||||
optional: true
|
optional: true
|
||||||
{{- range .Values.emailWorker.env }}
|
{{- range .Values.emailWorker.env }}
|
||||||
- name: {{ .name }}
|
- name: {{ .name }}
|
||||||
@ -43,6 +43,30 @@ spec:
|
|||||||
{{- end }}
|
{{- end }}
|
||||||
resources:
|
resources:
|
||||||
{{- toYaml .Values.emailWorker.resources | nindent 10 }}
|
{{- 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 }}
|
{{- with .Values.emailWorker.nodeSelector }}
|
||||||
nodeSelector:
|
nodeSelector:
|
||||||
{{- toYaml . | nindent 8 }}
|
{{- toYaml . | nindent 8 }}
|
||||||
@ -55,4 +79,10 @@ spec:
|
|||||||
tolerations:
|
tolerations:
|
||||||
{{- toYaml . | nindent 8 }}
|
{{- toYaml . | nindent 8 }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
{{- if .Values.storage.enabled }}
|
||||||
|
volumes:
|
||||||
|
- name: shared-data
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: {{ include "gitdata.fullname" . }}-shared-data
|
||||||
|
{{- end }}
|
||||||
{{- 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
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
name: {{ include "c-----code.fullname" . }}-git-hook
|
name: {{ include "gitdata.fullname" . }}-git-hook
|
||||||
namespace: {{ include "c-----code.namespace" . }}
|
namespace: {{ include "gitdata.namespace" . }}
|
||||||
labels:
|
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/instance: {{ .Release.Name }}
|
||||||
app.kubernetes.io/version: {{ .Chart.AppVersion }}
|
app.kubernetes.io/version: {{ .Chart.AppVersion }}
|
||||||
spec:
|
spec:
|
||||||
replicas: {{ .Values.gitHook.replicaCount | default 2 }}
|
replicas: {{ .Values.gitHook.replicaCount | default 2 }}
|
||||||
selector:
|
selector:
|
||||||
matchLabels:
|
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 }}
|
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||||
template:
|
template:
|
||||||
metadata:
|
metadata:
|
||||||
labels:
|
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/instance: {{ .Release.Name }}
|
||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
@ -27,28 +27,58 @@ spec:
|
|||||||
env:
|
env:
|
||||||
- name: APP_DATABASE_URL
|
- name: APP_DATABASE_URL
|
||||||
valueFrom:
|
valueFrom:
|
||||||
secretKeyRef:
|
configMapKeyRef:
|
||||||
name: {{ .Values.database.existingSecret | default (printf "%s-secrets" (include "c-----code.fullname" .)) }}
|
name: {{ include "gitdata.fullname" . }}-config
|
||||||
key: {{ .Values.database.secretKeys.url }}
|
key: APP_DATABASE_URL
|
||||||
optional: true
|
optional: true
|
||||||
- name: APP_REDIS_URL
|
- name: APP_REDIS_URL
|
||||||
valueFrom:
|
valueFrom:
|
||||||
secretKeyRef:
|
configMapKeyRef:
|
||||||
name: {{ .Values.redis.existingSecret | default (printf "%s-secrets" (include "c-----code.fullname" .)) }}
|
name: {{ include "gitdata.fullname" . }}-config
|
||||||
key: {{ .Values.redis.secretKeys.url }}
|
key: APP_REDIS_URL
|
||||||
optional: true
|
optional: true
|
||||||
{{- if .Values.nats.enabled }}
|
|
||||||
- name: HOOK_POOL_REDIS_LIST_PREFIX
|
- 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
|
- name: HOOK_POOL_REDIS_LOG_CHANNEL
|
||||||
value: "hook:logs"
|
valueFrom:
|
||||||
{{- end }}
|
configMapKeyRef:
|
||||||
|
name: {{ include "gitdata.fullname" . }}-config
|
||||||
|
key: HOOK_POOL_REDIS_LOG_CHANNEL
|
||||||
|
optional: true
|
||||||
{{- range .Values.gitHook.env }}
|
{{- range .Values.gitHook.env }}
|
||||||
- name: {{ .name }}
|
- name: {{ .name }}
|
||||||
value: {{ .value | quote }}
|
value: {{ .value | quote }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
resources:
|
resources:
|
||||||
{{- toYaml .Values.gitHook.resources | nindent 10 }}
|
{{- 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 }}
|
{{- with .Values.gitHook.nodeSelector }}
|
||||||
nodeSelector:
|
nodeSelector:
|
||||||
{{- toYaml . | nindent 8 }}
|
{{- toYaml . | nindent 8 }}
|
||||||
@ -61,4 +91,10 @@ spec:
|
|||||||
tolerations:
|
tolerations:
|
||||||
{{- toYaml . | nindent 8 }}
|
{{- toYaml . | nindent 8 }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
{{- if .Values.storage.enabled }}
|
||||||
|
volumes:
|
||||||
|
- name: shared-data
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: {{ include "gitdata.fullname" . }}-shared-data
|
||||||
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|||||||
@ -1,29 +1,9 @@
|
|||||||
{{- if .Values.gitserver.enabled -}}
|
{{- if .Values.gitserver.enabled -}}
|
||||||
{{- $fullName := include "c-----code.fullname" . -}}
|
{{- $fullName := include "gitdata.fullname" . -}}
|
||||||
{{- $ns := include "c-----code.namespace" . -}}
|
{{- $ns := include "gitdata.namespace" . -}}
|
||||||
{{- $svc := .Values.gitserver -}}
|
{{- $svc := .Values.gitserver -}}
|
||||||
|
|
||||||
{{/* PersistentVolumeClaim for git repositories */}}
|
{{/* Uses shared PVC defined in storage.yaml */}}
|
||||||
{{- 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 }}
|
|
||||||
|
|
||||||
---
|
---
|
||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
@ -56,47 +36,70 @@ spec:
|
|||||||
containerPort: {{ $svc.service.http.port }}
|
containerPort: {{ $svc.service.http.port }}
|
||||||
protocol: TCP
|
protocol: TCP
|
||||||
- name: ssh
|
- name: ssh
|
||||||
containerPort: {{ $svc.ssh.port }}
|
containerPort: {{ $svc.service.ssh.port }}
|
||||||
protocol: TCP
|
protocol: TCP
|
||||||
env:
|
env:
|
||||||
- name: APP_REPOS_ROOT
|
- name: APP_REPOS_ROOT
|
||||||
value: /data/repos
|
value: /data/repos
|
||||||
- name: APP_DATABASE_URL
|
- name: APP_DATABASE_URL
|
||||||
valueFrom:
|
valueFrom:
|
||||||
secretKeyRef:
|
configMapKeyRef:
|
||||||
name: {{ $.Values.database.existingSecret | default (printf "%s-secrets" $fullName) }}
|
name: {{ $fullName }}-config
|
||||||
key: {{ $.Values.database.secretKeys.url }}
|
key: APP_DATABASE_URL
|
||||||
optional: true
|
optional: true
|
||||||
- name: APP_REDIS_URL
|
- name: APP_REDIS_URL
|
||||||
valueFrom:
|
valueFrom:
|
||||||
secretKeyRef:
|
configMapKeyRef:
|
||||||
name: {{ $.Values.redis.existingSecret | default (printf "%s-secrets" $fullName) }}
|
name: {{ $fullName }}-config
|
||||||
key: {{ $.Values.redis.secretKeys.url }}
|
key: APP_REDIS_URL
|
||||||
optional: true
|
optional: true
|
||||||
{{- if $svc.ssh.domain }}
|
|
||||||
- name: APP_SSH_DOMAIN
|
- name: APP_SSH_DOMAIN
|
||||||
value: {{ $svc.ssh.domain }}
|
valueFrom:
|
||||||
{{- end }}
|
configMapKeyRef:
|
||||||
{{- if $svc.ssh.port }}
|
name: {{ $fullName }}-config
|
||||||
|
key: APP_SSH_DOMAIN
|
||||||
|
optional: true
|
||||||
- name: APP_SSH_PORT
|
- name: APP_SSH_PORT
|
||||||
value: {{ $svc.ssh.port | quote }}
|
valueFrom:
|
||||||
{{- end }}
|
configMapKeyRef:
|
||||||
|
name: {{ $fullName }}-config
|
||||||
|
key: APP_SSH_PORT
|
||||||
|
optional: true
|
||||||
{{- range $svc.env }}
|
{{- range $svc.env }}
|
||||||
- name: {{ .name }}
|
- name: {{ .name }}
|
||||||
value: {{ .value | quote }}
|
value: {{ .value | quote }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
resources:
|
resources:
|
||||||
{{- toYaml $svc.resources | nindent 10 }}
|
{{- 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:
|
volumeMounts:
|
||||||
{{- if $svc.persistence.enabled }}
|
{{- if and $svc.persistence.enabled $.Values.storage.enabled }}
|
||||||
- name: repos
|
- name: shared-data
|
||||||
mountPath: /data/repos
|
mountPath: /data/repos
|
||||||
|
subPath: repos/
|
||||||
{{- end }}
|
{{- end }}
|
||||||
volumes:
|
volumes:
|
||||||
{{- if $svc.persistence.enabled }}
|
{{- if and $svc.persistence.enabled $.Values.storage.enabled }}
|
||||||
- name: repos
|
- name: shared-data
|
||||||
persistentVolumeClaim:
|
persistentVolumeClaim:
|
||||||
claimName: {{ $fullName }}-repos
|
claimName: {{ $fullName }}-shared-data
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- with $svc.nodeSelector }}
|
{{- with $svc.nodeSelector }}
|
||||||
nodeSelector:
|
nodeSelector:
|
||||||
@ -142,19 +145,40 @@ metadata:
|
|||||||
labels:
|
labels:
|
||||||
app.kubernetes.io/name: {{ $fullName }}-gitserver
|
app.kubernetes.io/name: {{ $fullName }}-gitserver
|
||||||
app.kubernetes.io/instance: {{ $.Release.Name }}
|
app.kubernetes.io/instance: {{ $.Release.Name }}
|
||||||
|
{{- if $svc.service.ssh.loadBalancerSourceRanges }}
|
||||||
|
annotations:
|
||||||
|
metallb.universe.tf/loadBalancerIPs: {{ $svc.service.ssh.loadBalancerIP | default "" }}
|
||||||
|
{{- end }}
|
||||||
spec:
|
spec:
|
||||||
type: {{ $svc.service.ssh.type }}
|
type: {{ $svc.service.ssh.type }}
|
||||||
{{- if eq $svc.service.ssh.type "NodePort" }}
|
{{- if eq $svc.service.ssh.type "LoadBalancer" }}
|
||||||
ports:
|
ports:
|
||||||
- name: ssh
|
- name: ssh
|
||||||
port: {{ $svc.ssh.port }}
|
port: {{ $svc.service.ssh.port }}
|
||||||
targetPort: ssh
|
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 }}
|
{{- else }}
|
||||||
ports:
|
ports:
|
||||||
- name: ssh
|
- name: ssh
|
||||||
port: {{ $svc.ssh.port }}
|
port: {{ $svc.service.ssh.port }}
|
||||||
targetPort: ssh
|
targetPort: ssh
|
||||||
|
protocol: TCP
|
||||||
{{- end }}
|
{{- end }}
|
||||||
selector:
|
selector:
|
||||||
app.kubernetes.io/name: {{ $fullName }}-gitserver
|
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 -}}
|
{{- if .Values.app.ingress.enabled -}}
|
||||||
{{- $svcName := printf "%s-app" (include "c-----code.fullname" .) -}}
|
{{- $svcName := printf "%s-app" (include "gitdata.fullname" .) -}}
|
||||||
{{- $ns := include "c-----code.namespace" . -}}
|
{{- $ns := include "gitdata.namespace" . -}}
|
||||||
{{- $ing := .Values.app.ingress -}}
|
{{- $ing := .Values.app.ingress -}}
|
||||||
apiVersion: networking.k8s.io/v1
|
apiVersion: networking.k8s.io/v1
|
||||||
kind: Ingress
|
kind: Ingress
|
||||||
metadata:
|
metadata:
|
||||||
name: {{ include "c-----code.fullname" . }}-ingress
|
name: {{ include "gitdata.fullname" . }}-ingress
|
||||||
namespace: {{ $ns }}
|
namespace: {{ $ns }}
|
||||||
labels:
|
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/instance: {{ .Release.Name }}
|
||||||
{{- with $ing.annotations }}
|
|
||||||
annotations:
|
annotations:
|
||||||
{{- toYaml . | nindent 4 }}
|
cert-manager.io/cluster-issuer: {{ $ing.clusterIssuer | default "cloudflare-acme-cluster-issuer" }}
|
||||||
{{- end }}
|
{{- if $ing.annotations }}
|
||||||
spec:
|
{{ toYaml $ing.annotations | indent 4 }}
|
||||||
{{- if $ing.className }}
|
{{- end }}
|
||||||
ingressClassName: {{ $ing.className }}
|
{{- if not (hasKey ($ing.annotations | default dict) "nginx.ingress.kubernetes.io/proxy-body-size") }}
|
||||||
{{- end }}
|
{{- if or (not $ing.className) (eq $ing.className "nginx") (contains "nginx" $ing.className) }}
|
||||||
{{- if $ing.tls }}
|
nginx.ingress.kubernetes.io/proxy-body-size: "0"
|
||||||
tls:
|
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
|
||||||
{{- range $ing.tls }}
|
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
|
||||||
- hosts:
|
{{- end }}
|
||||||
{{- range .hosts }}
|
{{- end }}
|
||||||
- {{ . | quote }}
|
spec:
|
||||||
{{- end }}
|
{{- if $ing.className }}
|
||||||
secretName: {{ .secretName }}
|
ingressClassName: {{ $ing.className }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- end }}
|
{{- if $ing.tls }}
|
||||||
rules:
|
tls:
|
||||||
{{- range $ing.hosts }}
|
{{- range $ing.tls }}
|
||||||
- host: {{ .host | quote }}
|
- hosts:
|
||||||
http:
|
{{- range .hosts }}
|
||||||
paths:
|
- {{ . | quote }}
|
||||||
{{- range .paths }}
|
{{- end }}
|
||||||
- path: {{ .path }}
|
secretName: {{ .secretName }}
|
||||||
pathType: {{ .pathType | default "Prefix" }}
|
{{- end }}
|
||||||
backend:
|
{{- else }}
|
||||||
service:
|
tls:
|
||||||
name: {{ $svcName }}
|
{{- range $ing.hosts }}
|
||||||
port:
|
- hosts:
|
||||||
number: {{ $.Values.app.service.port }}
|
- {{ .host | quote }}
|
||||||
{{- end }}
|
secretName: {{ include "gitdata.fullname" $ }}-app-tls
|
||||||
{{- end }}
|
{{- 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 }}
|
{{- end }}
|
||||||
|
|||||||
@ -2,10 +2,10 @@
|
|||||||
apiVersion: batch/v1
|
apiVersion: batch/v1
|
||||||
kind: Job
|
kind: Job
|
||||||
metadata:
|
metadata:
|
||||||
name: {{ include "c-----code.fullname" . }}-migrate
|
name: {{ include "gitdata.fullname" . }}-migrate
|
||||||
namespace: {{ include "c-----code.namespace" . }}
|
namespace: {{ include "gitdata.namespace" . }}
|
||||||
labels:
|
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/instance: {{ .Release.Name }}
|
||||||
app.kubernetes.io/version: {{ .Chart.AppVersion }}
|
app.kubernetes.io/version: {{ .Chart.AppVersion }}
|
||||||
helm.sh/hook: post-install,post-upgrade
|
helm.sh/hook: post-install,post-upgrade
|
||||||
@ -15,7 +15,7 @@ spec:
|
|||||||
template:
|
template:
|
||||||
metadata:
|
metadata:
|
||||||
labels:
|
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/instance: {{ .Release.Name }}
|
||||||
spec:
|
spec:
|
||||||
restartPolicy: OnFailure
|
restartPolicy: OnFailure
|
||||||
@ -32,9 +32,9 @@ spec:
|
|||||||
env:
|
env:
|
||||||
- name: APP_DATABASE_URL
|
- name: APP_DATABASE_URL
|
||||||
valueFrom:
|
valueFrom:
|
||||||
secretKeyRef:
|
configMapKeyRef:
|
||||||
name: {{ .Values.database.existingSecret | default (printf "%s-secrets" (include "c-----code.fullname" .)) }}
|
name: {{ include "gitdata.fullname" . }}-config
|
||||||
key: {{ .Values.database.secretKeys.url }}
|
key: APP_DATABASE_URL
|
||||||
{{- range .Values.migrate.env }}
|
{{- range .Values.migrate.env }}
|
||||||
- name: {{ .name }}
|
- name: {{ .name }}
|
||||||
value: {{ .value | quote }}
|
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
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
name: {{ include "c-----code.fullname" . }}-operator
|
name: {{ include "gitdata.fullname" . }}-operator
|
||||||
namespace: {{ include "c-----code.namespace" . }}
|
namespace: {{ include "gitdata.namespace" . }}
|
||||||
labels:
|
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/instance: {{ .Release.Name }}
|
||||||
app.kubernetes.io/version: {{ .Chart.AppVersion }}
|
app.kubernetes.io/version: {{ .Chart.AppVersion }}
|
||||||
spec:
|
spec:
|
||||||
replicas: 1
|
replicas: 1
|
||||||
selector:
|
selector:
|
||||||
matchLabels:
|
matchLabels:
|
||||||
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/instance: {{ .Release.Name }}
|
||||||
template:
|
template:
|
||||||
metadata:
|
metadata:
|
||||||
labels:
|
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/instance: {{ .Release.Name }}
|
||||||
spec:
|
spec:
|
||||||
serviceAccountName: {{ include "c-----code.fullname" . }}-operator
|
serviceAccountName: {{ include "gitdata.fullname" . }}-operator
|
||||||
|
terminationGracePeriodSeconds: 10
|
||||||
|
volumes:
|
||||||
|
- name: tmp
|
||||||
|
emptyDir: {}
|
||||||
containers:
|
containers:
|
||||||
- name: operator
|
- name: operator
|
||||||
image: "{{ .Values.image.registry }}/{{ .Values.operator.image.repository }}:{{ .Values.operator.image.tag }}"
|
image: "{{ .Values.image.registry }}/{{ .Values.operator.image.repository }}:{{ .Values.operator.image.tag }}"
|
||||||
imagePullPolicy: {{ .Values.operator.image.pullPolicy | default .Values.image.pullPolicy }}
|
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:
|
resources:
|
||||||
{{- toYaml .Values.operator.resources | nindent 10 }}
|
{{- toYaml .Values.operator.resources | nindent 10 }}
|
||||||
|
volumeMounts:
|
||||||
|
- name: tmp
|
||||||
|
mountPath: /tmp
|
||||||
|
securityContext:
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
readOnlyRootFilesystem: true
|
||||||
|
capabilities:
|
||||||
|
drop:
|
||||||
|
- ALL
|
||||||
{{- with .Values.operator.nodeSelector }}
|
{{- with .Values.operator.nodeSelector }}
|
||||||
nodeSelector:
|
nodeSelector:
|
||||||
{{- toYaml . | nindent 8 }}
|
{{- toYaml . | nindent 8 }}
|
||||||
@ -44,9 +66,51 @@ spec:
|
|||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: ServiceAccount
|
kind: ServiceAccount
|
||||||
metadata:
|
metadata:
|
||||||
name: {{ include "c-----code.fullname" . }}-operator
|
name: {{ include "gitdata.fullname" . }}-operator
|
||||||
namespace: {{ include "c-----code.namespace" . }}
|
namespace: {{ include "gitdata.namespace" . }}
|
||||||
labels:
|
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/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 }}
|
{{- 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
|
apiVersion: v1
|
||||||
kind: Secret
|
kind: Secret
|
||||||
metadata:
|
metadata:
|
||||||
name: {{ include "c-----code.fullname" . }}-secrets
|
name: {{ include "gitdata.fullname" . }}-secrets
|
||||||
namespace: {{ include "c-----code.namespace" . }}
|
namespace: {{ include "gitdata.namespace" . }}
|
||||||
labels:
|
labels:
|
||||||
app.kubernetes.io/name: {{ .Chart.Name }}
|
app.kubernetes.io/name: {{ .Chart.Name }}
|
||||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||||
app.kubernetes.io/version: {{ .Chart.AppVersion }}
|
annotations:
|
||||||
|
"helm.sh/resource-policy": keep
|
||||||
type: Opaque
|
type: Opaque
|
||||||
stringData:
|
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 }}
|
{{ $key }}: {{ $value | quote }}
|
||||||
{{- end }}
|
{{- 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
|
# PostgreSQL
|
||||||
database:
|
database:
|
||||||
existingSecret: c-----code-secrets
|
existingSecret: gitdata-secrets
|
||||||
secretKeys:
|
secretKeys:
|
||||||
url: APP_DATABASE_URL
|
url: APP_DATABASE_URL
|
||||||
|
|
||||||
# Redis
|
# Redis
|
||||||
redis:
|
redis:
|
||||||
existingSecret: c-----code-secrets
|
existingSecret: gitdata-secrets
|
||||||
secretKeys:
|
secretKeys:
|
||||||
url: APP_REDIS_URL
|
url: APP_REDIS_URL
|
||||||
|
|
||||||
@ -31,12 +31,15 @@ app:
|
|||||||
hosts:
|
hosts:
|
||||||
- host: git.example.com
|
- host: git.example.com
|
||||||
|
|
||||||
# Gitserver persistence
|
# Gitserver
|
||||||
gitserver:
|
gitserver:
|
||||||
persistence:
|
persistence:
|
||||||
size: 100Gi
|
size: 100Gi
|
||||||
storageClass: fast-ssd
|
storageClass: fast-ssd
|
||||||
|
ingress:
|
||||||
# Act Runner
|
enabled: true
|
||||||
actRunner:
|
hosts:
|
||||||
enabled: false
|
- 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
|
# Global / common settings
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
namespace: c-----code
|
namespace: gitdataai
|
||||||
releaseName: c-----code
|
releaseName: gitdata
|
||||||
|
|
||||||
image:
|
image:
|
||||||
registry: harbor.gitdata.me/gta_team
|
registry: harbor.gitdata.me/gta_team
|
||||||
pullPolicy: IfNotPresent
|
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:
|
database:
|
||||||
existingSecret: ""
|
existingSecret: "" # 留空则使用默认名 {release-name}-secrets
|
||||||
secretKeys:
|
secretKeys:
|
||||||
url: APP_DATABASE_URL
|
url: APP_DATABASE_URL
|
||||||
|
|
||||||
@ -20,19 +108,64 @@ redis:
|
|||||||
secretKeys:
|
secretKeys:
|
||||||
url: APP_REDIS_URL
|
url: APP_REDIS_URL
|
||||||
|
|
||||||
# NATS (optional – required only if HOOK_POOL is enabled)
|
# NATS (optional)
|
||||||
nats:
|
nats:
|
||||||
enabled: false
|
enabled: true
|
||||||
url: nats://nats:4222
|
url: "nats://nats-client.nats.svc.cluster.local:4222"
|
||||||
|
|
||||||
# Qdrant (optional – required only if AI embeddings are used)
|
# Qdrant (optional)
|
||||||
qdrant:
|
qdrant:
|
||||||
enabled: false
|
enabled: true
|
||||||
url: http://qdrant:6333
|
url: "http://qdrant.qdrant.svc.cluster.local:6333"
|
||||||
existingSecret: ""
|
existingSecret: ""
|
||||||
secretKeys:
|
secretKeys:
|
||||||
apiKey: APP_QDRANT_API_KEY
|
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
|
# App – main web/API service
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
@ -44,19 +177,26 @@ app:
|
|||||||
repository: app
|
repository: app
|
||||||
tag: latest
|
tag: latest
|
||||||
|
|
||||||
|
# Pod disruption budget
|
||||||
|
pdb:
|
||||||
|
enabled: true
|
||||||
|
minAvailable: 2 # Keep at least 2 pods available during disruptions
|
||||||
|
|
||||||
service:
|
service:
|
||||||
type: ClusterIP
|
type: ClusterIP
|
||||||
port: 8080
|
port: 8080
|
||||||
|
|
||||||
ingress:
|
ingress:
|
||||||
enabled: false
|
enabled: true
|
||||||
className: cilium # Cilium Ingress (or envoy for EnvoyGateway)
|
className: nginx
|
||||||
annotations: {}
|
annotations: {}
|
||||||
hosts:
|
hosts:
|
||||||
- host: c-----.local
|
- host: gitdata.ai
|
||||||
paths:
|
paths:
|
||||||
- path: /
|
- path: /
|
||||||
pathType: Prefix
|
pathType: Prefix
|
||||||
|
- path: /api
|
||||||
|
pathType: Prefix
|
||||||
tls: []
|
tls: []
|
||||||
|
|
||||||
resources:
|
resources:
|
||||||
@ -79,13 +219,76 @@ app:
|
|||||||
initialDelaySeconds: 5
|
initialDelaySeconds: 5
|
||||||
periodSeconds: 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: []
|
env: []
|
||||||
|
|
||||||
nodeSelector: {}
|
nodeSelector: {}
|
||||||
tolerations: []
|
tolerations: []
|
||||||
affinity: {}
|
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
|
# Gitserver – git daemon / SSH + HTTP server
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
@ -102,8 +305,11 @@ gitserver:
|
|||||||
type: ClusterIP
|
type: ClusterIP
|
||||||
port: 8022
|
port: 8022
|
||||||
ssh:
|
ssh:
|
||||||
type: NodePort
|
type: LoadBalancer
|
||||||
nodePort: 30222
|
port: 22
|
||||||
|
domain: ""
|
||||||
|
loadBalancerIP: ""
|
||||||
|
loadBalancerSourceRanges: []
|
||||||
|
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
@ -113,16 +319,38 @@ gitserver:
|
|||||||
cpu: 500m
|
cpu: 500m
|
||||||
memory: 512Mi
|
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:
|
persistence:
|
||||||
enabled: true
|
enabled: true
|
||||||
storageClass: ""
|
storageClass: ""
|
||||||
size: 50Gi
|
size: 50Gi
|
||||||
accessMode: ReadWriteOnce
|
accessMode: ReadWriteOnce
|
||||||
|
|
||||||
ssh:
|
ingress:
|
||||||
domain: ""
|
enabled: true
|
||||||
port: 22
|
className: nginx
|
||||||
|
annotations: {}
|
||||||
|
hosts:
|
||||||
|
- host: git.gitdata.ai
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
tls: []
|
||||||
|
|
||||||
env: []
|
env: []
|
||||||
|
|
||||||
@ -140,6 +368,28 @@ emailWorker:
|
|||||||
repository: email-worker
|
repository: email-worker
|
||||||
tag: latest
|
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:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
cpu: 50m
|
cpu: 50m
|
||||||
@ -166,6 +416,32 @@ gitHook:
|
|||||||
|
|
||||||
replicaCount: 2
|
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:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
cpu: 50m
|
cpu: 50m
|
||||||
@ -196,15 +472,18 @@ migrate:
|
|||||||
env: []
|
env: []
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# Operator – Kubernetes operator (manages custom App/GitServer CRDs)
|
# Operator – Kubernetes operator
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
operator:
|
operator:
|
||||||
enabled: false # Enable only if running the custom operator
|
enabled: false
|
||||||
|
|
||||||
image:
|
image:
|
||||||
repository: operator
|
repository: operator
|
||||||
tag: latest
|
tag: latest
|
||||||
|
|
||||||
|
imagePrefix: ""
|
||||||
|
logLevel: info
|
||||||
|
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
cpu: 50m
|
cpu: 50m
|
||||||
@ -216,47 +495,3 @@ operator:
|
|||||||
nodeSelector: {}
|
nodeSelector: {}
|
||||||
tolerations: []
|
tolerations: []
|
||||||
affinity: {}
|
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` | 镜像仓库 |
|
| `REGISTRY` | `harbor.gitdata.me/gta_team` | 镜像仓库 |
|
||||||
| `TAG` | `latest` | 镜像标签 |
|
| `TAG` | `latest` | 镜像标签 |
|
||||||
| `TARGET` | `x86_64-unknown-linux-gnu` | Rust 交叉编译目标 |
|
| `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` | 镜像仓库 |
|
| `REGISTRY` | `harbor.gitdata.me/gta_team` | 镜像仓库 |
|
||||||
| `TAG` | `latest` 或 Git SHA | 镜像标签 |
|
| `TAG` | `latest` 或 Git SHA | 镜像标签 |
|
||||||
| `HARBOR_USERNAME` | - | **必填** 仓库用户名 |
|
| `HARBOR_USERNAME` | - | **必填** 仓库用户名 |
|
||||||
| `HARBOR_PASSWORD` | - | **必填** 仓库密码 |
|
| `HARBOR_PASSWORD` | - | **必填** 仓库密码 |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -70,13 +70,13 @@ NAMESPACE=staging node scripts/deploy.js
|
|||||||
|
|
||||||
**环境变量:**
|
**环境变量:**
|
||||||
|
|
||||||
| 变量 | 默认值 | 说明 |
|
| 变量 | 默认值 | 说明 |
|
||||||
|------|--------|------|
|
|--------------|------------------------------|-----------------|
|
||||||
| `REGISTRY` | `harbor.gitdata.me/gta_team` | 镜像仓库 |
|
| `REGISTRY` | `harbor.gitdata.me/gta_team` | 镜像仓库 |
|
||||||
| `TAG` | `latest` 或 Git SHA | 镜像标签 |
|
| `TAG` | `latest` 或 Git SHA | 镜像标签 |
|
||||||
| `NAMESPACE` | `c-----code` | K8s 命名空间 |
|
| `NAMESPACE` | `gitdata` | K8s 命名空间 |
|
||||||
| `RELEASE` | `c-----code` | Helm Release 名称 |
|
| `RELEASE` | `gitdata` | Helm Release 名称 |
|
||||||
| `KUBECONFIG` | `~/.kube/config` | Kubeconfig 路径 |
|
| `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 TAG = process.env.TAG || 'latest';
|
||||||
const BUILD_TARGET = process.env.TARGET || 'x86_64-unknown-linux-gnu';
|
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 args = process.argv.slice(2);
|
||||||
const targets = args.length > 0 ? args : SERVICES;
|
const targets = args.length > 0 ? args : SERVICES;
|
||||||
|
|||||||
@ -10,19 +10,19 @@
|
|||||||
* Environment:
|
* Environment:
|
||||||
* REGISTRY - Docker registry (default: harbor.gitdata.me/gta_team)
|
* REGISTRY - Docker registry (default: harbor.gitdata.me/gta_team)
|
||||||
* TAG - Image tag (default: latest)
|
* TAG - Image tag (default: latest)
|
||||||
* NAMESPACE - Kubernetes namespace (default: c-----code)
|
* NAMESPACE - Kubernetes namespace (default: gitdata)
|
||||||
* RELEASE - Helm release name (default: c-----code)
|
* RELEASE - Helm release name (default: gitdata)
|
||||||
* KUBECONFIG - Path to kubeconfig (default: ~/.kube/config)
|
* KUBECONFIG - Path to kubeconfig (default: ~/.kube/config)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const { execSync } = require('child_process');
|
const {execSync} = require('child_process');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
|
|
||||||
const REGISTRY = process.env.REGISTRY || 'harbor.gitdata.me/gta_team';
|
const REGISTRY = process.env.REGISTRY || 'harbor.gitdata.me/gta_team';
|
||||||
const TAG = process.env.TAG || process.env.GITHUB_SHA?.substring(0, 8) || 'latest';
|
const TAG = process.env.TAG || process.env.GITHUB_SHA?.substring(0, 8) || 'latest';
|
||||||
const NAMESPACE = process.env.NAMESPACE || 'c-----code';
|
const NAMESPACE = process.env.NAMESPACE || 'gitdata';
|
||||||
const RELEASE = process.env.RELEASE || 'c-----code';
|
const RELEASE = process.env.RELEASE || 'gitdata';
|
||||||
const CHART_PATH = path.join(__dirname, '..', 'deploy');
|
const CHART_PATH = path.join(__dirname, '..', 'deploy');
|
||||||
const KUBECONFIG = process.env.KUBECONFIG || path.join(process.env.HOME || process.env.USERPROFILE, '.kube', 'config');
|
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
|
// Validate kubeconfig
|
||||||
if (!fs.existsSync(KUBECONFIG)) {
|
if (!fs.existsSync(KUBECONFIG)) {
|
||||||
console.error(`Error: kubeconfig not found at ${KUBECONFIG}`);
|
console.error(`Error: kubeconfig not found at ${KUBECONFIG}`);
|
||||||
console.error('Set KUBECONFIG environment variable or ensure ~/.kube/config exists');
|
console.error('Set KUBECONFIG environment variable or ensure ~/.kube/config exists');
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`\n=== Deploy Configuration ===`);
|
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 userValuesFile = path.join(CHART_PATH, 'values.user.yaml');
|
||||||
|
|
||||||
const setValues = [
|
const setValues = [
|
||||||
`image.registry=${REGISTRY}`,
|
`image.registry=${REGISTRY}`,
|
||||||
`app.image.tag=${TAG}`,
|
`app.image.tag=${TAG}`,
|
||||||
`gitserver.image.tag=${TAG}`,
|
`gitserver.image.tag=${TAG}`,
|
||||||
`emailWorker.image.tag=${TAG}`,
|
`emailWorker.image.tag=${TAG}`,
|
||||||
`gitHook.image.tag=${TAG}`,
|
`gitHook.image.tag=${TAG}`,
|
||||||
`operator.image.tag=${TAG}`,
|
`operator.image.tag=${TAG}`,
|
||||||
];
|
];
|
||||||
|
|
||||||
if (runMigrate) {
|
if (runMigrate) {
|
||||||
setValues.push('migrate.enabled=true');
|
setValues.push('migrate.enabled=true');
|
||||||
}
|
}
|
||||||
|
|
||||||
const helmArgs = [
|
const helmArgs = [
|
||||||
'upgrade', '--install', RELEASE, CHART_PATH,
|
'upgrade', '--install', RELEASE, CHART_PATH,
|
||||||
'--namespace', NAMESPACE,
|
'--namespace', NAMESPACE,
|
||||||
'--create-namespace',
|
'--create-namespace',
|
||||||
'-f', valuesFile,
|
'-f', valuesFile,
|
||||||
...(fs.existsSync(userValuesFile) ? ['-f', userValuesFile] : []),
|
...(fs.existsSync(userValuesFile) ? ['-f', userValuesFile] : []),
|
||||||
...setValues.flatMap(v => ['--set', v]),
|
...setValues.flatMap(v => ['--set', v]),
|
||||||
'--wait',
|
'--wait',
|
||||||
'--timeout', '5m',
|
'--timeout', '5m',
|
||||||
];
|
];
|
||||||
|
|
||||||
if (isDryRun) {
|
if (isDryRun) {
|
||||||
helmArgs.push('--dry-run');
|
helmArgs.push('--dry-run');
|
||||||
console.log('==> Dry run mode - no changes will be made\n');
|
console.log('==> Dry run mode - no changes will be made\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helm upgrade
|
// Helm upgrade
|
||||||
@ -86,29 +86,29 @@ console.log(`==> Running helm upgrade`);
|
|||||||
console.log(` Command: helm ${helmArgs.join(' ')}\n`);
|
console.log(` Command: helm ${helmArgs.join(' ')}\n`);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
execSync(`helm ${helmArgs.join(' ')}`, { stdio: 'inherit', env: { ...process.env, KUBECONFIG } });
|
execSync(`helm ${helmArgs.join(' ')}`, {stdio: 'inherit', env: {...process.env, KUBECONFIG}});
|
||||||
console.log(`\n[OK] Deployment ${isDryRun ? '(dry-run) ' : ''}complete`);
|
console.log(`\n[OK] Deployment ${isDryRun ? '(dry-run) ' : ''}complete`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('\n[FAIL] Deployment failed');
|
console.error('\n[FAIL] Deployment failed');
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rollout status
|
// Rollout status
|
||||||
if (!isDryRun) {
|
if (!isDryRun) {
|
||||||
console.log('\n==> Checking rollout status');
|
console.log('\n==> Checking rollout status');
|
||||||
for (const service of SERVICES) {
|
for (const service of SERVICES) {
|
||||||
const deploymentName = `${RELEASE}-${service}`;
|
const deploymentName = `${RELEASE}-${service}`;
|
||||||
console.log(` Checking ${deploymentName}...`);
|
console.log(` Checking ${deploymentName}...`);
|
||||||
try {
|
try {
|
||||||
execSync(
|
execSync(
|
||||||
`kubectl rollout status deployment/${deploymentName} -n ${NAMESPACE} --timeout=120s`,
|
`kubectl rollout status deployment/${deploymentName} -n ${NAMESPACE} --timeout=120s`,
|
||||||
{ stdio: 'pipe', env: { ...process.env, KUBECONFIG } }
|
{stdio: 'pipe', env: {...process.env, KUBECONFIG}}
|
||||||
);
|
);
|
||||||
console.log(` [OK] ${deploymentName}`);
|
console.log(` [OK] ${deploymentName}`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(` [WARN] ${deploymentName} rollout timeout or failed`);
|
console.error(` [WARN] ${deploymentName} rollout timeout or failed`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('\n=== Deploy Complete ===\n');
|
console.log('\n=== Deploy Complete ===\n');
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user