Archify Sync GitOps template

A Copier template for deploying Archify Sync with Argo CD: an app-of-apps,
the server's Helm chart and its values, optional secrets through External
Secrets and an optional static NFS volume for PostgreSQL.
This commit is contained in:
root-at-skic committed 2026-11-08 21:55:40 +02:00
commit e2adb79e2d
15 files changed
+572

No files matched your search

@@ -0,0 +1,36 @@
{%- set es = archify_sync.get('external_secrets', {}) -%}
# Secret `archify-sync-secrets` from your secret store through External Secrets.
# ESO's own templating is escaped below so it reaches the cluster as written.
#
# The store needs two entries (named in external_secrets):
# postgres_password_key password of the bundled postgres role `archify`;
# letters and digits only (it goes into a URL)
# oidc_client_secret_key secret of the archify-sync client at the identity provider
#
# The URL names the chart's database Service, `<release>-postgresql`; the release is
# `archify-sync` (0200-archify-sync).
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: archify-sync-secrets
namespace: {{ archify_sync.get('namespace', 'archify-sync') }}
spec:
refreshInterval: 1h
secretStoreRef:
name: {{ es.get('store') }}
kind: {{ es.get('store_kind', 'ClusterSecretStore') }}
target:
name: archify-sync-secrets
template:
engineVersion: v2
data:
password: "{% raw %}{{ .postgresPassword }}{% endraw %}"
url: "postgres://archify:{% raw %}{{ .postgresPassword }}{% endraw %}@archify-sync-postgresql:5432/archify"
client-secret: "{% raw %}{{ .oidcClientSecret }}{% endraw %}"
data:
- secretKey: postgresPassword
remoteRef:
key: {{ es.get('postgres_password_key', 'archify-sync-postgres-password') }}
- secretKey: oidcClientSecret
remoteRef:
key: {{ es.get('oidc_client_secret_key', 'archify-sync-oidc-client-secret') }}
@@ -0,0 +1,27 @@
{%- set pull = archify_sync.get('external_secrets', {}).get('image_pull', {}) -%}
{%- set es = archify_sync.get('external_secrets', {}) -%}
{%- set user = pull.get('username') | tojson -%}
# The image pull secret for a private registry: its password from your secret store.
# ESO's own templating is escaped below so it reaches the cluster as written.
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: {{ archify_sync.image.pull_secret }}
namespace: {{ archify_sync.get('namespace', 'archify-sync') }}
spec:
refreshInterval: 1h
secretStoreRef:
name: {{ es.get('store') }}
kind: {{ es.get('store_kind', 'ClusterSecretStore') }}
target:
name: {{ archify_sync.image.pull_secret }}
creationPolicy: Owner
template:
engineVersion: v2
type: kubernetes.io/dockerconfigjson
data:
.dockerconfigjson: '{{ '{{' }} dict "auths" (dict {{ pull.get('registry') | tojson }} (dict "username" {{ user }} "password" .password "auth" (printf "{{ pull.get('username') }}:%s" .password | b64enc))) | toJson {{ '}}' }}'
data:
- secretKey: password
remoteRef:
key: {{ pull.get('password_key') }}
@@ -0,0 +1,49 @@
{% macro render() %}
{%- set database = archify_sync.get('database', {}) %}
{%- set namespace = archify_sync.get('namespace', 'archify-sync') %}
---
# Static NFS volume: an export owned by postgres:17-alpine's uid 70 with mode 0700,
# shared with maproot. Shares that map every user to root are refused by PostgreSQL.
# Retain: deleting the app never deletes the data.
apiVersion: v1
kind: PersistentVolume
metadata:
name: {{ namespace }}-database
labels:
app.kubernetes.io/part-of: archify-sync
spec:
capacity:
storage: {{ database.get('size', '8Gi') }}
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: ""
nfs:
server: {{ database.get('nfs_server') }}
path: {{ database.get('nfs_path') }}
claimRef:
namespace: {{ namespace }}
name: archify-sync-database
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: archify-sync-database
namespace: {{ namespace }}
labels:
app.kubernetes.io/part-of: archify-sync
spec:
accessModes:
- ReadWriteOnce
storageClassName: ""
volumeName: {{ namespace }}-database
resources:
requests:
storage: {{ database.get('size', '8Gi') }}
{% endmacro %}
{%- set result = render() -%}
{%- for line in result.split('\n') -%}
{% if line | trim | length != 0 -%}
{{ line }}
{% endif %}
{%- endfor %}
@@ -0,0 +1,72 @@
{% macro render() %}
{%- set image = archify_sync.get('image', {}) %}
{%- set database = archify_sync.get('database', {}) %}
{%- set oidc = archify_sync.get('oidc', {}) %}
{%- set metrics = archify_sync.get('metrics', {}) %}
{%- set host = archify_sync.get('host', 'archify.example.com') %}
# Values for charts/archify-sync of the server repository.
image:
repository: {{ image.get('repository', 'registry.example.com/archify-sync') }}
tag: {{ image.get('tag', '0.1.0') | string | tojson }}
pullPolicy: IfNotPresent
{%- if image.get('pull_secret') %}
imagePullSecrets:
- name: {{ image.get('pull_secret') }}
{%- endif %}
# TLS ends at your ingress or edge proxy; people reach the server here.
publicUrl: https://{{ host }}
# The bundled PostgreSQL, its password and URL from Secret archify-sync-secrets
# (0100 with External Secrets, or made by hand).
postgresql:
enabled: true
existingSecret: archify-sync-secrets
{%- if database.get('nfs_path') %}
# The static NFS volume from 0150-archify-sync-storage.
existingClaim: archify-sync-database
{%- else %}
{%- if database.get('storage_class') %}
storageClass: {{ database.get('storage_class') }}
{%- endif %}
storage: {{ database.get('size', '8Gi') }}
{%- endif %}
config:
name: Archify Sync
membersCanInvite: {{ archify_sync.get('members_can_invite', false) | tojson }}
logJson: true
{%- if oidc.get('is_enabled', false) %}
oidc:
enabled: true
issuer: {{ oidc.get('issuer', 'https://sso.example.com/realms/home') }}
clientId: {{ oidc.get('client_id', 'archify-sync') }}
existingSecret: archify-sync-secrets
existingSecretKey: client-secret
label: {{ oidc.get('label', 'Keycloak') | tojson }}
allowedGroups: {{ oidc.get('allowed_groups', []) | tojson }}
adminGroups: {{ oidc.get('admin_groups', []) | tojson }}
{%- endif %}
ingress:
enabled: true
className: {{ archify_sync.get('ingress_class', 'nginx') }}
host: {{ host }}
annotations:
# Edits travel over a WebSocket that stays open for hours.
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
nginx.ingress.kubernetes.io/proxy-body-size: 8m
metrics:
enabled: {{ metrics.get('is_enabled', true) | tojson }}
serviceMonitor:
enabled: {{ metrics.get('service_monitor', false) | tojson }}
{% endmacro %}
{%- set result = render() -%}
{%- for line in result.split('\n') -%}
{% if line | trim | length != 0 -%}
{{ line }}
{% endif %}
{%- endfor %}