Compare commits
58
Commits
cb86b45293
...
prod
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d66fef8f2b | ||
|
|
9865f5b386 | ||
|
|
5ccf1ffffa | ||
|
|
6ca5c7b396 | ||
|
|
73e25266df | ||
|
|
0050dbc3af | ||
|
|
9505761c9b | ||
|
|
224fffe7d2 | ||
|
|
815e29ed16 | ||
|
|
2ae3c26880 | ||
|
|
c5db75828a | ||
|
|
66a5d976bf | ||
|
|
a1a9dfdcf4 | ||
|
|
546212679f | ||
|
|
8cf2b66fa1 | ||
|
|
a27119e04b | ||
|
|
51cf68683d | ||
|
|
e0e4232bad | ||
|
|
fce161e13e | ||
|
|
e9b0ae25c7 | ||
|
|
a243ccccdb | ||
|
|
a29ecfdfa6 | ||
|
|
dd9c364860 | ||
|
|
57ed781366 | ||
|
|
b992f47264 | ||
|
|
d909f3e317 | ||
|
|
406678fdc2 | ||
|
|
dedba652d6 | ||
|
|
1e0908ee90 | ||
|
|
ecf03f2b01 | ||
|
|
44b33f8030 | ||
|
|
a31372b953 | ||
|
|
b8c581eab8 | ||
|
|
1af1a3527d | ||
|
|
954a0b4000 | ||
|
|
8494263a3f | ||
|
|
050f86e503 | ||
|
|
06d92a034f | ||
|
|
60fd88b9c1 | ||
|
|
cbbe199633 | ||
|
|
a10942bb3c | ||
|
|
454922b475 | ||
|
|
4623c7c9f7 | ||
|
|
f2045463c4 | ||
|
|
891727b487 | ||
|
|
67284c4d32 | ||
|
|
852ca6c8f3 | ||
|
|
489439d330 | ||
|
|
5cabacee84 | ||
|
|
07fd7110e9 | ||
|
|
2d78870b94 | ||
|
|
a6c72aa3bc | ||
|
|
3b833cc575 | ||
|
|
6600fa660e | ||
|
|
f59b01e290 | ||
|
|
1df90d3a6e | ||
|
|
90014b22c1 | ||
|
|
cc7eabfedc |
+3
-1
@@ -1,3 +1,5 @@
|
||||
migration-from-old-files/
|
||||
migration-from-docker/
|
||||
.decrypted~secret.enc.yaml
|
||||
.decrypted~secret.enc.yaml
|
||||
gitea-backup/
|
||||
*.agekey
|
||||
|
||||
+50
-2
@@ -1,4 +1,52 @@
|
||||
creation_rules:
|
||||
- path_regex: .*\.enc\.yaml$
|
||||
- path_regex: authelia.*\.enc\.yaml$
|
||||
encrypted_regex: ^(data|stringData)$
|
||||
age: age14x4jjs2fwdgw28g2pkr6jyj2yzmwc544xwmaaglrxwz5e99seutqtr8jv5
|
||||
age: age1ncw6uagcgncd5m2admqxt73ey0mcd99jsw9sa9lcdv3gu70mcerql8ya0k
|
||||
- path_regex: davical.*\.enc\.yaml$
|
||||
encrypted_regex: ^(data|stringData)$
|
||||
age: age1yx8mey02c0mu6te9hwxwdqp5n4enjz35e8thchsmvhqw7xsrzy0syg367g
|
||||
- path_regex: immich.*\.enc\.yaml$
|
||||
encrypted_regex: ^(data|stringData)$
|
||||
age: age1wmm8qrqnjzvd5nkraed6ylrsxlpn3ru7d7zettdudj7y9sg9dd2su0u3mr
|
||||
- path_regex: markdown-vault-mcp.*\.enc\.yaml$
|
||||
encrypted_regex: ^(data|stringData)$
|
||||
age: age1kct5g7d7eus2hvdnmx99ewsrtz70lhlasxa25euqwdctqhwqqpxqz0n7gg
|
||||
- path_regex: mosquitto.*\.enc\.yaml$
|
||||
encrypted_regex: ^(data|stringData)$
|
||||
age: age1u236u5mzkzj72y4mfxx68gfqw0u0j6tdgkudnm5pdfpe7apq4u6s89jr2h
|
||||
- path_regex: vaultwarden.*\.enc\.yaml$
|
||||
encrypted_regex: ^(data|stringData)$
|
||||
age: age109zta6l0cwpkxn5wek82kvauxn6yqrq80rsz4mvu5atdnpcn9pusuvnqk5
|
||||
- path_regex: webdav.*\.enc\.yaml$
|
||||
encrypted_regex: ^(data|stringData)$
|
||||
age: age1y8t9v56yuvskznddqfsd4yddzzch0yf2dutvvt8rrx6rjh5f9g0s3qeays
|
||||
- path_regex: zigbee2mqtt.*\.enc\.yaml$
|
||||
encrypted_regex: ^(data|stringData)$
|
||||
age: age1tu4xgfefvgdda0vn2thaqndq4p9tuydq2ud6qa98tzzgnff6749qnlcx29
|
||||
- path_regex: longhorn-system.*\.enc\.yaml$
|
||||
encrypted_regex: ^(data|stringData)$
|
||||
age: age18hhmdmupj90zjgjpxk3z5cf3lx36hcznnmqsp0fpyg50823pudrqjupydt
|
||||
- path_regex: s3-backup-proxy.*\.enc\.yaml$
|
||||
encrypted_regex: ^(data|stringData)$
|
||||
age: age15vc3geq4lsec69rnxczluvwgcexeqae02zxzjpswsuatthaasu7qzath48
|
||||
- path_regex: joplin.*\.enc\.yaml$
|
||||
encrypted_regex: ^(data|stringData)$
|
||||
age: age1dertyl956fjsmh00cw468gdnl7lf3frasg4n4c82z0chm6qm2cks6w8gha
|
||||
- path_regex: gitea.*\.enc\.yaml$
|
||||
encrypted_regex: ^(data|stringData)$
|
||||
age: age1ktlxm0hukw6jxm62txqy5x2nl8hpdnal8nv00kfhrf3pw33574aqa6j5cj
|
||||
- path_regex: woodpecker.*\.enc\.yaml$
|
||||
encrypted_regex: ^(data|stringData)$
|
||||
age: age13qwkssk8esashln2j3gfv6e9csashr4vddkdav5v38hm5wejl36qd2ew9s
|
||||
- path_regex: tinyauth.*\.enc\.yaml$
|
||||
encrypted_regex: ^(data|stringData)$
|
||||
age: age1rvyt7nlnjqeyt6ykwh9fj9d88kjmq9vetcx667ul3ql6fyfz4gqqh9lq9q
|
||||
- path_regex: ntfy.*\.enc\.yaml$
|
||||
encrypted_regex: ^(data|stringData)$
|
||||
age: age1uzs33ep6k3htnuwyyp54y373wkf7urd0qvk5kxcmptr5tt0fffus4v06gn
|
||||
- path_regex: map_monitor.*\.enc\.yaml$
|
||||
encrypted_regex: ^(data|stringData)$
|
||||
age: age1k4j5vyqqt7w7k52gvkpfe6znqr9mlgt076l7xgdtyc75lamsh4aqshj5qs
|
||||
- path_regex: jitsi.*\.enc\.yaml$
|
||||
encrypted_regex: ^(data|stringData)$
|
||||
age: age1zmr32r5mcgyh73asvzl8l690pzwqsx9hle27u3cydngsgv56wykq3v67px
|
||||
@@ -17,7 +17,7 @@ spec:
|
||||
app:
|
||||
image:
|
||||
repository: authelia/authelia
|
||||
tag: v4.39.20
|
||||
tag: 4.39.21
|
||||
probes:
|
||||
liveness:
|
||||
enabled: true
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -4,21 +4,21 @@ metadata:
|
||||
name: davical-secrets
|
||||
namespace: pim
|
||||
stringData:
|
||||
PGSQL_ROOT_PASS: ENC[AES256_GCM,data:EwTwpAg3FBcZoMDLonNAFjDPDO8wgjwx0aQm85n7BkCTkV6c5JX7tF7TIX4HW4RB,iv:rVeHe4suCagHl1V1EFG3FOfL45tdT1cdr3GyGcHxHu4=,tag:vlJn7lJWhGxKBgZr6XDHPA==,type:str]
|
||||
PASSDAVDB: ENC[AES256_GCM,data:MqEb6sAZc8sPRYq9rB+ESV9UFMGmH3VFRW3nUYPpGp/umAyTJxqc59LzBavYtcZ7,iv:sGw/1HmYvKSizczpDiLZ4zWGLB1vfB+NwfycwOEsZSk=,tag:wxbrjiMSnJssH3o9FOPOXQ==,type:str]
|
||||
ADMINDAVICALPASS: ENC[AES256_GCM,data:Mx3z8QUCWasAqqoUF/FOsT11iBAGtHNrYI/iMdkIRhc=,iv:kBnQjC5VvDolB1Uwe3DDzbfTTU3lHbziXR5X3bQRXvU=,tag:yP74K66C5Np1fu2DmJN04w==,type:str]
|
||||
PGSQL_ROOT_PASS: ENC[AES256_GCM,data:XEhP2zDIz0QCpAXXnZi5JtPsVIfns9zp4fvxcg9/bskHiLU5rR+EgU5n/SdOEDkJ,iv:wR3CGk3csHSCSBqFX+ukOUAmS/p+oZMmdNgvCFNHZlI=,tag:ttAe0GuLmwqA77cWLlne2Q==,type:str]
|
||||
PASSDAVDB: ENC[AES256_GCM,data:d9RazQG7xeIH4g3ovti6HwyiIyLTzyaPjAcQvLmhsrwdgev7i0AJK7yQeRXxu/16,iv:9ZdfWTlOuyUNpV2ycykOgx8SY7Golz7/Lb+gfTa9fW0=,tag:eL1euF9uQJ+nDLsR1kxtvg==,type:str]
|
||||
ADMINDAVICALPASS: ENC[AES256_GCM,data:1Zq7duPTIfJX2Stp6AEhKcLHkmQB6vWf4y1f0Iju/zI=,iv:PMOyD3O7UzVPRlFmHTOQSAys032iD4CF8JbI51agWcg=,tag:eDgMbg2lRMnl57NCf5iIkw==,type:str]
|
||||
sops:
|
||||
age:
|
||||
- recipient: age1yx8mey02c0mu6te9hwxwdqp5n4enjz35e8thchsmvhqw7xsrzy0syg367g
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB1T2dJTmlMWXQrWldYM3lZ
|
||||
SDNTZjZ0NnpDNklCalR6dm9oNHU2Z2REczBnCjJhZkFaU1dsZHZlRktVbjVOZStP
|
||||
b3hPN1BMNjJMUDNFa3REV0RNUkhVS2cKLS0tIEVUWUhtWU1UWXcwWU5RYTY1M2Zj
|
||||
a0hUaksyZW1KV2Jvd2RWM04ramJjNGMK6qIWzTHhAMJRNtIU+t/QR6iZsVN05bOv
|
||||
CX8233dl+T76qrrfYV5+EQ3AKCDnIIkU6Mg1jdnaaorTpfo/qOAHgQ==
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBjNTVJZEFuRFhGazF6T1Yv
|
||||
dnhhTHVUb1h4SEN2eEtDUGREUERkR2wrTUVVCktGSkVLZmlYR3BjekhjNmk4L3Q4
|
||||
UEJsQXJjZXY1VlNDaFV2eER4NTdwRGcKLS0tIDJxb1AyYm01YlNUVk93Tm1Hb0xK
|
||||
NVh0K25yOFUya0dYSGt2SGdJQURnQ2sKaKgwThB5ePeM091/zYgQXmiPeBeIhTdo
|
||||
60PkAPNs659xyVqnlZw2YKEhxbEHS3ZMTBgC4tgng0yjClBizcTv5w==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
lastmodified: "2026-08-26T10:29:45Z"
|
||||
mac: ENC[AES256_GCM,data:FtJ1YtmHAj9FIMDILjm5R2ZO3CElJN3j6uAZkw9z4Odu6GaIhPfeAp0HOdgvu/NiU1LC4K/GGPZ+NdEbOLgAtLKW22TBG2iCnuS1PUguogI8IG8+rpGbuatJhn9ntkEZFfMQqPSxKK4DijIj5YrNvezHTJPvKyxY5R6pcegV8h4=,iv:+aLt4+soEa8+AgGiHPG1+87Mhvjs8lxVcdiChUqg1mo=,tag:DHt5lXFDx9911k7MpI8ZrA==,type:str]
|
||||
lastmodified: "2026-08-08T16:37:01Z"
|
||||
mac: ENC[AES256_GCM,data:OoE6fml/3DSH2EMafCoeYz/JHo89Fb9uwQ58k7hxQDU6YMazdO/eGM0jKX5ghjuMKJqA/zQs4FeZ4yASkIUT1CBbxRpycmE9qo6Zny121NLeqveBp3YMjmUZGt3tgw2dNqtkhpOnl/BmHQCtTTvX2brtSVmANx3LbFxjqbK2OGM=,iv:8Us7LJSZ2aHZQnYIjnsvkR7Av0KeHFEYEETZd7WZX4Q=,tag:7NbbEOq1k2c5IcsnqpvlOQ==,type:str]
|
||||
encrypted_regex: ^(data|stringData)$
|
||||
version: 3.11.0
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
# Three Ingresses on one host because middlewares and router priority are
|
||||
# per-Ingress. Traefik matches pathType Prefix character-wise (not per path
|
||||
# segment), so public prefixes carry a trailing slash and priorities are
|
||||
# explicit - by default Traefik orders routers by rule length, which would
|
||||
# not reliably put /api/admin above /api/.
|
||||
# 300 dev-admin /api/admin -> Authelia -> api (prefix /api stripped)
|
||||
# 200 dev-public /api/ /m /m/ -> api / m, public (prefixes stripped)
|
||||
# 100 dev / -> Authelia -> ui (also bare /api)
|
||||
# All carry the tls section (otherwise the router is http-only), but only
|
||||
# "dev" has the cert-manager annotation so a single Certificate owns dev-tls.
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: dev
|
||||
namespace: dev
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||
traefik.ingress.kubernetes.io/router.priority: "100"
|
||||
traefik.ingress.kubernetes.io/router.middlewares: auth-tinyauth@kubernetescrd
|
||||
spec:
|
||||
ingressClassName: traefik
|
||||
rules:
|
||||
- host: dev.aggtaa.com
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: dev
|
||||
port:
|
||||
name: ui
|
||||
tls:
|
||||
- secretName: dev-tls
|
||||
hosts:
|
||||
- dev.aggtaa.com
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: dev-admin
|
||||
namespace: dev
|
||||
annotations:
|
||||
traefik.ingress.kubernetes.io/router.priority: "300"
|
||||
traefik.ingress.kubernetes.io/router.middlewares: auth-tinyauth@kubernetescrd,dev-strip-prefix@kubernetescrd
|
||||
spec:
|
||||
ingressClassName: traefik
|
||||
rules:
|
||||
- host: dev.aggtaa.com
|
||||
http:
|
||||
paths:
|
||||
# no trailing slash on purpose: also catches bare /api/admin
|
||||
# (and /api/administrator...), all of which stay behind Authelia
|
||||
- path: /api/admin
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: dev
|
||||
port:
|
||||
name: api
|
||||
tls:
|
||||
- secretName: dev-tls
|
||||
hosts:
|
||||
- dev.aggtaa.com
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: dev-public
|
||||
namespace: dev
|
||||
annotations:
|
||||
traefik.ingress.kubernetes.io/router.priority: "200"
|
||||
traefik.ingress.kubernetes.io/router.middlewares: dev-strip-prefix@kubernetescrd
|
||||
spec:
|
||||
ingressClassName: traefik
|
||||
rules:
|
||||
- host: dev.aggtaa.com
|
||||
http:
|
||||
paths:
|
||||
- path: /api/
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: dev
|
||||
port:
|
||||
name: api
|
||||
- path: /m
|
||||
pathType: Exact
|
||||
backend:
|
||||
service:
|
||||
name: dev
|
||||
port:
|
||||
name: m
|
||||
- path: /m/
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: dev
|
||||
port:
|
||||
name: m
|
||||
tls:
|
||||
- secretName: dev-tls
|
||||
hosts:
|
||||
- dev.aggtaa.com
|
||||
@@ -0,0 +1,6 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- service.yaml
|
||||
- middleware.yaml
|
||||
- ingress.yaml
|
||||
@@ -0,0 +1,13 @@
|
||||
# Shared by dev-admin and dev-public: /api/a -> /a, /api/admin/b -> /admin/b,
|
||||
# /m/main.css -> /main.css. Only the first matching prefix is stripped, and
|
||||
# none of these routes can match both.
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: strip-prefix
|
||||
namespace: dev
|
||||
spec:
|
||||
stripPrefix:
|
||||
prefixes:
|
||||
- /api
|
||||
- /m
|
||||
@@ -0,0 +1,40 @@
|
||||
# dev.aggtaa.com backends live outside the cluster on 10.0.64.157:
|
||||
# selector-less Service + hand-written EndpointSlice point at them.
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: dev
|
||||
namespace: dev
|
||||
spec:
|
||||
ports:
|
||||
- name: ui
|
||||
port: 10001
|
||||
- name: api
|
||||
port: 10002
|
||||
- name: m
|
||||
port: 10003
|
||||
---
|
||||
apiVersion: discovery.k8s.io/v1
|
||||
kind: EndpointSlice
|
||||
metadata:
|
||||
name: dev-external
|
||||
namespace: dev
|
||||
labels:
|
||||
kubernetes.io/service-name: dev
|
||||
endpointslice.kubernetes.io/managed-by: flux
|
||||
addressType: IPv4
|
||||
ports:
|
||||
- name: ui
|
||||
port: 10001
|
||||
protocol: TCP
|
||||
- name: api
|
||||
port: 10002
|
||||
protocol: TCP
|
||||
- name: m
|
||||
port: 10003
|
||||
protocol: TCP
|
||||
endpoints:
|
||||
- addresses:
|
||||
- 10.0.64.157
|
||||
conditions:
|
||||
ready: true
|
||||
@@ -29,7 +29,7 @@ spec:
|
||||
app:
|
||||
image:
|
||||
repository: yegle/fava
|
||||
tag: "1.30.4"
|
||||
tag: "v1.30"
|
||||
env:
|
||||
TZ: Europe/Moscow
|
||||
BEANCOUNT_FILE: /documents/main.beancount
|
||||
@@ -59,7 +59,7 @@ spec:
|
||||
className: traefik
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||
traefik.ingress.kubernetes.io/router.middlewares: auth-authelia@kubernetescrd
|
||||
traefik.ingress.kubernetes.io/router.middlewares: auth-tinyauth@kubernetescrd
|
||||
hosts:
|
||||
- host: acc.aggtaa.com
|
||||
paths:
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
apiVersion: helm.toolkit.fluxcd.io/v2
|
||||
kind: HelmRelease
|
||||
metadata:
|
||||
name: gitea
|
||||
namespace: git
|
||||
spec:
|
||||
interval: 10m
|
||||
chartRef:
|
||||
kind: OCIRepository
|
||||
name: gitea
|
||||
driftDetection:
|
||||
mode: enabled
|
||||
values:
|
||||
controllers:
|
||||
app:
|
||||
replicas: 1
|
||||
containers:
|
||||
app:
|
||||
image:
|
||||
repository: gitea/gitea
|
||||
tag: "1.27.0"
|
||||
env:
|
||||
USER_UID: "1000"
|
||||
USER_GID: "1000"
|
||||
GITEA__server__DOMAIN: git.aggtaa.com
|
||||
GITEA__server__ROOT_URL: https://git.aggtaa.com/
|
||||
GITEA__server__SSH_DOMAIN: git-ssh.aggtaa.com
|
||||
GITEA__server__SSH_PORT: "2222"
|
||||
GITEA__server__LFS_START_SERVER: "true"
|
||||
GITEA__webhook__ALLOWED_HOST_LIST: ci.aggtaa.com
|
||||
GITEA__security__INSTALL_LOCK: "true"
|
||||
GITEA__security__PASSWORD_HASH_ALGO: pbkdf2
|
||||
GITEA__security__INTERNAL_TOKEN:
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: gitea-secrets
|
||||
key: INTERNAL_TOKEN
|
||||
GITEA__oauth2__JWT_SECRET:
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: gitea-secrets
|
||||
key: OAUTH2_JWT_SECRET
|
||||
GITEA__server__LFS_JWT_SECRET:
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: gitea-secrets
|
||||
key: LFS_JWT_SECRET
|
||||
probes:
|
||||
startup:
|
||||
enabled: true
|
||||
spec:
|
||||
periodSeconds: 5
|
||||
failureThreshold: 60
|
||||
liveness:
|
||||
enabled: true
|
||||
readiness:
|
||||
enabled: true
|
||||
resources:
|
||||
requests:
|
||||
cpu: 50m
|
||||
memory: 256Mi
|
||||
limits:
|
||||
memory: 1Gi
|
||||
|
||||
service:
|
||||
app:
|
||||
controller: app
|
||||
ports:
|
||||
http:
|
||||
port: 3000
|
||||
ssh:
|
||||
controller: app
|
||||
type: LoadBalancer
|
||||
labels:
|
||||
loadBalancerPool: default
|
||||
ports:
|
||||
ssh:
|
||||
port: 2222
|
||||
targetPort: 22
|
||||
protocol: TCP
|
||||
|
||||
ingress:
|
||||
app:
|
||||
className: traefik
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||
hosts:
|
||||
- host: git.aggtaa.com
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
service:
|
||||
identifier: app
|
||||
port: http
|
||||
tls:
|
||||
- secretName: gitea-tls
|
||||
hosts:
|
||||
- git.aggtaa.com
|
||||
|
||||
persistence:
|
||||
data:
|
||||
type: persistentVolumeClaim
|
||||
existingClaim: gitea-data
|
||||
globalMounts:
|
||||
- path: /data
|
||||
@@ -0,0 +1,10 @@
|
||||
apiVersion: source.toolkit.fluxcd.io/v1
|
||||
kind: OCIRepository
|
||||
metadata:
|
||||
name: gitea
|
||||
namespace: git
|
||||
spec:
|
||||
interval: 10m
|
||||
url: oci://ghcr.io/bjw-s-labs/helm/app-template
|
||||
ref:
|
||||
tag: "5.0.1"
|
||||
@@ -0,0 +1,7 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- helmrepository.yaml
|
||||
- secret.enc.yaml
|
||||
- pvc.yaml
|
||||
- helmrelease.yaml
|
||||
@@ -0,0 +1,12 @@
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: gitea-data
|
||||
namespace: git
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
storageClassName: longhorn
|
||||
resources:
|
||||
requests:
|
||||
storage: 3Gi
|
||||
@@ -0,0 +1,24 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: gitea-secrets
|
||||
namespace: git
|
||||
stringData:
|
||||
INTERNAL_TOKEN: ENC[AES256_GCM,data:+eS1bjyL/NKvOpkXa1Kiyk9dBPemWvfRplJJCXG+cLXipbMlyHBDQLEMeFEnz9VdnwN/MFRWYL5ink3Lh6yNGf0vmVNR+OLMlvlaKDNaCA28HuUBxJbWLAqhITsRImH6rKcy/EfqEEcK,iv:ModTSwxLMj4Gx0e/bVKY8GVWzBjgNxATKnkWYfvKiIs=,tag:6gFkA/0toCBJ7QKL16654A==,type:str]
|
||||
OAUTH2_JWT_SECRET: ENC[AES256_GCM,data:9626EzmbEmyAsTqfbRhASqLkzS+4xnJxpSEgJDSLzkjfuNfAq7uMfc/HsA==,iv:lMCRwHt4gT31hYZ5Ywt4GU/DJNj7Fya2GOUkyr/l6ro=,tag:aQ8UlVwpaVNDoOHju1oiMQ==,type:str]
|
||||
LFS_JWT_SECRET: ENC[AES256_GCM,data:gZ37cb9uqSF1MkdoUFbVM3VhqBxEIyUv3IxiV4c3gbIVTk7FMHncZekM7Q==,iv:m7JxF7S1OnHy86s5s1tJHQ8kqhRJq5kFRoArLL/ab0o=,tag:GZuE7f9pNq15T+R+PlSZdA==,type:str]
|
||||
sops:
|
||||
age:
|
||||
- recipient: age1ktlxm0hukw6jxm62txqy5x2nl8hpdnal8nv00kfhrf3pw33574aqa6j5cj
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBkRVpZRTVLWU80RjEvZnRs
|
||||
TU5YVko4V1M5Q0d5SXZGT1h2NStCYk5UZWpRCmNxVXVtR3VCZXJqNHYyaDUyZmdr
|
||||
WXJKZHhJaFJhZll0VVBld0QrSGhtbncKLS0tIGZZREFXRUMvTi8rRHIyaXBUOE45
|
||||
d2JBTG5oT2kvZzdLejMzdEpRbm03QmcKItsS4nKJRu3pRC8xLTf9kYpqFiD9S1tx
|
||||
BFnJf3IsbGpl1RM8RmkN9O5QsZSq1hbw5pFhlx0XKeH5KgoJInbnog==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
lastmodified: "2026-09-05T11:29:22Z"
|
||||
mac: ENC[AES256_GCM,data:906TL61C7WcxxTAfH3zpXLTLQn2WSIg2RPm0y/6LeVA6pvI6fMbFA32Usvg+EkpWVRGqcm8JPgHy63WQDhq1Ap3imJXpgVDgTgfo64TxJLmdUtCAdm0/CaGxtGeU2J3gm653wl75hOGoCyfBR3iOt0Vo1kUdUxS9B5h3u5L6P6o=,iv:C+CZe31F/AWk0ZqM6lgV248ys/L3mG6S8Tz44b5o628=,tag:C9LdYCtsiHWiHSZWaYCGWA==,type:str]
|
||||
encrypted_regex: ^(data|stringData)$
|
||||
version: 3.11.0
|
||||
@@ -75,3 +75,11 @@ spec:
|
||||
retain: true
|
||||
globalMounts:
|
||||
- path: /config
|
||||
media:
|
||||
type: persistentVolumeClaim
|
||||
accessMode: ReadWriteOnce
|
||||
size: 1Gi
|
||||
storageClass: longhorn
|
||||
retain: true
|
||||
globalMounts:
|
||||
- path: /media
|
||||
|
||||
@@ -189,15 +189,47 @@ spec:
|
||||
server:
|
||||
mergerfs:
|
||||
- path: /dev/fuse
|
||||
# everything immich keeps outside "library" (backups, encoded-video,
|
||||
# profile, thumbs, upload) - plain volume, no mergerfs involved.
|
||||
other:
|
||||
# split out of the old combined "other" volume below: each of these
|
||||
# purposes now gets its own Longhorn volume instead of sharing one
|
||||
# 200Gi disk, so a single hot subtree (e.g. thumbs) doesn't force
|
||||
# replica rebuilds/relocation to drag the whole 200Gi with it.
|
||||
data:
|
||||
type: persistentVolumeClaim
|
||||
accessMode: ReadWriteOnce
|
||||
size: 200Gi
|
||||
storageClass: longhorn-single-replica
|
||||
size: 20Gi
|
||||
storageClass: longhorn
|
||||
retain: true
|
||||
advancedMounts:
|
||||
server:
|
||||
app:
|
||||
- path: /data
|
||||
encoded-video:
|
||||
type: persistentVolumeClaim
|
||||
accessMode: ReadWriteOnce
|
||||
size: 100Gi
|
||||
storageClass: longhorn
|
||||
retain: true
|
||||
advancedMounts:
|
||||
server:
|
||||
app:
|
||||
- path: /data/encoded-video
|
||||
thumbs:
|
||||
type: persistentVolumeClaim
|
||||
accessMode: ReadWriteOnce
|
||||
size: 100Gi
|
||||
storageClass: longhorn
|
||||
retain: true
|
||||
advancedMounts:
|
||||
server:
|
||||
app:
|
||||
- path: /data/thumbs
|
||||
backups:
|
||||
type: persistentVolumeClaim
|
||||
accessMode: ReadWriteOnce
|
||||
size: 30Gi
|
||||
storageClass: longhorn
|
||||
retain: true
|
||||
advancedMounts:
|
||||
server:
|
||||
app:
|
||||
- path: /data/backups
|
||||
|
||||
@@ -4,19 +4,19 @@ metadata:
|
||||
name: immich-secrets
|
||||
namespace: photo
|
||||
stringData:
|
||||
DB_PASSWORD: ENC[AES256_GCM,data:OumSCUdG9NT5FNCApJ9D04VIXgRf2X/ieCjJbWqGsc0=,iv:IAC9IXiVeOqFngqOqxReBPYNwPg3p/e4auHeUCudcS0=,tag:uhg56rWb5IzJApJm3tqDHA==,type:str]
|
||||
DB_PASSWORD: ENC[AES256_GCM,data:+bJ/+NEQCT3ZEqjnkzep4OsbLkJ9gyLZmGxCpoww2Wo=,iv:n1sLYgLl3zNZBdjMBhIrbSv/qHJFQ/nvZfBknFAUdug=,tag:DFnoc5K6XvHngVIrgJlM6Q==,type:str]
|
||||
sops:
|
||||
age:
|
||||
- recipient: age1wmm8qrqnjzvd5nkraed6ylrsxlpn3ru7d7zettdudj7y9sg9dd2su0u3mr
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBqTnlDR1dRUDNaTlQ2RHpM
|
||||
OFArT3BjOEhleXhVaTRlVDRPcFF1ZFpyakR3Ck1BUHhYQXdsTXMveGs2OG9mbzFQ
|
||||
QWR6dW4zL2VsQWtDNWgrVVBDeWd4L1kKLS0tIDY3WHo1MEl4SzJKM0ROalBKNERa
|
||||
SlQwMEdnZmhSWUdYUnBGRk9MdjV0cGMKxhON65iPrpNMnqBYYUN6rQfhAo3EhhE4
|
||||
Vun3sqVBk1OH8aekutrYSOj/RhrIbzYlbFXTY+pDnp3U3o1+xrknig==
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBtd1hFZy82d0c0RXZMd28r
|
||||
dWs1VWNlVG9tTE5WZDVLdGpFSXhuVXQ5anprCk5LWWMrWUVCd1N4Y1JENnRyWExC
|
||||
d2VRNDJON2RzSHRyMGhRdmMva1NNY3cKLS0tIDNML2Q0YXFRMEs3V3prUkZYSS85
|
||||
MWRGa3duNHgvbjNvVnZLOXpYMW1mbGcKaN7h3W0YKsRjnyk6P9+bziDy6If5xLQ8
|
||||
kxFJf4CX9XU5jgYXqw2UNqRDusphclqfULUMRaEzMJkkPhd1cZ9PvQ==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
lastmodified: "2026-08-26T10:29:46Z"
|
||||
mac: ENC[AES256_GCM,data:/CgR0m+7TJh2hHQ+pee5bP1lbJhWMrJiPjTrS8pP05z4OobLXxScEzPKtuO8+0Ru0eyjg/i1eAk5tzDMzDPwW3/JiU9elQKeFYxzGn6LmT17KIf+ofPP9vuVFP93FW4vqYNZIO4qUtF/RUfZBRgPlf6rokUMRLILTRGI00lvfR4=,iv:z9xX6wGL7I+NZzybQd0j4+rkU+Xb2JKO2sedrrGUss4=,tag:P5E3e/s8bXJBDUhxTqaf8g==,type:str]
|
||||
lastmodified: "2026-08-21T12:23:20Z"
|
||||
mac: ENC[AES256_GCM,data:vGSUhl73AIQr1Ld1SHc+i4GpvOc0b0j8Vx9DmoRDjNs17TQSfmfulEZwIua12P5DHIz36P9yqggHfSyyrrEoMjfaUSTIDxCIGGvsfTl4vBt9Vis0e2gALaHtAgWZwxr5QMe+OP1tkXOZoX9E8VcoBq1ULvbIjqsPs2uxPVKsEWk=,iv:1exDUqurlFdBt1eZYWWMlkar75HbTLZ6RZelC0RsYcU=,tag:A0IhJHjVum2HBT5RwHo5qg==,type:str]
|
||||
encrypted_regex: ^(data|stringData)$
|
||||
version: 3.11.0
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
apiVersion: helm.toolkit.fluxcd.io/v2
|
||||
kind: HelmRelease
|
||||
metadata:
|
||||
name: it-tools
|
||||
namespace: tools
|
||||
spec:
|
||||
interval: 10m
|
||||
chartRef:
|
||||
kind: OCIRepository
|
||||
name: it-tools
|
||||
driftDetection:
|
||||
mode: enabled
|
||||
values:
|
||||
controllers:
|
||||
it-tools:
|
||||
containers:
|
||||
app:
|
||||
image:
|
||||
repository: ghcr.io/willjayyyy/next-tools
|
||||
tag: 1.10.3
|
||||
probes:
|
||||
liveness:
|
||||
enabled: true
|
||||
readiness:
|
||||
enabled: true
|
||||
resources:
|
||||
requests:
|
||||
cpu: 10m
|
||||
memory: 32Mi
|
||||
limits:
|
||||
memory: 128Mi
|
||||
|
||||
service:
|
||||
app:
|
||||
controller: it-tools
|
||||
ports:
|
||||
http:
|
||||
port: 80
|
||||
|
||||
ingress:
|
||||
app:
|
||||
className: traefik
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||
traefik.ingress.kubernetes.io/router.middlewares: auth-tinyauth@kubernetescrd
|
||||
hosts:
|
||||
- host: tools.aggtaa.com
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
service:
|
||||
identifier: app
|
||||
port: http
|
||||
tls:
|
||||
- secretName: it-tools-tls
|
||||
hosts:
|
||||
- tools.aggtaa.com
|
||||
@@ -0,0 +1,10 @@
|
||||
apiVersion: source.toolkit.fluxcd.io/v1
|
||||
kind: OCIRepository
|
||||
metadata:
|
||||
name: it-tools
|
||||
namespace: tools
|
||||
spec:
|
||||
interval: 1h
|
||||
url: oci://ghcr.io/bjw-s-labs/helm/app-template
|
||||
ref:
|
||||
tag: "5.0.1"
|
||||
@@ -0,0 +1,77 @@
|
||||
apiVersion: helm.toolkit.fluxcd.io/v2
|
||||
kind: HelmRelease
|
||||
metadata:
|
||||
name: jitsi
|
||||
namespace: video
|
||||
spec:
|
||||
interval: 30m
|
||||
chart:
|
||||
spec:
|
||||
chart: jitsi-meet
|
||||
version: ">=1.0.0 <2.0.0"
|
||||
sourceRef:
|
||||
kind: HelmRepository
|
||||
name: jitsi
|
||||
install:
|
||||
remediation:
|
||||
retries: -1
|
||||
upgrade:
|
||||
remediation:
|
||||
retries: 5
|
||||
driftDetection:
|
||||
mode: enabled
|
||||
# fixed xmpp credentials: the chart generates random ones on every render, which
|
||||
# desyncs jicofo/jvb from the already running prosody after an upgrade
|
||||
valuesFrom:
|
||||
- kind: Secret
|
||||
name: jitsi-secrets
|
||||
valuesKey: JICOFO_AUTH_PASSWORD
|
||||
targetPath: jicofo.xmpp.password
|
||||
- kind: Secret
|
||||
name: jitsi-secrets
|
||||
valuesKey: JICOFO_COMPONENT_SECRET
|
||||
targetPath: jicofo.xmpp.componentSecret
|
||||
- kind: Secret
|
||||
name: jitsi-secrets
|
||||
valuesKey: JVB_AUTH_PASSWORD
|
||||
targetPath: jvb.xmpp.password
|
||||
values:
|
||||
publicURL: https://v.aggtaa.com
|
||||
|
||||
web:
|
||||
ingress:
|
||||
enabled: true
|
||||
ingressClassName: traefik
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||
hosts:
|
||||
- host: v.aggtaa.com
|
||||
paths: ["/"]
|
||||
tls:
|
||||
- secretName: jitsi-tls
|
||||
hosts:
|
||||
- v.aggtaa.com
|
||||
|
||||
# media traffic: UDP 10000 must be forwarded from the WAN router to the JVB service ip (kubectl get svc -n video)
|
||||
jvb:
|
||||
UDPPort: 10000
|
||||
# wan ip first, then the service ip for clients on the lan (no hairpin nat needed);
|
||||
# the chart passes this string as-is to JVB_ADVERTISE_IPS, which accepts a comma separated list
|
||||
publicIPs:
|
||||
- 91.233.45.43,10.0.64.9
|
||||
service:
|
||||
enabled: true
|
||||
type: LoadBalancer
|
||||
externalTrafficPolicy: Cluster
|
||||
|
||||
postRenderers:
|
||||
- kustomize:
|
||||
patches:
|
||||
# dmz-pool has a single ip held by traefik, so use the dedicated public-ports-pool (see infra/metallb/config.yaml)
|
||||
- target:
|
||||
kind: Service
|
||||
name: jitsi-jitsi-meet-jvb
|
||||
patch: |
|
||||
- op: add
|
||||
path: /metadata/annotations/metallb.io~1address-pool
|
||||
value: public-ports-pool
|
||||
@@ -0,0 +1,8 @@
|
||||
apiVersion: source.toolkit.fluxcd.io/v1
|
||||
kind: HelmRepository
|
||||
metadata:
|
||||
name: jitsi
|
||||
namespace: video
|
||||
spec:
|
||||
interval: 1h
|
||||
url: https://jitsi-contrib.github.io/jitsi-helm/
|
||||
@@ -0,0 +1,6 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- helmrepository.yaml
|
||||
- helmrelease.yaml
|
||||
- secret.enc.yaml
|
||||
@@ -0,0 +1,24 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: jitsi-secrets
|
||||
namespace: video
|
||||
stringData:
|
||||
JICOFO_AUTH_PASSWORD: ENC[AES256_GCM,data:OUEZWPlqpkuhEI8kf65kKUooeahC3z03STevw7oOWx8=,iv:KSfrwehZG9kW7bfzQ5yavq6gYj+TrYKS/LZPNzaZdLI=,tag:/FiUF75ib3RXPuzO0EhIpw==,type:str]
|
||||
JICOFO_COMPONENT_SECRET: ENC[AES256_GCM,data:y8a84NdaClBRUFDPtXhulJxrX68Tn+4s1NrNqyhBjvI=,iv:fdqlgRwHNTdqegvfOrvX1Iph5aMKAtyW5zJUr+kBNx0=,tag:yNQ53KQQWafV7CSbNttJUQ==,type:str]
|
||||
JVB_AUTH_PASSWORD: ENC[AES256_GCM,data:GWSHUDfEZmLbKzU02U+ImCR0nVIp5ebngWVKBOmjOjY=,iv:uG7/4QPD8Wd2Q6lqPgKTD533GdbkXjdtZqJnshmNzjI=,tag:jhj5L86v0ZFalyhfQOTgCA==,type:str]
|
||||
sops:
|
||||
age:
|
||||
- recipient: age1zmr32r5mcgyh73asvzl8l690pzwqsx9hle27u3cydngsgv56wykq3v67px
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBuSXZWTzloNTMzWk5samRU
|
||||
amhURmFvdDlSMjd1RVFjUWxuWEtoVE13WUNJClptVUgxblRWL1RIYmZPZ2x2MG1H
|
||||
Y3ovWWlwL2dLeW9xbndXWEMvQVZONGcKLS0tIGxZNDZkRDBkZ0NDVWxMNGxoUFR4
|
||||
VG1wSm5wUWRVUEZ3cWlMb2lBNTVkZGcKAa4/S8EWBMt+uvT/6hYRl1GascDul+ox
|
||||
qlSV/20eA9uamssuId63ewaO4hL7ekwKwqM5cAFH+wx2dno9Ajuang==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
lastmodified: "2026-11-04T11:21:36Z"
|
||||
mac: ENC[AES256_GCM,data:r7iq6iTFL70Zat0sVw9nAHiueZNUWzV2j6q6POBUjeGLqn53ygJAXqG31REBLNKBwabLxsNlTmZRujpP6ySkbFve6fN1C6+6HFWdHnkeJx1nk4iJTvb5+Ld7Exp8yt6b46M/hHZxOffO23jVHuAa47hZ4lHphFpSrlgif79W/CI=,iv:bP9ll+tuTFOfh3kE7xiXtF0cH0sCfhaIs9fhNt0JoEU=,tag:hpBZBwRZxyAgn20aaGoGWA==,type:str]
|
||||
encrypted_regex: ^(data|stringData)$
|
||||
version: 3.11.0
|
||||
@@ -0,0 +1,80 @@
|
||||
apiVersion: helm.toolkit.fluxcd.io/v2
|
||||
kind: HelmRelease
|
||||
metadata:
|
||||
name: joplin
|
||||
namespace: pim
|
||||
spec:
|
||||
interval: 10m
|
||||
dependsOn:
|
||||
- name: joplin-postgres
|
||||
chartRef:
|
||||
kind: OCIRepository
|
||||
name: joplin
|
||||
driftDetection:
|
||||
mode: enabled
|
||||
values:
|
||||
controllers:
|
||||
app:
|
||||
containers:
|
||||
app:
|
||||
image:
|
||||
repository: joplin/server
|
||||
# verified via Docker Hub API (hub.docker.com/v2/repositories/
|
||||
# joplin/server/tags): "3.7.1" and "latest" were pushed at the
|
||||
# same timestamp, i.e. this is what "latest" (the original
|
||||
# compose.yaml's tag) currently resolves to.
|
||||
tag: "3.7.1"
|
||||
env:
|
||||
APP_PORT: "22300"
|
||||
APP_BASE_URL: https://notes.aggtaa.com
|
||||
DB_CLIENT: pg
|
||||
POSTGRES_DATABASE: joplin
|
||||
POSTGRES_USER: joplin
|
||||
POSTGRES_HOST: joplin-postgres
|
||||
POSTGRES_PORT: "5432"
|
||||
POSTGRES_PASSWORD:
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: joplin-secrets
|
||||
key: POSTGRES_PASSWORD
|
||||
probes:
|
||||
startup:
|
||||
enabled: true
|
||||
spec:
|
||||
periodSeconds: 5
|
||||
failureThreshold: 60
|
||||
liveness:
|
||||
enabled: true
|
||||
readiness:
|
||||
enabled: true
|
||||
resources:
|
||||
requests:
|
||||
cpu: 50m
|
||||
memory: 128Mi
|
||||
limits:
|
||||
memory: 1Gi
|
||||
|
||||
service:
|
||||
app:
|
||||
controller: app
|
||||
ports:
|
||||
http:
|
||||
port: 22300
|
||||
|
||||
ingress:
|
||||
app:
|
||||
className: traefik
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||
hosts:
|
||||
- host: notes.aggtaa.com
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
service:
|
||||
identifier: app
|
||||
port: http
|
||||
tls:
|
||||
- secretName: joplin-tls
|
||||
hosts:
|
||||
- notes.aggtaa.com
|
||||
@@ -0,0 +1,50 @@
|
||||
apiVersion: helm.toolkit.fluxcd.io/v2
|
||||
kind: HelmRelease
|
||||
metadata:
|
||||
name: joplin-postgres
|
||||
namespace: pim
|
||||
spec:
|
||||
interval: 10m
|
||||
chartRef:
|
||||
kind: OCIRepository
|
||||
name: joplin
|
||||
driftDetection:
|
||||
mode: enabled
|
||||
values:
|
||||
controllers:
|
||||
postgres:
|
||||
containers:
|
||||
app:
|
||||
image:
|
||||
repository: postgres
|
||||
# not alpine: joplin server needs a glibc-collation postgres,
|
||||
# matching the official (Debian-based) image used everywhere
|
||||
# else this pattern is followed in this repo.
|
||||
tag: "16.15"
|
||||
env:
|
||||
TZ: Europe/Moscow
|
||||
POSTGRES_USER: joplin
|
||||
POSTGRES_DB: joplin
|
||||
POSTGRES_PASSWORD:
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: joplin-secrets
|
||||
key: POSTGRES_PASSWORD
|
||||
|
||||
service:
|
||||
app:
|
||||
controller: postgres
|
||||
ports:
|
||||
postgres:
|
||||
port: 5432
|
||||
|
||||
persistence:
|
||||
data:
|
||||
type: persistentVolumeClaim
|
||||
accessMode: ReadWriteOnce
|
||||
size: 20Gi
|
||||
storageClass: longhorn
|
||||
retain: true
|
||||
globalMounts:
|
||||
- path: /var/lib/postgresql/data
|
||||
subPath: data
|
||||
@@ -0,0 +1,10 @@
|
||||
apiVersion: source.toolkit.fluxcd.io/v1
|
||||
kind: OCIRepository
|
||||
metadata:
|
||||
name: joplin
|
||||
namespace: pim
|
||||
spec:
|
||||
interval: 10m
|
||||
url: oci://ghcr.io/bjw-s-labs/helm/app-template
|
||||
ref:
|
||||
tag: "5.0.1"
|
||||
@@ -0,0 +1,7 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- helmrepository.yaml
|
||||
- secret.enc.yaml
|
||||
- helmrelease-postgres.yaml
|
||||
- helmrelease-joplin.yaml
|
||||
@@ -0,0 +1,22 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: joplin-secrets
|
||||
namespace: pim
|
||||
stringData:
|
||||
POSTGRES_PASSWORD: ENC[AES256_GCM,data:cI3zfdaJUbo2344RuLIG4DjPsgx4Afl6GKMJVHrOHOg=,iv:8QliTSQ44ScVUchDxh0DF/wU9bTLK9Jq4ojxSMXsNC8=,tag:VB2mf4uhLnRnafWg0mRRpg==,type:str]
|
||||
sops:
|
||||
age:
|
||||
- recipient: age1dertyl956fjsmh00cw468gdnl7lf3frasg4n4c82z0chm6qm2cks6w8gha
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBFQ2JKZWxseVAxUWU5NlhL
|
||||
S0xWQUh1NFpBU2ZpQkJXbkg4TlZ2cTR5TXhjCjlMTGdGMEF4UzBEbS9wdndJb1VE
|
||||
OXBOanpJS1lpTFVhWm52K2xhaGx2M00KLS0tIGF5b3FZOWRNVWNpenRmUDVOT3Vp
|
||||
aHpCbXkvdXM3SjYxWTlsT0cxU2RDOFkKximxt9bmd6FZAtU/SBirzDH3NMitQKrZ
|
||||
PfwicphmFEXVN+HtD9vwRbP4TMa1swOMbOVINGKuA8YZwEk1GyPe4w==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
lastmodified: "2026-08-27T10:16:36Z"
|
||||
mac: ENC[AES256_GCM,data:85dGV8WPFqd+4l6k7PLqDROm5+kwiAjO80ElNKfSJFOgeI9y7DyhyhDklcBJXMJljatbEfAmCFFqnoyRGmeIjc6FBfteUGQtpLgI6e8RTlRHPvaRzqDwA1OhnlQbAW9TTf5vha6tyYso/PprCWjJSMjBEfiu7ApiRMdZcLd1V4c=,iv:Dh9z/r7UbhdREwXT787HkmVM04X/BAtQmQteN3j7AKU=,tag:oUMYT5CL85PAYfItf5TIdw==,type:str]
|
||||
encrypted_regex: ^(data|stringData)$
|
||||
version: 3.11.0
|
||||
@@ -0,0 +1,63 @@
|
||||
apiVersion: helm.toolkit.fluxcd.io/v2
|
||||
kind: HelmRelease
|
||||
metadata:
|
||||
name: map-monitor
|
||||
namespace: iot
|
||||
spec:
|
||||
interval: 30m
|
||||
chartRef:
|
||||
kind: OCIRepository
|
||||
name: map-monitor
|
||||
install:
|
||||
remediation:
|
||||
retries: -1
|
||||
upgrade:
|
||||
remediation:
|
||||
retries: 5
|
||||
driftDetection:
|
||||
mode: enabled
|
||||
values:
|
||||
defaultPodOptions:
|
||||
securityContext:
|
||||
runAsUser: 65534
|
||||
runAsGroup: 65534
|
||||
runAsNonRoot: true
|
||||
|
||||
controllers:
|
||||
map-monitor:
|
||||
containers:
|
||||
app:
|
||||
image:
|
||||
repository: python
|
||||
tag: 3.12-slim
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- pip install --no-cache-dir --target /tmp/site -r /app/requirements.txt && exec python /app/map_mqtt.py
|
||||
env:
|
||||
PYTHONPATH: /tmp/site
|
||||
PYTHONUNBUFFERED: "1"
|
||||
PYTHONDONTWRITEBYTECODE: "1"
|
||||
PIP_DISABLE_PIP_VERSION_CHECK: "1"
|
||||
HOME: /tmp
|
||||
envFrom:
|
||||
- secretRef:
|
||||
name: map-monitor-secrets
|
||||
resources:
|
||||
requests:
|
||||
cpu: 10m
|
||||
memory: 32Mi
|
||||
limits:
|
||||
memory: 128Mi
|
||||
|
||||
persistence:
|
||||
code:
|
||||
type: configMap
|
||||
name: map-monitor-code
|
||||
globalMounts:
|
||||
- path: /app
|
||||
readOnly: true
|
||||
tmp:
|
||||
type: emptyDir
|
||||
globalMounts:
|
||||
- path: /tmp
|
||||
@@ -0,0 +1,10 @@
|
||||
apiVersion: source.toolkit.fluxcd.io/v1
|
||||
kind: OCIRepository
|
||||
metadata:
|
||||
name: map-monitor
|
||||
namespace: iot
|
||||
spec:
|
||||
interval: 1h
|
||||
url: oci://ghcr.io/bjw-s-labs/helm/app-template
|
||||
ref:
|
||||
tag: "5.0.1"
|
||||
@@ -0,0 +1,15 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- helmrepository.yaml
|
||||
- secret.enc.yaml
|
||||
- helmrelease.yaml
|
||||
configMapGenerator:
|
||||
- name: map-monitor-code
|
||||
namespace: iot
|
||||
files:
|
||||
- src/map_mqtt.py
|
||||
- src/map_read.py
|
||||
- src/requirements.txt
|
||||
generatorOptions:
|
||||
disableNameSuffixHash: true
|
||||
@@ -0,0 +1,36 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: map-monitor-secrets
|
||||
namespace: iot
|
||||
stringData:
|
||||
SERIAL_HOST: ENC[AES256_GCM,data:6cCm6shCy2kymQ==,iv:mqUOG6RZ6HGh3dBWy2LdWWXklU2FFhra9Xi3VgFdQi4=,tag:sJq/S+QslUWxeuK1JgQuBA==,type:str]
|
||||
SERIAL_PORT: ENC[AES256_GCM,data:ZiqkpB0=,iv:SryQv6eUrTZwA896oG83xHeLjzABqnn4pwlDPA56S3A=,tag:WPmz9uw+G+QQZW4L/Qfm1Q==,type:str]
|
||||
SERIAL_POLL_INTERVAL: ENC[AES256_GCM,data:Cw==,iv:myGXUNhVKALsedj1Do56clisSiAvqE19rqTGQjtYxCI=,tag:XvTcCvI9B5YyizJ4skfB1A==,type:str]
|
||||
SERIAL_TIMEOUT: ENC[AES256_GCM,data:mMtT,iv:nz7nJXuLU3tpO2l04+aRTczCwnmgubLOw7a/cg6Yjic=,tag:nMed9+RH6VKZDQURwuMd/g==,type:str]
|
||||
MQTT_HOST: ENC[AES256_GCM,data:qyjHpa6fNG+IaQvj6LsUGF8iPxWU4NzdzPCt1ZcodFE=,iv:dxCP9gfasYovuBI6pxkynKkNAh99bUIEr8fn9Qbqxww=,tag:mz1BgruIsUXE/sJdiCqH6g==,type:str]
|
||||
MQTT_PORT: ENC[AES256_GCM,data:PPxXlQ==,iv:s4b8gCGna5Va0B9BN02ZLlofYlIQiVn9KU8qJNECK5I=,tag:neXH/dwhfW1u1UfkRuY2mg==,type:str]
|
||||
MQTT_USER: ENC[AES256_GCM,data:Xs6v,iv:DlyX9ErjbcJ4WxQFBhCdiBCRUqOpEYwWSg/X3uA4sSk=,tag:4N/85y5h2u754qP4iyIeiw==,type:str]
|
||||
MQTT_PASSWORD: ENC[AES256_GCM,data:CD/cSnauAZ29KHuwGblqqDxSdrw=,iv:1mUsaq847o4rjbMIpSRErVIF8ZI+4oS4LDJGwbas0Jo=,tag:y7uSxXNFFM5HD/1IMRj5og==,type:str]
|
||||
MQTT_TLS: ENC[AES256_GCM,data:lhmlb+8=,iv:mZiHwfgmkpWiBBRF5SvuSP/wlXMnAQmNnSZTYc0kMRM=,tag:VNxesMInF1Vj/gbeK/FlJA==,type:str]
|
||||
MQTT_CLIENT_ID: ENC[AES256_GCM,data:Epdn4DGpQtgl53sc+Qo=,iv:gjVPQA1g0IFrzNJuqOWAAUgaFZsnZ2te5V32Q/SPTJg=,tag:zSauVShmjG0K8FDVevvolQ==,type:str]
|
||||
MQTT_DISCOVERY_PREFIX: ENC[AES256_GCM,data:9ThR6rD3yXShgW1TmA==,iv:yn+89NBc6rXqbUnnKSqiWhzCruf0HPt3DfgxrhGZq7g=,tag:YoWynvyWRxdJ+UCbfjCJtQ==,type:str]
|
||||
MQTT_BASE_TOPIC: ENC[AES256_GCM,data:Y8fGesOJmsXOvdE0khg=,iv:CyyDnQkUzGivWWAQnzWyElqoLeXmT7uLns5te03Hq0E=,tag:5CCuHp2ZeaZyXF4LmoLTUg==,type:str]
|
||||
DEVICE_ID: ENC[AES256_GCM,data:RF2wLrHe/+CA0em/Yc0=,iv:IQx6zlX31rywQlhxchmGu3pjYg7JJlyNw1KT1/ELsL4=,tag:wVQ2s6XDN1l+tM9EQnjX/g==,type:str]
|
||||
DEVICE_NAME: ENC[AES256_GCM,data:fHTyCXeA0aDlNqp7HRCuppTGkYnP,iv:wMp+umM2Y6S/54t5nc4h9PYCZd5NloOYIpCp3/4vOoE=,tag:PcP3e3hrJ+r78oPC7etm5g==,type:str]
|
||||
LOG_LEVEL: ENC[AES256_GCM,data:/oGKyg==,iv:3A/971xbMz+dm+czrslz2nS3J1PRaM+7zLNACEHX7OM=,tag:OmLgstVHAT4GpviplU5V8Q==,type:str]
|
||||
sops:
|
||||
age:
|
||||
- recipient: age1k4j5vyqqt7w7k52gvkpfe6znqr9mlgt076l7xgdtyc75lamsh4aqshj5qs
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBZZ0R5UzhmOXV6T01KbTdr
|
||||
Y2tCR2owUHZVV2VVakpEWXZjK3BNcTkzOVdZCjAzUnJaK2lMTWFhS0tTY2EvSU9u
|
||||
OGh4SlI0em9YYUxkTGZZOUR2SG0yZjAKLS0tIFE5MWt4b3VWcmtVWXpwWjlTbHlT
|
||||
R3ZQckkwMVJTekNRZW1uQVZVYXAvcTQKTeXGo0pBSFXderktCrgX6/hDRBraiOMF
|
||||
SPr6hDe0ejMfWyOUSA9XQRQnn20gssRtA5DzNfpkjA3Gam+CU9Lu0w==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
lastmodified: "2026-10-26T11:29:23Z"
|
||||
mac: ENC[AES256_GCM,data:jVnj8WpNjbFHwDfU2NBCcoqyfRYotmvc7w1b2A7e40GPYBKmkqVkZUlxBp4oc2p4qj+SRfPPKSUqDfxNqIS+oiqidui41/EhsJtPBjqyjoWmLfMMriwYUMlxrdFeCNNL97cUJin+Cy/OvPXgIU1BX9hnqyz0mTU5ce1zWju25Mc=,iv:4GJialKu0t9WmGoxKAA1P6wuan5gD8fSn3sToEL0QRU=,tag:yZbaQpIfUFh5eZvWQlKwxg==,type:str]
|
||||
encrypted_regex: ^(data|stringData)$
|
||||
version: 3.11.0
|
||||
@@ -0,0 +1,10 @@
|
||||
FROM python:3.12-slim
|
||||
|
||||
WORKDIR /app
|
||||
COPY requirements.txt .
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
COPY map_read.py map_mqtt.py ./
|
||||
|
||||
ENV PYTHONUNBUFFERED=1
|
||||
USER nobody
|
||||
CMD ["python", "map_mqtt.py"]
|
||||
@@ -0,0 +1,259 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Service: polls a MAP inverter via ser2net and publishes to MQTT for Home Assistant
|
||||
(MQTT discovery). Values are also written to the console for diagnostics.
|
||||
|
||||
All configuration is done via environment variables (see .env.example).
|
||||
"""
|
||||
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import signal
|
||||
import sys
|
||||
import threading
|
||||
|
||||
import paho.mqtt.client as mqtt
|
||||
|
||||
from map_read import MapClient, MapError, read_status
|
||||
|
||||
log = logging.getLogger("map_mqtt")
|
||||
|
||||
|
||||
def env(name, default=None, cast=str):
|
||||
v = os.environ.get(name, "")
|
||||
if v == "":
|
||||
if default is None:
|
||||
sys.exit("Environment variable %s is not set" % name)
|
||||
return default
|
||||
return cast(v)
|
||||
|
||||
|
||||
SERIAL_HOST = env("SERIAL_HOST", "10.0.64.24")
|
||||
SERIAL_PORT = env("SERIAL_PORT", 33333, int)
|
||||
SERIAL_TIMEOUT = env("SERIAL_TIMEOUT", 1.0, float)
|
||||
SERIAL_POLL_INTERVAL = env("SERIAL_POLL_INTERVAL", 5.0, float)
|
||||
|
||||
MQTT_HOST = env("MQTT_HOST")
|
||||
MQTT_PORT = env("MQTT_PORT", 1883, int)
|
||||
MQTT_USER = env("MQTT_USER", "")
|
||||
MQTT_PASSWORD = env("MQTT_PASSWORD", "")
|
||||
MQTT_CLIENT_ID = env("MQTT_CLIENT_ID", "map-inverter")
|
||||
MQTT_TLS = env("MQTT_TLS", "false").lower() in ("1", "true", "yes")
|
||||
DISCOVERY_PREFIX = env("MQTT_DISCOVERY_PREFIX", "homeassistant")
|
||||
BASE_TOPIC = env("MQTT_BASE_TOPIC", "map_inverter")
|
||||
|
||||
DEVICE_ID = env("DEVICE_ID", "map_inverter")
|
||||
DEVICE_NAME = env("DEVICE_NAME", "MAP Energy")
|
||||
|
||||
STATE_TOPIC = "%s/state" % BASE_TOPIC
|
||||
AVAIL_TOPIC = "%s/availability" % BASE_TOPIC
|
||||
HA_STATUS_TOPIC = "%s/status" % DISCOVERY_PREFIX
|
||||
|
||||
# (key, component, name, unit, device_class, state_class, extra)
|
||||
ENTITIES = [
|
||||
("mode_text", "sensor", "Mode", None, None, None, {"icon": "mdi:state-machine"}),
|
||||
("mode", "sensor", "Mode code", None, None, None,
|
||||
{"icon": "mdi:numeric", "entity_category": "diagnostic"}),
|
||||
("u_acc", "sensor", "Battery voltage", "V", "voltage", "measurement", {}),
|
||||
("i_acc", "sensor", "Battery current", "A", "current", "measurement", {}),
|
||||
("p_acc", "sensor", "Battery power", "W", "power", "measurement", {}),
|
||||
("p_load", "sensor", "Load power", "W", "power", "measurement", {}),
|
||||
("u_net", "sensor", "Grid voltage", "V", "voltage", "measurement", {}),
|
||||
("i_net", "sensor", "Grid current", "A", "current", "measurement", {}),
|
||||
("p_net", "sensor", "Grid power", "W", "power", "measurement", {}),
|
||||
("f_net", "sensor", "Grid frequency", "Hz", "frequency", "measurement", {}),
|
||||
("u_out", "sensor", "Output voltage", "V", "voltage", "measurement", {}),
|
||||
("f_out", "sensor", "Output frequency", "Hz", "frequency", "measurement", {}),
|
||||
("t_acc", "sensor", "Battery temperature", "°C", "temperature", "measurement", {}),
|
||||
("t_tor", "sensor", "Transformer temperature", "°C", "temperature", "measurement", {}),
|
||||
("t_trans", "sensor", "Transistor temperature", "°C", "temperature", "measurement", {}),
|
||||
("u_net_limit", "sensor", "Last out-of-range grid voltage", "V", "voltage", None,
|
||||
{"entity_category": "diagnostic"}),
|
||||
("e_net", "sensor", "Energy from grid", "kWh", "energy", "total_increasing", {}),
|
||||
("e_acc", "sensor", "Energy from battery", "kWh", "energy", "total_increasing", {}),
|
||||
("e_acc_charge", "sensor", "Battery charge energy", "kWh", "energy", "total_increasing", {}),
|
||||
("errors_text", "sensor", "Errors", None, None, None,
|
||||
{"icon": "mdi:alert-circle-outline", "entity_category": "diagnostic"}),
|
||||
("problem", "binary_sensor", "Problem", None, "problem", None,
|
||||
{"entity_category": "diagnostic"}),
|
||||
("net_reverse", "binary_sensor", "Grid export", None, None, None,
|
||||
{"icon": "mdi:transmission-tower-export"}),
|
||||
("relay1", "binary_sensor", "Relay 1", None, None, None, {"icon": "mdi:electric-switch"}),
|
||||
("relay2", "binary_sensor", "Relay 2", None, None, None, {"icon": "mdi:electric-switch"}),
|
||||
]
|
||||
|
||||
|
||||
def to_payload(s):
|
||||
"""Flatten the read_status result into JSON for the state topic."""
|
||||
p = {k: s[k] for k in ("mode", "mode_text", "u_acc", "i_acc", "p_acc", "p_load", "u_net",
|
||||
"i_net", "p_net", "f_net", "u_out", "f_out", "t_acc", "t_tor",
|
||||
"t_trans", "u_net_limit")}
|
||||
# counter unit is 0.01 kWh (malina html/meters.js; confirmed against integrated grid power)
|
||||
p["e_net"] = s["e_net_raw"] / 100
|
||||
p["e_acc"] = s["e_acc_raw"] / 100
|
||||
p["e_acc_charge"] = s["e_acc_charge_raw"] / 100
|
||||
for k in ("net_reverse", "relay1", "relay2"):
|
||||
p[k] = "ON" if s[k] else "OFF"
|
||||
p["problem"] = "ON" if s["errors"] else "OFF"
|
||||
texts = ["%s: %s" % (name, "; ".join(e["bits"])) for name, e in s["errors"].items()]
|
||||
p["errors_text"] = (" | ".join(texts) or "none")[:255]
|
||||
p["errors"] = {name: e["value"] for name, e in s["errors"].items()}
|
||||
return p
|
||||
|
||||
|
||||
def discovery_messages():
|
||||
device = {
|
||||
"identifiers": [DEVICE_ID],
|
||||
"name": DEVICE_NAME,
|
||||
"manufacturer": "microART",
|
||||
"model": "MAP",
|
||||
}
|
||||
for key, component, name, unit, dev_class, state_class, extra in ENTITIES:
|
||||
cfg = {
|
||||
"name": name,
|
||||
"unique_id": "%s_%s" % (DEVICE_ID, key),
|
||||
"state_topic": STATE_TOPIC,
|
||||
"value_template": "{{ value_json.%s }}" % key,
|
||||
"availability_topic": AVAIL_TOPIC,
|
||||
"device": device,
|
||||
}
|
||||
if unit:
|
||||
cfg["unit_of_measurement"] = unit
|
||||
if dev_class:
|
||||
cfg["device_class"] = dev_class
|
||||
if state_class:
|
||||
cfg["state_class"] = state_class
|
||||
if key == "errors_text":
|
||||
cfg["json_attributes_topic"] = STATE_TOPIC
|
||||
cfg["json_attributes_template"] = "{{ value_json.errors | tojson }}"
|
||||
cfg.update(extra)
|
||||
topic = "%s/%s/%s/%s/config" % (DISCOVERY_PREFIX, component, DEVICE_ID, key)
|
||||
yield topic, json.dumps(cfg, ensure_ascii=False)
|
||||
|
||||
|
||||
class Publisher:
|
||||
def __init__(self):
|
||||
self.client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id=MQTT_CLIENT_ID)
|
||||
if MQTT_USER:
|
||||
self.client.username_pw_set(MQTT_USER, MQTT_PASSWORD)
|
||||
if MQTT_TLS:
|
||||
self.client.tls_set()
|
||||
self.client.will_set(AVAIL_TOPIC, "offline", qos=1, retain=True)
|
||||
self.client.on_connect = self._on_connect
|
||||
self.client.on_disconnect = self._on_disconnect
|
||||
self.client.on_message = self._on_message
|
||||
self.online = False
|
||||
self._connack = threading.Event()
|
||||
self._connect_error = None
|
||||
|
||||
def start(self, timeout=10):
|
||||
"""Connect to the broker; raise on failure (the program will exit).
|
||||
Later disconnects are handled by paho's automatic reconnect."""
|
||||
self.client.connect(MQTT_HOST, MQTT_PORT, keepalive=60) # OSError on a bad address
|
||||
self.client.loop_start()
|
||||
if not self._connack.wait(timeout):
|
||||
self.client.loop_stop()
|
||||
raise ConnectionError("broker did not respond within %d s" % timeout)
|
||||
if self._connect_error:
|
||||
self.client.loop_stop()
|
||||
raise ConnectionError("broker refused connection: %s" % self._connect_error)
|
||||
|
||||
def stop(self):
|
||||
self.client.publish(AVAIL_TOPIC, "offline", qos=1, retain=True).wait_for_publish(2)
|
||||
self.client.disconnect()
|
||||
self.client.loop_stop()
|
||||
|
||||
def _on_connect(self, client, userdata, flags, reason_code, properties):
|
||||
if reason_code.is_failure:
|
||||
log.error("MQTT: broker refused connection: %s", reason_code)
|
||||
if not self._connack.is_set():
|
||||
self._connect_error = reason_code
|
||||
self._connack.set()
|
||||
return
|
||||
self._connack.set()
|
||||
log.info("MQTT: connected to %s:%d", MQTT_HOST, MQTT_PORT)
|
||||
client.subscribe(HA_STATUS_TOPIC)
|
||||
self.publish_discovery()
|
||||
self.set_available(self.online)
|
||||
|
||||
def _on_disconnect(self, client, userdata, flags, reason_code, properties):
|
||||
log.warning("MQTT: disconnected (%s), reconnecting...", reason_code)
|
||||
|
||||
def _on_message(self, client, userdata, msg):
|
||||
# Home Assistant restarted - republish discovery
|
||||
if msg.topic == HA_STATUS_TOPIC and msg.payload == b"online":
|
||||
log.info("MQTT: Home Assistant online, republishing discovery")
|
||||
self.publish_discovery()
|
||||
self.set_available(self.online)
|
||||
|
||||
def publish_discovery(self):
|
||||
for topic, payload in discovery_messages():
|
||||
self.client.publish(topic, payload, qos=1, retain=True)
|
||||
|
||||
def set_available(self, online):
|
||||
self.online = online
|
||||
self.client.publish(AVAIL_TOPIC, "online" if online else "offline", qos=1, retain=True)
|
||||
|
||||
def publish_state(self, payload):
|
||||
self.client.publish(STATE_TOPIC, json.dumps(payload, ensure_ascii=False), qos=0)
|
||||
|
||||
|
||||
def format_line(p):
|
||||
return ("mode=%d (%s) Ubat=%.1fV Ibat=%.1fA Pbat=%dW Pload=%dW Ugrid=%dV Igrid=%.1fA "
|
||||
"Pgrid=%dW Fgrid=%sHz Uout=%dV Fout=%sHz Tbat=%d Ttr=%d Ttrans=%d "
|
||||
"Egrid=%.2f Ebat=%.2f Echarge=%.2f errors=%s") % (
|
||||
p["mode"], p["mode_text"], p["u_acc"], p["i_acc"], p["p_acc"], p["p_load"],
|
||||
p["u_net"], p["i_net"], p["p_net"], p["f_net"], p["u_out"], p["f_out"],
|
||||
p["t_acc"], p["t_tor"], p["t_trans"], p["e_net"], p["e_acc"], p["e_acc_charge"],
|
||||
p["errors_text"])
|
||||
|
||||
|
||||
def main():
|
||||
logging.basicConfig(level=env("LOG_LEVEL", "INFO").upper(), stream=sys.stdout,
|
||||
format="%(asctime)s %(levelname)s %(message)s")
|
||||
if hasattr(sys.stdout, "reconfigure"):
|
||||
sys.stdout.reconfigure(encoding="utf-8", line_buffering=True)
|
||||
|
||||
stop = threading.Event()
|
||||
signal.signal(signal.SIGTERM, lambda *a: stop.set())
|
||||
signal.signal(signal.SIGINT, lambda *a: stop.set())
|
||||
|
||||
log.info("Starting: ser2net %s:%d, poll every %.1f s, MQTT %s:%d, topic %s",
|
||||
SERIAL_HOST, SERIAL_PORT, SERIAL_POLL_INTERVAL, MQTT_HOST, MQTT_PORT, STATE_TOPIC)
|
||||
pub = Publisher()
|
||||
try:
|
||||
pub.start()
|
||||
except OSError as e: # ConnectionError is an OSError too
|
||||
log.error("MQTT: failed to connect to %s:%d: %s", MQTT_HOST, MQTT_PORT, e)
|
||||
sys.exit(1)
|
||||
|
||||
client = None
|
||||
while not stop.is_set():
|
||||
try:
|
||||
if client is None:
|
||||
client = MapClient(SERIAL_HOST, SERIAL_PORT, SERIAL_TIMEOUT)
|
||||
client.connect()
|
||||
log.info("ser2net: connected to %s:%d", SERIAL_HOST, SERIAL_PORT)
|
||||
payload = to_payload(read_status(client))
|
||||
log.info(format_line(payload))
|
||||
pub.publish_state(payload)
|
||||
if not pub.online:
|
||||
pub.set_available(True)
|
||||
except (MapError, OSError) as e:
|
||||
log.error("ser2net: %s", e)
|
||||
if client is not None:
|
||||
client.close()
|
||||
client = None
|
||||
if pub.online:
|
||||
pub.set_available(False)
|
||||
stop.wait(SERIAL_POLL_INTERVAL)
|
||||
|
||||
log.info("Stopping")
|
||||
if client is not None:
|
||||
client.close()
|
||||
pub.stop()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,385 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Read the current operating parameters of a MAP inverter (microART) via ser2net (raw TCP).
|
||||
|
||||
Protocol reverse-engineered from thirdparty/malina/usr/bin/mapd.c:
|
||||
* 19200 8N1 (configured on the ser2net side);
|
||||
* every byte sent by the host is echoed back by the MAP; every byte of the MAP
|
||||
reply must be echoed back by the host, otherwise the MAP won't send the next one;
|
||||
* request: cmd('r'=0x72) | count-1 | addr_hi | addr_lo | crc | '\\n'
|
||||
* reply: 'o'(0x6F) | data... | crc | '\\n' ('e'=0x65 means error)
|
||||
* byte 0x0A inside a frame is encoded as DB DC, byte 0xDB as DB DD;
|
||||
* crc = (0x100 - sum of all frame bytes in encoded form) & 0xFF;
|
||||
if crc == 0x0A it also serves as the frame terminator.
|
||||
|
||||
Usage:
|
||||
python map_read.py # single read, 10.0.64.24:33333
|
||||
python map_read.py --loop 2 # poll every 2 s
|
||||
python map_read.py --json # JSON output
|
||||
python map_read.py --host 1.2.3.4 --port 4001
|
||||
|
||||
The ser2net port must be in raw mode (not telnet), for example:
|
||||
33333:raw:0:/dev/ttyUSB0:19200 8DATABITS NONE 1STOPBIT
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import select
|
||||
import socket
|
||||
import sys
|
||||
import time
|
||||
|
||||
DEFAULT_HOST = "10.0.64.24"
|
||||
DEFAULT_PORT = 33333
|
||||
|
||||
CMD_READ = 0x72 # 'r'
|
||||
ANS_OK = 0x6F # 'o'
|
||||
ANS_ERR = 0x65 # 'e'
|
||||
LF = 0x0A
|
||||
ESC = 0xDB
|
||||
|
||||
MODES = {
|
||||
0: "System: OFF, Input grid: OFF",
|
||||
1: "System: OFF, Input grid: ON",
|
||||
2: "System: ON, Input grid: OFF, Local grid: BATTERY, Battery: DISCHARGING",
|
||||
3: "System: ON, Input grid: ON, Local grid: PASS-THROUGH",
|
||||
4: "System: ON, Input grid: ON, Local grid: PASS-THROUGH, Battery: CHARGING",
|
||||
}
|
||||
|
||||
# Error bit field descriptions (from html/local/RU/local.inc)
|
||||
ERROR_BITS = {
|
||||
"RSErrJobM": [
|
||||
"Battery fully discharged, voltage critically low",
|
||||
"Battery overvoltage, inverting/charging suspended",
|
||||
"Battery short circuit while charging, charging suspended",
|
||||
"Battery short circuit, inverting/charging suspended",
|
||||
"Main relay may be stuck",
|
||||
"Short circuit on 220V grid",
|
||||
"External voltage on 220V output, inverting disabled",
|
||||
"Firmware reset (interference)",
|
||||
],
|
||||
"RSErrJob": [
|
||||
"Battery discharged, inverting will stop in 1 minute",
|
||||
"Battery overload",
|
||||
"Load above rated power (limited operating time)",
|
||||
"Overheating, inverting/charging suspended",
|
||||
"Fan not spinning",
|
||||
"Grid overload, switching to inverter",
|
||||
"Operating mode failure (power loss/interference)",
|
||||
"Shutdown after repeated short circuits while charging (cleared after 2 h)",
|
||||
],
|
||||
"RSWarning": [
|
||||
"No action for START+CHARGE button combination",
|
||||
"Grid voltage out of range",
|
||||
"External voltage on output or voltage spikes from load",
|
||||
"Voltage spikes on grid input",
|
||||
"START or CHARGE button stuck",
|
||||
"Charging not possible - no grid",
|
||||
"Load power above EE_LCD_NetMaxPow, switching to inverter",
|
||||
"Grid unstable",
|
||||
],
|
||||
"RSErrDop": [
|
||||
"Invalid data from previous phase / no link",
|
||||
"Phase shift outside 60 deg synchronization window",
|
||||
"BMS I2C error",
|
||||
"MPPT I2C error",
|
||||
"Outdated MPPT firmware",
|
||||
"Parallel MAP synchronization error",
|
||||
"Slave MAP has no grid while master switched to grid",
|
||||
None,
|
||||
],
|
||||
"I2C_Err": ["I2C Err Ack", "I2C Err Sum", "I2C Err Data Size", "I2C Err Protocol",
|
||||
None, None, None, None],
|
||||
"F_Acc_Over": [
|
||||
"Shutdown: battery overcurrent",
|
||||
"Shutdown: battery overcurrent while charging",
|
||||
"Shutdown: battery voltage critically low",
|
||||
"Shutdown: fan failure",
|
||||
"Shutdown: power above rated for more than 30 min",
|
||||
"Shutdown: battery fully discharged",
|
||||
"Shutdown: temperature sensor out of range",
|
||||
"Full shutdown after repeated battery overloads (press START)",
|
||||
],
|
||||
"F_Net_Over": [
|
||||
"Inverting disabled - external voltage on output or faulty relay",
|
||||
"Switched to inverter - grid overload",
|
||||
None,
|
||||
"Shutdown after repeated grid overloads (press START)",
|
||||
None, None, None, None,
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
class MapError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class MapClient:
|
||||
def __init__(self, host, port, timeout=1.0):
|
||||
self.host = host
|
||||
self.port = port
|
||||
self.timeout = timeout
|
||||
self.sock = None
|
||||
|
||||
def connect(self):
|
||||
self.sock = socket.create_connection((self.host, self.port), timeout=5)
|
||||
self.sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
|
||||
self.sock.settimeout(self.timeout)
|
||||
self.flush()
|
||||
|
||||
def close(self):
|
||||
if self.sock:
|
||||
self.sock.close()
|
||||
self.sock = None
|
||||
|
||||
def __enter__(self):
|
||||
self.connect()
|
||||
return self
|
||||
|
||||
def __exit__(self, *exc):
|
||||
self.close()
|
||||
|
||||
# --- byte level ------------------------------------------------------
|
||||
|
||||
def flush(self):
|
||||
"""Discard everything accumulated in the input buffer."""
|
||||
while True:
|
||||
r, _, _ = select.select([self.sock], [], [], 0.05)
|
||||
if not r:
|
||||
return
|
||||
if not self.sock.recv(4096):
|
||||
raise MapError("connection closed by ser2net")
|
||||
|
||||
def _recv1(self):
|
||||
try:
|
||||
b = self.sock.recv(1)
|
||||
except socket.timeout:
|
||||
raise MapError("MAP response timeout")
|
||||
if not b:
|
||||
raise MapError("connection closed by ser2net")
|
||||
return b[0]
|
||||
|
||||
def _put(self, a):
|
||||
"""Send a byte and wait for its echo (resyncing to the stream, as mapd.c does)."""
|
||||
self.sock.sendall(bytes([a]))
|
||||
for _ in range(21):
|
||||
if self._recv1() == a:
|
||||
return
|
||||
raise MapError("no echo from MAP (0x%02X)" % a)
|
||||
|
||||
def _put_coded(self, a, csum):
|
||||
if a == LF:
|
||||
seq = (ESC, 0xDC)
|
||||
elif a == ESC:
|
||||
seq = (ESC, 0xDD)
|
||||
else:
|
||||
seq = (a,)
|
||||
for b in seq:
|
||||
self._put(b)
|
||||
csum += b
|
||||
return csum
|
||||
|
||||
# --- frames ----------------------------------------------------------
|
||||
|
||||
def _send_command(self, cmd, addr, count):
|
||||
csum = 0
|
||||
for b in (cmd, count - 1, addr >> 8, addr & 0xFF):
|
||||
csum = self._put_coded(b, csum)
|
||||
crc = (-csum) & 0xFF
|
||||
self._put(crc)
|
||||
if crc != LF:
|
||||
self._put(LF)
|
||||
|
||||
def _read_answer(self):
|
||||
raw = bytearray()
|
||||
while True:
|
||||
b = self._recv1()
|
||||
raw.append(b)
|
||||
self.sock.sendall(bytes([b])) # echo back to the MAP
|
||||
if b == LF or len(raw) > 600:
|
||||
break
|
||||
|
||||
if raw[0] == ANS_ERR:
|
||||
raise MapError("MAP returned an error ('e')")
|
||||
if raw[0] != ANS_OK or len(raw) < 3:
|
||||
raise MapError("unexpected reply: %s" % raw[:16].hex())
|
||||
|
||||
if ((-sum(raw[:-2])) & 0xFF) == raw[-2]:
|
||||
body = raw[1:-2]
|
||||
elif ((-sum(raw[:-1])) & 0xFF) == LF:
|
||||
body = raw[1:-1] # crc == 0x0A is itself the frame terminator
|
||||
else:
|
||||
raise MapError("checksum error")
|
||||
|
||||
data = bytearray()
|
||||
i = 0
|
||||
while i < len(body):
|
||||
if body[i] == ESC and i + 1 < len(body) and body[i + 1] in (0xDC, 0xDD):
|
||||
data.append(LF if body[i + 1] == 0xDC else ESC)
|
||||
i += 2
|
||||
else:
|
||||
data.append(body[i])
|
||||
i += 1
|
||||
return bytes(data)
|
||||
|
||||
def read(self, addr, count, retries=3):
|
||||
"""Read count (1..256) bytes of MAP memory starting at addr."""
|
||||
last = None
|
||||
for _ in range(retries):
|
||||
try:
|
||||
self._send_command(CMD_READ, addr, count)
|
||||
data = self._read_answer()
|
||||
if len(data) < count:
|
||||
raise MapError("short reply: %d of %d bytes" % (len(data), count))
|
||||
return data[:count]
|
||||
except MapError as e:
|
||||
last = e
|
||||
time.sleep(0.2)
|
||||
self.flush()
|
||||
raise last
|
||||
|
||||
|
||||
# --- data decoding -------------------------------------------------------
|
||||
|
||||
def decode_bits(name, value):
|
||||
texts = ERROR_BITS.get(name, [])
|
||||
out = []
|
||||
for bit in range(8):
|
||||
if value >> bit & 1:
|
||||
t = texts[bit] if bit < len(texts) and texts[bit] else "bit %d" % bit
|
||||
out.append(t)
|
||||
return out
|
||||
|
||||
|
||||
def phase_current(lo, hi):
|
||||
v = (lo + (hi & 0x7F) * 256) / 10
|
||||
return -v if hi & 0x80 else v
|
||||
|
||||
|
||||
def read_status(client):
|
||||
m = client.read(0x400, 256)
|
||||
x = lambda addr: m[addr - 0x400]
|
||||
e = client.read(0x527, 96)
|
||||
y = lambda addr: e[addr - 0x527]
|
||||
|
||||
unet = x(0x422) + 100 if x(0x422) else 0
|
||||
uout = x(0x427) + 100 if x(0x427) else 0
|
||||
inet_raw = x(0x423)
|
||||
hz = lambda t: round(6250 / t, 1) if t else None
|
||||
|
||||
s = {
|
||||
"mode": x(0x400),
|
||||
"mode_text": MODES.get(x(0x400), "unknown mode"),
|
||||
"status_char": x(0x402),
|
||||
"u_acc": (x(0x405) * 256 + x(0x406)) / 10,
|
||||
"i_acc": round(x(0x432) / 16 + x(0x433) * 16, 1),
|
||||
"i_acc_coarse": x(0x408) * 2,
|
||||
"p_load": x(0x409) * 100,
|
||||
"u_net": unet,
|
||||
"i_net": round(x(0x431) / (16 if inet_raw < 16 else 4), 1),
|
||||
"p_net": x(0x424) * 100,
|
||||
"f_net": hz(x(0x425)),
|
||||
"u_out": uout,
|
||||
"f_out": hz(x(0x426)),
|
||||
"u_net_limit": x(0x429) + 100,
|
||||
"f_net_limit": round(2500 / x(0x428), 1) if x(0x428) else None,
|
||||
"t_acc": x(0x42E) - 50,
|
||||
"t_tor": x(0x42F) - 50,
|
||||
"t_trans": x(0x430) - 50,
|
||||
"net_reverse": (x(0x443) + x(0x444) * 256) > 32768,
|
||||
"e_net_raw": x(0x44D) | x(0x44E) << 8 | x(0x44F) << 16,
|
||||
"e_acc_raw": x(0x450) | x(0x451) << 8 | x(0x452) << 16,
|
||||
"e_acc_charge_raw": x(0x453) | x(0x454) << 8 | x(0x455) << 16,
|
||||
"flag_eco": y(0x585),
|
||||
"relay1": bool(y(0x586) & 1),
|
||||
"relay2": bool(y(0x586) & 2),
|
||||
# meaningful only in a three-phase setup, otherwise these cells hold garbage
|
||||
"i_phase": [phase_current(y(0x528), y(0x529)),
|
||||
phase_current(y(0x52A), y(0x52B)),
|
||||
phase_current(y(0x52C), y(0x52D))],
|
||||
"errors": {},
|
||||
}
|
||||
s["p_acc"] = round(s["u_acc"] * s["i_acc"])
|
||||
|
||||
for name, addr in (("RSErrSis", 0x42A), ("RSErrJobM", 0x42B), ("RSErrJob", 0x42C),
|
||||
("RSWarning", 0x42D), ("RSErrDop", 0x447), ("I2C_Err", 0x45A),
|
||||
("F_Acc_Over", 0x41C), ("F_Net_Over", 0x41D)):
|
||||
v = x(addr)
|
||||
if v:
|
||||
s["errors"][name] = {"value": v, "bits": decode_bits(name, v)}
|
||||
return s
|
||||
|
||||
|
||||
def print_status(s):
|
||||
rows = [
|
||||
("Mode", "%d - %s" % (s["mode"], s["mode_text"])),
|
||||
("Battery voltage", "%.1f V" % s["u_acc"]),
|
||||
("Battery current", "%.1f A (coarse %d A)" % (s["i_acc"], s["i_acc_coarse"])),
|
||||
("Battery power (calc.)", "%d W" % s["p_acc"]),
|
||||
("MAP load power", "%d W" % s["p_load"]),
|
||||
("Grid voltage", "%d V" % s["u_net"]),
|
||||
("Grid current", "%.1f A" % s["i_net"]),
|
||||
("Grid power", "%d W%s" % (s["p_net"], " (export to grid)" if s["net_reverse"] else "")),
|
||||
("Grid frequency", "%s Hz" % s["f_net"]),
|
||||
("Output voltage", "%d V" % s["u_out"]),
|
||||
("Output frequency", "%s Hz" % s["f_out"]),
|
||||
("Battery temp.", "%d °C" % s["t_acc"]),
|
||||
("Transformer temp.", "%d °C" % s["t_tor"]),
|
||||
("Transistor temp.", "%d °C" % s["t_trans"]),
|
||||
("Last out-of-range U", "%d V" % s["u_net_limit"]),
|
||||
("Relay 1 / Relay 2", "%s / %s" % ("on" if s["relay1"] else "off",
|
||||
"on" if s["relay2"] else "off")),
|
||||
("Energy from grid", "%.2f kWh" % (s["e_net_raw"] / 100)),
|
||||
("Energy from battery", "%.2f kWh" % (s["e_acc_raw"] / 100)),
|
||||
("Battery charge energy", "%.2f kWh" % (s["e_acc_charge_raw"] / 100)),
|
||||
]
|
||||
w =max(len(r[0]) for r in rows)
|
||||
print(time.strftime("%Y-%m-%d %H:%M:%S"))
|
||||
for k, v in rows:
|
||||
print(" %-*s : %s" % (w, k, v))
|
||||
if s["errors"]:
|
||||
print(" Errors:")
|
||||
for name, err in s["errors"].items():
|
||||
print(" %s = 0x%02X: %s" % (name, err["value"], "; ".join(err["bits"])))
|
||||
else:
|
||||
print(" No errors")
|
||||
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser(description="Read MAP inverter parameters via ser2net")
|
||||
ap.add_argument("--host", default=DEFAULT_HOST)
|
||||
ap.add_argument("--port", type=int, default=DEFAULT_PORT)
|
||||
ap.add_argument("--timeout", type=float, default=1.0, help="per-byte timeout, s")
|
||||
ap.add_argument("--loop", type=float, metavar="SEC", help="poll every SEC seconds")
|
||||
ap.add_argument("--json", action="store_true", help="JSON output")
|
||||
args = ap.parse_args()
|
||||
|
||||
if hasattr(sys.stdout, "reconfigure"):
|
||||
sys.stdout.reconfigure(encoding="utf-8")
|
||||
|
||||
with MapClient(args.host, args.port, args.timeout) as c:
|
||||
while True:
|
||||
try:
|
||||
s = read_status(c)
|
||||
if args.json:
|
||||
print(json.dumps(s, ensure_ascii=False), flush=True)
|
||||
else:
|
||||
print_status(s)
|
||||
print(flush=True)
|
||||
except MapError as e:
|
||||
print("Error: %s" % e, file=sys.stderr)
|
||||
if not args.loop:
|
||||
return 1
|
||||
if not args.loop:
|
||||
return 0
|
||||
time.sleep(args.loop)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
sys.exit(main())
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
except OSError as e:
|
||||
print("ser2net connection error: %s" % e, file=sys.stderr)
|
||||
sys.exit(2)
|
||||
@@ -0,0 +1 @@
|
||||
paho-mqtt==2.1.0
|
||||
@@ -17,7 +17,7 @@ spec:
|
||||
app:
|
||||
image:
|
||||
repository: ghcr.io/pvliesdonk/markdown-vault-mcp
|
||||
tag: "3.1.0"
|
||||
tag: "v3.1.0"
|
||||
env:
|
||||
MARKDOWN_VAULT_MCP_SOURCE_DIR: /vault
|
||||
MARKDOWN_VAULT_MCP_INDEX_PATH: /data/state/index.db
|
||||
@@ -44,6 +44,16 @@ spec:
|
||||
name: markdown-vault-mcp-secrets
|
||||
key: BEARER_TOKEN
|
||||
probes:
|
||||
# first boot downloads embedding models from HuggingFace Hub
|
||||
# and builds the vector index/embeddings before binding the
|
||||
# port - the default liveness probe budget (periodSeconds=10,
|
||||
# failureThreshold=3 = 30s) isn't enough, so it gets killed
|
||||
# mid-startup on every restart, in an endless loop.
|
||||
startup:
|
||||
enabled: true
|
||||
spec:
|
||||
periodSeconds: 5
|
||||
failureThreshold: 36
|
||||
liveness:
|
||||
enabled: true
|
||||
readiness:
|
||||
|
||||
@@ -4,21 +4,21 @@ metadata:
|
||||
name: markdown-vault-mcp-secrets
|
||||
namespace: mcp
|
||||
stringData:
|
||||
BEARER_TOKEN: ENC[AES256_GCM,data:UFy6rlwEWje7mO8WJFFvgq8SEKaf0dP9mx00BLPxfKTzgcZqbce2Sr1U5aWVf8iphKapcBWRPEKqa/f1dC93tw==,iv:G8owKrU8ueTnQJ5p6O4U5x5H5WVriqqTUH5iAlW3ZoU=,tag:wuDlQmY622xLZvdJ17cxkQ==,type:str]
|
||||
OIDC_CLIENT_SECRET: ENC[AES256_GCM,data:NEAQqXz7zICa+3bSTRxfnURV0+toWhTexHBYXPB42tBomNg4kf3k9sspSJQYATcxuNIK5xv6XOCna4J1fm/+cw==,iv:T9gj9Jb/RcQcpFQUeqnH6S6Ri/XrlVntv9oU7bwnjEM=,tag:UqR4VqMe75s40TgcggbOrw==,type:str]
|
||||
OIDC_JWT_SIGNING_KEY: ENC[AES256_GCM,data:AwY8V9EQ1Z/NJmc/8msG2RpyCIhEKMzLTLdsLHpC2QfgB652aYEHAYg6u8quRvSypw1cG2zdJJQEym/MJ7CGdw==,iv:FjMwdBE51PuQCqhrojAWiwxoYkemSxO1+9ebw3kRRrk=,tag:X/b/t4e5qZmFJ1FSrWQOfw==,type:str]
|
||||
BEARER_TOKEN: ENC[AES256_GCM,data:vRsc/kmZ1qySDUrI1dMeLqSSn+jEgvPivw3dRYTLr7NRm6T7SYnmhhBb81CG6xQAl0Wz8RfOCescQpUJlbPl4w==,iv:Zha9o8uIdR6DPMk+KRL6ZnKdh3zPXuyjCCK9yKnuYFI=,tag:l+8oHY/hgZcKVQx9yiaEmg==,type:str]
|
||||
OIDC_CLIENT_SECRET: ENC[AES256_GCM,data:2unvRtI/V0aTULgSacGvEoYYQN0uWBR3b2TKjl7hjvQTXesuglTtSNz9YsjDqc8ZHGNBndiz2Q6VZagS3ERprw==,iv:fjMhiKamjbIrNYAK9TU2PPn0smJR+Kr3qhRhEUbjm04=,tag:wuUZbccOBoFcdiTPqb8QCQ==,type:str]
|
||||
OIDC_JWT_SIGNING_KEY: ENC[AES256_GCM,data:63S/0TsEis959MJRLd5atPXQrv5pNMC5iyMHJvT67luLLPkd2bdgfmX4Pu7R3Hr5YIGoujn1/xCuOdZH0RtIog==,iv:3Gi2ZukSzU9SIy7fPzmlvWbA4ykaNgta95DuviHf5zk=,tag:BPUXUPMIxW9kbyyQqoz0gQ==,type:str]
|
||||
sops:
|
||||
age:
|
||||
- recipient: age1kct5g7d7eus2hvdnmx99ewsrtz70lhlasxa25euqwdctqhwqqpxqz0n7gg
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBqUm5qNE93WUhKTlRIUXl3
|
||||
TmZMREJSQmVOWXlDdW9DZlFheGpDUHIvYmxFClozek5MVitWYVhIY3I2Nmk3YlJS
|
||||
cEhJS0NKNy90emovR1dCeHZ4UjNvVWcKLS0tIHFmTGMrVjRaSTFCNGQwSzB4NitT
|
||||
K2hIS3FuTHNoRHhxMEFIcFkvQjZmTHMKQls9vNvWQ+zc27JmQXxJilkiVTDqjEzD
|
||||
55M/azYogOsp0Kfe3MBm740tdaPiD6iyLXrEuZKNywD2mPtNT8+3JA==
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBPOVJCaXpjeUEzWkN4SEdz
|
||||
RnFkZmtXa0IwaE9xdGtBdVRwV1B5MkdDbVMwCmVYeUJpQmQwZ29BbnRPK1AzWGJx
|
||||
NHV0NnRxenRWV2M4MytrZ3llNmxaMzQKLS0tIHVOcDVyTDkrNHJRMkhRVzFPSGpW
|
||||
V1RRNTdiUTBjSWZlMlEvRXF3OUowZ00KXf/+ucgZuDAczE1WlEW7D2/cR+sB66BQ
|
||||
7JC42VJiyEf2djlODmvK26bDTeiJ/Uk9HsSuvamGUM8b8vAj2w/r/A==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
lastmodified: "2026-08-26T10:29:46Z"
|
||||
mac: ENC[AES256_GCM,data:sfdT7eRXMpgbWtJhu5U6/T03ckavKNcojfkg9Tu0uLwigsAsaxgiMhBA3kQWYU3tV9gxy6BXIak8cdF8EfCEAWBYSQC6iQLgOZPXvLpWFoaiigNHbKSYLYcimlD1wmHlRb5L0x5+QNANxD22Hkjlkw0kgPQ+GZKP7SzDsixXpBA=,iv:1rC3zYmRWM1/8O8xgitTwvQ9qORXNR20qABDKPqGpSc=,tag:YkJNRwxoGfGXnfcX5AJXtw==,type:str]
|
||||
lastmodified: "2026-07-27T06:42:40Z"
|
||||
mac: ENC[AES256_GCM,data:XRxbyHL4iJMoRMb4X6C2y1ChTNSkqou01bwtIb6zNfwcGCt7uMGbm1HxvmjbdeJI/zQIIVfgxbbTxhZw+sL2FF+PYAjPcaGvaJ86O97lr9fUB30NC0tMluW82pt2iiisK+6dEEPH9i/kGFrJHN6RlaYVkEfv6U8xjlpIcaNx0+A=,iv:YnqMRlHl1WVYNqqN9hRH88hgIALrfgv6WrJGyeNDstI=,tag:M1DYFr3G9ub/R2kNF8ZnNQ==,type:str]
|
||||
encrypted_regex: ^(data|stringData)$
|
||||
version: 3.11.0
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
image:
|
||||
repository: eclipse-mosquitto
|
||||
tag: "2.1.2"
|
||||
tag: "2.1.2-alpine"
|
||||
pullPolicy: IfNotPresent
|
||||
|
||||
# not really needed, as StatefulSet has hardcoded "replicas: 1"
|
||||
|
||||
@@ -18,7 +18,7 @@ spec:
|
||||
values:
|
||||
image:
|
||||
repository: eclipse-mosquitto
|
||||
tag: "2.1.2"
|
||||
tag: "2.1.2-alpine"
|
||||
pullPolicy: IfNotPresent
|
||||
|
||||
replicaCount: 1
|
||||
|
||||
@@ -4,19 +4,19 @@ metadata:
|
||||
name: mosquitto-passwd
|
||||
namespace: mqtt
|
||||
stringData:
|
||||
passwd: ENC[AES256_GCM,data:RHKtt4UgqElKW/rw9BnpZKOnhchsqmO5jVVVRJBy82b+9KrbUN5iGQ3k5X4/6gjrKKOcs5QabJahR+i/aVSr5fVyCJR7Y45YvKk+eyKqGuDTFCkzjxpSDvO4AseQvOHSGTMRXQx73jdpCnEEYtoXZNCLuhGtueKvrhkNDDCLFwtybaWsrI4g3fwo5auHbyWwjoxXskv0+pwi7vnESIJudJl4ul3Ie4NpyispZ+H0O6p9cn+Hwu2qoTJbR/zbpA==,iv:Blp/QsgEVD73JhGFzM3GNFPfUcwB58fzKJlQIGBw5Yg=,tag:InRGXl9vB/DF778pbhoqfw==,type:str]
|
||||
passwd: ENC[AES256_GCM,data:YpTczjZ73h4Td+TmEZIgil9DN7WfVwBsi75F/t3D1oWGjGsifklnRsZUJqXiXyUwIxTxlFiWgfb01LjmILE0nB9rxoEbFdrASaLgtnCoYz/fvSZLqwCK+FSSub3+r0nJTNvxzD+bC/av8JEPNDW/8CSrHMrTrVCcLhAchOAvviRLgO18862XWcvPh1plO8luaZG38cuh+VbKKwidkwozc6B7Ghys5NfZuB1rP4vLZ6/f1PzcFRugtJ0fzzl/BA==,iv:9FKm4V/lYXott/6aVBKg4g8GtzVqgT/xndj0CKqMm+Y=,tag:41gCVbrK6Rp2IvVUt98Hpw==,type:str]
|
||||
sops:
|
||||
age:
|
||||
- recipient: age1u236u5mzkzj72y4mfxx68gfqw0u0j6tdgkudnm5pdfpe7apq4u6s89jr2h
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBudUhrOVlvUU82cG45K3ll
|
||||
R05Dc0NUdFN3b0k2UmZoSWlxd1diQ0dNcjBFCm1icmlvQUhIaFYwSFZ0MURmQVUy
|
||||
bTJPWk5mWVpQb1JNQXhCOFhpNXByNTAKLS0tIE1vR0t3SUdGTnRiWFVXOG5yYVhk
|
||||
UVBsRDlZSVpJbk1KYmJGYlRmelNWWVkKBVabDs2XS6XAVKiKbAtk3CqraoBXOD5I
|
||||
+0uq5YeFvMxhrnX6wXffCS7S3zbvNV6/2Enbt7SBJ8EhCvKbfaOtfg==
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBobk1BQW0yemEzV1FQM2ZJ
|
||||
YkZJbjJPZlRiSDlyamx1WVdyNTJBNXo1YlQwCnhBT01SeE0rZDVOcFRkZm9KQ0t2
|
||||
dUIyOHpzenVZc3lsa2hmMjF3LzRGMFUKLS0tIENmM05Ud2xGblNpdjZjWWFPeWg3
|
||||
UEtuZWZ5enkwSGk0MXR1czBibzQ1M2sKfp+76C0X2DgsffWZVtBevI4lCs8RM09p
|
||||
tzsrneX4iIX6WCn1kRLsWTZpN6Vg8Wsl6kUWnSA3WfHWI9W4CJdrag==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
lastmodified: "2026-08-26T10:29:47Z"
|
||||
mac: ENC[AES256_GCM,data:/NEEVA/hO2NUIWOhVjL7ZmtD9Ac169CL4D71qPueZbNSHtTqx8GHeo8DI1tpsUBuGytVBQxh1MXK3REt/bD2GzU1dCpvtTtQmQb+B57H6Za3RIyPU51QTt9nHYHiWend3tcxlR3Xc8h5TBa0kKwjXvlij4jEUM+dA5UESE/QGFk=,iv:yTyP3PVw+pVzPPqMN7EyIfM/BN/wK9nIHx84F65A+/k=,tag:oTpIqbAOq5aqlCWnVqaKNw==,type:str]
|
||||
lastmodified: "2026-07-21T19:09:49Z"
|
||||
mac: ENC[AES256_GCM,data:qecTVUaC/3j/oP1DVnXEKV9Ub+k5gvGHfteol4W5I3gq8IB2YYZ+vfuinPVJJeSsN5HvK62ftnIgRNu0dtzDOrnuZENczEMwPrOz90RCUbX7WBeKh23KZ8gSSw2MBn6gsDsz1gXFWENIyjQTJFZ4qAJY6jfeH2IFC9RkpoU3j14=,iv:ksLG/aHHBAkl6aA52Xufs2vijZlpsaXccoxheYV3Gm4=,tag:4YiaPGMBWSWhVBO1tNF6vQ==,type:str]
|
||||
encrypted_regex: ^(data|stringData)$
|
||||
version: 3.11.0
|
||||
version: 3.13.2
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
apiVersion: helm.toolkit.fluxcd.io/v2
|
||||
kind: HelmRelease
|
||||
metadata:
|
||||
name: ntfy
|
||||
namespace: notify
|
||||
spec:
|
||||
interval: 30m
|
||||
chartRef:
|
||||
kind: OCIRepository
|
||||
name: ntfy
|
||||
install:
|
||||
remediation:
|
||||
retries: -1
|
||||
upgrade:
|
||||
remediation:
|
||||
retries: 5
|
||||
driftDetection:
|
||||
mode: enabled
|
||||
values:
|
||||
controllers:
|
||||
ntfy:
|
||||
containers:
|
||||
app:
|
||||
image:
|
||||
repository: binwiederhier/ntfy
|
||||
tag: v2.34.0
|
||||
args:
|
||||
- serve
|
||||
env:
|
||||
NTFY_BASE_URL: https://notify.aggtaa.com
|
||||
NTFY_LISTEN_HTTP: ":80"
|
||||
NTFY_BEHIND_PROXY: "true"
|
||||
NTFY_CACHE_FILE: /var/lib/ntfy/cache.db
|
||||
NTFY_AUTH_FILE: /var/lib/ntfy/user.db
|
||||
NTFY_AUTH_DEFAULT_ACCESS: deny-all
|
||||
NTFY_ATTACHMENT_CACHE_DIR: /var/lib/ntfy/attachments
|
||||
NTFY_ENABLE_LOGIN: "true"
|
||||
envFrom:
|
||||
- secretRef:
|
||||
name: ntfy-secrets
|
||||
probes:
|
||||
liveness:
|
||||
enabled: true
|
||||
custom: true
|
||||
spec:
|
||||
httpGet:
|
||||
path: /v1/health
|
||||
port: 80
|
||||
readiness:
|
||||
enabled: true
|
||||
custom: true
|
||||
spec:
|
||||
httpGet:
|
||||
path: /v1/health
|
||||
port: 80
|
||||
resources:
|
||||
requests:
|
||||
cpu: 10m
|
||||
memory: 32Mi
|
||||
limits:
|
||||
memory: 256Mi
|
||||
|
||||
service:
|
||||
app:
|
||||
controller: ntfy
|
||||
ports:
|
||||
http:
|
||||
port: 80
|
||||
|
||||
ingress:
|
||||
app:
|
||||
className: traefik
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||
hosts:
|
||||
- host: notify.aggtaa.com
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
service:
|
||||
identifier: app
|
||||
port: http
|
||||
tls:
|
||||
- secretName: ntfy-tls
|
||||
hosts:
|
||||
- notify.aggtaa.com
|
||||
|
||||
persistence:
|
||||
data:
|
||||
type: persistentVolumeClaim
|
||||
storageClass: longhorn
|
||||
accessMode: ReadWriteOnce
|
||||
size: 2Gi
|
||||
retain: true
|
||||
globalMounts:
|
||||
- path: /var/lib/ntfy
|
||||
+2
-2
@@ -1,8 +1,8 @@
|
||||
apiVersion: source.toolkit.fluxcd.io/v1
|
||||
kind: OCIRepository
|
||||
metadata:
|
||||
name: openwebui
|
||||
namespace: ai
|
||||
name: ntfy
|
||||
namespace: notify
|
||||
spec:
|
||||
interval: 1h
|
||||
url: oci://ghcr.io/bjw-s-labs/helm/app-template
|
||||
@@ -0,0 +1,6 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- helmrepository.yaml
|
||||
- helmrelease.yaml
|
||||
- secret.enc.yaml
|
||||
@@ -0,0 +1,25 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: ntfy-secrets
|
||||
namespace: notify
|
||||
stringData:
|
||||
#ENC[AES256_GCM,data:XneiueSaauWV0MEAzJcs730dwgrSt970o99Jq9iYbAF/RGAXPq0aMhSdNtK4PIgY5nSuVDsaGjXMEu+hF7kX4zWdIQg8MQ2n82fpcNc15RCMsyMNn9WVI1WKr5y7gonz5w==,iv:SPiP6hSzqdBk9WUVKT6TYp3qdZ3gje70CclLXaQNPkw=,tag:H8RtqMaF3bmMNUvfZMJtXQ==,type:comment]
|
||||
NTFY_AUTH_USERS: ENC[AES256_GCM,data:G6VE3ZkkiHU1dFY52J2XVKg4RL55SBTNZRp9DKeUHFJho/PURi+UIzS0gk2377ZAIRdX7gn8DOqfCZ4gvUw40TnlC/wFRAgZO1a6G1WKEZHceUr3cwFGQQhN0pwbc7RfK+amWR4Ov3m/lsNCZjU2KxUps8jNCvnGNR9IxHXBGoNt7PzeNnn6vL5JDBFba3MNsNDUVOm3Q4pTwG9pb1cvQYUU89OMIq/MkZfwotlR0HyEG/8hDiClr9PGJSuVSerL3JmtV10txM2bKRCFRtDb1DtYrRu8EzQ=,iv:IukIdkjr1vRdQJBMI+adN8O0UPo4Vv25gB5vCzim74A=,tag:QYGGERjRr7n1Pww9bg6Oiw==,type:str]
|
||||
#ENC[AES256_GCM,data:WDat/Zx7qfe6gY1t8npcfvHz+EpTbtEuHJMoUijlJq5FJEu6nVbrASJOkkWDxfhT,iv:6GX4Jff9YZ27RHaCym1ziSkZiF7VifRkxjleLcYVYHY=,tag:RhsfsYqNc9dyFc53TxAFcw==,type:comment]
|
||||
NTFY_AUTH_ACCESS: ENC[AES256_GCM,data:Mc4c8bDGwIEUZnx2x1N5IDiLPCdHZw==,iv:LCFN1XXjGfzel/3O4FHumcJpn1DhqdqOhjjpzBSUpYs=,tag:QCqj6hIClhXTnINq+hQuow==,type:str]
|
||||
sops:
|
||||
age:
|
||||
- recipient: age1uzs33ep6k3htnuwyyp54y373wkf7urd0qvk5kxcmptr5tt0fffus4v06gn
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA4ZTg3RVF1Y2sxUjAzTVgw
|
||||
d2ZkQVpmdzNqYzIwRVR1RGExUjM4SVRMSVN3Cis1bEpZNWZkY1VaWDkzUUlnN2RZ
|
||||
TVUyZ2VNb0MvS3R5c283Ui9DRzkydUEKLS0tIFZMKzhJWnVZUVRsSFNHYStUaGti
|
||||
aGFRSVg5alBnNnA4emxkeFFpZ3BnUFkKUPOqUjkjSl77Xvb3i+THWINbvtzrioqF
|
||||
QBkQh5SSzq8fWrHoHHp7XHu02+p34dEJMOmEg1rlhu7pYRMNbbaRsQ==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
lastmodified: "2026-10-26T09:44:43Z"
|
||||
mac: ENC[AES256_GCM,data:0z4ety9M00u1vIGn1NyqO9K42IGOQt28L08sKU4D3aB6sroqbY6UkafabBYGyzB7LCaOc3iukDCFtB8hBwg6UarNPbeQlZqG3yuHmVuNB2vOubE4U1YFxeTJ5bNvyP4kpSp6DwUiC9QeJtQ0T98aqj9R7dB3x4vU1s/hPmYSLxU=,iv:+5kSIP8prdAOaYCUhQzUlugncFH54tTMweMfo+tP4BY=,tag:bpjq0X3gCy+LbLeSmIX5Jw==,type:str]
|
||||
encrypted_regex: ^(data|stringData)$
|
||||
version: 3.11.0
|
||||
@@ -1,73 +0,0 @@
|
||||
apiVersion: helm.toolkit.fluxcd.io/v2
|
||||
kind: HelmRelease
|
||||
metadata:
|
||||
name: openwebui
|
||||
namespace: ai
|
||||
spec:
|
||||
interval: 30m
|
||||
chartRef:
|
||||
kind: OCIRepository
|
||||
name: openwebui
|
||||
driftDetection:
|
||||
mode: enabled
|
||||
values:
|
||||
controllers:
|
||||
app:
|
||||
containers:
|
||||
app:
|
||||
image:
|
||||
repository: ghcr.io/open-webui/open-webui
|
||||
tag: v0.11.0
|
||||
env:
|
||||
TZ: Europe/Moscow
|
||||
probes:
|
||||
liveness:
|
||||
enabled: true
|
||||
readiness:
|
||||
enabled: true
|
||||
startup:
|
||||
enabled: true
|
||||
spec:
|
||||
periodSeconds: 10
|
||||
failureThreshold: 30 # first boot pulls the embedding model
|
||||
resources:
|
||||
requests:
|
||||
cpu: 200m
|
||||
memory: 512Mi
|
||||
limits:
|
||||
memory: 2Gi
|
||||
|
||||
service:
|
||||
app:
|
||||
controller: app
|
||||
ports:
|
||||
http:
|
||||
port: 8080
|
||||
|
||||
ingress:
|
||||
app:
|
||||
className: traefik
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||
hosts:
|
||||
- host: ai2.aggtaa.com
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
service:
|
||||
identifier: app
|
||||
port: http
|
||||
tls:
|
||||
- secretName: openwebui-tls
|
||||
hosts:
|
||||
- ai2.aggtaa.com
|
||||
|
||||
persistence:
|
||||
data:
|
||||
type: persistentVolumeClaim
|
||||
accessMode: ReadWriteOnce
|
||||
size: 10Gi
|
||||
storageClass: longhorn
|
||||
retain: true
|
||||
globalMounts:
|
||||
- path: /app/backend/data
|
||||
@@ -40,7 +40,7 @@ spec:
|
||||
# behind Authelia the same way fava/zigbee2mqtt are.
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||
traefik.ingress.kubernetes.io/router.middlewares: auth-authelia@kubernetescrd
|
||||
traefik.ingress.kubernetes.io/router.middlewares: auth-tinyauth@kubernetescrd
|
||||
hosts:
|
||||
- host: sync.aggtaa.com
|
||||
paths:
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
File diff suppressed because one or more lines are too long
@@ -0,0 +1,108 @@
|
||||
apiVersion: helm.toolkit.fluxcd.io/v2
|
||||
kind: HelmRelease
|
||||
metadata:
|
||||
name: tinyauth
|
||||
namespace: auth
|
||||
spec:
|
||||
interval: 10m
|
||||
chartRef:
|
||||
kind: OCIRepository
|
||||
name: tinyauth
|
||||
driftDetection:
|
||||
mode: enabled
|
||||
values:
|
||||
controllers:
|
||||
tinyauth:
|
||||
containers:
|
||||
app:
|
||||
image:
|
||||
repository: ghcr.io/tinyauthapp/tinyauth
|
||||
tag: v5.2.0
|
||||
env:
|
||||
TZ: Europe/Moscow
|
||||
TINYAUTH_APPURL: https://login.aggtaa.com
|
||||
TINYAUTH_UI_TITLE: "Welcome"
|
||||
TINYAUTH_RESOURCES_PATH: /resources
|
||||
TINYAUTH_UI_BACKGROUNDIMAGE: /resources/background.webp
|
||||
TINYAUTH_AUTH_USERSFILE: /config/users
|
||||
TINYAUTH_AUTH_SECURECOOKIE: "true"
|
||||
TINYAUTH_LABELPROVIDER: none
|
||||
TINYAUTH_ANALYTICS_ENABLED: "false"
|
||||
TINYAUTH_DATABASE_DRIVER: memory
|
||||
TINYAUTH_OIDC_PRIVATEKEYPATH: /oidc/key.pem
|
||||
TINYAUTH_OIDC_PUBLICKEYPATH: /oidc/key.pub
|
||||
|
||||
TINYAUTH_OIDC_CLIENTS_FILEBROWSER_CLIENTID: filebrowser-quantum
|
||||
TINYAUTH_OIDC_CLIENTS_FILEBROWSER_NAME: files.aggtaa.com
|
||||
TINYAUTH_OIDC_CLIENTS_FILEBROWSER_TRUSTEDREDIRECTURIS: https://files.aggtaa.com/api/auth/oidc/callback
|
||||
TINYAUTH_OIDC_CLIENTS_FILEBROWSER_CLIENTSECRET:
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: tinyauth-secrets
|
||||
key: TINYAUTH_OIDC_CLIENTS_FILEBROWSER_CLIENTSECRET
|
||||
|
||||
TINYAUTH_OIDC_CLIENTS_MDVAULT_CLIENTID: markdown-vault-mcp
|
||||
TINYAUTH_OIDC_CLIENTS_MDVAULT_NAME: markdown-vault-mcp
|
||||
TINYAUTH_OIDC_CLIENTS_MDVAULT_TRUSTEDREDIRECTURIS: https://md-vault.mcp.aggtaa.com/auth/callback
|
||||
TINYAUTH_OIDC_CLIENTS_MDVAULT_CLIENTSECRET:
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: tinyauth-secrets
|
||||
key: TINYAUTH_OIDC_CLIENTS_MDVAULT_CLIENTSECRET
|
||||
probes:
|
||||
liveness:
|
||||
enabled: true
|
||||
readiness:
|
||||
enabled: true
|
||||
resources:
|
||||
requests:
|
||||
cpu: 20m
|
||||
memory: 64Mi
|
||||
limits:
|
||||
memory: 256Mi
|
||||
|
||||
service:
|
||||
app:
|
||||
controller: tinyauth
|
||||
ports:
|
||||
http:
|
||||
port: 3000
|
||||
|
||||
ingress:
|
||||
app:
|
||||
className: traefik
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||
hosts:
|
||||
- host: login.aggtaa.com
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
service:
|
||||
identifier: app
|
||||
port: http
|
||||
tls:
|
||||
- secretName: tinyauth-tls
|
||||
hosts:
|
||||
- login.aggtaa.com
|
||||
|
||||
persistence:
|
||||
users:
|
||||
type: secret
|
||||
name: tinyauth-secrets
|
||||
globalMounts:
|
||||
- path: /config/users
|
||||
subPath: users
|
||||
readOnly: true
|
||||
oidc-key:
|
||||
type: secret
|
||||
name: tinyauth-oidc-key
|
||||
globalMounts:
|
||||
- path: /oidc
|
||||
readOnly: true
|
||||
resources:
|
||||
type: configMap
|
||||
name: tinyauth-resources
|
||||
globalMounts:
|
||||
- path: /resources
|
||||
readOnly: true
|
||||
@@ -0,0 +1,10 @@
|
||||
apiVersion: source.toolkit.fluxcd.io/v1
|
||||
kind: OCIRepository
|
||||
metadata:
|
||||
name: tinyauth
|
||||
namespace: auth
|
||||
spec:
|
||||
interval: 1h
|
||||
url: oci://ghcr.io/bjw-s-labs/helm/app-template
|
||||
ref:
|
||||
tag: "5.0.1"
|
||||
@@ -0,0 +1,9 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- helmrepository.yaml
|
||||
- helmrelease.yaml
|
||||
- middleware.yaml
|
||||
- secret.enc.yaml
|
||||
- configmap.yaml
|
||||
- oidc-key.enc.yaml
|
||||
@@ -0,0 +1,14 @@
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: tinyauth
|
||||
namespace: auth
|
||||
spec:
|
||||
forwardAuth:
|
||||
address: http://tinyauth.auth.svc.cluster.local:3000/api/auth/traefik
|
||||
trustForwardHeader: true
|
||||
authResponseHeaders:
|
||||
- Remote-User
|
||||
- Remote-Groups
|
||||
- Remote-Name
|
||||
- Remote-Email
|
||||
@@ -0,0 +1,23 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: tinyauth-oidc-key
|
||||
namespace: auth
|
||||
stringData:
|
||||
key.pem: ENC[AES256_GCM,data:1LGq+HOfsvba2hrMBgwTiaJY4oSXNVRRyBQt7k+Dv5ZunCNbc57qxGIAi259zekb4yqdnP9SHUo0Uzmz1lgOUwhw4pPNq8YmWkjoLthjBB5FaNqilifUzFXYG3+fC4WP0IxHWUFDhB4tgP9zwnc682/QnQBMKzDXAL9bnRf8OTemNLnAjHt/+vbOtW6ySSmjnF+RRS0gz9/CjPwnCwfqqqRoIaiHT2I5nKuzSggGDNRENlGHsUCBypP08ZbuyQ+wRMWNDhtuG8KY8pWxkvOfwAjbJtJ34/xTGeWwCUQ0fs6khMXzMmvnPKmG/HTAAWrgLeMlhicDLB74nBMY7zbjX1y2HzJPVXAnWNE2sbWXhBIhi+/koyRdWSoUoD7flEu1O44cgRJSh2QqEa4cw4NC+tRm0Dm0R37vOEgMHF/D3cKBxSmgKLxUKw+ZCn5aYF2+Dwo5L+HtuI0VnQ5caq0HCrPN17m63gceVS/mbGYT/A9XSvxhWh5hrtzzn1v3xER/HdOEK1GlZBOL2QPfzyRx9Yx05f/NLGghK+Jk/OBtaV8+0ORGfjJFi+uU2tus8gznESTtZGG6Oz25aIYj7cYCNM93szk2q2lle8wCK8DX48wD5LEwS/7zcWJ2J0FeH/+ihIi2N6cRAgT2P5CHATFX4ghQkAH3UZF0oC2x0EfRXmVE9K2twuD70CSqmBIZvSqC1zEb5KpL283E5lsfVZu3RRryplONMaZZM2bIJqwaEq0wqbtvTnKFTWQEA4JRzgy4i8cFyxfq8ELoEacsjVgZCrASvMjK9NmuqUt4dbKMSuIz0S780Om1V0OoshJiGi9Thu7AWIi0WURRi0ZkvaiLDuqwx+VS5Vt+1y6JByUlsKZg4Dg6saYePKEqClD5nqTv4KsVU3psldOdlS/S4MhBCK31RPAI0yZbDF7job1K4pYWpzuJNH3jh/EDqzbBbNpnTnt6VA9KJ6obJ1vzOVAQB804WB0+hM8ap8vcqHLRPhqa7wZ9mJKVkPBxcr0B3ZulXn428FpjEzCLhUPXVNdJsxpPq0LtmN4yHsfGA/BVwXveT2gLxF+cT5IHOpQVR1ZI/I62ebCfupHYPhZ5aU/UFbCykc2PPQTVM5acVKnwbkU9nR8PmrrZxNmgTQ1akrrQoAMkPkKBsE8R3MIH4md4QhH1B7NV79OwJHrShGDajCPPkGnvFP6w+S4ecdwLkutg57Vhf9Gpq81ztzaq1W/W5y1ax4rGowlRU5nOHy5hDfyLUr0O79319oit4LD7VVWzFiBxWFNaky617V9B/xXFqxInGmQAJVPoPkCE9cHCNVbrblAeND36zjcr/tEWYlNCakt3sNFRQTWaO0MoF1+iLxCQvK7dpRpA3IhOPhFdBRj11J9PI+zpeSXZHYXP2XrfYna062KYb7BxiRiCrO2HAtgKY2TTcA8LHYQ+QiNefSqiNSN3zI7vclb4D6RmDpbm8Hg+SZV1KdvBYw/laj0ctNOnTqwZY51foDgjDnhbRcR5M1mbpq3LUY6TUUoV4+blR1cUKk3pQD5eHVEB/gI5r/mLoK/aesDhVsqEsI1fmwzGESJOL2zRXwyzuPrWj65yfcN0dDK/d06o7vnHdaJIPrEaAmX0M+jD92thIrrUMgkD6r6WqtCYKy81tKqBkMIb4M4wO1ttZ/6WjM7LjNfGAeYhMOTI/LWjmHR/JKrAantSgRgsE6hNGA+C8VUQTpO1rDWFNXRb/vxsibFSypi481ydaySw6Qum/f+eLrLGJdIgWCtI3H+L42N80+k5l03pyuJixqCk0kqVrDQmITNdkGJvbqA7uR3YncSOjPIWn7q79KUca4qW+O1CwtgBJYJqSJiDCVwi3tZ6zv7eDBcq7PGrN4R3hcarY9GVo0Vr4YdSN9VU5PkaXFfG10XZyrHBOLmm4/2iy7NxxWY8d4Z3nXUjitEIAkUa/CGhA3WMiqMkkbeLeiRtmbXZ8ZcCBO5FEUSG/z11PyLRi0o5kct3GlaUtl/QRg4SBGx4t3iDf5gHPb298+ulSErL40GjKLyiZh+YfNPDqRdIXBpKTjOand1EZe1yiY3otCj9NVUdrvkSFL6lYXcCQvVtzLIvrfev/QVqpIOf9d0gxp/em4JTZ+YauRNu5fXcnqezncpQAcXy27O4y2+4cko8tk7aoBwcrl/fKp13nx22I62IJGzsLA7BNjRHUG13iddZoBOzhbJ3xlgNR0nNlIYNSQ==,iv:ZO366aMLKSUkaMdlejlGGZ8rLAQITDJ+rtqHIDjHJCk=,tag:m3eUo6FRn5Gmrf/ozMGldQ==,type:str]
|
||||
key.pub: ENC[AES256_GCM,data:F0YQFFEAwB+bruva4HB4BKeIjAPhnssnd13JLMRMyLMfF8JdIBbjyKcz8NUVq8l5FxFDy3W3jAJmOfVqUwHfajgdT61S2Rj+dBXwV947ruwBiLS3rTnJvgfLIEOf1f4mG2hZH4X7jodInh7wL+IPC7N9Wqmccdfc1eTvn7GjM5KgU6yzsDIdq8CMTOWciRIgLz81sDCP6mLAy4AG+a6nyzhCYSfoQogbl00CP9i6JdV1FcJfrzQY2lgshgrDOynK2bNxwaRP0CVajAn5ccj8sawvIA5EgcEdoasfGGf3WCUnFKDVmYZDZjpeTGDnCRZMFIpKfXbNavaNn2Gwl1icR58UFKsi7tXCePY8MW12gseONFXDoU6OKo+xtgiEk5SPryrskK3m7Dq+9O7No12f2XNhISGlf/sRtY+WmxxXceUTywoOHVRkbcapODRs0svmJBeQZKJ85tE+Fre1l+1mjLGB4ZeaA0euKEZDtTXT95icepMaHIcbZHURwp5jRfYxp7a9VzpWY+m1rwNtnpHe4A16JoU+0ZARPLCs8kX/DqgZDaSy9f+IUjvQYbNTsUNEJCvtMZPWmr/Vz8Je61/8pGz99g==,iv:L5JDiEFJnBPcXGZMmFUVC8Uq12Bb08qYFWhdZCYBivY=,tag:Lpz7BAOaQ1GK9W6WaZ4LLw==,type:str]
|
||||
sops:
|
||||
age:
|
||||
- recipient: age1rvyt7nlnjqeyt6ykwh9fj9d88kjmq9vetcx667ul3ql6fyfz4gqqh9lq9q
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBFZGwrK2lEVXBWQnBaeVlx
|
||||
aUVPQVRyOTB2WE5HdWR2VldUbmQxZTBuTFIwCks1dkc5aGVXWnpIN1NYNVA0em14
|
||||
c3h4K3hLYkZlU0VhRUEyajFEZzI3UDgKLS0tIFpLQkxlWGtUTGhoVUpiSW9WOStT
|
||||
blZOcjI3TS84K1hZY0ZxbS95SndsUUEKt3ZYkU2/5uPeU7C72luZYP3tLJJ73ERX
|
||||
A8eUMsVOI5T7Y6/i4B1OQSt1xFBXkMSJu3YU739fxFumdb8juALxzg==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
lastmodified: "2026-10-20T08:48:16Z"
|
||||
mac: ENC[AES256_GCM,data:IcHXiY7PJpNy/sGirwh7rm8XzyuC/ZfajaxolOgfP0p1bMF6yn2tzgf1vyHJszVEwXE7rLZEriR357PaHyGgkIxDnb76FwLTiw+feEBgpl/77HY1oOnI4yc0LrHh5fkanxadw/krJoQ8JD827Ek9h1LR7ICTJ40EDSpdfwdH/1E=,iv:OXMfJyXrXH4S5v2cTdwJijzE2/4L475ZArA/nw06s48=,tag:ykl0rz2xmhJ9NZIjuU111A==,type:str]
|
||||
encrypted_regex: ^(data|stringData)$
|
||||
version: 3.11.0
|
||||
@@ -0,0 +1,24 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: tinyauth-secrets
|
||||
namespace: auth
|
||||
stringData:
|
||||
users: ENC[AES256_GCM,data:C3Dhfymnr+WLWy18EpY9upXn+f7sY6w0cf3oXO9352PTPCP+rLYQTm8eiJtsU8gp/Uea7lMpsRPHSy8CoRdI8DOGT+hyPyK1ovjLdyO7bEiq0TtYOIFlHSR7Kwo0Cm+pZegSN9e1dm/v51+YyFfX3JpLaymYrlmXL3sFPQ0yOzEuMp3zXSV3VAkJe6gZrswIAUNhY0xmaGItr4Vc2isItDuc16lx7tW2wJHI7NgLI98p9FyU8HlXd9MsiPMxDaXSGeAwnjGU+TEvQv9NbhcZO0sUocSi2zgnRbi0i8Zt,iv:5OVryBqH4VNC71QdZkqZsoDrfbT5++Z5xZjgCFNOAu0=,tag:V+OC7Mad6Dw38u91gp6d/Q==,type:str]
|
||||
TINYAUTH_OIDC_CLIENTS_FILEBROWSER_CLIENTSECRET: ENC[AES256_GCM,data:kBA3jDc+xFyvLNtfPjO+gYtRrT3HgdsoC1MktIgFomA=,iv:JKStNWy9BHcpkSwAG917sC4zzStKcgtU7ZXpKdSraRQ=,tag:VV96+U1EaIQevZHnCDmQag==,type:str]
|
||||
TINYAUTH_OIDC_CLIENTS_MDVAULT_CLIENTSECRET: ENC[AES256_GCM,data:SiipG4qFp536YfrMqfjeZyIA5hxXfDH1JgGGDrkz0bb2mwdSV2S3szLffxNwibL9xAF/dST6I++N5ErLXGH10w==,iv:hzJyoLO1z4eBuDmBYJ5AfSh4RPggJN07EWeKbP+FFV4=,tag:R46K78XLC0BmQ0n6b+irQA==,type:str]
|
||||
sops:
|
||||
age:
|
||||
- recipient: age1rvyt7nlnjqeyt6ykwh9fj9d88kjmq9vetcx667ul3ql6fyfz4gqqh9lq9q
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBJS1llcTdHUmx2ZXdjVFh1
|
||||
ekJheVN2MVBwa0V1a2JOY2pFM1pmYUJrMzFRCllaRnlnTGFVYTlQeXVxNXFsNEZu
|
||||
bWUxd3BWZTlEOWxsZVRnREx6YUJ6em8KLS0tIGNDd1Znb0dlSDZEUE1JUkdWMlBG
|
||||
ajBNVW1pa20zKzhISmFBUmdiazA4T1UK0wyvTMGsyJthx2Py1LITvRePQsjKN/9v
|
||||
jqKjeeCuVutQCo3FvoVrlkkmiD19jqPDoXjWz95sTN6QjWmP7u6AIA==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
lastmodified: "2026-10-20T08:39:59Z"
|
||||
mac: ENC[AES256_GCM,data:pKMx3OwJ5x41WghATDCwDNJADs2KCQkDmDsjfbL6Vx98jFOL+MwvCRujOM2UzzAl8QnNLFddimmpNwoFBifQEbeHTpVnT1uqZkiSV89mM1nIoyYIo3exNoynVUoqp1NXxhfwRrRVC3beF3keTxES//kh8/W3as16R1vgBSLoj6s=,iv:AAiLBicP0tywLWXA67cin51TqV8TBXtlpjazta2PyFs=,tag:wSkJBOIhryUNVlGeKrgmnA==,type:str]
|
||||
encrypted_regex: ^(data|stringData)$
|
||||
version: 3.11.0
|
||||
@@ -4,20 +4,20 @@ metadata:
|
||||
name: vaultwarden-secrets
|
||||
namespace: vaultwarden
|
||||
stringData:
|
||||
#ENC[AES256_GCM,data:bFZ/wUZ6oINU4pYH5EnWQSyOsLngnr8CMgIMDDNTN9F1HCqPQMp2TQjh5nLpBIWegJ8VxhaGc5+d,iv:Jvrw4+Cuec/X/AV8iK+SmO3P7C8Ua2ko9vTOBUAhSEI=,tag:bQ66e+Uz4BAbMEPzbONFaw==,type:comment]
|
||||
ADMIN_TOKEN: ENC[AES256_GCM,data:yYxQ9/DkzA8KCZYqsDnQbkDBynnLTHZ/CTnZQvl2sijMaeHAeAgFDUhFC8ew8ud6Gu9vvh9V1hUHeBnsxKASxmuNP9HOOSu0irpcgUDYU5nxcAhEVzgKvP9JGhc/XinbA/7jVxXiEf2I6hEApGylPQmoIe9QJw==,iv:hqNaSZovw+3ao5059kgwJQ024HohHRXf02FR2/rLWFM=,tag:ez/enc/6s8CHoJ+264gURg==,type:str]
|
||||
#ENC[AES256_GCM,data:b8Yuhc+eN6k2X6xPhUUBAMyNmJhZl+cpszwhb9OUiZeDJUNC1CUFTSD4//XH81kud+iM3/6o854S,iv:0F4/f5sjeFBqp7zZfJhYd8tkiDRlfKJ6p5n337THiWo=,tag:ZNHbaR0tbHT6aWzyfqeqPw==,type:comment]
|
||||
ADMIN_TOKEN: ENC[AES256_GCM,data:pYY8Nc2PevrFGU2pbZaFH7O+WNJzOHSEXMM3TAFYHO46/GGzQjrxYbc9IY/8PgY86N73kQAFLvw2bpVnjiliilLpnxm9Z0LyYDlAhui8545J67IqoQFDyZt5o3NHceWRP2eCxEL4Bf9gD6j4YfObRVYrp38x2Q==,iv:IvzPkKi/w/S8ueYl/m8kckWiddfl1oQKYiT8S77IVAA=,tag:rD5RsmPt4uihMHWSt4gGwA==,type:str]
|
||||
sops:
|
||||
age:
|
||||
- recipient: age109zta6l0cwpkxn5wek82kvauxn6yqrq80rsz4mvu5atdnpcn9pusuvnqk5
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBncHhhUW9MNkUwcHlMS1Vm
|
||||
dERHL0dyN2ZIVklSSkJwRnNQR2dtZjhpWHlBCjVVVGN5ZUhtdGpNSEhXUjhCWkln
|
||||
b0h3TkpaN0UrRWFuZzd2d1JiWlRIV3MKLS0tIGJKNE1jSTVxamsva2tUSUVpbzhj
|
||||
KzVYek9IZldwSStXN3BCSXNvcFVNTUEKRivXr6lUXL/45wgxPIuQAqfgSzZe6Ofz
|
||||
vT5NsMte67eCYwmAF/+wSPZP5Y7OI7UzPedTUIMvn5vUMy70vssB/Q==
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB6RVkzM041NFZDMzlYRllw
|
||||
a3BRS0JGZ1B0UGYyaTRLUkp2UTJ1S1pybDFnCnZhVWNYMFRlSXlFVTMvRXlpdlF3
|
||||
Vk1xT1pKV1hzSUYwQXd4ZG92cnhDY0UKLS0tIEtLWXZiZUFDeGhFdytKbTJHSjRH
|
||||
YkJhS2FJOTdLbHlRelBpUWRNUTdTMDQKhgb66tV4L0PKkPY8DvbypTpcBlavUvRH
|
||||
0+Rz/UxfZpX8u8G9GeqF5glIpNG2x28VSOHchJxhvMKHIUq9ZUrHGw==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
lastmodified: "2026-08-26T10:29:48Z"
|
||||
mac: ENC[AES256_GCM,data:Td2STb6nbH3Q383YxUMgecnmBRnsH1cNq0Iv1/q5OvESpIzhVCeVgJMIKBWEQJNfuxdyXR9mbFJ5zELIBS2ymGihtr4pHMKxj/kFpj1zPBqy+OKhP+E67juiRVMg6DJDSbdFHP21dOetllkcRgG6SImuOPQXQ3eozmPg/vpi3Xw=,iv:Q1B8KUrzBGIb2wBTZPjdb0a7XMyp5BpDf9qa8wx0smw=,tag:k54imcB/x03ttFVQKamKiQ==,type:str]
|
||||
lastmodified: "2026-07-18T19:13:05Z"
|
||||
mac: ENC[AES256_GCM,data:Ufdytxb9uH6JVXsWu39YhE1AfD/oG7bXhIwoTXYhYBE4IWvugrwZLCvBrgkfuazVXyKBuDIuEa5Vj/bzlTGDSlRNx7SDqabvilhmYAsBcuU5DAVU47pDz1YnXeHd9TuQI1dHAc1Q3uvkZwWNxh2YYXKZGwNMy3tOAkaOxwI1rMw=,iv:iUZenTP/9JhmjcR4p5+RM5K2YuXBLnRj0cd/RHseqFY=,tag:pesF8Pp8vBoQXcniwrep9g==,type:str]
|
||||
encrypted_regex: ^(data|stringData)$
|
||||
version: 3.11.0
|
||||
version: 3.13.2
|
||||
|
||||
@@ -90,13 +90,18 @@ spec:
|
||||
existingClaim: ganesha-export
|
||||
globalMounts:
|
||||
- path: /webdav/export
|
||||
# NAS may be off at pod start: the PVs mount with "bg", so the NFS
|
||||
# mount lands on the host later. HostToContainer relays that late
|
||||
# mount into the container instead of leaving an empty dir.
|
||||
sda2:
|
||||
type: persistentVolumeClaim
|
||||
existingClaim: nas1-sda2
|
||||
globalMounts:
|
||||
- path: /webdav/nas1/sda2
|
||||
mountPropagation: HostToContainer
|
||||
sdb2:
|
||||
type: persistentVolumeClaim
|
||||
existingClaim: nas1-sdb2
|
||||
globalMounts:
|
||||
- path: /webdav/nas1/sdb2
|
||||
mountPropagation: HostToContainer
|
||||
|
||||
@@ -48,6 +48,11 @@ spec:
|
||||
mountOptions:
|
||||
- nfsvers=3
|
||||
- nolock
|
||||
- soft
|
||||
- bg
|
||||
- retry=525600 # bg gives up after 10000 min by default; ~1 year instead
|
||||
- timeo=50
|
||||
- retrans=2
|
||||
nfs:
|
||||
server: 10.0.64.80
|
||||
path: /mnt/sda2
|
||||
@@ -85,6 +90,11 @@ spec:
|
||||
mountOptions:
|
||||
- nfsvers=3
|
||||
- nolock
|
||||
- soft
|
||||
- bg
|
||||
- retry=525600 # bg gives up after 10000 min by default; ~1 year instead
|
||||
- timeo=50
|
||||
- retrans=2
|
||||
nfs:
|
||||
server: 10.0.64.80
|
||||
path: /mnt/sdb2
|
||||
|
||||
@@ -4,20 +4,20 @@ metadata:
|
||||
name: webdav-secrets
|
||||
namespace: webdav
|
||||
stringData:
|
||||
WEBDAV_USERNAME: ENC[AES256_GCM,data:leD9Xfk=,iv:PLT4ctrHZUoSVCxkel99UyaI2FQVCjWq/pgCC7u/W18=,tag:W7ypg88sYu9tNJOxjlgeSA==,type:str]
|
||||
WEBDAV_PASSWORD: ENC[AES256_GCM,data:mpVRd5XzbQJdJKrEuixG8DVBmez4IW4+rp3/47QfGs7TLnMkJ3olPbHHleYFv1z4,iv:O066w8Sf4V8V6SFNjV3YoFUTm22vlSg8458GdSmo56Y=,tag:AHd0KrEqpBbsj3Pm4AcR/A==,type:str]
|
||||
WEBDAV_USERNAME: ENC[AES256_GCM,data:BeN5VS8=,iv:XpUr5PG9RWTRGXs7/EzDyLGwUm05Mr0YWpW7PwzNfm8=,tag:3py47tIcTeFxuuAidk2wBg==,type:str]
|
||||
WEBDAV_PASSWORD: ENC[AES256_GCM,data:Rh1ryftcmxgJAHvC/N1o5QeagCvyb3XIpDS7jOTCpJm3Wb5rUcLNmtcW22f0xljw,iv:GmgQJEuzUzSEql+fx5KURKv8CnhXF/z5UlmEn4ta+K0=,tag:AZD1CEbVRm6DiBt66pB9Vg==,type:str]
|
||||
sops:
|
||||
age:
|
||||
- recipient: age1y8t9v56yuvskznddqfsd4yddzzch0yf2dutvvt8rrx6rjh5f9g0s3qeays
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB6bGRvZEc5Q3dVNHM1ZnIv
|
||||
cDhGKzVhR2UwSnE2VW5JQVo5UEcyTzlXQ1M4CnptNERCNEMyUFh6aTFrc1FHV2pW
|
||||
RWUvUGRNL3U5dnJhK0kwSEFFUzhneHMKLS0tIHgrWHFGMDgzdVpMRjFFWEU2ZDZC
|
||||
SUN3WFMyODdxdlNoMlhmbFJUbEJQejAKRoY0DzKyIQmeyq9yf0IZe2A5LPVyA+Mi
|
||||
aShqop1PqAytaLmizdqryTR9gfGACILuY/bzBhs2MzvTLaaXzkExbw==
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA5UkRLNWVyZUpLREtZcm8r
|
||||
V0VPTkZDN1pSWDNxWFZXOUlON1c3cHhSZFVzClpEMmhvQnlFMnF6aXV6MjJnMnBu
|
||||
c2pxTDBGZVBUYjZNR1doQ3UraDQ3dlEKLS0tIE42dTZWMUhZdnVMYUNLTGdrSWZC
|
||||
UFM0V08reGVmZTRMUWw5T1R2OUdGWW8KWAZq4TG36Njlw4//vPCxzM1Qqr/6Ievw
|
||||
taBvLXpw9wkrjfZJ8gBU+0Q8WrsEy+tYtR9chfz1n/SmiGHCkskFGQ==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
lastmodified: "2026-08-26T10:29:49Z"
|
||||
mac: ENC[AES256_GCM,data:9iTiXBfG3Ua05tye8fhtcccE+Px6nef6ZvUrM1IlLNNvMg71A7s24/4WTHrSptLtcswOXLKtLrV9uHBg4ssT3HMOer7RBb2kmkUBLKJPwNKBZdQOo/YB2ETA302IGEeBQNLLsNSrw4PiwSkzTMI6PErsAbdxRn80hjFig+gyozw=,iv:YetHHW1EpB/saKxvEWO90JQTEPPF1EOHD8h+KNbQECA=,tag:B8z9mcYTQibaGi4pUGcJeA==,type:str]
|
||||
lastmodified: "2026-07-29T18:57:24Z"
|
||||
mac: ENC[AES256_GCM,data:bW2QvjSbA4JmfmZFzC1oIfEnVBxf1pE4jtKDsp2sf7mozVEdqMTD2nNpq4Pro9zRiXQfzxQAXAyzT48dBhIunXKDNIS7vbPpLUbs0nwSF4Dgp/q02ZX3Vrewx80iz5wdMYvLk6c2viZ9ndMwRqBbdBBsuSa5O9nIVj1edG9tj70=,iv:8bgXaA9RiQtbd1Xaht5r5NB3lFedX7Wi/X4z10VLLuA=,tag:Qnr8Ij6XN/FMcQf9Kx1IvA==,type:str]
|
||||
encrypted_regex: ^(data|stringData)$
|
||||
version: 3.11.0
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
apiVersion: helm.toolkit.fluxcd.io/v2
|
||||
kind: HelmRelease
|
||||
metadata:
|
||||
name: woodpecker
|
||||
namespace: ci
|
||||
spec:
|
||||
interval: 10m
|
||||
chartRef:
|
||||
kind: OCIRepository
|
||||
name: woodpecker
|
||||
driftDetection:
|
||||
mode: enabled
|
||||
values:
|
||||
defaultPodOptions:
|
||||
securityContext:
|
||||
fsGroup: 1000 # non-root image, fresh longhorn volume is root-owned
|
||||
fsGroupChangePolicy: OnRootMismatch
|
||||
|
||||
controllers:
|
||||
server:
|
||||
replicas: 1
|
||||
strategy: Recreate # sqlite on RWO volume
|
||||
containers:
|
||||
app:
|
||||
image:
|
||||
repository: woodpeckerci/woodpecker-server
|
||||
tag: v3.18.1
|
||||
env:
|
||||
WOODPECKER_HOST: https://ci.aggtaa.com
|
||||
WOODPECKER_OPEN: "false"
|
||||
WOODPECKER_ADMIN: anton
|
||||
WOODPECKER_GITEA: "true"
|
||||
WOODPECKER_GITEA_URL: https://git.aggtaa.com
|
||||
WOODPECKER_DATABASE_DRIVER: sqlite3
|
||||
WOODPECKER_DATABASE_DATASOURCE: /var/lib/woodpecker/woodpecker.sqlite
|
||||
envFrom:
|
||||
- secretRef:
|
||||
name: woodpecker-secrets
|
||||
resources:
|
||||
requests:
|
||||
cpu: 50m
|
||||
memory: 128Mi
|
||||
limits:
|
||||
memory: 512Mi
|
||||
agent:
|
||||
replicas: 1
|
||||
strategy: Recreate # RWO volume for agent id
|
||||
serviceAccount:
|
||||
name: woodpecker-agent # created in rbac.yaml
|
||||
pod:
|
||||
automountServiceAccountToken: true # kubernetes backend uses in-cluster config
|
||||
containers:
|
||||
app:
|
||||
image:
|
||||
repository: woodpeckerci/woodpecker-agent
|
||||
tag: v3.18.1
|
||||
env:
|
||||
WOODPECKER_SERVER: woodpecker:9000
|
||||
WOODPECKER_BACKEND: kubernetes
|
||||
WOODPECKER_BACKEND_K8S_NAMESPACE: ci
|
||||
WOODPECKER_BACKEND_K8S_STORAGE_CLASS: longhorn-no-retain
|
||||
WOODPECKER_BACKEND_K8S_VOLUME_SIZE: 5G
|
||||
WOODPECKER_MAX_WORKFLOWS: "2"
|
||||
envFrom:
|
||||
- secretRef:
|
||||
name: woodpecker-secrets
|
||||
resources:
|
||||
requests:
|
||||
cpu: 20m
|
||||
memory: 64Mi
|
||||
limits:
|
||||
memory: 256Mi
|
||||
|
||||
service:
|
||||
server:
|
||||
controller: server
|
||||
ports:
|
||||
http:
|
||||
port: 8000
|
||||
grpc:
|
||||
port: 9000
|
||||
|
||||
ingress:
|
||||
server:
|
||||
className: traefik
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||
hosts:
|
||||
- host: ci.aggtaa.com
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
service:
|
||||
identifier: server
|
||||
port: http
|
||||
tls:
|
||||
- secretName: woodpecker-tls
|
||||
hosts:
|
||||
- ci.aggtaa.com
|
||||
|
||||
persistence:
|
||||
data:
|
||||
type: persistentVolumeClaim
|
||||
existingClaim: woodpecker-data
|
||||
advancedMounts:
|
||||
server:
|
||||
app:
|
||||
- path: /var/lib/woodpecker
|
||||
agent-config:
|
||||
type: persistentVolumeClaim
|
||||
existingClaim: woodpecker-agent-config
|
||||
advancedMounts:
|
||||
agent:
|
||||
app:
|
||||
- path: /etc/woodpecker
|
||||
@@ -0,0 +1,10 @@
|
||||
apiVersion: source.toolkit.fluxcd.io/v1
|
||||
kind: OCIRepository
|
||||
metadata:
|
||||
name: woodpecker
|
||||
namespace: ci
|
||||
spec:
|
||||
interval: 10m
|
||||
url: oci://ghcr.io/bjw-s-labs/helm/app-template
|
||||
ref:
|
||||
tag: "5.0.1"
|
||||
@@ -0,0 +1,8 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- helmrepository.yaml
|
||||
- secret.enc.yaml
|
||||
- pvc.yaml
|
||||
- rbac.yaml
|
||||
- helmrelease.yaml
|
||||
@@ -0,0 +1,25 @@
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: woodpecker-data
|
||||
namespace: ci
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
storageClassName: longhorn
|
||||
resources:
|
||||
requests:
|
||||
storage: 2Gi
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: woodpecker-agent-config
|
||||
namespace: ci
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
storageClassName: longhorn
|
||||
resources:
|
||||
requests:
|
||||
storage: 1Gi
|
||||
@@ -0,0 +1,33 @@
|
||||
# Agent runs pipeline steps as pods in this namespace (kubernetes backend)
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: woodpecker-agent
|
||||
namespace: ci
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: woodpecker-agent
|
||||
namespace: ci
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: [pods, pods/log]
|
||||
verbs: [create, get, list, watch, delete]
|
||||
- apiGroups: [""]
|
||||
resources: [persistentvolumeclaims, services, secrets, configmaps]
|
||||
verbs: [create, get, list, watch, update, delete]
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: woodpecker-agent
|
||||
namespace: ci
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: woodpecker-agent
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: woodpecker-agent
|
||||
namespace: ci
|
||||
@@ -0,0 +1,25 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: woodpecker-secrets
|
||||
namespace: ci
|
||||
stringData:
|
||||
WOODPECKER_AGENT_SECRET: ENC[AES256_GCM,data:UyYPJpkHb2G1Vpe2tEtkNDMktp6zFbeNtDF34Kp8vf6nAY5/2EYXBJvT4+Ns2oOGNZOupdCUmTowrJ+ITNFwhQ==,iv:EtXILwt+FFYvqvLw9kLODh0wyhrHG+GJNGZRu6wzXd4=,tag:Ly5dsTWio741VxgtPy51XQ==,type:str]
|
||||
WOODPECKER_GITEA_CLIENT: ENC[AES256_GCM,data:hXBo5EwhHuCTQ4vQBAmjnLTlQ6cY2dKeJ5vZJ27wMFUsKZpS,iv:Pzt78GVSWngjVvpVSEgvsImK+siHEHOqQy+jOAxrGkc=,tag:JYu+Jf+n9J4L4LPwRPPbSw==,type:str]
|
||||
WOODPECKER_GITEA_SECRET: ENC[AES256_GCM,data:nu4FTBjdJe7oHx2Vt1ElxJXVnYzONC3kKYlXwvtmVI3/DokjSGA0YwLy0jI58l7K9nBbzGKuuZM=,iv:U6mfIG+LYhSfooIK3yhJay+fQh5oCNyGUggN+MrY4os=,tag:Oho0FnhePMLhFzsyhFISZQ==,type:str]
|
||||
WOODPECKER_GRPC_SECRET: ENC[AES256_GCM,data:rLiZToTcqf03gY/psoboYUsDUC16/0ZPkgOo/5ABrOvuyvHFoJPnAlvYhvSu/+qCIU1vlv7AvhfEJyEig+ULaA==,iv:q42abGbWSQb1noVhkXwiAWoIXcDUT01MTbnhaV5Plos=,tag:gioDH0cIPGoRD4auPEq71w==,type:str]
|
||||
sops:
|
||||
age:
|
||||
- recipient: age13qwkssk8esashln2j3gfv6e9csashr4vddkdav5v38hm5wejl36qd2ew9s
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA1anNnNDlnSjhMU2h4clVV
|
||||
eFJnNEx6VmU1RjR0a1RQQTRML3lBaUphSkU4CnNuM0I2NkFPMlU1clFNY3V5Sk9Y
|
||||
b0NJNzlUMjJsRVZMdndzUWYyNWhjeHMKLS0tIEp0Y2E3dTRwRTUyUmprRktFNUJp
|
||||
TXlXWjViSGNFb1FhQ0xDT0gvajdwSlEKXB7N64RmaWgCCSvG/nNWOziO7QnN729i
|
||||
jJLB6SPiHjgNMn1GP+rsAstVFStB0fn2mh6QpWrdhAM3/NFBqQfy7A==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
lastmodified: "2026-10-07T08:38:39Z"
|
||||
mac: ENC[AES256_GCM,data:+beUA2t2YPqjsk7KXnPgJBiiQSjB7qypni669F2W3YNdTXx/ChenMxo7srjvejW3YfzPccbnBY6/TJgKCLPGm/Kf0hntejbBgYeu9hltSrIZX28efoE6tq4NicqJkPT8oD24v++H5jxRZP4epmef5t6rzJSq1xc4ETZerK0f9PU=,iv:wekT7WxL/Xm+vqCYCsZ4nvwl8VeOugURNvbHs/KQhRk=,tag:gH5efL/YUtJEewcY0G3Ctw==,type:str]
|
||||
encrypted_regex: ^(data|stringData)$
|
||||
version: 3.11.0
|
||||
@@ -38,7 +38,7 @@ spec:
|
||||
zigbee2mqtt:
|
||||
homeassistant:
|
||||
enabled: true
|
||||
legacy_entity_attributes: true
|
||||
experimental_event_entities: true
|
||||
|
||||
permit_join: false
|
||||
timezone: Europe/Moscow
|
||||
@@ -75,7 +75,7 @@ spec:
|
||||
ingressClassName: traefik
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||
traefik.ingress.kubernetes.io/router.middlewares: auth-authelia@kubernetescrd
|
||||
traefik.ingress.kubernetes.io/router.middlewares: auth-tinyauth@kubernetescrd
|
||||
hosts:
|
||||
- host: zigbee2mqtt.aggtaa.com
|
||||
paths:
|
||||
|
||||
@@ -4,19 +4,19 @@ metadata:
|
||||
name: zigbee2mqtt-secrets
|
||||
namespace: zigbee2mqtt
|
||||
stringData:
|
||||
secret.yaml: ENC[AES256_GCM,data:RdMKYeSHeJpHVJqglYAOyfdDyZyuc7KQheiq0vaxb5fs0DrgOYP2EgMKOcKA8Lh933W7u9qx/VrkOjBz+fm66vyAxwQKXvGZjnrM4RqtN0rW5UMG9C5s9zyQrepVECsqDiNpC2NCzRE9DsWX7Ux6Ak0RpMV0wkX1fAzVVwE=,iv:Uee5eN7qFyI2K7VgUEnTP506zy+ZK1uNFkemax48DhU=,tag:gvFAAUva/gJy1gBeZek50w==,type:str]
|
||||
secret.yaml: ENC[AES256_GCM,data:mDb7Vt4sOSaqn9+T3QEAR0yutRIFwiYpBBZDMQI4FMvAPWPkAdsYTIfvv+41JbpBafklDJ5gzPPKZJ6Qk1f8KBvjRuHP/bJqTUPrv+Q46ZKsuXECQq+qB8TKAj51FiJssyx0jYy9bCYgn+Z9r+WBT4YSAvv1XS/UHs4S8UA=,iv:8RHjs0g1ee38yUSHjvQv06Z7xbzMOG6LNzCJ/7s4+Pc=,tag:jb+VgAVApqIpN3lERqrfBg==,type:str]
|
||||
sops:
|
||||
age:
|
||||
- recipient: age1tu4xgfefvgdda0vn2thaqndq4p9tuydq2ud6qa98tzzgnff6749qnlcx29
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB0Z3ZTdXMreGl0OWdjSkI0
|
||||
T3lWRTNrUUJrSk9KVm12eW1na3AxZCtuNURVCk9UMHpOY1R0Uk9ZT2V4K0RMeDk1
|
||||
cFBzcEE1RTJnUHFPVWZVaDh3R0xkQVUKLS0tIGxVVVNWSlAzVzR2dWdDZXFtTkNR
|
||||
L3JVQ1ZCY3lRL25SLzBka2RBRFVNRWsKu3/3f9tH7GyzCEENtCTGDyK6l7lvQMw0
|
||||
GSOZzZVClKfbCDrdjAqgly8ouGeYx0X19KtoHmggfH95nvcYheFFTA==
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAzcUFqU2RpTXUwR3hsSEJr
|
||||
WUV1NkpqQitDRDF6MUpWMWlnSS9TaStRZ1hNClNkSEIzOVVSTUh6LzdXdTdld3Zj
|
||||
U1pVcE5IaFhuQ0lTZlZ0RzFDSHVkREUKLS0tIDdTbEJLbE9KUmxRei9lVlc4TW1t
|
||||
TE0yUERpQkpqZFg3aGpvSkg4M04zMGcKcYmSgyzhpZ8BGAp+0zkQ7+ZnF2w/Nk9D
|
||||
ZT8zwqCJcaRldg59JzmhLBfiuYAtnH2wqWj06LiIfvt+P3pgY79f3g==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
lastmodified: "2026-08-26T10:29:50Z"
|
||||
mac: ENC[AES256_GCM,data:ZJAwVpj9OKeLqN3kEVtHdlouks29xb5a9DxRUnq7pNmf5lww8GKG1r8nfm9t6Z4JeuOBjN3zELjuEC9zBJ5Xpcdp2Ru8e3oD2816fu0feuiVkTXjaSrq1ZfHezvN5eHQqTU6Pmx5vSQcy8c7e61mI0VyYvOIUSXY4zfd1mDrIGc=,iv:qqFi/nUg+KWi/aBfJqlXqU3lnn8NZ8LS9CzbJcLOlpg=,tag:oykm3cfYCn3m63ajTS4rRQ==,type:str]
|
||||
lastmodified: "2026-07-19T09:01:11Z"
|
||||
mac: ENC[AES256_GCM,data:fKfDsAg1Ya8c//x0xw9ytQR7hiF/BssuqlwA57PYiB1yjCW3Kddcdt95UF1amF+9tvJb2XwRjb2LwN4RrYj0RyScLmLa3u/l1r79EoUKQWQ4qF7GNdD5ZGaxqnWjgorxkfYcU7ahJBRDEIsvJXJivk6Wjm309ISzl8xR/tUpFCM=,iv:TmFo1gbRsATh6O0uJvJxwyj7hSzCfpPPuo55EkQQabk=,tag:CJ0cTn9BJs+87AvdwJ0MsA==,type:str]
|
||||
encrypted_regex: ^(data|stringData)$
|
||||
version: 3.11.0
|
||||
version: 3.13.2
|
||||
|
||||
@@ -24,6 +24,28 @@ spec:
|
||||
upgrade:
|
||||
remediation:
|
||||
retries: 3
|
||||
postRenderers:
|
||||
- kustomize:
|
||||
patches:
|
||||
- target:
|
||||
kind: DaemonSet
|
||||
name: longhorn-manager
|
||||
# chart hardcodes readinessProbe without timeoutSeconds, so it falls back to the
|
||||
# k8s default of 1s; under CPU contention (e.g. busy nodes) that's too tight and
|
||||
# causes spurious "Readiness probe failed ... Client.Timeout exceeded" flapping
|
||||
patch: |
|
||||
apiVersion: apps/v1
|
||||
kind: DaemonSet
|
||||
metadata:
|
||||
name: longhorn-manager
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: longhorn-manager
|
||||
readinessProbe:
|
||||
timeoutSeconds: 5
|
||||
failureThreshold: 5
|
||||
values:
|
||||
defaultSettings:
|
||||
defaultReplicaCount: 3 # по числу нод control-plane
|
||||
@@ -39,10 +61,9 @@ spec:
|
||||
# чтобы не разъезжались реплики при 3 нодах
|
||||
replicaSoftAntiAffinity: false
|
||||
persistence:
|
||||
defaultClass: true
|
||||
defaultClassReplicaCount: 3
|
||||
defaultFsType: ext4
|
||||
reclaimPolicy: Retain
|
||||
# the default "longhorn" StorageClass lives in ../storage-classes/longhorn.yaml -
|
||||
# the chart hardcodes staleReplicaTimeout: "30" and offers no value to override it
|
||||
createStorageClass: false
|
||||
csi:
|
||||
attacherReplicaCount: 3
|
||||
provisionerReplicaCount: 3
|
||||
|
||||
@@ -5,7 +5,7 @@ metadata:
|
||||
namespace: longhorn-system
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||
traefik.ingress.kubernetes.io/router.middlewares: auth-authelia@kubernetescrd
|
||||
traefik.ingress.kubernetes.io/router.middlewares: auth-tinyauth@kubernetescrd
|
||||
spec:
|
||||
ingressClassName: traefik
|
||||
rules:
|
||||
|
||||
@@ -4,21 +4,21 @@ metadata:
|
||||
name: longhorn-backup-target-secret
|
||||
namespace: longhorn-system
|
||||
stringData:
|
||||
AWS_ACCESS_KEY_ID: ENC[AES256_GCM,data:Yf3CM07ST98zuo595rsWL0ltYmc=,iv:+JOv1TEjFGygopzMHsQvpdaKfX3tWg1woLRtgw+hY4Q=,tag:+9flP+/Ap3cUwMWJ4LZj5w==,type:str]
|
||||
AWS_SECRET_ACCESS_KEY: ENC[AES256_GCM,data:rzAUUcv4de7AbvAziJVfAYlwwn4TZhzrYwNhICPp+CNtn5hlhoZOTA==,iv:EQhgZ8iJlI7yHX0Pu1GKGACfGiyNT9ui8p6MhSrdvn0=,tag:Oku1Q/o54jx1pY5K73u8Dw==,type:str]
|
||||
AWS_ENDPOINTS: ENC[AES256_GCM,data:upvLav5iZdAwfcZ7pJd7hgVRrTEn800Yh+js8KvCukZf1ybNSA2QAX9Dn3/c6gsmI9iJN8Ztg93MGCI85w==,iv:usiTtOM+uLcxVghNeoHo8+/bTIR9QfWiMz+ke+xPFDs=,tag:WPVw/nVNUSBbCUeVlxoKrg==,type:str]
|
||||
AWS_ACCESS_KEY_ID: ENC[AES256_GCM,data:QPvQnrkMSKK4Whj7DaMONoDW7LQ=,iv:K1x/VDp4VZUnC7u86wpEfVBDW7T9cI4CZojMZMCaS+A=,tag:eFAAnCMCVjNBHnFAhzFS3w==,type:str]
|
||||
AWS_SECRET_ACCESS_KEY: ENC[AES256_GCM,data:zFjxH1uqnYRrxM4Yrll9Na+mDj16aLtiJC2ZlNO+2r70JcXJqnTASQ==,iv:B7eV80h4APk3QCuoDR9EFpKs5dkMF8GjQ2v9lSF/ev8=,tag:xLbWN0Gy2idB9j2G8HZYKQ==,type:str]
|
||||
AWS_ENDPOINTS: ENC[AES256_GCM,data:HWVPThBb5GLpiRqAuSLvmAat0XiUu5R5CMv2Fv6jdieZ11lUmbS2MBD6lx0vQDSIzC36hd6Tu0hgqtknQA==,iv:XLqWSNHgj8O0uQPeBbnN05Za8G9VW6F802CCPoUoq9A=,tag:dsKXCq21hDlJy4KTyQTp/w==,type:str]
|
||||
sops:
|
||||
age:
|
||||
- recipient: age18hhmdmupj90zjgjpxk3z5cf3lx36hcznnmqsp0fpyg50823pudrqjupydt
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBqSmJQYTFDN2tSZDBPYVpt
|
||||
M2tub09CRkpUd0ZtS3M5TDdoU0k0N2FKdzJRCkNndkhaenBIQ0lUVWtjY0FCTTMx
|
||||
ZGg2eWh6eEFudzg0d0lnRFN5VnN1MzAKLS0tIDZqUEswbmdmQ2d4aXlUVFdFREFM
|
||||
WUkzNUZSRDgxeDVlN29aMFdWOWZRSHcKvoZaEwnjkOVw8pvkdpaTQvpbBSTuWUYN
|
||||
XkzUPKQmtRLNp0bOgXyWpWWJj2i8ue5SI313g8GiJJWZZ4WesA/atA==
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBqRndobTFybElvakN3c013
|
||||
T3d6ekVUM0V4OVNEMjl1ak5XTzNPS0xKRmtVCjBXMjVybEs0bFZKN3ByWmFpWm9K
|
||||
TVVLVVBPYmE2NnJMT3Q3dVJRa250aXcKLS0tIEVKeXBGQ0x4ZDlIWENMa3k3S3Zz
|
||||
YUdxZXoycXBPbm5raWxFZ3owc2xkQmsKNzw+5kn73FZhApzfN/RBj4yAd7GLl5/X
|
||||
wyXVy0te83ZDeVQvqhXLkUPsbF8CYewC6xibZSdSY/WBh2ojedJXrQ==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
lastmodified: "2026-08-26T10:29:51Z"
|
||||
mac: ENC[AES256_GCM,data:Gq7jEOcEjsJmJutnkUQZ/mr4aU11bCgHFz1cK0U3k61A9IULUqyV1j0/+ZNAF4JsXv255XcFsn6qouvFbKlAw3mg0LtjwP4zIkhIj+eThZ+EqfuoJ8F0vvLFijohu+kRNyafLJpNGHEqNvTFyd8OXKMNZET74UTHV4qseBMIf5o=,iv:EdEQVzK3yRa4RgP09m2gZirszwLv8Efwpt74jS/lpA0=,tag:YpZOC1kvpZMye24Ha1KEXA==,type:str]
|
||||
lastmodified: "2026-08-11T19:04:53Z"
|
||||
mac: ENC[AES256_GCM,data:SO2tMq3UA0JcsTZyH3oNhmCsWZ2OhxEmJSn1b/3sH78cZvWalXUsdQqD1GBArFgS+oCSaSgarl2Ve06iNJtM8k6oq0fDkm0dxsLou+67qHlle4CbkP1KPFEQid2Nx8o/5b6cjI2zHz3bYmQTQh9DD7mE8roqo6lX3rYY35MpPJw=,iv:Ad13teWF+lZfzOY/PIALI3/Wohn/0BBoSuE0mtiH8/Y=,tag:sQVQfH0mFFMLnF4zbRC2VQ==,type:str]
|
||||
encrypted_regex: ^(data|stringData)$
|
||||
version: 3.11.0
|
||||
|
||||
@@ -88,6 +88,13 @@ spec:
|
||||
enabled: true
|
||||
readiness:
|
||||
enabled: true
|
||||
resources:
|
||||
requests:
|
||||
cpu: 50m
|
||||
memory: 64Mi
|
||||
limits:
|
||||
cpu: 750m
|
||||
memory: 512Mi
|
||||
|
||||
service:
|
||||
app:
|
||||
|
||||
@@ -4,24 +4,24 @@ metadata:
|
||||
name: s3-backup-proxy-secrets
|
||||
namespace: longhorn-system
|
||||
stringData:
|
||||
WASABI_ACCESS_KEY_ID: ENC[AES256_GCM,data:okf70ogiDqqAkpnSCBYkW9oATC4=,iv:iVs6x/2z2+gejRQMyXwpa/hXQ6xq7eXdMVA27IHiPqw=,tag:qXcpGptnTCipk/NX3Ph9Gw==,type:str]
|
||||
WASABI_SECRET_ACCESS_KEY: ENC[AES256_GCM,data:Pltg8OsVpXcET0qe5Zdwu38KBlR+oR6lT4yVi2rwNMmJxu4HryqMEw==,iv:oROBr2u09mdUVeffu/dyCIwmKabFMpOK17BL9uHx0VU=,tag:Tgmnqy4RWe4tvbEuqz5t7w==,type:str]
|
||||
CRYPT_PASSWORD: ENC[AES256_GCM,data:PbwJlJfz6jTM67qGi0tGkF9b5nVd0OhzRu3cTUn8IZVHIaDq7JQpykmq3g==,iv:UNkWK3DpY3Ux5g/SG5tAY5RU0spm1D/B+j5lp4eTxkg=,tag:0l9WxfSalrKaCDF4RAWoew==,type:str]
|
||||
CRYPT_PASSWORD2: ENC[AES256_GCM,data:An7PTYE6Kp4ym17cFJ4HD+kiXbFgz0qOxRUTPjXFpoj++4QFzgG5PwnZuQ==,iv:TwcnYlyuN3o/tvQrxhuirBNL48lD66GzL4XUTdKzyIA=,tag:NoEp7DfdLCFQ8ju6Tk8adQ==,type:str]
|
||||
PROXY_ACCESS_KEY: ENC[AES256_GCM,data:AIpKJPLYOrda/lyklBKtkbfyBx8=,iv:b0xXnfhsp4gh/v+wYYSinKCpj0fZcgm+yrrOC5MYJWs=,tag:CNMVLrAouXmDxLqlkYI3CQ==,type:str]
|
||||
PROXY_SECRET_KEY: ENC[AES256_GCM,data:hz3GyFtbbTnVqWi8O+P7aRUS2IA0oDipgtBq8KPpDEyclv1rdBGkfQ==,iv:UqL4wYouaVuJwBlgJzfbrPfs7hksgyaY2a2cBPPUQn4=,tag:w4cYoFVkRodXC8dK9CG3IQ==,type:str]
|
||||
WASABI_ACCESS_KEY_ID: ENC[AES256_GCM,data:YP9bOIarPh6DJVo0vevVN2T3c3A=,iv:bTKwVx/Ij+GMCisO4WEDCJz8rsHe8PtSET/h4+P2dyM=,tag:fdXr+wAx/SvKNwlYlmKvRw==,type:str]
|
||||
WASABI_SECRET_ACCESS_KEY: ENC[AES256_GCM,data:Aa0ZYxiVipW2g4mGzyhCspVF67m7hnouMg4Tcr6kSinY+ULpHtEDBA==,iv:txr1ual5z7dXi/27T3FOMsccQtSPObHpg+7IfxvfWuw=,tag:MW7fl0iRB/6flbN+iA+2QA==,type:str]
|
||||
CRYPT_PASSWORD: ENC[AES256_GCM,data:x8kMqkX4OzduFbW1BGc2EcFxaVm4ah4BBgLNxzQfIHeuL3UuJXt+Cj8isg==,iv:xoFXHqUDK/yamkDaSaQaMIkC7p+q/4qtsrYNwKT7944=,tag:92nej0/10KVTsugwFzdB0w==,type:str]
|
||||
CRYPT_PASSWORD2: ENC[AES256_GCM,data:TdcfVmkgd36Hq80XaLRM8lY2dUq95h4v4ONCy/O7DOMoRwVxDUktgCRgNA==,iv:9EluJOnjKjCo2272sIeJ58iFu54DKfbkX785ZySj3C0=,tag:WUMKDLASA9grCilKNLVmZA==,type:str]
|
||||
PROXY_ACCESS_KEY: ENC[AES256_GCM,data:A1ZF8ejApPiH3nISLvrO7+vWTzM=,iv:fSFwYL/6zxtK4wkz+G3WItzq6P92eGviQ7WaVquDYuk=,tag:n9fjuW/cXU7QWe5IUkXf/w==,type:str]
|
||||
PROXY_SECRET_KEY: ENC[AES256_GCM,data:iU6GHL09tzxgyxcl6wKlDNhaO6YVYS/8yy/qCPbSxE3RlHk0Yw9EnQ==,iv:i0R6SzOJlEDsyEhxLrLMVaJu7ZAzNsnnmdyrxbv6ys0=,tag:h290ZIcFevBQeImcfqQbjg==,type:str]
|
||||
sops:
|
||||
age:
|
||||
- recipient: age15vc3geq4lsec69rnxczluvwgcexeqae02zxzjpswsuatthaasu7qzath48
|
||||
enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBoVVVHYXlTM00ydVJjdXFL
|
||||
U0k5clRFY2VlMStzZE9DeVlweDNDelJUTjNBCmNwbWw1UldxNG5XZzdZZzh1UStw
|
||||
eFlQa2k4UU1DWUdlMUF6N20rOUNwSmsKLS0tIEtsbUdBNnZYT1BmRmg3enF5Nmp0
|
||||
Z3p0UzZkS0VHdDhRbEU4Q3M5bnA0RDQKWcny31QSOW0t/XDeBspoymNK5vN1ltqI
|
||||
mdWodYgxrZ7qgaBABL18QENAJMm2i/C3VY6upqGjTjxSq7+huKfTQg==
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBxR0hwMUhqVHFJSVBUckZW
|
||||
cTdCeUx0bC8zdjB5dmhRNDJrc1ZOTnY4WmxVCjJNZEUrMEFEYmNGUWQxbHRZL3Bj
|
||||
S3dnOGhENlJkV2oxR1RhSmdCWXczVWsKLS0tIHIxSnVSdGtKaE52UHNtaWVnRUNW
|
||||
Unc4QUJ3YmF3N2xVVDg2VjBrZW80QmsKZ5HiOTiYRCrfWJf2Qpxyc4D+1wNWxHzK
|
||||
hCe6G9ANAX/EAlGwmOIn3k7cFbN1VRt50TV/UCj+FsJBuifUYVMvTQ==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
lastmodified: "2026-08-26T10:29:52Z"
|
||||
mac: ENC[AES256_GCM,data:knkRyXRoKdjhyWZIWDCRW5MuhxtxeTm42Fm+rtVZawECWCSIqxTYSfQ6xW9RlalMcsHpdW4QTHDBgZhp6APDe3f+9Frn59UCDa415hqm4VCreDFhqy+x5kUslpT8Zg1ggsiWTv6/XxI2NM0LswoDu6akAEKnBRYJ6S7aam1++oc=,iv:Z8y1HAlzSgbEjX8sh8drHQj6Oigt13m3kYLvWAJZTGs=,tag:iunewDP8PGlj6iTaqAnbnw==,type:str]
|
||||
lastmodified: "2026-08-11T18:28:22Z"
|
||||
mac: ENC[AES256_GCM,data:eICyFKuJAyCE8ZbdpWc4rOHRxtnrFhdxTeznIWXie5CrHRyo+n21CPg5L/VQUy2LF1rXINIDJRNqQWcLXJEXDKWGpqyaL/YcW+OawpbCq0DMJAe/DsvBdy5ySwGFdRlwU5x7ivVjsHKnsr8UgcbHdE/ZVRq93nZOfZlUepjb1u0=,iv:l+SFwIobBbxeZNUmwK6U9W5YpLh4t5GOtnRIH10Z7W4=,tag:6Zs+tneNcF1d5i43ns6Rmw==,type:str]
|
||||
encrypted_regex: ^(data|stringData)$
|
||||
version: 3.11.0
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- longhorn.yaml
|
||||
- longhorn-no-retain.yaml
|
||||
- longhorn-single-replica.yaml
|
||||
|
||||
@@ -4,9 +4,11 @@ metadata:
|
||||
name: longhorn-no-retain
|
||||
annotations:
|
||||
storageclass.kubernetes.io/is-default-class: "false"
|
||||
# StorageClass parameters are immutable - let Flux recreate the object on change
|
||||
kustomize.toolkit.fluxcd.io/force: enabled
|
||||
provisioner: driver.longhorn.io
|
||||
reclaimPolicy: Delete
|
||||
allowVolumeExpansion: true
|
||||
parameters:
|
||||
numberOfReplicas: "3"
|
||||
staleReplicaTimeout: "30"
|
||||
staleReplicaTimeout: "2880"
|
||||
|
||||
@@ -4,9 +4,11 @@ metadata:
|
||||
name: longhorn-single-replica
|
||||
annotations:
|
||||
storageclass.kubernetes.io/is-default-class: "false"
|
||||
# StorageClass parameters are immutable - let Flux recreate the object on change
|
||||
kustomize.toolkit.fluxcd.io/force: enabled
|
||||
provisioner: driver.longhorn.io
|
||||
reclaimPolicy: Retain
|
||||
allowVolumeExpansion: true
|
||||
parameters:
|
||||
numberOfReplicas: "1"
|
||||
staleReplicaTimeout: "30"
|
||||
staleReplicaTimeout: "2880"
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
# Default Longhorn class. Managed here instead of by the chart (persistence.createStorageClass: false
|
||||
# in the HelmRelease) because the chart hardcodes staleReplicaTimeout: "30".
|
||||
# Parameters otherwise mirror what chart 1.12.1 rendered.
|
||||
apiVersion: storage.k8s.io/v1
|
||||
kind: StorageClass
|
||||
metadata:
|
||||
name: longhorn
|
||||
annotations:
|
||||
storageclass.kubernetes.io/is-default-class: "true"
|
||||
# StorageClass parameters are immutable - let Flux recreate the object on change
|
||||
kustomize.toolkit.fluxcd.io/force: enabled
|
||||
provisioner: driver.longhorn.io
|
||||
reclaimPolicy: Retain
|
||||
allowVolumeExpansion: true
|
||||
volumeBindingMode: Immediate
|
||||
parameters:
|
||||
numberOfReplicas: "3"
|
||||
# minutes a failed replica is kept for reuse before it is discarded and fully rebuilt;
|
||||
# 30 was shorter than a planned node shutdown and caused a ~1.2TB full rebuild of kube-3
|
||||
staleReplicaTimeout: "2880"
|
||||
fromBackup: ""
|
||||
fsType: ext4
|
||||
dataLocality: disabled
|
||||
unmapMarkSnapChainRemoved: ignored
|
||||
disableRevisionCounter: "true"
|
||||
dataEngine: v1
|
||||
backupTargetName: default
|
||||
@@ -10,7 +10,8 @@ spec:
|
||||
- 10.0.64.6/32
|
||||
# exclude 10.0.64.7, its in dmz-pool
|
||||
# exclude 10.0.64.8, its in mqtt-pool
|
||||
- 10.0.64.9-10.0.64.19
|
||||
# exclude 10.0.64.9, its in public-ports-pool
|
||||
- 10.0.64.10-10.0.64.19
|
||||
autoAssign: true
|
||||
serviceAllocation:
|
||||
serviceSelectors:
|
||||
@@ -62,6 +63,19 @@ spec:
|
||||
- matchLabels:
|
||||
loadBalancerPool: mqtt
|
||||
---
|
||||
# ip for services that need individual ports forwarded from WAN router (e.g. jitsi jvb udp)
|
||||
# not auto-assigned: a service gets it only with an explicit annotation
|
||||
# metallb.io/address-pool: public-ports-pool
|
||||
apiVersion: metallb.io/v1beta1
|
||||
kind: IPAddressPool
|
||||
metadata:
|
||||
name: public-ports-pool
|
||||
namespace: metallb-system
|
||||
spec:
|
||||
addresses:
|
||||
- 10.0.64.9/32
|
||||
autoAssign: false
|
||||
---
|
||||
apiVersion: metallb.io/v1beta1
|
||||
kind: L2Advertisement
|
||||
metadata:
|
||||
@@ -73,3 +87,4 @@ spec:
|
||||
- dmz-pool
|
||||
- mqtt-pool
|
||||
- nfs-pool
|
||||
- public-ports-pool
|
||||
|
||||
@@ -15,3 +15,29 @@ spec:
|
||||
namespace: metallb-system
|
||||
driftDetection:
|
||||
mode: enabled
|
||||
postRenderers:
|
||||
- kustomize:
|
||||
patches:
|
||||
# frr's liveness/startup probes default to timeoutSeconds: 1,
|
||||
# which is too tight when the node is under CPU pressure (an
|
||||
# HTTPS healthz call can't always complete in 1s) - kubelet then
|
||||
# kills+restarts the container, which itself adds more CPU load,
|
||||
# compounding the problem. Give the probes more slack instead.
|
||||
- target:
|
||||
kind: DaemonSet
|
||||
name: metallb-frr-k8s
|
||||
patch: |
|
||||
apiVersion: apps/v1
|
||||
kind: DaemonSet
|
||||
metadata:
|
||||
name: metallb-frr-k8s
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: frr
|
||||
livenessProbe:
|
||||
timeoutSeconds: 5
|
||||
failureThreshold: 6
|
||||
startupProbe:
|
||||
timeoutSeconds: 5
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: ci
|
||||
@@ -0,0 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: dev
|
||||
@@ -0,0 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: git
|
||||
@@ -0,0 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: iot
|
||||
@@ -0,0 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: notify
|
||||
@@ -0,0 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: tools
|
||||
@@ -0,0 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: video
|
||||
@@ -18,4 +18,4 @@ spec:
|
||||
decryption:
|
||||
provider: sops
|
||||
secretRef:
|
||||
name: sops-age
|
||||
name: sops-age-authelia
|
||||
|
||||
@@ -18,4 +18,4 @@ spec:
|
||||
decryption:
|
||||
provider: sops
|
||||
secretRef:
|
||||
name: sops-age
|
||||
name: sops-age-davical
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
apiVersion: kustomize.toolkit.fluxcd.io/v1
|
||||
kind: Kustomization
|
||||
metadata:
|
||||
name: dev
|
||||
namespace: flux-system
|
||||
spec:
|
||||
interval: 10m
|
||||
sourceRef:
|
||||
kind: GitRepository
|
||||
name: flux-system
|
||||
path: ./clusters/base/apps/dev
|
||||
prune: true
|
||||
wait: true
|
||||
dependsOn:
|
||||
- name: namespaces
|
||||
- name: infra
|
||||
- name: auth
|
||||
retryInterval: 5s
|
||||
@@ -0,0 +1,21 @@
|
||||
apiVersion: kustomize.toolkit.fluxcd.io/v1
|
||||
kind: Kustomization
|
||||
metadata:
|
||||
name: gitea
|
||||
namespace: flux-system
|
||||
spec:
|
||||
interval: 10m
|
||||
sourceRef:
|
||||
kind: GitRepository
|
||||
name: flux-system
|
||||
path: ./clusters/base/apps/gitea
|
||||
prune: true
|
||||
wait: true
|
||||
dependsOn:
|
||||
- name: namespaces
|
||||
- name: infra
|
||||
retryInterval: 5s
|
||||
decryption:
|
||||
provider: sops
|
||||
secretRef:
|
||||
name: sops-age-gitea
|
||||
@@ -18,4 +18,4 @@ spec:
|
||||
decryption:
|
||||
provider: sops
|
||||
secretRef:
|
||||
name: sops-age
|
||||
name: sops-age-immich
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
apiVersion: kustomize.toolkit.fluxcd.io/v1
|
||||
kind: Kustomization
|
||||
metadata:
|
||||
name: openwebui
|
||||
name: it-tools
|
||||
namespace: flux-system
|
||||
spec:
|
||||
interval: 10m
|
||||
sourceRef:
|
||||
kind: GitRepository
|
||||
name: flux-system
|
||||
path: ./clusters/base/apps/openwebui
|
||||
path: ./clusters/base/apps/it-tools
|
||||
prune: true
|
||||
wait: true
|
||||
dependsOn:
|
||||
@@ -0,0 +1,21 @@
|
||||
apiVersion: kustomize.toolkit.fluxcd.io/v1
|
||||
kind: Kustomization
|
||||
metadata:
|
||||
name: jitsi
|
||||
namespace: flux-system
|
||||
spec:
|
||||
interval: 10m
|
||||
sourceRef:
|
||||
kind: GitRepository
|
||||
name: flux-system
|
||||
path: ./clusters/base/apps/jitsi
|
||||
prune: true
|
||||
wait: true
|
||||
dependsOn:
|
||||
- name: namespaces
|
||||
- name: infra
|
||||
retryInterval: 5s
|
||||
decryption:
|
||||
provider: sops
|
||||
secretRef:
|
||||
name: sops-age-jitsi
|
||||
@@ -0,0 +1,21 @@
|
||||
apiVersion: kustomize.toolkit.fluxcd.io/v1
|
||||
kind: Kustomization
|
||||
metadata:
|
||||
name: joplin
|
||||
namespace: flux-system
|
||||
spec:
|
||||
interval: 10m
|
||||
sourceRef:
|
||||
kind: GitRepository
|
||||
name: flux-system
|
||||
path: ./clusters/base/apps/joplin
|
||||
prune: true
|
||||
wait: true
|
||||
dependsOn:
|
||||
- name: namespaces
|
||||
- name: infra
|
||||
retryInterval: 5s
|
||||
decryption:
|
||||
provider: sops
|
||||
secretRef:
|
||||
name: sops-age-joplin
|
||||
@@ -7,12 +7,19 @@ resources:
|
||||
- authelia.yaml
|
||||
- mosquitto.yaml
|
||||
- homeassistant.yaml
|
||||
- openwebui.yaml
|
||||
- markdown-vault-mcp.yaml
|
||||
- nfs-ganesha.yaml
|
||||
- webdav.yaml
|
||||
- fava.yaml
|
||||
- infcloud.yaml
|
||||
- syncthing.yaml
|
||||
- photo-stats.yaml
|
||||
- immich.yaml
|
||||
- immich.yaml
|
||||
- joplin.yaml
|
||||
- gitea.yaml
|
||||
- dev.yaml
|
||||
- woodpecker.yaml
|
||||
- tinyauth.yaml
|
||||
- it-tools.yaml
|
||||
- ntfy.yaml
|
||||
- map-monitor.yaml
|
||||
- jitsi.yaml
|
||||
@@ -0,0 +1,21 @@
|
||||
apiVersion: kustomize.toolkit.fluxcd.io/v1
|
||||
kind: Kustomization
|
||||
metadata:
|
||||
name: map-monitor
|
||||
namespace: flux-system
|
||||
spec:
|
||||
interval: 10m
|
||||
sourceRef:
|
||||
kind: GitRepository
|
||||
name: flux-system
|
||||
path: ./clusters/base/apps/map_monitor
|
||||
prune: true
|
||||
wait: true
|
||||
dependsOn:
|
||||
- name: namespaces
|
||||
- name: infra
|
||||
retryInterval: 5s
|
||||
decryption:
|
||||
provider: sops
|
||||
secretRef:
|
||||
name: sops-age-map-monitor
|
||||
@@ -19,4 +19,4 @@ spec:
|
||||
decryption:
|
||||
provider: sops
|
||||
secretRef:
|
||||
name: sops-age
|
||||
name: sops-age-markdown-vault-mcp
|
||||
|
||||
@@ -15,4 +15,4 @@ spec:
|
||||
decryption:
|
||||
provider: sops
|
||||
secretRef:
|
||||
name: sops-age
|
||||
name: sops-age-mosquitto
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
apiVersion: kustomize.toolkit.fluxcd.io/v1
|
||||
kind: Kustomization
|
||||
metadata:
|
||||
name: ntfy
|
||||
namespace: flux-system
|
||||
spec:
|
||||
interval: 10m
|
||||
sourceRef:
|
||||
kind: GitRepository
|
||||
name: flux-system
|
||||
path: ./clusters/base/apps/ntfy
|
||||
prune: true
|
||||
wait: true
|
||||
dependsOn:
|
||||
- name: namespaces
|
||||
- name: infra
|
||||
retryInterval: 5s
|
||||
decryption:
|
||||
provider: sops
|
||||
secretRef:
|
||||
name: sops-age-ntfy
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user