Two replicas with cache=ispn, clustered through Keycloak's default jdbc-ping stack: discovery runs over the PostgreSQL that is there anyway, so no headless Service and no JGroups wiring. Deployment rather than StatefulSet - Keycloak 26 keeps everything in the database, user sessions included. The chart's defining property is that it has TWO INIT CONTAINERS and needs both. db, health-enabled and metrics-enabled are Keycloak BUILD options (verified in the 26.8.0 option table), the published image is augmented with their defaults, and supplying different ones at runtime makes Keycloak rewrite /opt/keycloak/lib/quarkus at start - which readOnlyRootFilesystem: true forbids and which upstream describes as a start that "creates an image that is mutable". Not setting db is no way out: the probes alone force it, because health-enabled is a build option too. An empty emptyDir over that path fails as well, because QuarkusEntryPoint loads quarkus/quarkus-application.dat before it dispatches any command, `build` included. So one init container seeds the directory into a volume, the next runs `kc.sh build` into it, and the serving container runs `start --optimized` - every container keeping the full hardening baseline, with no documented deviation to carry. Build options therefore exist in exactly one place, and the asymmetry is enforced rather than trusted: the serving container passes no build option at all, and a build option's variable name in keycloak.env fails the render with a message naming it. Hostname handling is the security-relevant part. KC_HOSTNAME is derived from ingress.domain as a full URL (which upstream requires alongside hostname-admin), hostname-strict stays at its default true, and proxy-headers is set rather than optional. The admin hostname is NOT presented as an access control: upstream states that hostname-admin "does not prevent accessing the Administration REST API endpoints via the frontend URL specified by the hostname option", so the chart renders no /admin deny rule and values.yaml, NOTES.txt and the wiki all say in the same words that restricting that API is reverse-proxy work. The management port 9000 is a containerPort and a ClusterIP Service for in-cluster scraping, and is in no Ingress: it serves /health/* and optionally /metrics without authentication. Liveness uses /health/live and deliberately not /health or /health/ready - those include the database, and a liveness probe on them would restart the whole cluster for as long as the database is away. Also in this change: - First PodDisruptionBudget in this repository, which makes it a convention (README section 11): minAvailable as a value, and rendered only while the computed replica count is >= 2, because minAvailable: 1 with one replica blocks every node drain forever with a message that names the PDB rather than the replica count. - First quay.io image, so quay.io joins the trusted registries in ci/trivy/data/ksv0125.yaml - configured rather than suppressed, so AVD-KSV-0125 keeps being able to say something. - Renovate block with NO version constraint, which is the counter-case to garage and stalwart and is measured rather than assumed: docker versioning already excludes the -N rebuild tags, the floating minors and latest/nightly. Three dry-run fixtures are recorded at the block, and against the committed config 26.7.4 offers exactly 26.7.5 (patch) and 26.8.0 (minor). - No automerge exception, by decision (Gitea #83): the global automerge applies, and the minor-upgrade procedure plus `kc.sh update-compatibility` is documented in NOTES.txt instead. - Two upstream defaults deviated from, each with its reason at the value: db-pool-max-size 20 instead of 100 (two replicas at 100 ask a default PostgreSQL for twice its max_connections), and uid 1000 / gid 0 instead of this repo's 20000/1000, because the image declares keycloak:x:1000:0 and chowns its install tree to that pair. Part of #83
110 lines
4.1 KiB
YAML
110 lines
4.1 KiB
YAML
name: Change App-Version
|
|
on:
|
|
workflow_dispatch:
|
|
inputs:
|
|
app-version:
|
|
required: true
|
|
type: string
|
|
description: "change the version of the underlying application"
|
|
chart-location:
|
|
required: false
|
|
type: string
|
|
default: "."
|
|
description: "location of the helm chart"
|
|
chart-name:
|
|
required: true
|
|
type: choice
|
|
description: "helm chart to be updated"
|
|
options:
|
|
- zipline
|
|
- calibre-web-automated
|
|
- samba
|
|
- teamspeak-server
|
|
- urlaubsverwaltung
|
|
- apache-tika
|
|
- gotenberg
|
|
- homeassistant
|
|
- satisfactory
|
|
- cyberchef
|
|
- matrix-synapse
|
|
- outline
|
|
- paperless-ngx
|
|
- patchmon
|
|
- rallly
|
|
- voucher-vault
|
|
- minecraft-router
|
|
- minecraft-server
|
|
- rss-bridge
|
|
- searxng
|
|
- bentopdf
|
|
- ytdlp-web-player
|
|
- sure
|
|
- valkey
|
|
- stalwart
|
|
- garage
|
|
- keycloak
|
|
# freesailarr is deliberately absent: none of its ten images takes
|
|
# its tag from appVersion (they are all pinned in its values.yaml),
|
|
# so this workflow would rewrite appVersion and republish the chart
|
|
# without changing a single deployed image. Update its images through
|
|
# a Renovate PR, and its appVersion by hand.
|
|
workflow_call:
|
|
inputs:
|
|
app-version:
|
|
required: true
|
|
type: string
|
|
description: "change the version of the underlying application"
|
|
chart-location:
|
|
required: false
|
|
type: string
|
|
default: "."
|
|
description: "location of the helm chart"
|
|
chart-name:
|
|
required: true
|
|
type: string
|
|
description: "name of the helm chart"
|
|
|
|
jobs:
|
|
change-app-version:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: "Configure OP-Connect"
|
|
uses: 1password/load-secrets-action/configure@70062d7a876d3eb6334754fa26efd2fbd90c32f2 # v5
|
|
with:
|
|
connect-host: https://op-connect.jk-dev.de
|
|
- name: "Load GitHub Credentials"
|
|
id: load-jk-cluster-bot-creds
|
|
uses: 1password/load-secrets-action@70062d7a876d3eb6334754fa26efd2fbd90c32f2 # v5
|
|
env:
|
|
OP_CONNECT_TOKEN: ${{ secrets.OP_CONNECT_TOKEN }}
|
|
JK_CLUSTER_BOT_TOKEN: op://GitHub-Actions/github-helm-charts-push-token/credential
|
|
JK_CLUSTER_USERNAME: op://GitHub-Actions/github-helm-charts-push-token/username
|
|
JK_CLUSTER_EMAIL: op://GitHub-Actions/github-helm-charts-push-token/email
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
with:
|
|
token: ${{ env.JK_CLUSTER_BOT_TOKEN }}
|
|
- name: "Get Chart Version"
|
|
run: |
|
|
CHART_VERSION=$(grep '^version:' ${{ inputs.chart-name }}/Chart.yaml | awk '{print $2}')
|
|
CHART_PART=$(echo $CHART_VERSION | cut -d'+' -f1)
|
|
echo "CHART_VERSION=$CHART_PART" >> $GITHUB_ENV
|
|
working-directory: ${{ inputs.chart-location }}
|
|
- name: "Get new Chart Version"
|
|
run: |
|
|
APP_VERSION_NORMALIZED=$(echo "${{ inputs.app-version }}" | tr '-' '.')
|
|
NEW_VERSION="${CHART_VERSION}+up${APP_VERSION_NORMALIZED}"
|
|
sed -i "s/^version:.*/version: $NEW_VERSION/" ${{ inputs.chart-name }}/Chart.yaml
|
|
sed -i "s/^appVersion:.*/appVersion: ${{ inputs.app-version }}/" ${{ inputs.chart-name }}/Chart.yaml
|
|
working-directory: ${{ inputs.chart-location }}
|
|
- name: "View chart-directory contents"
|
|
run: ls -al
|
|
working-directory: ${{ inputs.chart-location }}
|
|
- name: "View helm-chart.yaml"
|
|
run: cat Chart.yaml
|
|
working-directory: ${{ inputs.chart-location }}/${{ inputs.chart-name }}
|
|
- name: Commit and Push Changes
|
|
run: |
|
|
git config --global user.name '${{ env.JK_CLUSTER_USERNAME }}'
|
|
git config --global user.email '${{ env.JK_CLUSTER_EMAIL }}'
|
|
git commit -am "Updated ${{ inputs.chart-name }} application version to ${{ inputs.app-version }}"
|
|
git push |