- deploy/authentik.yaml: PostgreSQL StatefulSet, Redis, Authentik server (NodePort 30900) and worker, all in cameleer namespace - deploy/server.yaml: Add CAMELEER_JWT_SECRET and CAMELEER_OIDC_* env vars from secrets (all optional for backward compat) - ci.yml: Create authentik-credentials and cameleer-oidc secrets, deploy Authentik before the server - HOWTO.md: Authentik setup instructions, updated architecture diagram and Gitea secrets list Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
215 lines
8.9 KiB
YAML
215 lines
8.9 KiB
YAML
name: CI
|
|
|
|
on:
|
|
push:
|
|
branches: [main]
|
|
tags-ignore:
|
|
- 'v*'
|
|
pull_request:
|
|
branches: [main]
|
|
|
|
jobs:
|
|
build:
|
|
runs-on: ubuntu-latest
|
|
container:
|
|
image: maven:3.9-eclipse-temurin-17
|
|
steps:
|
|
- name: Install Node.js 22
|
|
run: |
|
|
apt-get update && apt-get install -y ca-certificates curl gnupg
|
|
mkdir -p /etc/apt/keyrings
|
|
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
|
|
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_22.x nodistro main" > /etc/apt/sources.list.d/nodesource.list
|
|
apt-get update && apt-get install -y nodejs
|
|
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Configure Gitea Maven Registry
|
|
run: |
|
|
mkdir -p ~/.m2
|
|
cat > ~/.m2/settings.xml << 'SETTINGS'
|
|
<settings>
|
|
<servers>
|
|
<server>
|
|
<id>gitea</id>
|
|
<username>cameleer</username>
|
|
<password>${env.REGISTRY_TOKEN}</password>
|
|
</server>
|
|
</servers>
|
|
</settings>
|
|
SETTINGS
|
|
env:
|
|
REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
|
|
|
|
- name: Cache Maven dependencies
|
|
uses: actions/cache@v4
|
|
with:
|
|
path: ~/.m2/repository
|
|
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
|
|
restore-keys: ${{ runner.os }}-maven-
|
|
|
|
- name: Build UI
|
|
working-directory: ui
|
|
run: |
|
|
npm ci
|
|
npm run build
|
|
|
|
- name: Build and Test
|
|
run: mvn clean verify -DskipITs --batch-mode
|
|
|
|
docker:
|
|
needs: build
|
|
runs-on: ubuntu-latest
|
|
if: github.ref == 'refs/heads/main'
|
|
container:
|
|
image: docker:27
|
|
steps:
|
|
- name: Checkout
|
|
run: |
|
|
apk add --no-cache git
|
|
git clone --depth=1 --branch=${GITHUB_REF_NAME} https://cameleer:${REGISTRY_TOKEN}@gitea.siegeln.net/${GITHUB_REPOSITORY}.git .
|
|
env:
|
|
REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
|
|
- name: Login to registry
|
|
run: echo "$REGISTRY_TOKEN" | docker login gitea.siegeln.net -u cameleer --password-stdin
|
|
env:
|
|
REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
|
|
- name: Set up QEMU for cross-platform builds
|
|
run: docker run --rm --privileged tonistiigi/binfmt --install all
|
|
- name: Build and push server
|
|
run: |
|
|
docker buildx create --use --name cibuilder
|
|
docker buildx build --platform linux/amd64 \
|
|
--build-arg REGISTRY_TOKEN="$REGISTRY_TOKEN" \
|
|
-t gitea.siegeln.net/cameleer/cameleer3-server:${{ github.sha }} \
|
|
-t gitea.siegeln.net/cameleer/cameleer3-server:latest \
|
|
--cache-from type=registry,ref=gitea.siegeln.net/cameleer/cameleer3-server:buildcache \
|
|
--cache-to type=registry,ref=gitea.siegeln.net/cameleer/cameleer3-server:buildcache,mode=max \
|
|
--provenance=false \
|
|
--push .
|
|
env:
|
|
REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
|
|
- name: Build and push UI
|
|
run: |
|
|
docker buildx build --platform linux/amd64 \
|
|
-f ui/Dockerfile \
|
|
-t gitea.siegeln.net/cameleer/cameleer3-server-ui:${{ github.sha }} \
|
|
-t gitea.siegeln.net/cameleer/cameleer3-server-ui:latest \
|
|
--cache-from type=registry,ref=gitea.siegeln.net/cameleer/cameleer3-server-ui:buildcache \
|
|
--cache-to type=registry,ref=gitea.siegeln.net/cameleer/cameleer3-server-ui:buildcache,mode=max \
|
|
--provenance=false \
|
|
--push ui/
|
|
env:
|
|
REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
|
|
- name: Cleanup local Docker
|
|
run: docker system prune -af --filter "until=24h"
|
|
if: always()
|
|
- name: Cleanup old container images
|
|
run: |
|
|
apk add --no-cache curl jq
|
|
API="https://gitea.siegeln.net/api/v1"
|
|
AUTH="Authorization: token ${REGISTRY_TOKEN}"
|
|
CURRENT_SHA="${{ github.sha }}"
|
|
for PKG in cameleer3-server cameleer3-server-ui; do
|
|
curl -sf -H "$AUTH" "$API/packages/cameleer/container/$PKG" | \
|
|
jq -r '.[] | "\(.id) \(.version)"' | \
|
|
while read id version; do
|
|
if [ "$version" != "latest" ] && [ "$version" != "$CURRENT_SHA" ]; then
|
|
echo "Deleting old image tag: $PKG:$version"
|
|
curl -sf -X DELETE -H "$AUTH" "$API/packages/cameleer/container/$PKG/$version"
|
|
fi
|
|
done
|
|
done
|
|
env:
|
|
REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
|
|
if: always()
|
|
|
|
deploy:
|
|
needs: docker
|
|
runs-on: ubuntu-latest
|
|
if: github.ref == 'refs/heads/main'
|
|
container:
|
|
image: bitnami/kubectl:latest
|
|
steps:
|
|
- name: Checkout
|
|
run: |
|
|
git clone --depth=1 --branch=${GITHUB_REF_NAME} https://cameleer:${REGISTRY_TOKEN}@gitea.siegeln.net/${GITHUB_REPOSITORY}.git .
|
|
env:
|
|
REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
|
|
- name: Configure kubectl
|
|
run: |
|
|
mkdir -p ~/.kube
|
|
echo "$KUBECONFIG_B64" | base64 -d > ~/.kube/config
|
|
env:
|
|
KUBECONFIG_B64: ${{ secrets.KUBECONFIG_BASE64 }}
|
|
- name: Deploy
|
|
run: |
|
|
kubectl create namespace cameleer --dry-run=client -o yaml | kubectl apply -f -
|
|
|
|
kubectl create secret docker-registry gitea-registry \
|
|
--namespace=cameleer \
|
|
--docker-server=gitea.siegeln.net \
|
|
--docker-username=cameleer \
|
|
--docker-password="$REGISTRY_TOKEN" \
|
|
--dry-run=client -o yaml | kubectl apply -f -
|
|
|
|
kubectl create secret generic cameleer-auth \
|
|
--namespace=cameleer \
|
|
--from-literal=CAMELEER_AUTH_TOKEN="$CAMELEER_AUTH_TOKEN" \
|
|
--from-literal=CAMELEER_UI_USER="${CAMELEER_UI_USER:-admin}" \
|
|
--from-literal=CAMELEER_UI_PASSWORD="${CAMELEER_UI_PASSWORD:-admin}" \
|
|
--from-literal=CAMELEER_JWT_SECRET="${CAMELEER_JWT_SECRET}" \
|
|
--dry-run=client -o yaml | kubectl apply -f -
|
|
|
|
kubectl create secret generic clickhouse-credentials \
|
|
--namespace=cameleer \
|
|
--from-literal=CLICKHOUSE_USER="$CLICKHOUSE_USER" \
|
|
--from-literal=CLICKHOUSE_PASSWORD="$CLICKHOUSE_PASSWORD" \
|
|
--dry-run=client -o yaml | kubectl apply -f -
|
|
|
|
kubectl create secret generic authentik-credentials \
|
|
--namespace=cameleer \
|
|
--from-literal=PG_USER="${AUTHENTIK_PG_USER:-authentik}" \
|
|
--from-literal=PG_PASSWORD="${AUTHENTIK_PG_PASSWORD}" \
|
|
--from-literal=AUTHENTIK_SECRET_KEY="${AUTHENTIK_SECRET_KEY}" \
|
|
--dry-run=client -o yaml | kubectl apply -f -
|
|
|
|
kubectl create secret generic cameleer-oidc \
|
|
--namespace=cameleer \
|
|
--from-literal=CAMELEER_OIDC_ENABLED="${CAMELEER_OIDC_ENABLED:-false}" \
|
|
--from-literal=CAMELEER_OIDC_ISSUER="${CAMELEER_OIDC_ISSUER}" \
|
|
--from-literal=CAMELEER_OIDC_CLIENT_ID="${CAMELEER_OIDC_CLIENT_ID}" \
|
|
--from-literal=CAMELEER_OIDC_CLIENT_SECRET="${CAMELEER_OIDC_CLIENT_SECRET}" \
|
|
--dry-run=client -o yaml | kubectl apply -f -
|
|
|
|
kubectl apply -f deploy/clickhouse.yaml
|
|
kubectl -n cameleer rollout status statefulset/clickhouse --timeout=120s
|
|
|
|
kubectl apply -f deploy/authentik.yaml
|
|
kubectl -n cameleer rollout status deployment/authentik-server --timeout=180s
|
|
|
|
kubectl apply -f deploy/server.yaml
|
|
kubectl -n cameleer set image deployment/cameleer3-server \
|
|
server=gitea.siegeln.net/cameleer/cameleer3-server:${{ github.sha }}
|
|
kubectl -n cameleer rollout status deployment/cameleer3-server --timeout=120s
|
|
|
|
kubectl apply -f deploy/ui.yaml
|
|
kubectl -n cameleer set image deployment/cameleer3-ui \
|
|
ui=gitea.siegeln.net/cameleer/cameleer3-server-ui:${{ github.sha }}
|
|
kubectl -n cameleer rollout status deployment/cameleer3-ui --timeout=120s
|
|
env:
|
|
REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
|
|
CAMELEER_AUTH_TOKEN: ${{ secrets.CAMELEER_AUTH_TOKEN }}
|
|
CAMELEER_JWT_SECRET: ${{ secrets.CAMELEER_JWT_SECRET }}
|
|
CAMELEER_UI_USER: ${{ secrets.CAMELEER_UI_USER }}
|
|
CAMELEER_UI_PASSWORD: ${{ secrets.CAMELEER_UI_PASSWORD }}
|
|
CLICKHOUSE_USER: ${{ secrets.CLICKHOUSE_USER }}
|
|
CLICKHOUSE_PASSWORD: ${{ secrets.CLICKHOUSE_PASSWORD }}
|
|
AUTHENTIK_PG_USER: ${{ secrets.AUTHENTIK_PG_USER }}
|
|
AUTHENTIK_PG_PASSWORD: ${{ secrets.AUTHENTIK_PG_PASSWORD }}
|
|
AUTHENTIK_SECRET_KEY: ${{ secrets.AUTHENTIK_SECRET_KEY }}
|
|
CAMELEER_OIDC_ENABLED: ${{ secrets.CAMELEER_OIDC_ENABLED }}
|
|
CAMELEER_OIDC_ISSUER: ${{ secrets.CAMELEER_OIDC_ISSUER }}
|
|
CAMELEER_OIDC_CLIENT_ID: ${{ secrets.CAMELEER_OIDC_CLIENT_ID }}
|
|
CAMELEER_OIDC_CLIENT_SECRET: ${{ secrets.CAMELEER_OIDC_CLIENT_SECRET }}
|