Compare commits
45
Commits
bf506882a9
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0af896ab02 | ||
|
|
4238d82b40 | ||
|
|
adb5b9524b | ||
|
|
36ad140f66 | ||
|
|
36aba16de3 | ||
|
|
038b3396ab | ||
|
|
ffd5bde344 | ||
|
|
2f0e10a10b | ||
|
|
f3c0cf7060 | ||
|
|
b45f9a19a2 | ||
|
|
e9b199aca0 | ||
|
|
c1437d9199 | ||
|
|
9b5dff602a | ||
|
|
1f26627488 | ||
|
|
db3c8e4694 | ||
|
|
a8431d15c6 | ||
|
|
0663196fa0 | ||
|
|
5101df740d | ||
|
|
f56c6719da | ||
|
|
019039126a | ||
|
|
aa1bb9d838 | ||
|
|
faebef6c58 | ||
|
|
f79691f838 | ||
|
|
c7fce94b04 | ||
|
|
6f43b5e343 | ||
|
|
fc195c5379 | ||
|
|
e9574e3317 | ||
|
|
2ba48aa313 | ||
|
|
fbae9b0fc3 | ||
|
|
029ff24479 | ||
|
|
0b13c02899 | ||
|
|
4ddc5e0151 | ||
|
|
918435ac7c | ||
|
|
2d6e6a69e5 | ||
|
|
19ec6a37b2 | ||
|
|
397c4ec5f1 | ||
|
|
6e49cc860c | ||
|
|
a48787f39e | ||
|
|
c466da1fe0 | ||
|
|
781673bb47 | ||
|
|
cf61c8f96d | ||
|
|
9baa07dacb | ||
|
|
ab03650906 | ||
|
|
338b110969 | ||
|
|
362eb42f23 |
@@ -0,0 +1,32 @@
|
|||||||
|
# Authentik is deployed from its official Helm chart, while this repository's
|
||||||
|
# wrapper chart also owns its PostgreSQL cluster, backups, and persistent data.
|
||||||
|
# The database is created first with Authentik disabled so the existing Docker
|
||||||
|
# database can be restored before any new server or worker touches it.
|
||||||
|
#
|
||||||
|
# Deliberately NO resources-finalizer.argocd.argoproj.io here. This Application
|
||||||
|
# owns identity data, and deleting its Git entry must not cascade into deleting
|
||||||
|
# PostgreSQL or Authentik's uploaded files.
|
||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: authentik
|
||||||
|
namespace: argocd
|
||||||
|
spec:
|
||||||
|
project: default
|
||||||
|
|
||||||
|
source:
|
||||||
|
repoURL: https://tea.ahmza.com/ahmza.com/k8s-starter-pack.git
|
||||||
|
targetRevision: main
|
||||||
|
path: apps/authentik
|
||||||
|
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: authentik
|
||||||
|
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
- ServerSideApply=true
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
# The upstream Authentik chart is initially disabled. This wrapper first
|
||||||
|
# creates PostgreSQL, backup configuration, and persistent file storage so the
|
||||||
|
# existing installation can be restored before Authentik starts.
|
||||||
|
apiVersion: v2
|
||||||
|
name: authentik-app
|
||||||
|
description: Deploys Authentik with CloudNativePG and off-cluster backups
|
||||||
|
version: 0.1.0
|
||||||
|
type: application
|
||||||
|
|
||||||
|
dependencies:
|
||||||
|
- name: authentik
|
||||||
|
# Pin each release explicitly: Authentik database migrations require
|
||||||
|
# sequential, verified upgrades through every release train.
|
||||||
|
version: 2026.8.5
|
||||||
|
repository: https://charts.goauthentik.io
|
||||||
|
condition: authentikDeployment.enabled
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# Authentik keeps uploaded icons and branding under /data. The PostgreSQL dump
|
||||||
|
# does not include these files, so this separate Longhorn volume is restored
|
||||||
|
# from the source VM's data/ directory before Authentik is enabled.
|
||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: authentik-data
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
annotations:
|
||||||
|
# Uploaded files are identity-service state. Never let Argo CD prune the
|
||||||
|
# volume automatically because a template was renamed or removed.
|
||||||
|
argocd.argoproj.io/sync-options: Prune=false
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 5Gi
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
# Backups live outside the cluster so a Longhorn or cluster-wide failure does
|
||||||
|
# not remove both PostgreSQL and its recovery data. Credentials are produced by
|
||||||
|
# the encrypted SopsSecret in this chart.
|
||||||
|
apiVersion: barmancloud.cnpg.io/v1
|
||||||
|
kind: ObjectStore
|
||||||
|
metadata:
|
||||||
|
name: authentik-backups
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
spec:
|
||||||
|
retentionPolicy: 30d
|
||||||
|
configuration:
|
||||||
|
destinationPath: s3://ahmza-talos-cnpg-backups/authentik/
|
||||||
|
endpointURL: https://s3.eu-central-003.backblazeb2.com
|
||||||
|
s3Credentials:
|
||||||
|
accessKeyId:
|
||||||
|
name: backblaze-b2-credentials
|
||||||
|
key: ACCESS_KEY_ID
|
||||||
|
secretAccessKey:
|
||||||
|
name: backblaze-b2-credentials
|
||||||
|
key: ACCESS_SECRET_KEY
|
||||||
|
region:
|
||||||
|
name: backblaze-b2-credentials
|
||||||
|
key: AWS_REGION
|
||||||
|
wal:
|
||||||
|
compression: gzip
|
||||||
|
# Require Backblaze's S3-compatible SSE-B2 encryption rather than
|
||||||
|
# relying only on the bucket's default encryption policy.
|
||||||
|
encryption: AES256
|
||||||
|
maxParallel: 2
|
||||||
|
data:
|
||||||
|
compression: gzip
|
||||||
|
encryption: AES256
|
||||||
|
jobs: 2
|
||||||
|
# Backblaze implements the S3 API but does not require every optional AWS
|
||||||
|
# checksum behavior. These settings avoid incompatible optional checksums.
|
||||||
|
instanceSidecarConfiguration:
|
||||||
|
env:
|
||||||
|
- name: AWS_REQUEST_CHECKSUM_CALCULATION
|
||||||
|
value: when_required
|
||||||
|
- name: AWS_RESPONSE_CHECKSUM_VALIDATION
|
||||||
|
value: when_required
|
||||||
|
---
|
||||||
|
# One PostgreSQL instance is enough initially: Longhorn replicates its volume
|
||||||
|
# across workers and can reattach it after a node failure. A second database
|
||||||
|
# instance can be added later if shorter failover time justifies another full
|
||||||
|
# copy of the data and WAL.
|
||||||
|
apiVersion: postgresql.cnpg.io/v1
|
||||||
|
kind: Cluster
|
||||||
|
metadata:
|
||||||
|
name: authentik-postgres
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
annotations:
|
||||||
|
# Argo CD may update this database but must never delete it automatically
|
||||||
|
# merely because a manifest or parent Application was removed from Git.
|
||||||
|
argocd.argoproj.io/sync-options: Prune=false
|
||||||
|
spec:
|
||||||
|
instances: 1
|
||||||
|
imageName: >-
|
||||||
|
ghcr.io/cloudnative-pg/postgresql:16.13-202603020816-standard-trixie
|
||||||
|
|
||||||
|
bootstrap:
|
||||||
|
initdb:
|
||||||
|
database: authentik
|
||||||
|
owner: authentik
|
||||||
|
|
||||||
|
storage:
|
||||||
|
# The default StorageClass is Longhorn. Omitting storageClass here keeps the
|
||||||
|
# database on that established replicated storage path.
|
||||||
|
size: 10Gi
|
||||||
|
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 250m
|
||||||
|
memory: 512Mi
|
||||||
|
limits:
|
||||||
|
cpu: "2"
|
||||||
|
memory: 2Gi
|
||||||
|
|
||||||
|
plugins:
|
||||||
|
- name: barman-cloud.cloudnative-pg.io
|
||||||
|
# CloudNativePG defaults this to true. Keeping it explicit prevents Argo
|
||||||
|
# CD from reporting harmless drift between Git and the live resource.
|
||||||
|
enabled: true
|
||||||
|
isWALArchiver: true
|
||||||
|
parameters:
|
||||||
|
barmanObjectName: authentik-backups
|
||||||
|
---
|
||||||
|
# CloudNativePG cron expressions have six fields; the leading zero is seconds.
|
||||||
|
# WAL is archived continuously, while this creates a full base backup nightly.
|
||||||
|
apiVersion: postgresql.cnpg.io/v1
|
||||||
|
kind: ScheduledBackup
|
||||||
|
metadata:
|
||||||
|
name: authentik-postgres-daily
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
spec:
|
||||||
|
schedule: "0 0 2 * * *"
|
||||||
|
immediate: false
|
||||||
|
backupOwnerReference: self
|
||||||
|
cluster:
|
||||||
|
name: authentik-postgres
|
||||||
|
method: plugin
|
||||||
|
pluginConfiguration:
|
||||||
|
name: barman-cloud.cloudnative-pg.io
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
apiVersion: isindir.github.com/v1alpha3
|
||||||
|
kind: SopsSecret
|
||||||
|
metadata:
|
||||||
|
name: authentik-secrets
|
||||||
|
namespace: authentik
|
||||||
|
spec:
|
||||||
|
secretTemplates:
|
||||||
|
- name: authentik-secrets
|
||||||
|
data:
|
||||||
|
AUTHENTIK_SECRET_KEY: ENC[AES256_GCM,data:xwd512Zty1VmOcc79UK2MxgLG5PaSApHhhwZRkqNz2w6HbLMSx+QvbODTfIZ0pq+HfQHxQMTY5FeX7t6TKR9toI5tG6B5202Bf85U9Lph4ssVfGC7fU/2WBsdELmtJIxxPjrzpcoQBfybOaR,iv:/J5e8Ej1KmuiEaOm8lZkikx7eStmScUA6lc0civVpdY=,tag:+gxczl/b3K4KnF8LcSkHKQ==,type:str]
|
||||||
|
- name: backblaze-b2-credentials
|
||||||
|
data:
|
||||||
|
ACCESS_KEY_ID: ENC[AES256_GCM,data:4FjHGgdeDwbA22ekQr1jv2qDn+5xxEMqgB1wWanL8nXvt8EV,iv:csE6cZ0ifFFC0bq12eMGBwSuchH0u1lqbXflywoR9FY=,tag:xMhjAvxicV1nUpfBfJAKBw==,type:str]
|
||||||
|
ACCESS_SECRET_KEY: ENC[AES256_GCM,data:XWHpbgZWbfl3REQDraRMUemcRvoACdaE2hjgkcYFgpZGkSZQ3jO7/fg4tDo=,iv:bGvTZy9N/ooxykqki0WkaUMI5qORbceSjprLnUu2k1A=,tag:67LlMIj+wvhj++Li/WtEAw==,type:str]
|
||||||
|
AWS_REGION: ENC[AES256_GCM,data:TL4IGaKv2/LD1/PTL1JY0l/J+N8=,iv:JZtM2V0nwimMJaR5o7qK9Rx1FC6jTuFbknU/2qBrwYs=,tag:tUgyYeAYjEGxTAlnky679w==,type:str]
|
||||||
|
sops:
|
||||||
|
age:
|
||||||
|
- enc: |
|
||||||
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB4WDgwRkExNHhXa05hSkcy
|
||||||
|
ZVVUam44a0pVR2hTZk5oOTdWdzkvSGlWODJVCnp6REpkUWVBV2g0MXNVKzdCVG1t
|
||||||
|
aE9YQ25icitBWGJqQ3NtUjd1cCtRUk0KLS0tIHNPeFVkeFVGUlYxT3Nhd2UrVnl2
|
||||||
|
NlhTZFV1YVRSM2JJYk1WRnRiUFppMXMKtqNp3OzKTeBKWXos0+wUmn6YGEDXubtc
|
||||||
|
UPX7lOkLI6qaKg8+3HZV3x9yKgtaT32WF9faMBQhvxFMrhRR3UTTlQ==
|
||||||
|
-----END AGE ENCRYPTED FILE-----
|
||||||
|
recipient: age1udejf5qa66rd6yvj5r8dz0fjnqfh0quf4t339c3cpqr26mkx2ydq3zel07
|
||||||
|
encrypted_regex: ^(data|stringData)$
|
||||||
|
lastmodified: "2026-10-16T15:59:11Z"
|
||||||
|
mac: ENC[AES256_GCM,data:bqT+3/x/1DAgRRxjIXlxwNLiXT2f0rD7WxUk6RGBikOD0sZKBvCZVh4qTEVUIf2U6siZBgue39Gqa5eBlCCzx+rq/JxbKdsNd5klythOzmuaKSlOaIimSZLR9Ye1KJMGPkZI4G7eE5CAM17WJ5MMZDkhP9CtscRPEQ/AgHbVUSg=,iv:JqtI7n6uMkQ9lKr4oGGEA6czFtvoDrG510aLmltCdmI=,tag:1LU4a4Mlrxh8btQw4MY0eQ==,type:str]
|
||||||
|
version: 3.13.3
|
||||||
@@ -0,0 +1,135 @@
|
|||||||
|
# The trial server is enabled only after the source database and files have
|
||||||
|
# been restored. Its worker and Ingress remain disabled until cutover, which
|
||||||
|
# prevents background jobs and production traffic reaching this clone.
|
||||||
|
authentikDeployment:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
authentik:
|
||||||
|
global:
|
||||||
|
# Server and worker share one ReadWriteOnce Longhorn volume. Recreate stops
|
||||||
|
# the old Pods before replacements start, allowing the volume to move nodes
|
||||||
|
# instead of leaving a rolling update blocked by a multi-attach error.
|
||||||
|
deploymentStrategy:
|
||||||
|
type: Recreate
|
||||||
|
|
||||||
|
# CloudNativePG generates this connection Secret. Referencing individual
|
||||||
|
# keys avoids duplicating its generated database password in Git or SOPS.
|
||||||
|
env:
|
||||||
|
- name: AUTHENTIK_POSTGRESQL__HOST
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: authentik-postgres-app
|
||||||
|
key: host
|
||||||
|
- name: AUTHENTIK_POSTGRESQL__PORT
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: authentik-postgres-app
|
||||||
|
key: port
|
||||||
|
- name: AUTHENTIK_POSTGRESQL__NAME
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: authentik-postgres-app
|
||||||
|
key: dbname
|
||||||
|
- name: AUTHENTIK_POSTGRESQL__USER
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: authentik-postgres-app
|
||||||
|
key: username
|
||||||
|
- name: AUTHENTIK_POSTGRESQL__PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: authentik-postgres-app
|
||||||
|
key: password
|
||||||
|
# `require` encrypts traffic to PostgreSQL without depending on a public
|
||||||
|
# CA; CloudNativePG rotates its private in-cluster certificates itself.
|
||||||
|
- name: AUTHENTIK_POSTGRESQL__SSLMODE
|
||||||
|
value: require
|
||||||
|
# Authentik 2026.8 only honors forwarded HTTPS and client-address headers
|
||||||
|
# from explicit trusted proxies. This is the smallest aggregate covering
|
||||||
|
# all current node Pod subnets, so ingress-nginx stays trusted if moved.
|
||||||
|
- name: AUTHENTIK_LISTEN__TRUSTED_PROXY_CIDRS
|
||||||
|
value: 10.244.0.0/21
|
||||||
|
|
||||||
|
# The same Longhorn claim carries three restored source directories. Each
|
||||||
|
# subPath is mounted where the upstream container expects it.
|
||||||
|
volumes:
|
||||||
|
- name: authentik-data
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: authentik-data
|
||||||
|
volumeMounts:
|
||||||
|
- name: authentik-data
|
||||||
|
mountPath: /data
|
||||||
|
subPath: data
|
||||||
|
- name: authentik-data
|
||||||
|
mountPath: /templates
|
||||||
|
subPath: custom-templates
|
||||||
|
- name: authentik-data
|
||||||
|
mountPath: /certs
|
||||||
|
subPath: certs
|
||||||
|
|
||||||
|
authentik:
|
||||||
|
# This SOPS-managed Secret contains the source installation's exact secret
|
||||||
|
# key, preserving encrypted configuration and existing identity semantics.
|
||||||
|
existingSecret:
|
||||||
|
secretName: authentik-secrets
|
||||||
|
|
||||||
|
# CloudNativePG supplies PostgreSQL; do not deploy the bundled database.
|
||||||
|
postgresql:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
server:
|
||||||
|
# One server is sufficient for this homelab; Kubernetes recreates it if the
|
||||||
|
# Pod fails, while PostgreSQL and uploaded files live on persistent storage.
|
||||||
|
replicas: 1
|
||||||
|
# UID/GID 1000 matches the restored Docker files and satisfies this
|
||||||
|
# namespace's restricted Pod Security policy without running as root.
|
||||||
|
securityContext:
|
||||||
|
runAsNonRoot: true
|
||||||
|
runAsUser: 1000
|
||||||
|
runAsGroup: 1000
|
||||||
|
fsGroup: 1000
|
||||||
|
containerSecurityContext:
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
capabilities:
|
||||||
|
drop:
|
||||||
|
- ALL
|
||||||
|
seccompProfile:
|
||||||
|
type: RuntimeDefault
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 250m
|
||||||
|
memory: 512Mi
|
||||||
|
limits:
|
||||||
|
cpu: "2"
|
||||||
|
memory: 2Gi
|
||||||
|
# Route the LAN hostname through the cluster's shared ingress-nginx IP.
|
||||||
|
# DNS-01 issuance and HTTPS routing were proven against Let's Encrypt's
|
||||||
|
# staging service before switching to this browser-trusted issuer.
|
||||||
|
ingress:
|
||||||
|
enabled: true
|
||||||
|
ingressClassName: nginx
|
||||||
|
annotations:
|
||||||
|
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||||
|
hosts:
|
||||||
|
- auth.ahmza.com
|
||||||
|
tls:
|
||||||
|
- secretName: authentik-tls
|
||||||
|
hosts:
|
||||||
|
- auth.ahmza.com
|
||||||
|
|
||||||
|
worker:
|
||||||
|
# One worker handles scheduled jobs, source synchronization, email, and
|
||||||
|
# management of Kubernetes-native outposts.
|
||||||
|
replicas: 1
|
||||||
|
securityContext:
|
||||||
|
runAsNonRoot: true
|
||||||
|
runAsUser: 1000
|
||||||
|
runAsGroup: 1000
|
||||||
|
fsGroup: 1000
|
||||||
|
containerSecurityContext:
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
capabilities:
|
||||||
|
drop:
|
||||||
|
- ALL
|
||||||
|
seccompProfile:
|
||||||
|
type: RuntimeDefault
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
# This ArgoCD application deploys bazarr to manage subtitles for the media library
|
||||||
|
# This application pulls its image from hotio as they're generally light weight.
|
||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: bazarr
|
||||||
|
namespace: argocd
|
||||||
|
# skipping resources-finalizer.argocd.argoproj.io as it as bazaarr will create its configs
|
||||||
|
spec:
|
||||||
|
project: default
|
||||||
|
|
||||||
|
source:
|
||||||
|
repoURL: https://tea.ahmza.com/ahmza.com/k8s-starter-pack.git
|
||||||
|
targetRevision: main
|
||||||
|
path: apps/bazarr
|
||||||
|
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: bazarr
|
||||||
|
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
# bazarr image from hotio ghcr.io/hotio/bazarr
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: bazarr
|
||||||
|
namespace: bazarr
|
||||||
|
spec:
|
||||||
|
# not critical infrastructure a single pod should be sufficient
|
||||||
|
replicas: 1
|
||||||
|
strategy:
|
||||||
|
type: Recreate
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: bazarr
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: bazarr
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: bazarr
|
||||||
|
image: ghcr.io/hotio/bazarr:release
|
||||||
|
imagePullPolicy: Always
|
||||||
|
env:
|
||||||
|
- name: PUID
|
||||||
|
value: "1000"
|
||||||
|
- name: PGID
|
||||||
|
value: "1000"
|
||||||
|
- name: UMASK
|
||||||
|
value: "002"
|
||||||
|
- name: TZ
|
||||||
|
value: "Europe/London"
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
containerPort: 6767
|
||||||
|
protocol: TCP
|
||||||
|
volumeMounts:
|
||||||
|
- name: bazarr-config
|
||||||
|
mountPath: /config
|
||||||
|
# Mount each media directory directly instead of using subPath.
|
||||||
|
# The NFS export root is not listable by root-squashed clients, so
|
||||||
|
# kubelet cannot safely prepare subPath mounts from that root.
|
||||||
|
- name: movies
|
||||||
|
mountPath: /movies
|
||||||
|
- name: tv
|
||||||
|
mountPath: /tv
|
||||||
|
- name: anime
|
||||||
|
mountPath: /anime
|
||||||
|
volumes:
|
||||||
|
- name: bazarr-config
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: bazarr-data
|
||||||
|
- name: movies
|
||||||
|
nfs:
|
||||||
|
server: nas.ahmza.com
|
||||||
|
path: /srv/media/Movies
|
||||||
|
- name: tv
|
||||||
|
nfs:
|
||||||
|
server: nas.ahmza.com
|
||||||
|
path: /srv/media/TVShows
|
||||||
|
- name: anime
|
||||||
|
nfs:
|
||||||
|
server: nas.ahmza.com
|
||||||
|
path: /srv/media/Anime
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
# routes for bazarr.ahmza.com through ingress-nginx (docs/11-ingress.md)
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: bazarr
|
||||||
|
namespace: bazarr
|
||||||
|
annotations:
|
||||||
|
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||||
|
spec:
|
||||||
|
tls:
|
||||||
|
- hosts:
|
||||||
|
- bazarr.ahmza.com
|
||||||
|
# cert-manager keeps this up to date. nothing to do by hand
|
||||||
|
secretName: bazarr-tls
|
||||||
|
rules:
|
||||||
|
- host: bazarr.ahmza.com
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: bazarr
|
||||||
|
port:
|
||||||
|
number: 6767
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: bazarr
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# create a longhorn pvc for bazarr's config (see docs/06-longhorn.md)
|
||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: bazarr-data
|
||||||
|
namespace: bazarr
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 2Gi
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: bazarr
|
||||||
|
namespace: bazarr
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: bazarr
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
port: 6767
|
||||||
|
targetPort: http
|
||||||
@@ -7,3 +7,11 @@ cert-manager:
|
|||||||
# separate manual step. `installCRDs` is the older, deprecated name for
|
# separate manual step. `installCRDs` is the older, deprecated name for
|
||||||
# this same setting.
|
# this same setting.
|
||||||
enabled: true
|
enabled: true
|
||||||
|
|
||||||
|
# Technitium serves a private, split-horizon ahmza.com zone, while DNS-01
|
||||||
|
# challenge TXT records are created in the public Cloudflare zone. Use
|
||||||
|
# public resolvers for ACME self-checks so cert-manager sees the same TXT
|
||||||
|
# record Let's Encrypt sees; ordinary Pods still use normal cluster DNS.
|
||||||
|
extraArgs:
|
||||||
|
- --dns01-recursive-nameservers-only
|
||||||
|
- --dns01-recursive-nameservers=1.1.1.1:53,8.8.8.8:53
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
# CloudNativePG manages PostgreSQL databases as Kubernetes resources. The
|
||||||
|
# companion Barman Cloud plugin sends database backups and transaction logs to
|
||||||
|
# object storage; installing both here gives future apps one shared database
|
||||||
|
# operator without forcing them to share one PostgreSQL server.
|
||||||
|
#
|
||||||
|
# Deliberately NO resources-finalizer.argocd.argoproj.io here. PostgreSQL
|
||||||
|
# clusters managed by this operator hold application data, so removing this
|
||||||
|
# Application must not cascade into a surprise deletion of database machinery.
|
||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: cloudnative-pg
|
||||||
|
namespace: argocd
|
||||||
|
spec:
|
||||||
|
project: default
|
||||||
|
|
||||||
|
source:
|
||||||
|
repoURL: https://tea.ahmza.com/ahmza.com/k8s-starter-pack.git
|
||||||
|
targetRevision: main
|
||||||
|
path: apps/cloudnative-pg
|
||||||
|
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: cnpg-system
|
||||||
|
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
# Both dependencies install cluster-wide CRDs. Server-side apply avoids
|
||||||
|
# annotation-size limits and lets Kubernetes handle CRD fields safely.
|
||||||
|
- ServerSideApply=true
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# One umbrella chart installs the PostgreSQL operator and its current backup
|
||||||
|
# plugin together. Applications create their own independent PostgreSQL
|
||||||
|
# Cluster resources; these shared controllers hold no application data.
|
||||||
|
apiVersion: v2
|
||||||
|
name: cloudnative-pg-app
|
||||||
|
description: >-
|
||||||
|
Installs CloudNativePG and the Barman Cloud object-storage backup plugin
|
||||||
|
version: 0.1.0
|
||||||
|
type: application
|
||||||
|
|
||||||
|
dependencies:
|
||||||
|
- name: cloudnative-pg
|
||||||
|
# Pin versions so an unrelated Git sync cannot silently upgrade the
|
||||||
|
# controller responsible for every PostgreSQL database in the cluster.
|
||||||
|
version: 0.29.1
|
||||||
|
repository: https://cloudnative-pg.github.io/charts
|
||||||
|
- name: plugin-barman-cloud
|
||||||
|
version: 0.8.1
|
||||||
|
repository: https://cloudnative-pg.github.io/charts
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
# This Argo CD Application deploys Lidarr to manage the music library.
|
||||||
|
# It uses Hotio's lightweight Lidarr container image.
|
||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: lidarr
|
||||||
|
namespace: argocd
|
||||||
|
# Omit the cascading finalizer so deleting this Application does not
|
||||||
|
# automatically delete Lidarr's config-bearing PersistentVolumeClaim.
|
||||||
|
spec:
|
||||||
|
project: default
|
||||||
|
|
||||||
|
source:
|
||||||
|
repoURL: https://tea.ahmza.com/ahmza.com/k8s-starter-pack.git
|
||||||
|
targetRevision: main
|
||||||
|
path: apps/lidarr
|
||||||
|
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: lidarr
|
||||||
|
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
# Lidarr image maintained by Hotio: ghcr.io/hotio/lidarr.
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: lidarr
|
||||||
|
namespace: lidarr
|
||||||
|
spec:
|
||||||
|
# not critical infrastructure a single pod should be sufficient
|
||||||
|
replicas: 1
|
||||||
|
strategy:
|
||||||
|
type: Recreate
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: lidarr
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: lidarr
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: lidarr
|
||||||
|
image: ghcr.io/hotio/lidarr:release
|
||||||
|
imagePullPolicy: Always
|
||||||
|
env:
|
||||||
|
- name: PUID
|
||||||
|
value: "1000"
|
||||||
|
- name: PGID
|
||||||
|
value: "1000"
|
||||||
|
- name: UMASK
|
||||||
|
value: "002"
|
||||||
|
- name: TZ
|
||||||
|
value: "Europe/London"
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
containerPort: 8686
|
||||||
|
protocol: TCP
|
||||||
|
volumeMounts:
|
||||||
|
- name: lidarr-config
|
||||||
|
mountPath: /config
|
||||||
|
# Mount each media directory directly instead of using subPath.
|
||||||
|
# The NFS export root is not listable by root-squashed clients, so
|
||||||
|
# kubelet cannot safely prepare subPath mounts from that root.
|
||||||
|
- name: music
|
||||||
|
mountPath: /music
|
||||||
|
- name: torrents
|
||||||
|
mountPath: /data/torrents
|
||||||
|
- name: usenet
|
||||||
|
mountPath: /data/usenet
|
||||||
|
- name: import
|
||||||
|
mountPath: /data/import
|
||||||
|
volumes:
|
||||||
|
- name: lidarr-config
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: lidarr-data
|
||||||
|
- name: music
|
||||||
|
nfs:
|
||||||
|
server: nas.ahmza.com
|
||||||
|
path: /srv/media/Music
|
||||||
|
- name: torrents
|
||||||
|
nfs:
|
||||||
|
server: nas.ahmza.com
|
||||||
|
path: /srv/media/torrents
|
||||||
|
- name: usenet
|
||||||
|
nfs:
|
||||||
|
server: nas.ahmza.com
|
||||||
|
path: /srv/media/usenet
|
||||||
|
- name: import
|
||||||
|
nfs:
|
||||||
|
server: nas.ahmza.com
|
||||||
|
path: /srv/media/import
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
# Route lidarr.ahmza.com through ingress-nginx (docs/11-ingress.md).
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: lidarr
|
||||||
|
namespace: lidarr
|
||||||
|
annotations:
|
||||||
|
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||||
|
spec:
|
||||||
|
tls:
|
||||||
|
- hosts:
|
||||||
|
- lidarr.ahmza.com
|
||||||
|
# cert-manager keeps this up to date. nothing to do by hand
|
||||||
|
secretName: lidarr-tls
|
||||||
|
rules:
|
||||||
|
- host: lidarr.ahmza.com
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: lidarr
|
||||||
|
port:
|
||||||
|
number: 8686
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: lidarr
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
# Store Lidarr's config on a Longhorn volume (see docs/06-longhorn.md).
|
||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: lidarr-data
|
||||||
|
namespace: lidarr
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
# Album artwork and the music database outgrew the original 2Gi volume.
|
||||||
|
storage: 10Gi
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: lidarr
|
||||||
|
namespace: lidarr
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: lidarr
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
port: 8686
|
||||||
|
targetPort: http
|
||||||
@@ -47,7 +47,7 @@ spec:
|
|||||||
# The publishing workflow replaces this bootstrap tag with an
|
# The publishing workflow replaces this bootstrap tag with an
|
||||||
# immutable OCI digest. Never deploy the mutable latest tag after
|
# immutable OCI digest. Never deploy the mutable latest tag after
|
||||||
# bootstrap: recording the digest makes rollbacks and audits reliable.
|
# bootstrap: recording the digest makes rollbacks and audits reliable.
|
||||||
image: tea.ahmza.com/ahmza.com/mcpacks-site@sha256:276316400b26a5d50a9938694edf99bb6ea9d5cd6e0bc5b8f6ea581b0db0d5f2
|
image: tea.ahmza.com/ahmza.com/mcpacks-site@sha256:c9983dd9c31562f6518388f4d66f308e00cc229264b248536db8b4be7e7845db
|
||||||
imagePullPolicy: Always
|
imagePullPolicy: Always
|
||||||
ports:
|
ports:
|
||||||
- name: http
|
- name: http
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
apiVersion: v2
|
||||||
|
name: seerr-app
|
||||||
|
description: Deploys Seerr using its official upstream helm chart
|
||||||
|
type: application
|
||||||
|
version: 0.1.0
|
||||||
|
|
||||||
|
dependencies:
|
||||||
|
- name: seerr-chart
|
||||||
|
alias: seerr
|
||||||
|
version: "3.9.0"
|
||||||
|
repository: oci://ghcr.io/seerr-team/seerr
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
# This ArgoCD application deploys soulsync to manage media discovery.
|
||||||
|
# The Deployment pins a reviewed SoulSync release for repeatable GitOps syncs.
|
||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: soulsync
|
||||||
|
namespace: argocd
|
||||||
|
# skipping resources-finalizer.argocd.argoproj.io as soulsync will create configs
|
||||||
|
spec:
|
||||||
|
project: default
|
||||||
|
|
||||||
|
source:
|
||||||
|
repoURL: https://tea.ahmza.com/ahmza.com/k8s-starter-pack.git
|
||||||
|
targetRevision: main
|
||||||
|
path: apps/soulsync
|
||||||
|
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: soulsync
|
||||||
|
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
# Pin SoulSync so an upstream `latest` update cannot change the running app
|
||||||
|
# without a reviewed Git commit.
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: soulsync
|
||||||
|
namespace: soulsync
|
||||||
|
spec:
|
||||||
|
# not critical infra, a single pod should suffice
|
||||||
|
replicas: 1
|
||||||
|
strategy:
|
||||||
|
type: Recreate
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: soulsync
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: soulsync
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: soulsync
|
||||||
|
image: boulderbadgedad/soulsync:3.5.9
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
env:
|
||||||
|
- name: PUID
|
||||||
|
value: "1000"
|
||||||
|
- name: PGID
|
||||||
|
value: "1000"
|
||||||
|
- name: UMASK
|
||||||
|
value: "022"
|
||||||
|
- name: PYTHONPATH
|
||||||
|
value: "/app"
|
||||||
|
- name: SOULSYNC_CONFIG_PATH
|
||||||
|
value: "/app/config/config.json"
|
||||||
|
- name: TZ
|
||||||
|
value: "Europe/London"
|
||||||
|
ports:
|
||||||
|
# HTTPS terminates at ingress-nginx, which forwards the UI and both
|
||||||
|
# OAuth callback paths to SoulSync's main web server on this port.
|
||||||
|
- name: http
|
||||||
|
containerPort: 8008
|
||||||
|
protocol: TCP
|
||||||
|
# Kubernetes ignores the Docker image's HEALTHCHECK, so define probes
|
||||||
|
# here to keep traffic away until SoulSync has actually started and to
|
||||||
|
# restart it if its web server later stops responding.
|
||||||
|
startupProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: http
|
||||||
|
periodSeconds: 5
|
||||||
|
timeoutSeconds: 3
|
||||||
|
failureThreshold: 24
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: http
|
||||||
|
periodSeconds: 10
|
||||||
|
timeoutSeconds: 5
|
||||||
|
failureThreshold: 3
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: http
|
||||||
|
periodSeconds: 30
|
||||||
|
timeoutSeconds: 10
|
||||||
|
failureThreshold: 3
|
||||||
|
# Match the upstream Compose defaults: scheduling reserves enough for
|
||||||
|
# normal operation while limits protect the rest of the cluster.
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 500m
|
||||||
|
memory: 512Mi
|
||||||
|
limits:
|
||||||
|
cpu: "2"
|
||||||
|
memory: 2Gi
|
||||||
|
volumeMounts:
|
||||||
|
- name: soulsync-db
|
||||||
|
mountPath: /app/data
|
||||||
|
- name: soulsync-config
|
||||||
|
mountPath: /app/config
|
||||||
|
- name: soulsync-logs
|
||||||
|
mountPath: /app/logs
|
||||||
|
- name: usenet-downloads
|
||||||
|
mountPath: /data/usenet
|
||||||
|
- name: torrent-downloads
|
||||||
|
mountPath: /data/torrents
|
||||||
|
- name: downloads
|
||||||
|
mountPath: /app/downloads
|
||||||
|
- name: music
|
||||||
|
mountPath: /app/Transfer
|
||||||
|
volumes:
|
||||||
|
- name: soulsync-db
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: soulsync-db
|
||||||
|
- name: soulsync-config
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: soulsync-config
|
||||||
|
- name: soulsync-logs
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: soulsync-logs
|
||||||
|
- name: usenet-downloads
|
||||||
|
nfs:
|
||||||
|
server: nas.ahmza.com
|
||||||
|
path: /srv/media/usenet
|
||||||
|
- name: torrent-downloads
|
||||||
|
nfs:
|
||||||
|
server: nas.ahmza.com
|
||||||
|
path: /srv/media/torrents
|
||||||
|
- name: downloads
|
||||||
|
nfs:
|
||||||
|
server: nas.ahmza.com
|
||||||
|
path: /srv/media/torrents
|
||||||
|
- name: music
|
||||||
|
nfs:
|
||||||
|
server: nas.ahmza.com
|
||||||
|
path: /srv/media/Music
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
# routes for soulsync.ahmza.com through ingress-nginx (docs/11-ingress.md)
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: soulsync
|
||||||
|
namespace: soulsync
|
||||||
|
annotations:
|
||||||
|
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||||
|
spec:
|
||||||
|
# Select ingress-nginx explicitly rather than relying on whichever ingress
|
||||||
|
# controller happens to be configured as the cluster-wide default.
|
||||||
|
ingressClassName: nginx
|
||||||
|
tls:
|
||||||
|
- hosts:
|
||||||
|
- soulsync.ahmza.com
|
||||||
|
# cert-manager keeps this up to date. nothing to do by hand
|
||||||
|
secretName: soulsync-tls
|
||||||
|
rules:
|
||||||
|
- host: soulsync.ahmza.com
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: soulsync
|
||||||
|
port:
|
||||||
|
number: 8008
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: soulsync
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
# Keep SoulSync's databases and downloaded artwork on Longhorn so they survive
|
||||||
|
# Pod replacement (see docs/06-longhorn.md).
|
||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: soulsync-db
|
||||||
|
namespace: soulsync
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 10Gi
|
||||||
|
---
|
||||||
|
# Configuration can contain connection settings and OAuth tokens, so persist it
|
||||||
|
# without putting those credentials in this public Git repository.
|
||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: soulsync-config
|
||||||
|
namespace: soulsync
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 1Gi
|
||||||
|
---
|
||||||
|
# Persistent logs remain available when the container is recreated and make
|
||||||
|
# failures that happened before a restart easier to diagnose.
|
||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: soulsync-logs
|
||||||
|
namespace: soulsync
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 2Gi
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: soulsync
|
||||||
|
namespace: soulsync
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: soulsync
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
port: 8008
|
||||||
|
targetPort: http
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
# Cluster metrics collection for the external VictoriaMetrics and Grafana host.
|
||||||
|
# This Application installs only collectors and Kubernetes exporters: metrics
|
||||||
|
# are sent over NetBird to prd-vps-hel-01 and are not stored in this cluster.
|
||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: victoria-metrics
|
||||||
|
namespace: argocd
|
||||||
|
# The in-cluster pieces are stateless. Cascading deletion is safe because the
|
||||||
|
# durable metrics database lives on the external VPS, not in this namespace.
|
||||||
|
finalizers:
|
||||||
|
- resources-finalizer.argocd.argoproj.io
|
||||||
|
spec:
|
||||||
|
project: default
|
||||||
|
|
||||||
|
source:
|
||||||
|
repoURL: https://tea.ahmza.com/ahmza.com/k8s-starter-pack.git
|
||||||
|
targetRevision: main
|
||||||
|
path: apps/victoria-metrics
|
||||||
|
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: monitoring
|
||||||
|
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
# node-exporter reads host kernel and filesystem metrics through hostPath,
|
||||||
|
# hostNetwork, and hostPID. Scope the required privileged Pod Security
|
||||||
|
# profile to this dedicated monitoring namespace.
|
||||||
|
managedNamespaceMetadata:
|
||||||
|
labels:
|
||||||
|
pod-security.kubernetes.io/enforce: privileged
|
||||||
|
pod-security.kubernetes.io/audit: privileged
|
||||||
|
pod-security.kubernetes.io/warn: privileged
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
# VictoriaMetrics Operator CRDs are large. Server-side apply avoids the
|
||||||
|
# client-side last-applied annotation size limit and handles CRDs first.
|
||||||
|
- ServerSideApply=true
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
# Umbrella chart for the official VictoriaMetrics Kubernetes monitoring stack.
|
||||||
|
# Argo CD renders this dependency from Git just like the existing Longhorn and
|
||||||
|
# MetalLB wrapper charts.
|
||||||
|
apiVersion: v2
|
||||||
|
name: victoria-metrics-app
|
||||||
|
description: Forwards Kubernetes and node metrics to external VictoriaMetrics
|
||||||
|
version: 0.1.0
|
||||||
|
dependencies:
|
||||||
|
- name: victoria-metrics-k8s-stack
|
||||||
|
# Pin the exact chart version so monitoring upgrades are explicit and
|
||||||
|
# reviewable rather than changing during an unrelated Argo CD sync.
|
||||||
|
version: 0.96.0
|
||||||
|
repository: oci://ghcr.io/victoriametrics/helm-charts
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
# Scrapes Longhorn's own metrics (volume robustness, node and disk capacity)
|
||||||
|
# so the external Grafana can alert when a volume becomes degraded or faulted.
|
||||||
|
#
|
||||||
|
# Every longhorn-manager Pod serves /metrics on its `manager` port (9500)
|
||||||
|
# behind the longhorn-backend Service. A VMServiceScrape scrapes each Pod
|
||||||
|
# behind that Service, so metrics from managers on both storage workers are
|
||||||
|
# collected, not just whichever one a load-balanced request would hit.
|
||||||
|
#
|
||||||
|
# This lives in the victoria-metrics wrapper chart rather than the Longhorn
|
||||||
|
# app because it is monitoring configuration, and it depends on the
|
||||||
|
# VMServiceScrape CRD installed by this chart's operator. Sync wave "1" makes
|
||||||
|
# Argo CD apply it only after that CRD exists on a fresh install.
|
||||||
|
apiVersion: operator.victoriametrics.com/v1beta1
|
||||||
|
kind: VMServiceScrape
|
||||||
|
metadata:
|
||||||
|
name: longhorn
|
||||||
|
namespace: monitoring
|
||||||
|
annotations:
|
||||||
|
argocd.argoproj.io/sync-wave: "1"
|
||||||
|
spec:
|
||||||
|
namespaceSelector:
|
||||||
|
matchNames:
|
||||||
|
- longhorn-system
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: longhorn-manager
|
||||||
|
endpoints:
|
||||||
|
- port: manager
|
||||||
|
path: /metrics
|
||||||
|
interval: 30s
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
# Values for the upstream victoria-metrics-k8s-stack dependency. This cluster
|
||||||
|
# collects metrics only; durable storage and visualization run on the NetBird-
|
||||||
|
# connected VPS prd-vps-hel-01.ahmza.com (NetBird address 100.71.24.9).
|
||||||
|
victoria-metrics-k8s-stack:
|
||||||
|
# Identify this source if more clusters write to the same database later.
|
||||||
|
vmagent:
|
||||||
|
enabled: true
|
||||||
|
spec:
|
||||||
|
scrapeInterval: 30s
|
||||||
|
externalLabels:
|
||||||
|
cluster: gitops-starter
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 128Mi
|
||||||
|
limits:
|
||||||
|
memory: 512Mi
|
||||||
|
|
||||||
|
external:
|
||||||
|
vm:
|
||||||
|
# Queries are served from the VictoriaMetrics base URL. Remote write uses
|
||||||
|
# its Prometheus-compatible ingestion endpoint. NetBird encrypts the path
|
||||||
|
# between the Talos nodes and VPS, so no public endpoint is involved.
|
||||||
|
#
|
||||||
|
# The name resolves only through internal Technitium DNS (10.10.10.10),
|
||||||
|
# where an authoritative zone maps it to the VPS's NetBird address. If
|
||||||
|
# that address changes, update Technitium rather than this file.
|
||||||
|
read:
|
||||||
|
url: http://prd-vps-hel-01.ahmza.com:8428
|
||||||
|
write:
|
||||||
|
url: http://prd-vps-hel-01.ahmza.com:8428/api/v1/write
|
||||||
|
|
||||||
|
# Storage and UI already live on prd-vps-hel-01; do not duplicate them here.
|
||||||
|
vmsingle:
|
||||||
|
enabled: false
|
||||||
|
vmcluster:
|
||||||
|
enabled: false
|
||||||
|
vmdistributed:
|
||||||
|
enabled: false
|
||||||
|
grafana:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# Alert delivery is a separate follow-up once notification destinations are
|
||||||
|
# chosen. Disabling it also avoids deploying rules with nowhere to notify.
|
||||||
|
vmalert:
|
||||||
|
enabled: false
|
||||||
|
alertmanager:
|
||||||
|
enabled: false
|
||||||
|
defaultRules:
|
||||||
|
enabled: false
|
||||||
|
defaultDashboards:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# One node-exporter Pod runs on every node, including tainted control planes.
|
||||||
|
# Talos exposes the host root filesystem read-only; mount propagation is not
|
||||||
|
# needed and can be rejected by immutable hosts, so keep it disabled.
|
||||||
|
prometheus-node-exporter:
|
||||||
|
enabled: true
|
||||||
|
hostRootFsMount:
|
||||||
|
enabled: true
|
||||||
|
mountPropagation: None
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 20m
|
||||||
|
memory: 32Mi
|
||||||
|
limits:
|
||||||
|
memory: 128Mi
|
||||||
|
|
||||||
|
# Talos binds the scheduler and controller-manager metrics endpoints to
|
||||||
|
# 127.0.0.1, and runs etcd as a host service rather than a Pod. Scraping them
|
||||||
|
# from vmagent would require exposing those control-plane ports on the LAN,
|
||||||
|
# so skip them; API server, kubelet, CoreDNS, and node metrics remain.
|
||||||
|
kubeScheduler:
|
||||||
|
enabled: false
|
||||||
|
kubeControllerManager:
|
||||||
|
enabled: false
|
||||||
|
kubeEtcd:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# kube-state-metrics reports desired/current Kubernetes object state (for
|
||||||
|
# example unavailable Deployment replicas), complementing host metrics.
|
||||||
|
kube-state-metrics:
|
||||||
|
enabled: true
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 20m
|
||||||
|
memory: 64Mi
|
||||||
|
limits:
|
||||||
|
memory: 256Mi
|
||||||
+25
-4
@@ -32,6 +32,22 @@ on every node.
|
|||||||
| `10.10.10.204` | `talos-vba-ood` — worker02 (Proxmox VM on Titus) | 50000 | `https://10.10.10.204:50000` |
|
| `10.10.10.204` | `talos-vba-ood` — worker02 (Proxmox VM on Titus) | 50000 | `https://10.10.10.204:50000` |
|
||||||
| `10.10.10.210` | Cluster VIP (use this one, not a node's own address) | 6443 | `https://10.10.10.210:6443` |
|
| `10.10.10.210` | Cluster VIP (use this one, not a node's own address) | 6443 | `https://10.10.10.210:6443` |
|
||||||
|
|
||||||
|
## NetBird overlay
|
||||||
|
|
||||||
|
These addresses exist only inside the private NetBird overlay and are subject
|
||||||
|
to NetBird access policies. All Talos nodes use the official
|
||||||
|
`siderolabs/netbird` system extension.
|
||||||
|
|
||||||
|
| Address | What | Port(s) | URL(s) |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `100.71.24.9` | `prd-vps-hel-01` — external Grafana and VictoriaMetrics host; internal name `prd-vps-hel-01.ahmza.com` (authoritative zone in Technitium) | 3000, 8428 | `http://prd-vps-hel-01.ahmza.com:3000`, `http://prd-vps-hel-01.ahmza.com:8428` |
|
||||||
|
| `100.71.236.121` | `ingress1` — Caddy HTTP origin gateway used by NetBird Reverse Proxy; the WireGuard overlay encrypts this leg | 80 | `http://100.71.236.121` |
|
||||||
|
| `100.71.121.67` | `talos-455-i3b` — control plane NetBird address | 50000 | `https://100.71.121.67:50000` |
|
||||||
|
| `100.71.157.217` | `talos-9xy-iuk` — control plane NetBird address | 50000 | `https://100.71.157.217:50000` |
|
||||||
|
| `100.71.242.40` | `talos-k1b-7j5` — control plane NetBird address | 50000 | `https://100.71.242.40:50000` |
|
||||||
|
| `100.71.3.210` | `talos-rss-v5l` — worker01 NetBird address | 50000 | `https://100.71.3.210:50000` |
|
||||||
|
| `100.71.29.51` | `talos-vba-ood` — worker02 NetBird address | 50000 | `https://100.71.29.51:50000` |
|
||||||
|
|
||||||
## MetalLB pool
|
## MetalLB pool
|
||||||
|
|
||||||
This dedicated service range is advertised to the MikroTik at
|
This dedicated service range is advertised to the MikroTik at
|
||||||
@@ -49,6 +65,7 @@ This dedicated service range is advertised to the MikroTik at
|
|||||||
| Address | What | Namespace | Port(s) | URL | Source |
|
| Address | What | Namespace | Port(s) | URL | Source |
|
||||||
|---|---|---|---|---|---|
|
|---|---|---|---|---|---|
|
||||||
| `10.10.60.10` | Argo CD UI/API (`argocd-server`) | `argocd` | 443 | `https://10.10.60.10` | Patched to `LoadBalancer` by hand — see [`docs/05-metallb.md`](05-metallb.md) |
|
| `10.10.60.10` | Argo CD UI/API (`argocd-server`) | `argocd` | 443 | `https://10.10.60.10` | Patched to `LoadBalancer` by hand — see [`docs/05-metallb.md`](05-metallb.md) |
|
||||||
|
| `10.10.60.11` | Reserved for the Authentik LDAP Outpost used by Jellyfin | `authentik` | 636 | `ldaps://10.10.60.11:636` | Planned Authentik deployment; verify the address and TLS certificate before migrating Jellyfin |
|
||||||
| `10.10.60.12` | ingress-nginx (shared, routes by hostname) | `ingress-nginx` | 80, 443 | `http://10.10.60.12`, `https://10.10.60.12` | [`apps/ingress-nginx/values.yaml`](../apps/ingress-nginx/values.yaml) — see [`docs/11-ingress.md`](11-ingress.md) |
|
| `10.10.60.12` | ingress-nginx (shared, routes by hostname) | `ingress-nginx` | 80, 443 | `http://10.10.60.12`, `https://10.10.60.12` | [`apps/ingress-nginx/values.yaml`](../apps/ingress-nginx/values.yaml) — see [`docs/11-ingress.md`](11-ingress.md) |
|
||||||
|
|
||||||
Add a row here every time you add a new app with its own dedicated
|
Add a row here every time you add a new app with its own dedicated
|
||||||
@@ -61,13 +78,17 @@ only when it's the protocol default (80 for `http://`, 443 for `https://`)
|
|||||||
|
|
||||||
## Hostnames routed through ingress-nginx
|
## Hostnames routed through ingress-nginx
|
||||||
|
|
||||||
Every real DNS record pointing at ingress-nginx's shared address
|
Every real hostname routed to ingress-nginx's shared address
|
||||||
(`10.10.60.12`), and which app it reaches. All hosted on Cloudflare.
|
(`10.10.60.12`), and which app it reaches. Public DNS is hosted on
|
||||||
|
Cloudflare; internal overrides are served by Technitium where noted.
|
||||||
|
|
||||||
| Hostname | App | Namespace | TLS | Source |
|
| Hostname | App | Namespace | TLS | Source |
|
||||||
|---|---|---|---|---|
|
|---|---|---|---|---|
|
||||||
| `demo.ahmza.com` | Demo app | `demo` | Yes — `letsencrypt-prod`, real trusted cert (see [`docs/12-cert-manager.md`](12-cert-manager.md)) | [`apps/demo/ingress.yaml`](../apps/demo/ingress.yaml) |
|
| `demo.ahmza.com` | Demo app | `demo` | Yes — `letsencrypt-prod`, real trusted cert (see [`docs/12-cert-manager.md`](12-cert-manager.md)) | [`apps/demo/ingress.yaml`](../apps/demo/ingress.yaml) |
|
||||||
| `mc.ahmza.com` | Packwiz modpack files | `mcpacks` | Staging requested — promote to `letsencrypt-prod` after the staging Certificate is verified Ready | [`apps/mcpacks/ingress.yaml`](../apps/mcpacks/ingress.yaml) |
|
| `auth.ahmza.com` | Authentik identity provider | `authentik` | Yes — `letsencrypt-prod`, trusted certificate and browser login verified; Technitium routes LAN clients to `10.10.60.12`. For public traffic, NetBird terminates public TLS and proxies HTTP through its encrypted WireGuard overlay to Caddy on `ingress1`; Caddy then uses certificate-validated HTTPS with `auth.ahmza.com` as SNI and the HTTP `Host` when connecting to ingress-nginx at `10.10.60.12:443` | [`apps/authentik/values.yaml`](../apps/authentik/values.yaml) |
|
||||||
|
| `mc.ahmza.com` | Packwiz modpack files | `mcpacks` | Yes — `letsencrypt-prod`, real trusted certificate | [`apps/mcpacks/ingress.yaml`](../apps/mcpacks/ingress.yaml) |
|
||||||
|
| `bazarr.ahmza.com` | Bazarr subtitle manager | `bazarr` | Yes — `letsencrypt-prod`, real trusted certificate; Technitium overrides Cloudflare's NetBird route on the LAN | [`apps/bazarr/ingress.yaml`](../apps/bazarr/ingress.yaml) |
|
||||||
|
| `soulsync.ahmza.com` | SoulSync media discovery | `soulsync` | Configured for `letsencrypt-prod`; verify the certificate after the first deployment; Technitium routes LAN clients to `10.10.60.12` | [`apps/soulsync/ingress.yaml`](../apps/soulsync/ingress.yaml) |
|
||||||
|
|
||||||
Add a row here every time you point a new hostname at this cluster (see
|
Add a row here every time you point a new hostname at this cluster (see
|
||||||
[`docs/11-ingress.md`](11-ingress.md)). The DNS record itself lives in
|
[`docs/11-ingress.md`](11-ingress.md)). The DNS record itself lives in
|
||||||
@@ -79,7 +100,7 @@ Addresses from the range above that aren't spoken for yet. Update this
|
|||||||
alongside the table above so it's obvious at a glance what's safe to hand
|
alongside the table above so it's obvious at a glance what's safe to hand
|
||||||
to the next app.
|
to the next app.
|
||||||
|
|
||||||
- `10.10.60.11`, `10.10.60.13-10.10.60.250`
|
- `10.10.60.13-10.10.60.250`
|
||||||
|
|
||||||
(`whoami`'s former `10.10.60.12` was reclaimed here after that app was
|
(`whoami`'s former `10.10.60.12` was reclaimed here after that app was
|
||||||
removed as the docs/08 exercise — it now belongs to ingress-nginx instead.
|
removed as the docs/08 exercise — it now belongs to ingress-nginx instead.
|
||||||
|
|||||||
+49
-42
@@ -5,18 +5,14 @@ This is the detailed, copy-pasteable companion to
|
|||||||
first for the explanations — this one is here so you have every exact
|
first for the explanations — this one is here so you have every exact
|
||||||
command in one place once you understand what they do.
|
command in one place once you understand what they do.
|
||||||
|
|
||||||
Throughout, replace `<NODE1_IP>`, `<NODE2_IP>`, `<NODE3_IP>` with your three
|
Throughout, use the three control-plane and two worker addresses recorded in
|
||||||
machines' real IP addresses, and `<VIP_IP>` with the shared address you
|
[`docs/network.md`](../docs/network.md), plus the cluster's shared VIP. Give
|
||||||
picked (with Claude's help) for the cluster's VIP — see
|
each machine a DHCP reservation (a fixed IP tied to its MAC address) before
|
||||||
[`docs/02-talos-bootstrap.md`](../docs/02-talos-bootstrap.md#the-vip-one-address-for-a-cluster-that-moves).
|
installation so its address remains stable.
|
||||||
Give each machine a DHCP reservation (a fixed IP tied to its MAC address)
|
|
||||||
in your router or hypervisor before you start, so none of these addresses
|
|
||||||
change under the cluster. Talos bakes them into certificates during setup,
|
|
||||||
and changing one later means starting over for that node.
|
|
||||||
|
|
||||||
Steps 1–2 below run **once, total**. Steps 3 runs **once per node** (three
|
Steps 1–2 below run **once, total**. Step 3 runs **once per node** (five
|
||||||
times). Steps 4–6 run **once, total**, against whichever node you like
|
times, using the matching role configuration). Steps 4–6 run **once, total**;
|
||||||
(or, once it exists, the VIP).
|
Talos API commands target a control-plane node, while Kubernetes uses the VIP.
|
||||||
|
|
||||||
All commands assume you're running them from the root of this repo.
|
All commands assume you're running them from the root of this repo.
|
||||||
|
|
||||||
@@ -26,7 +22,10 @@ All commands assume you're running them from the root of this repo.
|
|||||||
talosctl gen config gitops-starter https://<VIP_IP>:6443 \
|
talosctl gen config gitops-starter https://<VIP_IP>:6443 \
|
||||||
--output-dir _out \
|
--output-dir _out \
|
||||||
--config-patch-control-plane @talos/patch-controlplane.yaml \
|
--config-patch-control-plane @talos/patch-controlplane.yaml \
|
||||||
--config-patch-control-plane @talos/patch-longhorn.yaml
|
--config-patch-control-plane @talos/patch-netbird.yaml \
|
||||||
|
--config-patch-worker @talos/patch-worker.yaml \
|
||||||
|
--config-patch-worker @talos/patch-longhorn.yaml \
|
||||||
|
--config-patch-worker @talos/patch-netbird.yaml
|
||||||
```
|
```
|
||||||
|
|
||||||
Note the cluster endpoint here is the **VIP**, not any one node's address
|
Note the cluster endpoint here is the **VIP**, not any one node's address
|
||||||
@@ -38,13 +37,12 @@ This writes three files into `_out/` (already covered by this repo's
|
|||||||
`.gitignore` — they contain private keys and must never be committed):
|
`.gitignore` — they contain private keys and must never be committed):
|
||||||
|
|
||||||
- `controlplane.yaml` — the machine configuration for a control-plane
|
- `controlplane.yaml` — the machine configuration for a control-plane
|
||||||
node, with both patches baked in. Applied identically to all three
|
node, with the Raspberry Pi/VIP and non-secret NetBird patches baked in.
|
||||||
nodes — there's no separate worker config in this setup, since every
|
It is applied identically to all three control-plane nodes.
|
||||||
node is both.
|
- `worker.yaml` — the machine configuration for the two Proxmox workers,
|
||||||
- `worker.yaml` — a plain worker config, generated automatically but
|
with their role, Longhorn data-disk, and non-secret NetBird patches baked
|
||||||
unused here since every node in this repo's setup is both control plane
|
in. The NetBird setup key is deliberately absent from both generated files;
|
||||||
and worker. Kept around for [`docs/09-growing-up.md`](../docs/09-growing-up.md),
|
enrollment uses a short-lived key applied separately and revoked afterward.
|
||||||
where a fourth-and-beyond node uses exactly this file.
|
|
||||||
- `talosconfig` — *your* client credentials for talking to the Talos API on
|
- `talosconfig` — *your* client credentials for talking to the Talos API on
|
||||||
this cluster (equivalent in spirit to a kubeconfig, but for Talos itself
|
this cluster (equivalent in spirit to a kubeconfig, but for Talos itself
|
||||||
rather than Kubernetes).
|
rather than Kubernetes).
|
||||||
@@ -68,34 +66,39 @@ separate.
|
|||||||
|
|
||||||
## 3. Apply the configuration — once per node
|
## 3. Apply the configuration — once per node
|
||||||
|
|
||||||
Boot each machine from your custom Talos ISO (see
|
Boot each machine from its architecture-appropriate custom Talos image (see
|
||||||
[docs/01-prerequisites.md](../docs/01-prerequisites.md)). Each boots into
|
[docs/01-prerequisites.md](../docs/01-prerequisites.md)). Each boots into
|
||||||
"maintenance mode" — alive enough to accept a configuration, with nothing
|
"maintenance mode" — alive enough to accept configuration, with nothing
|
||||||
installed yet. For **each** node in turn:
|
installed yet. Inspect its disks first:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
talosctl get disks --insecure --nodes <NODE_IP>
|
talosctl get disks --insecure --nodes <NODE_IP>
|
||||||
```
|
```
|
||||||
|
|
||||||
Confirm you see two disks: the one Talos will install itself to, and the
|
For each Raspberry Pi control plane, confirm `/dev/mmcblk0` is the intended
|
||||||
≥900GB one `talos/patch-longhorn.yaml`'s `UserVolumeConfig` will claim for
|
system disk, then apply the control-plane configuration:
|
||||||
Longhorn. Then:
|
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
talosctl apply-config --insecure \
|
talosctl apply-config --insecure \
|
||||||
--nodes <NODE_IP> \
|
--nodes <CONTROL_PLANE_IP> \
|
||||||
--file _out/controlplane.yaml
|
--file _out/controlplane.yaml
|
||||||
```
|
```
|
||||||
|
|
||||||
`--insecure` is required for this one command only: the node has no
|
For each Proxmox worker, confirm `/dev/sda` is the Talos system disk and
|
||||||
certificates yet, so talosctl can't authenticate to it normally. This is
|
`/dev/sdb` is the dedicated Longhorn disk selected by
|
||||||
the one moment during setup where you're trusting the network — do this on
|
`talos/patch-longhorn.yaml`, then apply the worker configuration:
|
||||||
a network you control. The node will reboot, install Talos to its system
|
|
||||||
disk, format and mount its second disk for Longhorn, and come back up
|
|
||||||
running the configuration you gave it — now *with* certificates, so every
|
|
||||||
command after this uses the secure path.
|
|
||||||
|
|
||||||
Repeat this for `<NODE1_IP>`, `<NODE2_IP>`, and `<NODE3_IP>` before moving on.
|
```sh
|
||||||
|
talosctl apply-config --insecure \
|
||||||
|
--nodes <WORKER_IP> \
|
||||||
|
--file _out/worker.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
`--insecure` is required for this one command only: the node has no
|
||||||
|
certificates yet, so talosctl cannot authenticate to it normally. This is
|
||||||
|
the one moment during setup where you trust the local network. After applying
|
||||||
|
configuration, the node installs Talos and returns with authenticated API
|
||||||
|
access. Configure all three control planes and both workers before continuing.
|
||||||
|
|
||||||
## 4. Bootstrap etcd — once, total
|
## 4. Bootstrap etcd — once, total
|
||||||
|
|
||||||
@@ -115,12 +118,14 @@ existing one. Running it again against an existing cluster can corrupt it.
|
|||||||
## 5. Get your kubeconfig
|
## 5. Get your kubeconfig
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
talosctl kubeconfig --nodes <VIP_IP> .
|
talosctl kubeconfig --nodes <CONTROL_PLANE_IP> .
|
||||||
```
|
```
|
||||||
|
|
||||||
Downloads a kubeconfig into the current directory (also gitignored —
|
Downloads a kubeconfig through a control-plane node's Talos API into the
|
||||||
it grants full cluster access), pointed at the VIP rather than any one
|
current directory (also gitignored — it grants full cluster access). The
|
||||||
node. Merge it with `~/.kube/config` or point `KUBECONFIG` at it directly:
|
resulting Kubernetes configuration points at the cluster VIP rather than one
|
||||||
|
specific control plane. Merge it with `~/.kube/config` or point `KUBECONFIG`
|
||||||
|
at it directly:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
export KUBECONFIG=$PWD/kubeconfig
|
export KUBECONFIG=$PWD/kubeconfig
|
||||||
@@ -132,15 +137,17 @@ export KUBECONFIG=$PWD/kubeconfig
|
|||||||
kubectl get nodes
|
kubectl get nodes
|
||||||
```
|
```
|
||||||
|
|
||||||
Expect to see **three** nodes, `Ready`, within a couple of minutes (it
|
Expect to see **five** nodes, `Ready`, within a couple of minutes (it takes
|
||||||
takes a moment for the default CNI — Talos ships Flannel out of the box —
|
a moment for the default CNI — Talos ships Flannel out of the box — to clear
|
||||||
to come up and clear each node's networking checks).
|
each node's networking checks).
|
||||||
|
|
||||||
```
|
```text
|
||||||
NAME STATUS ROLES AGE VERSION
|
NAME STATUS ROLES AGE VERSION
|
||||||
talos-... Ready control-plane 90s v1.3x.x
|
talos-... Ready control-plane 90s v1.3x.x
|
||||||
talos-... Ready control-plane 85s v1.3x.x
|
talos-... Ready control-plane 85s v1.3x.x
|
||||||
talos-... Ready control-plane 80s v1.3x.x
|
talos-... Ready control-plane 80s v1.3x.x
|
||||||
|
talos-... Ready worker 75s v1.3x.x
|
||||||
|
talos-... Ready worker 70s v1.3x.x
|
||||||
```
|
```
|
||||||
|
|
||||||
If any node is stuck on `NotReady`, give it another minute before
|
If any node is stuck on `NotReady`, give it another minute before
|
||||||
|
|||||||
@@ -12,9 +12,10 @@
|
|||||||
# --- install image ---
|
# --- install image ---
|
||||||
# All three control planes are Raspberry Pi 4 systems currently installed on
|
# All three control planes are Raspberry Pi 4 systems currently installed on
|
||||||
# their microSD (`mmcblk0`). The Image Factory schematic contains the
|
# their microSD (`mmcblk0`). The Image Factory schematic contains the
|
||||||
# `rpi_generic` ARM64 overlay needed to boot this hardware. Keep this custom
|
# `rpi_generic` ARM64 overlay needed to boot this hardware and the NetBird
|
||||||
# installer reference during upgrades or the board-specific boot support may
|
# system extension used for private overlay connectivity. Keep this custom
|
||||||
# be lost.
|
# installer reference during upgrades or the board-specific boot support and
|
||||||
|
# NetBird binary may be lost.
|
||||||
#
|
#
|
||||||
# --- vip ---
|
# --- vip ---
|
||||||
# With three control-plane nodes, "the cluster's API server" isn't one
|
# With three control-plane nodes, "the cluster's API server" isn't one
|
||||||
@@ -38,7 +39,8 @@ cluster:
|
|||||||
machine:
|
machine:
|
||||||
install:
|
install:
|
||||||
disk: /dev/mmcblk0
|
disk: /dev/mmcblk0
|
||||||
image: factory.talos.dev/metal-installer/ee21ef4a5ef808a9b7484cc0dda0f25075021691c8c09a276591eedb638ea1f9:v1.13.8
|
image: "factory.talos.dev/metal-installer/\
|
||||||
|
d093bb68c464b87cc637765535dde5f68fbb040da44280617dd11a42d6c03988:v1.13.8"
|
||||||
network:
|
network:
|
||||||
interfaces:
|
interfaces:
|
||||||
# Raspberry Pi 4's built-in Ethernet interface is named `end0` by
|
# Raspberry Pi 4's built-in Ethernet interface is named `end0` by
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# Persistent, non-secret configuration for the official SideroLabs NetBird
|
||||||
|
# system extension. Apply this patch to every Talos node alongside its normal
|
||||||
|
# role-specific patches.
|
||||||
|
#
|
||||||
|
# Enrollment still requires NB_SETUP_KEY, but that short-lived credential must
|
||||||
|
# never be committed to this public repository. Supply it separately from a
|
||||||
|
# silent shell prompt during first enrollment, revoke it after all nodes join,
|
||||||
|
# then remove it from the live ExtensionServiceConfig.
|
||||||
|
apiVersion: v1alpha1
|
||||||
|
kind: ExtensionServiceConfig
|
||||||
|
name: netbird
|
||||||
|
environment:
|
||||||
|
# Both endpoints use this installation's combined self-hosted NetBird URL.
|
||||||
|
- NB_MANAGEMENT_URL=https://netbird.ahmza.com
|
||||||
|
- NB_ADMIN_URL=https://netbird.ahmza.com
|
||||||
|
# Talos mounts /etc read-only. Prevent NetBird from repeatedly trying to
|
||||||
|
# rewrite resolv.conf and the OpenSSH client configuration there. Overlay
|
||||||
|
# networking remains active; NetBird-managed DNS is deliberately disabled.
|
||||||
|
- NB_DISABLE_DNS=true
|
||||||
|
- NB_DISABLE_SSH_CONFIG=true
|
||||||
@@ -8,9 +8,9 @@
|
|||||||
# claiming the wrong virtual disk.
|
# claiming the wrong virtual disk.
|
||||||
#
|
#
|
||||||
# The custom Image Factory installer contains Longhorn's `iscsi-tools` and
|
# The custom Image Factory installer contains Longhorn's `iscsi-tools` and
|
||||||
# `util-linux-tools` extensions plus `qemu-guest-agent`. Keep this schematic
|
# `util-linux-tools` extensions plus `qemu-guest-agent` and NetBird. Keep this
|
||||||
# reference during future upgrades; switching to the stock installer would
|
# schematic reference during future upgrades; switching to the stock installer
|
||||||
# silently remove those extensions.
|
# would silently remove those extensions.
|
||||||
#
|
#
|
||||||
# Both VMs use `ens18`. Their DHCP-reserved MAC addresses keep worker01 at
|
# Both VMs use `ens18`. Their DHCP-reserved MAC addresses keep worker01 at
|
||||||
# 10.10.10.203 and worker02 at 10.10.10.204 while DHCP supplies their gateway
|
# 10.10.10.203 and worker02 at 10.10.10.204 while DHCP supplies their gateway
|
||||||
@@ -26,7 +26,8 @@ machine:
|
|||||||
node.longhorn.io/create-default-disk: "true"
|
node.longhorn.io/create-default-disk: "true"
|
||||||
install:
|
install:
|
||||||
disk: /dev/sda
|
disk: /dev/sda
|
||||||
image: factory.talos.dev/metal-installer/88d1f7a5c4f1d3aba7df787c448c1d3d008ed29cfb34af53fa0df4336a56040b:v1.13.8
|
image: "factory.talos.dev/metal-installer/\
|
||||||
|
81fb1af7c03952593ba459c6c8b7fcc1268b6fe0cc80e6035ac629a741c183cc:v1.13.8"
|
||||||
network:
|
network:
|
||||||
interfaces:
|
interfaces:
|
||||||
- interface: ens18
|
- interface: ens18
|
||||||
|
|||||||
Reference in New Issue
Block a user