commit b320dfbe2bd2e754c21f6e55b57bf6015ffb1ecb
parent e88dba7dc57972ce7ea0527665a8b9855c9aabc5
Author: MTRNord <MTRNord@users.noreply.github.com>
Date: Thu, 9 Apr 2026 22:56:18 +0200
try to set up jenkins
Signed-off-by: MTRNord <MTRNord@users.noreply.github.com>
Diffstat:
8 files changed, 644 insertions(+), 2 deletions(-)
diff --git a/Jenkinsfile b/Jenkinsfile
@@ -0,0 +1,304 @@
+pipeline {
+ agent any
+
+ options {
+ timestamps()
+ timeout(time: 4, unit: 'HOURS')
+ buildDiscarder(logRotator(numToKeepStr: '10', artifactNumToKeepStr: '5'))
+ }
+
+ parameters {
+ choice(
+ name: 'BUILD_IMAGE',
+ choices: ['matrix-backup', 'continuwuity', 'blog', 'bookwyrm', 'all'],
+ description: 'Which image(s) to build'
+ )
+ }
+
+ environment {
+ REGISTRY = 'registry.midnightthoughts.space'
+ REGISTRY_URL = 'https://registry.midnightthoughts.space'
+ DOCKER_CONFIG = '/var/run/secrets/docker.io'
+ COSIGN_KEY_PATH = '/var/run/secrets/cosign/key'
+ }
+
+ stages {
+ stage('Prepare Build Environment') {
+ steps {
+ script {
+ echo "=== Preparing multi-arch build environment ==="
+ sh '''
+ # Register QEMU handlers for multi-arch builds
+ docker run --rm --privileged multiarch/qemu-user-static --reset -p yes || true
+
+ # Verify QEMU is registered
+ ls -la /proc/sys/fs/binfmt_misc/ || echo "binfmt_misc not available"
+
+ # Enable buildx for multi-arch support
+ docker buildx create --use --name multiarch-builder || docker buildx use multiarch-builder
+ docker buildx inspect --bootstrap
+ '''
+ }
+ }
+ }
+
+ stage('Clone Repository') {
+ steps {
+ checkout scm
+ }
+ }
+
+ stage('Build Images') {
+ parallel {
+ stage('matrix-backup') {
+ when {
+ expression { params.BUILD_IMAGE == 'matrix-backup' || params.BUILD_IMAGE == 'all' }
+ }
+ steps {
+ script {
+ build_matrix_backup()
+ }
+ }
+ }
+
+ stage('continuwuity') {
+ when {
+ expression { params.BUILD_IMAGE == 'continuwuity' || params.BUILD_IMAGE == 'all' }
+ }
+ steps {
+ script {
+ build_continuwuity()
+ }
+ }
+ }
+
+ stage('blog') {
+ when {
+ expression { params.BUILD_IMAGE == 'blog' || params.BUILD_IMAGE == 'all' }
+ }
+ steps {
+ script {
+ build_blog()
+ }
+ }
+ }
+
+ stage('bookwyrm') {
+ when {
+ expression { params.BUILD_IMAGE == 'bookwyrm' || params.BUILD_IMAGE == 'all' }
+ }
+ steps {
+ script {
+ build_bookwyrm()
+ }
+ }
+ }
+ }
+ }
+ }
+
+ post {
+ always {
+ cleanWs()
+ }
+ success {
+ echo "✓ Build pipeline completed successfully!"
+ }
+ failure {
+ echo "✗ Build pipeline failed!"
+ }
+ }
+}
+
+def build_matrix_backup() {
+ echo "=== Building matrix-backup ==="
+ docker.image('docker:latest').inside('--privileged') {
+ sh '''
+ set -eu
+
+ # Configure Docker login
+ mkdir -p ~/.docker
+ cp ${DOCKER_CONFIG}/config.json ~/.docker/config.json 2>/dev/null || true
+
+ # Get image metadata
+ TAG_TS=$(date -u +%Y%m%d-%H%M%S)
+ TAG_SHA="sha-$(git rev-parse --short HEAD)"
+ IMAGE="${REGISTRY}/mtrnord/cluster/matrix-backup"
+
+ echo "Building multi-arch image: ${IMAGE}"
+ echo "Tags: ${TAG_TS}, main, ${TAG_SHA}"
+
+ # Build and push multi-arch image
+ docker buildx build \
+ --platform linux/amd64,linux/arm64 \
+ --tag "${IMAGE}:${TAG_TS}" \
+ --tag "${IMAGE}:main" \
+ --tag "${IMAGE}:${TAG_SHA}" \
+ --push \
+ -f apps/talos_cluster/image-builder/matrix-backup/Dockerfile \
+ apps/talos_cluster/image-builder/matrix-backup/
+
+ # Sign all pushed digests with cosign
+ docker run --rm \
+ -v ${COSIGN_KEY_PATH}:/cosign/key:ro \
+ -v ~/.docker:/root/.docker:ro \
+ gcr.io/projectsigstore/cosign:latest \
+ sign --key /cosign/key "${IMAGE}:${TAG_TS}"
+
+ docker run --rm \
+ -v ${COSIGN_KEY_PATH}:/cosign/key:ro \
+ -v ~/.docker:/root/.docker:ro \
+ gcr.io/projectsigstore/cosign:latest \
+ sign --key /cosign/key "${IMAGE}:main"
+
+ docker run --rm \
+ -v ${COSIGN_KEY_PATH}:/cosign/key:ro \
+ -v ~/.docker:/root/.docker:ro \
+ gcr.io/projectsigstore/cosign:latest \
+ sign --key /cosign/key "${IMAGE}:${TAG_SHA}"
+ '''
+ }
+}
+
+def build_continuwuity() {
+ echo "=== Building continuwuity ==="
+ docker.image('docker:latest').inside('--privileged') {
+ sh '''
+ set -eu
+
+ # Configure Docker login
+ mkdir -p ~/.docker
+ cp ${DOCKER_CONFIG}/config.json ~/.docker/config.json 2>/dev/null || true
+
+ # Get image metadata
+ TAG_SHA="sha-$(git rev-parse --short HEAD)"
+ IMAGE="${REGISTRY}/mtrnord/cluster/continuwuity"
+
+ echo "Building multi-arch image: ${IMAGE}"
+ echo "Tags: main, ${TAG_SHA}"
+
+ # Build and push multi-arch image
+ docker buildx build \
+ --platform linux/amd64,linux/arm64 \
+ --tag "${IMAGE}:main" \
+ --tag "${IMAGE}:${TAG_SHA}" \
+ --push \
+ -f apps/talos_cluster/image-builder/continuwuity/Dockerfile \
+ apps/talos_cluster/image-builder/continuwuity/
+
+ # Sign all pushed digests with cosign
+ docker run --rm \
+ -v ${COSIGN_KEY_PATH}:/cosign/key:ro \
+ -v ~/.docker:/root/.docker:ro \
+ gcr.io/projectsigstore/cosign:latest \
+ sign --key /cosign/key "${IMAGE}:main"
+
+ docker run --rm \
+ -v ${COSIGN_KEY_PATH}:/cosign/key:ro \
+ -v ~/.docker:/root/.docker:ro \
+ gcr.io/projectsigstore/cosign:latest \
+ sign --key /cosign/key "${IMAGE}:${TAG_SHA}"
+ '''
+ }
+}
+
+def build_blog() {
+ echo "=== Building blog ==="
+ docker.image('docker:latest').inside('--privileged') {
+ sh '''
+ set -eu
+
+ # Configure Docker login
+ mkdir -p ~/.docker
+ cp ${DOCKER_CONFIG}/config.json ~/.docker/config.json 2>/dev/null || true
+
+ # Get image metadata
+ TAG_TS=$(date -u +%Y%m%d-%H%M%S)
+ TAG_SHA="sha-$(git rev-parse --short HEAD)"
+ IMAGE="${REGISTRY}/mtrnord/blog"
+
+ echo "Building multi-arch image: ${IMAGE}"
+ echo "Tags: ${TAG_TS}, latest, ${TAG_SHA}"
+
+ # Build and push multi-arch image
+ docker buildx build \
+ --platform linux/amd64,linux/arm64 \
+ --tag "${IMAGE}:${TAG_TS}" \
+ --tag "${IMAGE}:latest" \
+ --tag "${IMAGE}:${TAG_SHA}" \
+ --push \
+ -f apps/talos_cluster/image-builder/blog/Dockerfile \
+ apps/talos_cluster/image-builder/blog/
+
+ # Sign all pushed digests with cosign
+ docker run --rm \
+ -v ${COSIGN_KEY_PATH}:/cosign/key:ro \
+ -v ~/.docker:/root/.docker:ro \
+ gcr.io/projectsigstore/cosign:latest \
+ sign --key /cosign/key "${IMAGE}:${TAG_TS}"
+
+ docker run --rm \
+ -v ${COSIGN_KEY_PATH}:/cosign/key:ro \
+ -v ~/.docker:/root/.docker:ro \
+ gcr.io/projectsigstore/cosign:latest \
+ sign --key /cosign/key "${IMAGE}:latest"
+
+ docker run --rm \
+ -v ${COSIGN_KEY_PATH}:/cosign/key:ro \
+ -v ~/.docker:/root/.docker:ro \
+ gcr.io/projectsigstore/cosign:latest \
+ sign --key /cosign/key "${IMAGE}:${TAG_SHA}"
+ '''
+ }
+}
+
+def build_bookwyrm() {
+ echo "=== Building bookwyrm ==="
+ docker.image('docker:latest').inside('--privileged') {
+ sh '''
+ set -eu
+
+ # Configure Docker login
+ mkdir -p ~/.docker
+ cp ${DOCKER_CONFIG}/config.json ~/.docker/config.json 2>/dev/null || true
+
+ # Get upstream version
+ VERSION=$(docker run --rm curlimages/curl:latest \
+ curl -sf "https://api.github.com/repos/bookwyrm-social/bookwyrm/releases/latest" | \
+ grep '"tag_name"' | head -1 | cut -d'"' -f4)
+
+ if [ -z "$VERSION" ]; then
+ echo "ERROR: could not determine upstream version"
+ exit 1
+ fi
+
+ IMAGE="${REGISTRY}/mtrnord/cluster/bookwyrm"
+
+ echo "Building multi-arch image: ${IMAGE}"
+ echo "Tags: ${VERSION}, latest"
+
+ # Build and push multi-arch image
+ docker buildx build \
+ --platform linux/amd64,linux/arm64 \
+ --build-arg VERSION="${VERSION}" \
+ --tag "${IMAGE}:${VERSION}" \
+ --tag "${IMAGE}:latest" \
+ --push \
+ -f apps/talos_cluster/image-builder/bookwyrm/Dockerfile \
+ apps/talos_cluster/image-builder/bookwyrm/
+
+ # Sign all pushed digests with cosign
+ docker run --rm \
+ -v ${COSIGN_KEY_PATH}:/cosign/key:ro \
+ -v ~/.docker:/root/.docker:ro \
+ gcr.io/projectsigstore/cosign:latest \
+ sign --key /cosign/key "${IMAGE}:${VERSION}"
+
+ docker run --rm \
+ -v ${COSIGN_KEY_PATH}:/cosign/key:ro \
+ -v ~/.docker:/root/.docker:ro \
+ gcr.io/projectsigstore/cosign:latest \
+ sign --key /cosign/key "${IMAGE}:latest"
+ '''
+ }
+}
diff --git a/apps/talos_cluster/envoy-gateway/gateway_settings.yaml b/apps/talos_cluster/envoy-gateway/gateway_settings.yaml
@@ -833,6 +833,18 @@ spec:
certificateRefs:
- kind: Secret
name: registry.midnightthoughts.space-tls
+ - name: https-jenkins-midnightthoughts
+ protocol: HTTPS
+ hostname: jenkins.midnightthoughts.space
+ port: 443
+ allowedRoutes:
+ namespaces:
+ from: All
+ tls:
+ mode: Terminate
+ certificateRefs:
+ - kind: Secret
+ name: jenkins.midnightthoughts.space-tls
- name: http
protocol: HTTP
port: 80
diff --git a/apps/talos_cluster/jenkins/helm-repository.yaml b/apps/talos_cluster/jenkins/helm-repository.yaml
@@ -0,0 +1,8 @@
+apiVersion: source.toolkit.fluxcd.io/v1beta2
+kind: HelmRepository
+metadata:
+ name: jenkins-operator
+ namespace: jenkins
+spec:
+ interval: 1h
+ url: https://raw.githubusercontent.com/jenkinsci/kubernetes-operator/master/chart
diff --git a/apps/talos_cluster/jenkins/jenkins-instance.yaml b/apps/talos_cluster/jenkins/jenkins-instance.yaml
@@ -0,0 +1,284 @@
+apiVersion: jenkins.io/v1alpha2
+kind: Jenkins
+metadata:
+ name: jenkins
+ namespace: jenkins
+spec:
+ # Enable security validation
+ validateSecurityWarnings: true
+ # Configuration as Code
+ configurationAsCode:
+ configurations:
+ - name: jenkins-casc
+ content: ENC[AES256_GCM,data:lmtOI2KiZWTwq4H6oBcu0syAe9K0Zc+VQ8NhIHXmStzyGtPrlfvDZCxp2nJ6v5FZIsr7kcue+mnbtYpCFeFv1amYmqs1HDPnh/eTePt6/NAP9onaTzHtzGlVwl6gNr/5kXYZJO0dxVELHqejGwREAOyCY2+Ld1eip1UEKii0WfJAYKk1diD927YN2OKDbSv/aCI3XeLEtV9TbUCZojoazZSbfrTNwhx8XFA5D5OgQVFKCHvhOxLjAY5F4G66km5FlMGksJFcEMhpWvtT+H124RfcB5gmJalXQmhLZMocZvcHcXyDX1Ox10T/WP07be7I2lQttDi8l6rHF3cssTzL5Opw1XuJkHG3gmXoVD76Tf261vFJLUDe8FfcfDxcW3wyZvSljCJsAZ39Lrbwj76sFA1YiA7mS8EPEbR9MNWY5N7al6pIB4jShupFf7TnmcgKrNxopOlZSP40qWXH4QrGgihwF01KBuyKGV9D/5P61V9AY7TBGpYK+jTGTYKm+fvgJ2PZC+tYwcHD+9VyG0agCBTBZNM/R1TqCu5QzOdj9SJHlOM4otbZxsE/zHMZYlQVzBTlu1uNJPYNsfxsqJRyfX8zBGZsJ1kTRonYacUhE2LGopqkVvs0lOa5WHkMIsxPjPFzViDcjp6+0DGdXqii7molz84vwB+gGoPLSXwnfGCHcjXDmsNiASD4wrbDXJ4n/Ug0ch/r7sa7SonX/UIHHga7pLOFnZJw6V4QwDAv9nZh3MC4CowZxIjgCcSCewXVvt5jvak9LygapZIgdT+qR9KcSS2iOJlPyBG9JBPQP94hU2M9KafmHE1e01qxyBqptosbh4PpkVlUjrFgDtXC6qJQw43HgAyXoII2GJCHd5M+/WuCuxdSTkzVLV0ZHcF0aSKQcFIbNnuFGcbDmFflX2mha/qeeKbGRM2ieOTn7EqfPLMHmouPYlE8QwkxmZYSy6FMOjMWrSg/Bgu3S/5DGPvFTcv1KeWwUScJ7dxiOH/ujQee5NJ/mrZ4Hyl5TMlqQU0i9K87pDte7s0JXy0Gkdl6t4uttFlRSrOFNHrKDvg32ePBqPKk1CVmhnZw9edjA2dBbdhIGGHalXOkkqVFcOYCjQgfJxD+9zH3vozGDdfs1n/BQQxcvB1CbBNWWEjWgP5VCer0PVG1qA7SjcF9YUL/Qbd5j7a/5/UjqDyZnEp7ztnUkuqUn5ySTiWut/VRbuf1diDOliyeTmOgOJ+sMcMFTIt28Def1sirHlVmDFMO,iv:D6oladjgKIpT/F7H542ciASjAkz9OhdZDxUb5RPXNVQ=,tag:JN/gUMq+qwhh0Q+PgTFc9A==,type:str]
+ # API settings - IMPORTANT: jenkins-operator user must have admin rights
+ jenkinsAPISettings:
+ authorizationStrategy: createUser
+ # Service configuration
+ service:
+ type: ClusterIP
+ port: 8080
+ slaveService:
+ type: ClusterIP
+ port: 50000
+ # Master/Controller pod specification
+ master:
+ # Use specific LTS version instead of latest (best practice)
+ image: jenkins/jenkins:2.541.3-lts
+ imagePullPolicy: IfNotPresent
+ # Security context - run as jenkins user (1000)
+ securityContext:
+ runAsUser: 1000
+ fsGroup: 1000
+ # Disable CSRF protection is not recommended - keep enabled (default)
+ disableCSRFProtection: false
+ # Annotations and labels
+ annotations:
+ description: Jenkins instance for multi-arch container builds
+ labels:
+ app: jenkins
+ version: lts
+ # Base plugins (required by operator)
+ basePlugins:
+ - name: kubernetes
+ version: 4423.vb_59f230b_ce53
+ - name: workflow-job
+ version: 1573.v1465f6f78810
+ - name: workflow-aggregator
+ version: 608.v67378e9d3db_1
+ - name: git
+ version: 5.10.1
+ - name: job-dsl
+ version: 3654.vdf58f53e2d15
+ - name: configuration-as-code
+ version: 2065.v7a_20a_b_d84088
+ - name: kubernetes-credentials-provider
+ version: 1.303.vdfcf47fb_b_fef
+ # Additional plugins for our use case
+ plugins:
+ - name: oic-auth
+ version: 4.668.v653c6b_c6cb_f5
+ - name: matrix-auth
+ version: 3.2.9
+ - name: pipeline-stage-view
+ version: "2.39"
+ - name: generic-webhook-trigger
+ version: 2.4.1
+ - name: timestamper
+ version: "1.30"
+ - name: ansicolor
+ version: 536.v13fa_b_860c267
+ - name: docker-workflow
+ version: 634.vedc7242b_eda_7
+ # Container specification
+ containers:
+ - name: jenkins-master
+ image: jenkins/jenkins:2.440.1-lts
+ imagePullPolicy: IfNotPresent
+ # Security context for container
+ securityContext:
+ # Allow privileged for Docker socket access
+ privileged: true
+ allowPrivilegeEscalation: true
+ # Environment variables
+ env:
+ - name: JAVA_OPTS
+ value: -Djenkins.install.runSetupWizard=false -Djenkins.model.Jenkins.crumbIssuerProxyCompatibility=true -Dorg.jenkinsci.plugins.matrixauth.inheritance.InheritParentStrategy=true
+ # Liveness probe
+ livenessProbe:
+ failureThreshold: 12
+ httpGet:
+ path: /login
+ port: 8080
+ scheme: HTTP
+ initialDelaySeconds: 100
+ periodSeconds: 10
+ successThreshold: 1
+ timeoutSeconds: 5
+ # Readiness probe
+ readinessProbe:
+ failureThreshold: 10
+ httpGet:
+ path: /login
+ port: 8080
+ scheme: HTTP
+ initialDelaySeconds: 80
+ periodSeconds: 10
+ successThreshold: 1
+ timeoutSeconds: 1
+ # Resource management
+ resources:
+ limits:
+ cpu: 1500m
+ memory: 2Gi
+ requests:
+ cpu: 500m
+ memory: 1Gi
+ # Port configuration
+ ports:
+ - containerPort: 8080
+ name: http
+ protocol: TCP
+ - containerPort: 50000
+ name: agent
+ protocol: TCP
+ # Volume mounts
+ volumeMounts:
+ - name: jenkins-home
+ mountPath: /var/jenkins_home
+ - name: registry-secret
+ mountPath: /var/run/secrets/docker.io
+ readOnly: true
+ - name: cosign-key
+ mountPath: /var/run/secrets/cosign
+ readOnly: true
+ - name: docker-sock
+ mountPath: /var/run/docker.sock
+ # Volumes
+ volumes:
+ - name: jenkins-home
+ persistentVolumeClaim:
+ claimName: jenkins-home
+ - name: registry-secret
+ secret:
+ secretName: ENC[AES256_GCM,data:7USvSu9F1aAzUvE5GsVwJJVhwAg=,iv:gjniozAMy7KJbN92QTUz/dF1GJxd4cCNMry0foTi/ig=,tag:b1j7RzItnt+Ck+gmnBBgIQ==,type:str]
+ defaultMode: ENC[AES256_GCM,data:XRRC,iv:OhIgPF2mFh3kvms/rH58YeL2pmYUeWCSO7PDuhZpUZE=,tag:M77Kj3TEHZ0/ZOClsCF2xA==,type:int]
+ - name: cosign-key
+ secret:
+ secretName: ENC[AES256_GCM,data:ikUpHd2Wf3Xrc6l6C6Q15cJF,iv:kyJMlr5Mt0zHnQF2zrxZOgtGrEcg9F1PW5mav2OCgTE=,tag:vVnYPpGRWVljMbfaKos8qA==,type:str]
+ defaultMode: ENC[AES256_GCM,data:d958,iv:yEtCjaXo2Ai0ARBYIT+zCNdlkgMgRI3WO5iy1VEMNn4=,tag:0t/3muHtG//KomxrpmTQyQ==,type:int]
+ - name: docker-sock
+ hostPath:
+ path: /var/run/docker.sock
+ type: Socket
+sops:
+ kms: []
+ gcp_kms: []
+ azure_kv: []
+ hc_vault: []
+ age:
+ - recipient: age1esjyg2qfy49awv0ptkzvpk425adczjr38m37w2mmcahzc4p8n54sll2nzh
+ enc: |
+ -----BEGIN AGE ENCRYPTED FILE-----
+ YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSByOWRrKzUrSUxXUlhSdTlY
+ MkdYM0dOZ0JNaXU0cmp3MS9PcHR1LzJSN1dJCmhGYmw4TGVPNEpEWnlnQlV2Yjhh
+ Vi8yK21xZjBldXduWXhNZ3hNSFoyY1kKLS0tIGR5L1FWS2FxYkhHR3JWcXBFTjEr
+ dHkrRVI5c3FBeUxFL2ZyL09Sd2hIZ3cKsDbe8WLlZXSTWpKKY5dx21cEKOxFFtw+
+ 3DUtEJqIOAYdgxoFv/+Z4E44VtzLuA0swPk3DzY+bPvax31vZMdYkg==
+ -----END AGE ENCRYPTED FILE-----
+ lastmodified: "2026-04-09T20:54:47Z"
+ mac: ENC[AES256_GCM,data:Q1tSbclL62fLqa+FB1H6eFGqclWSkdVYTiOvnj8nJrWQxd1OGv/VVmTK6CRHpQKDJhro0H163X/Rmw2pUrw0DC30DAjbq+DxRDpYTr8BEcDT/u7mb1xNC093fSPcdRMvnOK+Jbq7Inv9XwlMAoG3NlNqNEgnInYxG10AnW9O4J4=,iv:xtZpt0c4mbh0XdDyOjwkwGZWD9ESycr8GyHptLfTp0M=,tag:pQVI7DcO0RidAoIUDa7oZw==,type:str]
+ pgp: []
+ encrypted_regex: ^(apiKey|appUserPassword|otelUserPassword|harborAdminPassword|totpVaultKey|kimaiAppSecret|kimaiAdminPassword|GITHUB_CLIENT_ID|GITHUB_CLIENT_SECRET|GITHUB_PRIVATE_KEY|woosh|root_password|rspamd_password|pgdb_password|matrix_access_token|pgdb_remote_url|hmac_secret_key|adminPassword|adminEmail|jenkinsAdminEmail|securityRealm|gerrit.config|routing_key|DATABASE_URL|SMTP_PASSWORD|SECRET_KEY_BASE|admin_password|extraCommands|key|clickhouseDatabaseURL|databaseURL|client_id|client_secret|secret_key_base|otp_secret|private_key|public_key|primaryKey|deterministicKey|keyDerivationSalt|token|clientId|secretKey|installationId|installationKey|uriOverride|adminToken.value|password.value|sql_password|erlangCookie|AUTHENTICATION_PASSWORD|ROOM_API_SECRET_KEY|adminPassword|configPassword|adminUser|configUser|MAIL_PASSWORD|APP_KEY|api_key|api_secret|keys|livekit_key|livekit_secret|secret_key|admin_pass|admin_email|mariadbPassword|mariadbRootPassword|privateKey|data|stringData|PASSWD|password|pass|postgresPassword|smtp_auth_password|addresses|smtp_auth_username|authorization_credentials|postgresqlPassword|redminePassword|smtpPassword|registration_shared_secret|shared_secret|secret|admin_token|integrationKey|integration_key|rootPassword|adminPassword|adminUser|adminEmail|emailPassword|secretKey|appId|clientSecret|webhookSecret|content)$
+ version: 3.9.1
+---
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+ name: jenkins-home
+ namespace: jenkins
+spec:
+ accessModes:
+ - ReadWriteOnce
+ resources:
+ requests:
+ storage: 10Gi
+ storageClassName: longhorn-2replicas
+sops:
+ kms: []
+ gcp_kms: []
+ azure_kv: []
+ hc_vault: []
+ age:
+ - recipient: age1esjyg2qfy49awv0ptkzvpk425adczjr38m37w2mmcahzc4p8n54sll2nzh
+ enc: |
+ -----BEGIN AGE ENCRYPTED FILE-----
+ YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSByOWRrKzUrSUxXUlhSdTlY
+ MkdYM0dOZ0JNaXU0cmp3MS9PcHR1LzJSN1dJCmhGYmw4TGVPNEpEWnlnQlV2Yjhh
+ Vi8yK21xZjBldXduWXhNZ3hNSFoyY1kKLS0tIGR5L1FWS2FxYkhHR3JWcXBFTjEr
+ dHkrRVI5c3FBeUxFL2ZyL09Sd2hIZ3cKsDbe8WLlZXSTWpKKY5dx21cEKOxFFtw+
+ 3DUtEJqIOAYdgxoFv/+Z4E44VtzLuA0swPk3DzY+bPvax31vZMdYkg==
+ -----END AGE ENCRYPTED FILE-----
+ lastmodified: "2026-04-09T20:54:47Z"
+ mac: ENC[AES256_GCM,data:Q1tSbclL62fLqa+FB1H6eFGqclWSkdVYTiOvnj8nJrWQxd1OGv/VVmTK6CRHpQKDJhro0H163X/Rmw2pUrw0DC30DAjbq+DxRDpYTr8BEcDT/u7mb1xNC093fSPcdRMvnOK+Jbq7Inv9XwlMAoG3NlNqNEgnInYxG10AnW9O4J4=,iv:xtZpt0c4mbh0XdDyOjwkwGZWD9ESycr8GyHptLfTp0M=,tag:pQVI7DcO0RidAoIUDa7oZw==,type:str]
+ pgp: []
+ encrypted_regex: ^(apiKey|appUserPassword|otelUserPassword|harborAdminPassword|totpVaultKey|kimaiAppSecret|kimaiAdminPassword|GITHUB_CLIENT_ID|GITHUB_CLIENT_SECRET|GITHUB_PRIVATE_KEY|woosh|root_password|rspamd_password|pgdb_password|matrix_access_token|pgdb_remote_url|hmac_secret_key|adminPassword|adminEmail|jenkinsAdminEmail|securityRealm|gerrit.config|routing_key|DATABASE_URL|SMTP_PASSWORD|SECRET_KEY_BASE|admin_password|extraCommands|key|clickhouseDatabaseURL|databaseURL|client_id|client_secret|secret_key_base|otp_secret|private_key|public_key|primaryKey|deterministicKey|keyDerivationSalt|token|clientId|secretKey|installationId|installationKey|uriOverride|adminToken.value|password.value|sql_password|erlangCookie|AUTHENTICATION_PASSWORD|ROOM_API_SECRET_KEY|adminPassword|configPassword|adminUser|configUser|MAIL_PASSWORD|APP_KEY|api_key|api_secret|keys|livekit_key|livekit_secret|secret_key|admin_pass|admin_email|mariadbPassword|mariadbRootPassword|privateKey|data|stringData|PASSWD|password|pass|postgresPassword|smtp_auth_password|addresses|smtp_auth_username|authorization_credentials|postgresqlPassword|redminePassword|smtpPassword|registration_shared_secret|shared_secret|secret|admin_token|integrationKey|integration_key|rootPassword|adminPassword|adminUser|adminEmail|emailPassword|secretKey|appId|clientSecret|webhookSecret|content)$
+ version: 3.9.1
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: jenkins
+ namespace: jenkins
+spec:
+ type: ClusterIP
+ selector:
+ jenkins.io/instance: jenkins
+ ports:
+ - port: 8080
+ targetPort: 8080
+ name: http
+ protocol: TCP
+ - port: 50000
+ targetPort: 50000
+ name: agent
+ protocol: TCP
+sops:
+ kms: []
+ gcp_kms: []
+ azure_kv: []
+ hc_vault: []
+ age:
+ - recipient: age1esjyg2qfy49awv0ptkzvpk425adczjr38m37w2mmcahzc4p8n54sll2nzh
+ enc: |
+ -----BEGIN AGE ENCRYPTED FILE-----
+ YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSByOWRrKzUrSUxXUlhSdTlY
+ MkdYM0dOZ0JNaXU0cmp3MS9PcHR1LzJSN1dJCmhGYmw4TGVPNEpEWnlnQlV2Yjhh
+ Vi8yK21xZjBldXduWXhNZ3hNSFoyY1kKLS0tIGR5L1FWS2FxYkhHR3JWcXBFTjEr
+ dHkrRVI5c3FBeUxFL2ZyL09Sd2hIZ3cKsDbe8WLlZXSTWpKKY5dx21cEKOxFFtw+
+ 3DUtEJqIOAYdgxoFv/+Z4E44VtzLuA0swPk3DzY+bPvax31vZMdYkg==
+ -----END AGE ENCRYPTED FILE-----
+ lastmodified: "2026-04-09T20:54:47Z"
+ mac: ENC[AES256_GCM,data:Q1tSbclL62fLqa+FB1H6eFGqclWSkdVYTiOvnj8nJrWQxd1OGv/VVmTK6CRHpQKDJhro0H163X/Rmw2pUrw0DC30DAjbq+DxRDpYTr8BEcDT/u7mb1xNC093fSPcdRMvnOK+Jbq7Inv9XwlMAoG3NlNqNEgnInYxG10AnW9O4J4=,iv:xtZpt0c4mbh0XdDyOjwkwGZWD9ESycr8GyHptLfTp0M=,tag:pQVI7DcO0RidAoIUDa7oZw==,type:str]
+ pgp: []
+ encrypted_regex: ^(apiKey|appUserPassword|otelUserPassword|harborAdminPassword|totpVaultKey|kimaiAppSecret|kimaiAdminPassword|GITHUB_CLIENT_ID|GITHUB_CLIENT_SECRET|GITHUB_PRIVATE_KEY|woosh|root_password|rspamd_password|pgdb_password|matrix_access_token|pgdb_remote_url|hmac_secret_key|adminPassword|adminEmail|jenkinsAdminEmail|securityRealm|gerrit.config|routing_key|DATABASE_URL|SMTP_PASSWORD|SECRET_KEY_BASE|admin_password|extraCommands|key|clickhouseDatabaseURL|databaseURL|client_id|client_secret|secret_key_base|otp_secret|private_key|public_key|primaryKey|deterministicKey|keyDerivationSalt|token|clientId|secretKey|installationId|installationKey|uriOverride|adminToken.value|password.value|sql_password|erlangCookie|AUTHENTICATION_PASSWORD|ROOM_API_SECRET_KEY|adminPassword|configPassword|adminUser|configUser|MAIL_PASSWORD|APP_KEY|api_key|api_secret|keys|livekit_key|livekit_secret|secret_key|admin_pass|admin_email|mariadbPassword|mariadbRootPassword|privateKey|data|stringData|PASSWD|password|pass|postgresPassword|smtp_auth_password|addresses|smtp_auth_username|authorization_credentials|postgresqlPassword|redminePassword|smtpPassword|registration_shared_secret|shared_secret|secret|admin_token|integrationKey|integration_key|rootPassword|adminPassword|adminUser|adminEmail|emailPassword|secretKey|appId|clientSecret|webhookSecret|content)$
+ version: 3.9.1
+---
+apiVersion: gateway.networking.k8s.io/v1
+kind: HTTPRoute
+metadata:
+ name: jenkins
+ namespace: jenkins
+spec:
+ parentRefs:
+ - name: envoy-gateway
+ namespace: envoy-gateway
+ hostnames:
+ - jenkins.midnightthoughts.space
+ rules:
+ - backendRefs:
+ - name: jenkins
+ port: 8080
+ timeouts:
+ request: 600s
+ backendRequest: 0s
+sops:
+ kms: []
+ gcp_kms: []
+ azure_kv: []
+ hc_vault: []
+ age:
+ - recipient: age1esjyg2qfy49awv0ptkzvpk425adczjr38m37w2mmcahzc4p8n54sll2nzh
+ enc: |
+ -----BEGIN AGE ENCRYPTED FILE-----
+ YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSByOWRrKzUrSUxXUlhSdTlY
+ MkdYM0dOZ0JNaXU0cmp3MS9PcHR1LzJSN1dJCmhGYmw4TGVPNEpEWnlnQlV2Yjhh
+ Vi8yK21xZjBldXduWXhNZ3hNSFoyY1kKLS0tIGR5L1FWS2FxYkhHR3JWcXBFTjEr
+ dHkrRVI5c3FBeUxFL2ZyL09Sd2hIZ3cKsDbe8WLlZXSTWpKKY5dx21cEKOxFFtw+
+ 3DUtEJqIOAYdgxoFv/+Z4E44VtzLuA0swPk3DzY+bPvax31vZMdYkg==
+ -----END AGE ENCRYPTED FILE-----
+ lastmodified: "2026-04-09T20:54:47Z"
+ mac: ENC[AES256_GCM,data:Q1tSbclL62fLqa+FB1H6eFGqclWSkdVYTiOvnj8nJrWQxd1OGv/VVmTK6CRHpQKDJhro0H163X/Rmw2pUrw0DC30DAjbq+DxRDpYTr8BEcDT/u7mb1xNC093fSPcdRMvnOK+Jbq7Inv9XwlMAoG3NlNqNEgnInYxG10AnW9O4J4=,iv:xtZpt0c4mbh0XdDyOjwkwGZWD9ESycr8GyHptLfTp0M=,tag:pQVI7DcO0RidAoIUDa7oZw==,type:str]
+ pgp: []
+ encrypted_regex: ^(apiKey|appUserPassword|otelUserPassword|harborAdminPassword|totpVaultKey|kimaiAppSecret|kimaiAdminPassword|GITHUB_CLIENT_ID|GITHUB_CLIENT_SECRET|GITHUB_PRIVATE_KEY|woosh|root_password|rspamd_password|pgdb_password|matrix_access_token|pgdb_remote_url|hmac_secret_key|adminPassword|adminEmail|jenkinsAdminEmail|securityRealm|gerrit.config|routing_key|DATABASE_URL|SMTP_PASSWORD|SECRET_KEY_BASE|admin_password|extraCommands|key|clickhouseDatabaseURL|databaseURL|client_id|client_secret|secret_key_base|otp_secret|private_key|public_key|primaryKey|deterministicKey|keyDerivationSalt|token|clientId|secretKey|installationId|installationKey|uriOverride|adminToken.value|password.value|sql_password|erlangCookie|AUTHENTICATION_PASSWORD|ROOM_API_SECRET_KEY|adminPassword|configPassword|adminUser|configUser|MAIL_PASSWORD|APP_KEY|api_key|api_secret|keys|livekit_key|livekit_secret|secret_key|admin_pass|admin_email|mariadbPassword|mariadbRootPassword|privateKey|data|stringData|PASSWD|password|pass|postgresPassword|smtp_auth_password|addresses|smtp_auth_username|authorization_credentials|postgresqlPassword|redminePassword|smtpPassword|registration_shared_secret|shared_secret|secret|admin_token|integrationKey|integration_key|rootPassword|adminPassword|adminUser|adminEmail|emailPassword|secretKey|appId|clientSecret|webhookSecret|content)$
+ version: 3.9.1
diff --git a/apps/talos_cluster/jenkins/kustomization.yaml b/apps/talos_cluster/jenkins/kustomization.yaml
@@ -0,0 +1,11 @@
+apiVersion: kustomize.config.k8s.io/v1beta1
+kind: Kustomization
+metadata:
+ name: jenkins
+ namespace: jenkins
+
+resources:
+ - namespace.yaml
+ - helm-repository.yaml
+ - operator-release.yaml
+ - jenkins-instance.yaml
diff --git a/apps/talos_cluster/jenkins/namespace.yaml b/apps/talos_cluster/jenkins/namespace.yaml
@@ -0,0 +1,4 @@
+apiVersion: v1
+kind: Namespace
+metadata:
+ name: jenkins
diff --git a/apps/talos_cluster/jenkins/operator-release.yaml b/apps/talos_cluster/jenkins/operator-release.yaml
@@ -0,0 +1,19 @@
+apiVersion: helm.toolkit.fluxcd.io/v2
+kind: HelmRelease
+metadata:
+ name: jenkins-operator
+ namespace: jenkins
+spec:
+ interval: 1h
+ releaseName: jenkins-operator
+ chart:
+ spec:
+ chart: jenkins-operator
+ sourceRef:
+ kind: HelmRepository
+ name: jenkins-operator
+ namespace: jenkins
+ values:
+ # Disable default Jenkins instance - we'll create our own via CRD
+ jenkins:
+ enabled: false
diff --git a/encrypt.sh b/encrypt.sh
@@ -5,13 +5,13 @@ if [ -z "$1" ]; then
# Encrypt apps/talos_cluster/externaldns/release.yaml as a whole
sops --age=age1esjyg2qfy49awv0ptkzvpk425adczjr38m37w2mmcahzc4p8n54sll2nzh \
--encrypt \
- --encrypted-regex '^(apiKey|appUserPassword|otelUserPassword|extraArgs|harborAdminPassword|totpVaultKey|kimaiAppSecret|kimaiAdminPassword|GITHUB_CLIENT_ID|GITHUB_CLIENT_SECRET|GITHUB_PRIVATE_KEY|woosh|root_password|rspamd_password|pgdb_password|matrix_access_token|pgdb_remote_url|hmac_secret_key|adminPassword|adminEmail|jenkinsAdminEmail|securityRealm|gerrit.config|routing_key|DATABASE_URL|SMTP_PASSWORD|SECRET_KEY_BASE|admin_password|extraCommands|key|clickhouseDatabaseURL|databaseURL|client_id|client_secret|secret_key_base|otp_secret|private_key|public_key|primaryKey|deterministicKey|keyDerivationSalt|token|clientId|secretKey|installationId|installationKey|uriOverride|adminToken.value|password.value|sql_password|erlangCookie|AUTHENTICATION_PASSWORD|ROOM_API_SECRET_KEY|adminPassword|configPassword|adminUser|configUser|MAIL_PASSWORD|APP_KEY|api_key|api_secret|keys|livekit_key|livekit_secret|secret_key|admin_pass|admin_email|mariadbPassword|mariadbRootPassword|privateKey|data|stringData|PASSWD|password|smtp_auth_password|addresses|smtp_auth_username|authorization_credentials||pass|postgresPassword|postgresqlPassword|redminePassword|smtpPassword|registration_shared_secret|shared_secret|secret|admin_token|integrationKey|integration_key|rootPassword|adminPassword|adminUser|adminEmail|emailPassword|secretKey|appId|clientSecret|webhookSecret)$' \
+ --encrypted-regex '^(apiKey|appUserPassword|otelUserPassword|extraArgs|harborAdminPassword|totpVaultKey|kimaiAppSecret|kimaiAdminPassword|GITHUB_CLIENT_ID|GITHUB_CLIENT_SECRET|GITHUB_PRIVATE_KEY|woosh|root_password|rspamd_password|pgdb_password|matrix_access_token|pgdb_remote_url|hmac_secret_key|adminPassword|adminEmail|jenkinsAdminEmail|securityRealm|gerrit.config|routing_key|DATABASE_URL|SMTP_PASSWORD|SECRET_KEY_BASE|admin_password|extraCommands|key|clickhouseDatabaseURL|databaseURL|client_id|client_secret|secret_key_base|otp_secret|private_key|public_key|primaryKey|deterministicKey|keyDerivationSalt|token|clientId|secretKey|installationId|installationKey|uriOverride|adminToken.value|password.value|sql_password|erlangCookie|AUTHENTICATION_PASSWORD|ROOM_API_SECRET_KEY|adminPassword|configPassword|adminUser|configUser|MAIL_PASSWORD|APP_KEY|api_key|api_secret|keys|livekit_key|livekit_secret|secret_key|admin_pass|admin_email|mariadbPassword|mariadbRootPassword|privateKey|data|stringData|PASSWD|password|smtp_auth_password|addresses|smtp_auth_username|authorization_credentials||pass|postgresPassword|postgresqlPassword|redminePassword|smtpPassword|registration_shared_secret|shared_secret|secret|admin_token|integrationKey|integration_key|rootPassword|adminPassword|adminUser|adminEmail|emailPassword|secretKey|appId|clientSecret|webhookSecret|content)$' \
--in-place apps/talos_cluster/externaldns/release2.yaml
else
echo "Encrypting file: $1"
sops --age=age1esjyg2qfy49awv0ptkzvpk425adczjr38m37w2mmcahzc4p8n54sll2nzh \
--encrypt \
- --encrypted-regex '^(apiKey|appUserPassword|otelUserPassword|harborAdminPassword|totpVaultKey|kimaiAppSecret|kimaiAdminPassword|GITHUB_CLIENT_ID|GITHUB_CLIENT_SECRET|GITHUB_PRIVATE_KEY|woosh|root_password|rspamd_password|pgdb_password|matrix_access_token|pgdb_remote_url|hmac_secret_key|adminPassword|adminEmail|jenkinsAdminEmail|securityRealm|gerrit.config|routing_key|DATABASE_URL|SMTP_PASSWORD|SECRET_KEY_BASE|admin_password|extraCommands|key|clickhouseDatabaseURL|databaseURL|client_id|client_secret|secret_key_base|otp_secret|private_key|public_key|primaryKey|deterministicKey|keyDerivationSalt|token|clientId|secretKey|installationId|installationKey|uriOverride|adminToken.value|password.value|sql_password|erlangCookie|AUTHENTICATION_PASSWORD|ROOM_API_SECRET_KEY|adminPassword|configPassword|adminUser|configUser|MAIL_PASSWORD|APP_KEY|api_key|api_secret|keys|livekit_key|livekit_secret|secret_key|admin_pass|admin_email|mariadbPassword|mariadbRootPassword|privateKey|data|stringData|PASSWD|password|pass|postgresPassword|smtp_auth_password|addresses|smtp_auth_username|authorization_credentials|postgresqlPassword|redminePassword|smtpPassword|registration_shared_secret|shared_secret|secret|admin_token|integrationKey|integration_key|rootPassword|adminPassword|adminUser|adminEmail|emailPassword|secretKey|appId|clientSecret|webhookSecret)$' \
+ --encrypted-regex '^(apiKey|appUserPassword|otelUserPassword|harborAdminPassword|totpVaultKey|kimaiAppSecret|kimaiAdminPassword|GITHUB_CLIENT_ID|GITHUB_CLIENT_SECRET|GITHUB_PRIVATE_KEY|woosh|root_password|rspamd_password|pgdb_password|matrix_access_token|pgdb_remote_url|hmac_secret_key|adminPassword|adminEmail|jenkinsAdminEmail|securityRealm|gerrit.config|routing_key|DATABASE_URL|SMTP_PASSWORD|SECRET_KEY_BASE|admin_password|extraCommands|key|clickhouseDatabaseURL|databaseURL|client_id|client_secret|secret_key_base|otp_secret|private_key|public_key|primaryKey|deterministicKey|keyDerivationSalt|token|clientId|secretKey|installationId|installationKey|uriOverride|adminToken.value|password.value|sql_password|erlangCookie|AUTHENTICATION_PASSWORD|ROOM_API_SECRET_KEY|adminPassword|configPassword|adminUser|configUser|MAIL_PASSWORD|APP_KEY|api_key|api_secret|keys|livekit_key|livekit_secret|secret_key|admin_pass|admin_email|mariadbPassword|mariadbRootPassword|privateKey|data|stringData|PASSWD|password|pass|postgresPassword|smtp_auth_password|addresses|smtp_auth_username|authorization_credentials|postgresqlPassword|redminePassword|smtpPassword|registration_shared_secret|shared_secret|secret|admin_token|integrationKey|integration_key|rootPassword|adminPassword|adminUser|adminEmail|emailPassword|secretKey|appId|clientSecret|webhookSecret|content)$' \
--in-place "$1"
fi