Update telephony-web image to v20260324d, resolve merge conflicts
This commit is contained in:
@@ -1,3 +1,3 @@
|
|||||||
# bluejay-infra
|
# bluejay-infra
|
||||||
|
|
||||||
Infrastructure manifests for ArgoCD
|
Infrastructure manifests for ArgoCD
|
||||||
@@ -1,150 +1,150 @@
|
|||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
name: asterisk
|
name: asterisk
|
||||||
namespace: telephony
|
namespace: telephony
|
||||||
labels:
|
labels:
|
||||||
app: asterisk
|
app: asterisk
|
||||||
spec:
|
spec:
|
||||||
replicas: 1
|
replicas: 1
|
||||||
strategy:
|
strategy:
|
||||||
type: Recreate
|
type: Recreate
|
||||||
selector:
|
selector:
|
||||||
matchLabels:
|
matchLabels:
|
||||||
app: asterisk
|
app: asterisk
|
||||||
template:
|
template:
|
||||||
metadata:
|
metadata:
|
||||||
labels:
|
labels:
|
||||||
app: asterisk
|
app: asterisk
|
||||||
spec:
|
spec:
|
||||||
hostNetwork: true
|
hostNetwork: true
|
||||||
dnsPolicy: ClusterFirstWithHostNet
|
dnsPolicy: ClusterFirstWithHostNet
|
||||||
securityContext:
|
securityContext:
|
||||||
fsGroup: 0
|
fsGroup: 0
|
||||||
initContainers:
|
initContainers:
|
||||||
- name: install-sounds
|
- name: install-sounds
|
||||||
image: busybox:latest
|
image: busybox:latest
|
||||||
command:
|
command:
|
||||||
- sh
|
- sh
|
||||||
- -c
|
- -c
|
||||||
- |
|
- |
|
||||||
mkdir -p /sounds/en &&
|
mkdir -p /sounds/en &&
|
||||||
wget -qO- http://downloads.asterisk.org/pub/telephony/sounds/asterisk-core-sounds-en-ulaw-current.tar.gz | tar xz -C /sounds/en/ &&
|
wget -qO- http://downloads.asterisk.org/pub/telephony/sounds/asterisk-core-sounds-en-ulaw-current.tar.gz | tar xz -C /sounds/en/ &&
|
||||||
wget -qO- http://downloads.asterisk.org/pub/telephony/sounds/asterisk-extra-sounds-en-ulaw-current.tar.gz | tar xz -C /sounds/en/ &&
|
wget -qO- http://downloads.asterisk.org/pub/telephony/sounds/asterisk-extra-sounds-en-ulaw-current.tar.gz | tar xz -C /sounds/en/ &&
|
||||||
echo "Sound files installed: $(find /sounds/en -type f | wc -l) files"
|
echo "Sound files installed: $(find /sounds/en -type f | wc -l) files"
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
- name: sounds
|
- name: sounds
|
||||||
mountPath: /sounds/en
|
mountPath: /sounds/en
|
||||||
containers:
|
containers:
|
||||||
- name: asterisk
|
- name: asterisk
|
||||||
image: localhost/andrius/asterisk:latest
|
image: localhost/andrius/asterisk:latest
|
||||||
imagePullPolicy: Never
|
imagePullPolicy: Never
|
||||||
ports:
|
ports:
|
||||||
- name: sip-udp
|
- name: sip-udp
|
||||||
containerPort: 5060
|
containerPort: 5060
|
||||||
protocol: UDP
|
protocol: UDP
|
||||||
- name: sip-tcp
|
- name: sip-tcp
|
||||||
containerPort: 5060
|
containerPort: 5060
|
||||||
protocol: TCP
|
protocol: TCP
|
||||||
- name: ari
|
- name: ari
|
||||||
containerPort: 8088
|
containerPort: 8088
|
||||||
protocol: TCP
|
protocol: TCP
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
- name: config-modules
|
- name: config-modules
|
||||||
mountPath: /etc/asterisk/modules.conf
|
mountPath: /etc/asterisk/modules.conf
|
||||||
subPath: modules.conf
|
subPath: modules.conf
|
||||||
- name: config-http
|
- name: config-http
|
||||||
mountPath: /etc/asterisk/http.conf
|
mountPath: /etc/asterisk/http.conf
|
||||||
subPath: http.conf
|
subPath: http.conf
|
||||||
- name: config-ari
|
- name: config-ari
|
||||||
mountPath: /etc/asterisk/ari.conf
|
mountPath: /etc/asterisk/ari.conf
|
||||||
subPath: ari.conf
|
subPath: ari.conf
|
||||||
- name: config-manager
|
- name: config-manager
|
||||||
mountPath: /etc/asterisk/manager.conf
|
mountPath: /etc/asterisk/manager.conf
|
||||||
subPath: manager.conf
|
subPath: manager.conf
|
||||||
- name: config-pjsip
|
- name: config-pjsip
|
||||||
mountPath: /etc/asterisk/pjsip.conf
|
mountPath: /etc/asterisk/pjsip.conf
|
||||||
subPath: pjsip.conf
|
subPath: pjsip.conf
|
||||||
- name: config-extensions
|
- name: config-extensions
|
||||||
mountPath: /etc/asterisk/extensions.conf
|
mountPath: /etc/asterisk/extensions.conf
|
||||||
subPath: extensions.conf
|
subPath: extensions.conf
|
||||||
- name: config-rtp
|
- name: config-rtp
|
||||||
mountPath: /etc/asterisk/rtp.conf
|
mountPath: /etc/asterisk/rtp.conf
|
||||||
subPath: rtp.conf
|
subPath: rtp.conf
|
||||||
- name: asterisk-data
|
- name: asterisk-data
|
||||||
mountPath: /var/spool/asterisk
|
mountPath: /var/spool/asterisk
|
||||||
- name: asterisk-logs
|
- name: asterisk-logs
|
||||||
mountPath: /var/log/asterisk
|
mountPath: /var/log/asterisk
|
||||||
- name: sounds
|
- name: sounds
|
||||||
mountPath: /var/lib/asterisk/sounds/en
|
mountPath: /var/lib/asterisk/sounds/en
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
cpu: 100m
|
cpu: 100m
|
||||||
memory: 128Mi
|
memory: 128Mi
|
||||||
limits:
|
limits:
|
||||||
cpu: "1"
|
cpu: "1"
|
||||||
memory: 512Mi
|
memory: 512Mi
|
||||||
livenessProbe:
|
livenessProbe:
|
||||||
tcpSocket:
|
tcpSocket:
|
||||||
port: 8088
|
port: 8088
|
||||||
initialDelaySeconds: 15
|
initialDelaySeconds: 15
|
||||||
periodSeconds: 10
|
periodSeconds: 10
|
||||||
readinessProbe:
|
readinessProbe:
|
||||||
httpGet:
|
httpGet:
|
||||||
path: /ari/asterisk/info
|
path: /ari/asterisk/info
|
||||||
port: 8088
|
port: 8088
|
||||||
httpHeaders:
|
httpHeaders:
|
||||||
- name: Authorization
|
- name: Authorization
|
||||||
value: "Basic Zmxvd2VyY29yZTpibHVlamF5LWFzdGVyaXNrLWFyaQ=="
|
value: "Basic Zmxvd2VyY29yZTpibHVlamF5LWFzdGVyaXNrLWFyaQ=="
|
||||||
initialDelaySeconds: 10
|
initialDelaySeconds: 10
|
||||||
periodSeconds: 5
|
periodSeconds: 5
|
||||||
volumes:
|
volumes:
|
||||||
- name: config-modules
|
- name: config-modules
|
||||||
configMap:
|
configMap:
|
||||||
name: asterisk-config
|
name: asterisk-config
|
||||||
items:
|
items:
|
||||||
- key: modules.conf
|
- key: modules.conf
|
||||||
path: modules.conf
|
path: modules.conf
|
||||||
- name: config-http
|
- name: config-http
|
||||||
configMap:
|
configMap:
|
||||||
name: asterisk-config
|
name: asterisk-config
|
||||||
items:
|
items:
|
||||||
- key: http.conf
|
- key: http.conf
|
||||||
path: http.conf
|
path: http.conf
|
||||||
- name: config-ari
|
- name: config-ari
|
||||||
configMap:
|
configMap:
|
||||||
name: asterisk-config
|
name: asterisk-config
|
||||||
items:
|
items:
|
||||||
- key: ari.conf
|
- key: ari.conf
|
||||||
path: ari.conf
|
path: ari.conf
|
||||||
- name: config-manager
|
- name: config-manager
|
||||||
configMap:
|
configMap:
|
||||||
name: asterisk-config
|
name: asterisk-config
|
||||||
items:
|
items:
|
||||||
- key: manager.conf
|
- key: manager.conf
|
||||||
path: manager.conf
|
path: manager.conf
|
||||||
- name: config-pjsip
|
- name: config-pjsip
|
||||||
configMap:
|
configMap:
|
||||||
name: asterisk-config
|
name: asterisk-config
|
||||||
items:
|
items:
|
||||||
- key: pjsip.conf
|
- key: pjsip.conf
|
||||||
path: pjsip.conf
|
path: pjsip.conf
|
||||||
- name: config-extensions
|
- name: config-extensions
|
||||||
configMap:
|
configMap:
|
||||||
name: asterisk-config
|
name: asterisk-config
|
||||||
items:
|
items:
|
||||||
- key: extensions.conf
|
- key: extensions.conf
|
||||||
path: extensions.conf
|
path: extensions.conf
|
||||||
- name: config-rtp
|
- name: config-rtp
|
||||||
configMap:
|
configMap:
|
||||||
name: asterisk-config
|
name: asterisk-config
|
||||||
items:
|
items:
|
||||||
- key: rtp.conf
|
- key: rtp.conf
|
||||||
path: rtp.conf
|
path: rtp.conf
|
||||||
- name: asterisk-data
|
- name: asterisk-data
|
||||||
persistentVolumeClaim:
|
persistentVolumeClaim:
|
||||||
claimName: asterisk-data
|
claimName: asterisk-data
|
||||||
- name: asterisk-logs
|
- name: asterisk-logs
|
||||||
emptyDir: {}
|
emptyDir: {}
|
||||||
- name: sounds
|
- name: sounds
|
||||||
emptyDir: {}
|
emptyDir: {}
|
||||||
|
|||||||
@@ -1,40 +1,40 @@
|
|||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Service
|
kind: Service
|
||||||
metadata:
|
metadata:
|
||||||
name: asterisk-sip
|
name: asterisk-sip
|
||||||
namespace: telephony
|
namespace: telephony
|
||||||
labels:
|
labels:
|
||||||
app: asterisk
|
app: asterisk
|
||||||
annotations:
|
annotations:
|
||||||
metallb.universe.tf/loadBalancerIPs: "10.0.56.207"
|
metallb.universe.tf/loadBalancerIPs: "10.0.56.207"
|
||||||
spec:
|
spec:
|
||||||
type: LoadBalancer
|
type: LoadBalancer
|
||||||
externalTrafficPolicy: Local
|
externalTrafficPolicy: Local
|
||||||
selector:
|
selector:
|
||||||
app: asterisk
|
app: asterisk
|
||||||
ports:
|
ports:
|
||||||
- name: sip-udp
|
- name: sip-udp
|
||||||
port: 5060
|
port: 5060
|
||||||
targetPort: 5060
|
targetPort: 5060
|
||||||
protocol: UDP
|
protocol: UDP
|
||||||
- name: sip-tcp
|
- name: sip-tcp
|
||||||
port: 5060
|
port: 5060
|
||||||
targetPort: 5060
|
targetPort: 5060
|
||||||
protocol: TCP
|
protocol: TCP
|
||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Service
|
kind: Service
|
||||||
metadata:
|
metadata:
|
||||||
name: asterisk-ari
|
name: asterisk-ari
|
||||||
namespace: telephony
|
namespace: telephony
|
||||||
labels:
|
labels:
|
||||||
app: asterisk
|
app: asterisk
|
||||||
spec:
|
spec:
|
||||||
type: ClusterIP
|
type: ClusterIP
|
||||||
selector:
|
selector:
|
||||||
app: asterisk
|
app: asterisk
|
||||||
ports:
|
ports:
|
||||||
- name: ari
|
- name: ari
|
||||||
port: 8088
|
port: 8088
|
||||||
targetPort: 8088
|
targetPort: 8088
|
||||||
protocol: TCP
|
protocol: TCP
|
||||||
|
|||||||
@@ -1,320 +1,320 @@
|
|||||||
# FlowerCore Landing Page
|
# FlowerCore Landing Page
|
||||||
# Blue Jay Lab branded landing page - PUBLIC facing
|
# Blue Jay Lab branded landing page - PUBLIC facing
|
||||||
# ArgoCD managed - BlueJay Lab
|
# ArgoCD managed - BlueJay Lab
|
||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Namespace
|
kind: Namespace
|
||||||
metadata:
|
metadata:
|
||||||
name: fc-system
|
name: fc-system
|
||||||
labels:
|
labels:
|
||||||
app.kubernetes.io/part-of: bluejay-infra
|
app.kubernetes.io/part-of: bluejay-infra
|
||||||
---
|
---
|
||||||
# Landing page HTML (public-safe - no internal LAN references)
|
# Landing page HTML (public-safe - no internal LAN references)
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: ConfigMap
|
kind: ConfigMap
|
||||||
metadata:
|
metadata:
|
||||||
name: fc-landing-html
|
name: fc-landing-html
|
||||||
namespace: fc-system
|
namespace: fc-system
|
||||||
data:
|
data:
|
||||||
index.html: |
|
index.html: |
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<title>FlowerCore</title>
|
<title>FlowerCore</title>
|
||||||
<style>
|
<style>
|
||||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||||
body {
|
body {
|
||||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||||
background: linear-gradient(135deg, #0a1628 0%, #1a2744 50%, #0d1f3c 100%);
|
background: linear-gradient(135deg, #0a1628 0%, #1a2744 50%, #0d1f3c 100%);
|
||||||
color: #e0e8f0;
|
color: #e0e8f0;
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
.hero {
|
.hero {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 3rem;
|
padding: 3rem;
|
||||||
max-width: 800px;
|
max-width: 800px;
|
||||||
}
|
}
|
||||||
.logo {
|
.logo {
|
||||||
font-size: 5rem;
|
font-size: 5rem;
|
||||||
margin-bottom: 1.5rem;
|
margin-bottom: 1.5rem;
|
||||||
filter: drop-shadow(0 0 20px rgba(74, 158, 255, 0.3));
|
filter: drop-shadow(0 0 20px rgba(74, 158, 255, 0.3));
|
||||||
}
|
}
|
||||||
h1 {
|
h1 {
|
||||||
font-size: 3rem;
|
font-size: 3rem;
|
||||||
background: linear-gradient(135deg, #4a9eff, #7ab3ff);
|
background: linear-gradient(135deg, #4a9eff, #7ab3ff);
|
||||||
-webkit-background-clip: text;
|
-webkit-background-clip: text;
|
||||||
-webkit-text-fill-color: transparent;
|
-webkit-text-fill-color: transparent;
|
||||||
background-clip: text;
|
background-clip: text;
|
||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0.5rem;
|
||||||
}
|
}
|
||||||
.subtitle {
|
.subtitle {
|
||||||
font-size: 1.3rem;
|
font-size: 1.3rem;
|
||||||
color: #7ab3ff;
|
color: #7ab3ff;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
}
|
}
|
||||||
.description {
|
.description {
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
color: #8aa8c4;
|
color: #8aa8c4;
|
||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
margin-bottom: 3rem;
|
margin-bottom: 3rem;
|
||||||
max-width: 600px;
|
max-width: 600px;
|
||||||
}
|
}
|
||||||
.services {
|
.services {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 700px;
|
max-width: 700px;
|
||||||
padding: 0 1rem;
|
padding: 0 1rem;
|
||||||
}
|
}
|
||||||
.service {
|
.service {
|
||||||
background: rgba(74, 158, 255, 0.08);
|
background: rgba(74, 158, 255, 0.08);
|
||||||
border: 1px solid rgba(74, 158, 255, 0.2);
|
border: 1px solid rgba(74, 158, 255, 0.2);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
padding: 1.2rem;
|
padding: 1.2rem;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
color: inherit;
|
color: inherit;
|
||||||
transition: all 0.2s;
|
transition: all 0.2s;
|
||||||
}
|
}
|
||||||
.service:hover {
|
.service:hover {
|
||||||
background: rgba(74, 158, 255, 0.15);
|
background: rgba(74, 158, 255, 0.15);
|
||||||
border-color: rgba(74, 158, 255, 0.5);
|
border-color: rgba(74, 158, 255, 0.5);
|
||||||
transform: translateY(-2px);
|
transform: translateY(-2px);
|
||||||
}
|
}
|
||||||
.service h3 { color: #4a9eff; font-size: 0.95rem; margin-bottom: 0.3rem; }
|
.service h3 { color: #4a9eff; font-size: 0.95rem; margin-bottom: 0.3rem; }
|
||||||
.service p { color: #8aa8c4; font-size: 0.8rem; }
|
.service p { color: #8aa8c4; font-size: 0.8rem; }
|
||||||
.status-bar {
|
.status-bar {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 2rem;
|
gap: 2rem;
|
||||||
margin-top: 2rem;
|
margin-top: 2rem;
|
||||||
padding: 1rem 2rem;
|
padding: 1rem 2rem;
|
||||||
background: rgba(74, 158, 255, 0.05);
|
background: rgba(74, 158, 255, 0.05);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
border: 1px solid rgba(74, 158, 255, 0.1);
|
border: 1px solid rgba(74, 158, 255, 0.1);
|
||||||
}
|
}
|
||||||
.status-item { text-align: center; }
|
.status-item { text-align: center; }
|
||||||
.status-item .value { color: #4a9eff; font-size: 1.5rem; font-weight: 700; }
|
.status-item .value { color: #4a9eff; font-size: 1.5rem; font-weight: 700; }
|
||||||
.status-item .label { color: #6a8ca4; font-size: 0.7rem; text-transform: uppercase; letter-spacing: 1px; }
|
.status-item .label { color: #6a8ca4; font-size: 0.7rem; text-transform: uppercase; letter-spacing: 1px; }
|
||||||
.footer {
|
.footer {
|
||||||
margin-top: 3rem;
|
margin-top: 3rem;
|
||||||
color: #4a6580;
|
color: #4a6580;
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
}
|
}
|
||||||
.footer a { color: #4a6580; text-decoration: none; }
|
.footer a { color: #4a6580; text-decoration: none; }
|
||||||
.footer a:hover { color: #7ab3ff; }
|
.footer a:hover { color: #7ab3ff; }
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="hero">
|
<div class="hero">
|
||||||
<div class="logo">🌻</div>
|
<div class="logo">🌻</div>
|
||||||
<h1>FlowerCore</h1>
|
<h1>FlowerCore</h1>
|
||||||
<p class="subtitle">Blue Jay Lab</p>
|
<p class="subtitle">Blue Jay Lab</p>
|
||||||
<p class="description">
|
<p class="description">
|
||||||
Multi-tenant service management platform built on .NET 10,
|
Multi-tenant service management platform built on .NET 10,
|
||||||
Kubernetes, and GitOps. Digital signage, telephony IVR,
|
Kubernetes, and GitOps. Digital signage, telephony IVR,
|
||||||
MySQL/PHP hosting, and infrastructure automation.
|
MySQL/PHP hosting, and infrastructure automation.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="services">
|
<div class="services">
|
||||||
<a class="service" href="https://gitea.flowercore.io">
|
<a class="service" href="https://gitea.flowercore.io">
|
||||||
<h3>Source</h3>
|
<h3>Source</h3>
|
||||||
<p>Gitea repositories</p>
|
<p>Gitea repositories</p>
|
||||||
</a>
|
</a>
|
||||||
<a class="service" href="https://webmail.flowercore.io">
|
<a class="service" href="https://webmail.flowercore.io">
|
||||||
<h3>Mail</h3>
|
<h3>Mail</h3>
|
||||||
<p>Webmail access</p>
|
<p>Webmail access</p>
|
||||||
</a>
|
</a>
|
||||||
<a class="service" href="https://element.flowercore.io">
|
<a class="service" href="https://element.flowercore.io">
|
||||||
<h3>Chat</h3>
|
<h3>Chat</h3>
|
||||||
<p>Matrix messaging</p>
|
<p>Matrix messaging</p>
|
||||||
</a>
|
</a>
|
||||||
<a class="service" href="https://github.com/FlowerCoreIO">
|
<a class="service" href="https://github.com/FlowerCoreIO">
|
||||||
<h3>GitHub</h3>
|
<h3>GitHub</h3>
|
||||||
<p>Open source</p>
|
<p>Open source</p>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="status-bar">
|
<div class="status-bar">
|
||||||
<div class="status-item">
|
<div class="status-item">
|
||||||
<div class="value">17</div>
|
<div class="value">17</div>
|
||||||
<div class="label">Services</div>
|
<div class="label">Services</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="status-item">
|
<div class="status-item">
|
||||||
<div class="value">13</div>
|
<div class="value">13</div>
|
||||||
<div class="label">VLANs</div>
|
<div class="label">VLANs</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="status-item">
|
<div class="status-item">
|
||||||
<div class="value">12k+</div>
|
<div class="value">12k+</div>
|
||||||
<div class="label">Tests</div>
|
<div class="label">Tests</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p class="footer">
|
<p class="footer">
|
||||||
FlowerCore · Bare-metal RKE2 · ArgoCD managed
|
FlowerCore · Bare-metal RKE2 · ArgoCD managed
|
||||||
· <a href="mailto:admin@flowercore.io">Contact</a>
|
· <a href="mailto:admin@flowercore.io">Contact</a>
|
||||||
</p>
|
</p>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
---
|
---
|
||||||
# nginx configuration
|
# nginx configuration
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: ConfigMap
|
kind: ConfigMap
|
||||||
metadata:
|
metadata:
|
||||||
name: fc-landing-nginx-conf
|
name: fc-landing-nginx-conf
|
||||||
namespace: fc-system
|
namespace: fc-system
|
||||||
data:
|
data:
|
||||||
default.conf: |
|
default.conf: |
|
||||||
server {
|
server {
|
||||||
listen 80;
|
listen 80;
|
||||||
server_name _;
|
server_name _;
|
||||||
root /usr/share/nginx/html;
|
root /usr/share/nginx/html;
|
||||||
index index.html;
|
index index.html;
|
||||||
|
|
||||||
location / {
|
location / {
|
||||||
try_files $uri $uri/ =404;
|
try_files $uri $uri/ =404;
|
||||||
}
|
}
|
||||||
|
|
||||||
location /healthz {
|
location /healthz {
|
||||||
access_log off;
|
access_log off;
|
||||||
return 200 "ok";
|
return 200 "ok";
|
||||||
add_header Content-Type text/plain;
|
add_header Content-Type text/plain;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
---
|
---
|
||||||
# Landing Page Deployment
|
# Landing Page Deployment
|
||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
name: fc-landing
|
name: fc-landing
|
||||||
namespace: fc-system
|
namespace: fc-system
|
||||||
labels:
|
labels:
|
||||||
app: fc-landing
|
app: fc-landing
|
||||||
spec:
|
spec:
|
||||||
replicas: 1
|
replicas: 1
|
||||||
selector:
|
selector:
|
||||||
matchLabels:
|
matchLabels:
|
||||||
app: fc-landing
|
app: fc-landing
|
||||||
template:
|
template:
|
||||||
metadata:
|
metadata:
|
||||||
labels:
|
labels:
|
||||||
app: fc-landing
|
app: fc-landing
|
||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: nginx
|
- name: nginx
|
||||||
image: nginx:alpine
|
image: nginx:alpine
|
||||||
ports:
|
ports:
|
||||||
- containerPort: 80
|
- containerPort: 80
|
||||||
name: http
|
name: http
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
- name: nginx-conf
|
- name: nginx-conf
|
||||||
mountPath: /etc/nginx/conf.d/default.conf
|
mountPath: /etc/nginx/conf.d/default.conf
|
||||||
subPath: default.conf
|
subPath: default.conf
|
||||||
- name: html
|
- name: html
|
||||||
mountPath: /usr/share/nginx/html
|
mountPath: /usr/share/nginx/html
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
memory: 16Mi
|
memory: 16Mi
|
||||||
cpu: 5m
|
cpu: 5m
|
||||||
limits:
|
limits:
|
||||||
memory: 64Mi
|
memory: 64Mi
|
||||||
cpu: 50m
|
cpu: 50m
|
||||||
livenessProbe:
|
livenessProbe:
|
||||||
httpGet:
|
httpGet:
|
||||||
path: /healthz
|
path: /healthz
|
||||||
port: 80
|
port: 80
|
||||||
initialDelaySeconds: 5
|
initialDelaySeconds: 5
|
||||||
periodSeconds: 10
|
periodSeconds: 10
|
||||||
readinessProbe:
|
readinessProbe:
|
||||||
httpGet:
|
httpGet:
|
||||||
path: /healthz
|
path: /healthz
|
||||||
port: 80
|
port: 80
|
||||||
initialDelaySeconds: 3
|
initialDelaySeconds: 3
|
||||||
periodSeconds: 5
|
periodSeconds: 5
|
||||||
volumes:
|
volumes:
|
||||||
- name: nginx-conf
|
- name: nginx-conf
|
||||||
configMap:
|
configMap:
|
||||||
name: fc-landing-nginx-conf
|
name: fc-landing-nginx-conf
|
||||||
- name: html
|
- name: html
|
||||||
configMap:
|
configMap:
|
||||||
name: fc-landing-html
|
name: fc-landing-html
|
||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Service
|
kind: Service
|
||||||
metadata:
|
metadata:
|
||||||
name: fc-landing
|
name: fc-landing
|
||||||
namespace: fc-system
|
namespace: fc-system
|
||||||
spec:
|
spec:
|
||||||
selector:
|
selector:
|
||||||
app: fc-landing
|
app: fc-landing
|
||||||
ports:
|
ports:
|
||||||
- port: 80
|
- port: 80
|
||||||
targetPort: 80
|
targetPort: 80
|
||||||
name: http
|
name: http
|
||||||
---
|
---
|
||||||
# Internal IngressRoute (LAN access)
|
# Internal IngressRoute (LAN access)
|
||||||
apiVersion: traefik.io/v1alpha1
|
apiVersion: traefik.io/v1alpha1
|
||||||
kind: IngressRoute
|
kind: IngressRoute
|
||||||
metadata:
|
metadata:
|
||||||
name: fc-landing
|
name: fc-landing
|
||||||
namespace: fc-system
|
namespace: fc-system
|
||||||
spec:
|
spec:
|
||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- match: Host(`flowercore.iamworkin.lan`)
|
- match: Host(`flowercore.iamworkin.lan`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
services:
|
services:
|
||||||
- name: fc-landing
|
- name: fc-landing
|
||||||
port: 80
|
port: 80
|
||||||
tls: {}
|
tls: {}
|
||||||
---
|
---
|
||||||
# Public IngressRoute (flowercore.io with Cloudflare origin cert)
|
# Public IngressRoute (flowercore.io with Cloudflare origin cert)
|
||||||
apiVersion: traefik.io/v1alpha1
|
apiVersion: traefik.io/v1alpha1
|
||||||
kind: IngressRoute
|
kind: IngressRoute
|
||||||
metadata:
|
metadata:
|
||||||
name: fc-landing-public
|
name: fc-landing-public
|
||||||
namespace: fc-system
|
namespace: fc-system
|
||||||
spec:
|
spec:
|
||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- match: Host(`flowercore.io`) || Host(`www.flowercore.io`)
|
- match: Host(`flowercore.io`) || Host(`www.flowercore.io`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
services:
|
services:
|
||||||
- name: fc-landing
|
- name: fc-landing
|
||||||
port: 80
|
port: 80
|
||||||
tls:
|
tls:
|
||||||
secretName: cf-origin-flowercore-io
|
secretName: cf-origin-flowercore-io
|
||||||
---
|
---
|
||||||
# HTTP to HTTPS redirect for public domain
|
# HTTP to HTTPS redirect for public domain
|
||||||
apiVersion: traefik.io/v1alpha1
|
apiVersion: traefik.io/v1alpha1
|
||||||
kind: IngressRoute
|
kind: IngressRoute
|
||||||
metadata:
|
metadata:
|
||||||
name: fc-landing-public-http
|
name: fc-landing-public-http
|
||||||
namespace: fc-system
|
namespace: fc-system
|
||||||
spec:
|
spec:
|
||||||
entryPoints:
|
entryPoints:
|
||||||
- web
|
- web
|
||||||
routes:
|
routes:
|
||||||
- match: Host(`flowercore.io`) || Host(`www.flowercore.io`)
|
- match: Host(`flowercore.io`) || Host(`www.flowercore.io`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
services:
|
services:
|
||||||
- name: fc-landing
|
- name: fc-landing
|
||||||
port: 80
|
port: 80
|
||||||
middlewares:
|
middlewares:
|
||||||
- name: redirect-https
|
- name: redirect-https
|
||||||
---
|
---
|
||||||
apiVersion: traefik.io/v1alpha1
|
apiVersion: traefik.io/v1alpha1
|
||||||
kind: Middleware
|
kind: Middleware
|
||||||
metadata:
|
metadata:
|
||||||
name: redirect-https
|
name: redirect-https
|
||||||
namespace: fc-system
|
namespace: fc-system
|
||||||
spec:
|
spec:
|
||||||
redirectScheme:
|
redirectScheme:
|
||||||
scheme: https
|
scheme: https
|
||||||
permanent: true
|
permanent: true
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
# Gitea Public IngressRoute
|
# Gitea Public IngressRoute
|
||||||
# Routes gitea.flowercore.io to internal Gitea service via Cloudflare origin cert
|
# Routes gitea.flowercore.io to internal Gitea service via Cloudflare origin cert
|
||||||
# ArgoCD managed - BlueJay Lab
|
# ArgoCD managed - BlueJay Lab
|
||||||
---
|
---
|
||||||
apiVersion: traefik.io/v1alpha1
|
apiVersion: traefik.io/v1alpha1
|
||||||
kind: IngressRoute
|
kind: IngressRoute
|
||||||
metadata:
|
metadata:
|
||||||
name: gitea-public
|
name: gitea-public
|
||||||
namespace: gitea
|
namespace: gitea
|
||||||
spec:
|
spec:
|
||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- match: Host(`gitea.flowercore.io`)
|
- match: Host(`gitea.flowercore.io`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
services:
|
services:
|
||||||
- name: gitea-http
|
- name: gitea-http
|
||||||
port: 3000
|
port: 3000
|
||||||
tls:
|
tls:
|
||||||
secretName: cf-origin-flowercore-io
|
secretName: cf-origin-flowercore-io
|
||||||
|
|||||||
@@ -1,426 +1,344 @@
|
|||||||
# Apache Guacamole - Blue Jay Remote Access
|
# Apache Guacamole - Remote Desktop Gateway
|
||||||
# FlowerCore Infrastructure Gateway
|
# MySQL 8 + guacd + guacamole web
|
||||||
# MySQL 8 + guacd + guacamole web (Blue Jay branded)
|
# ArgoCD managed - BlueJay Lab
|
||||||
# ArgoCD managed - BlueJay Lab
|
# ALL credentials sourced from 1Password via OnePasswordItem CRD (guacamole-credentials)
|
||||||
# ALL credentials sourced from 1Password via OnePasswordItem CRD (guacamole-credentials)
|
# Fields: username, password, DB-User, DB-Password, DB-Root-Password, DB-Name, URL
|
||||||
# Custom image: fc-guacamole:bluejay (Blue Jay branding + 1Password vault extension)
|
---
|
||||||
---
|
apiVersion: v1
|
||||||
apiVersion: v1
|
kind: Namespace
|
||||||
kind: Namespace
|
metadata:
|
||||||
metadata:
|
name: guacamole
|
||||||
name: guacamole
|
labels:
|
||||||
labels:
|
app.kubernetes.io/part-of: bluejay-infra
|
||||||
app.kubernetes.io/part-of: bluejay-infra
|
---
|
||||||
---
|
# MySQL 8 StatefulSet
|
||||||
# MySQL 8 StatefulSet
|
apiVersion: apps/v1
|
||||||
apiVersion: apps/v1
|
kind: StatefulSet
|
||||||
kind: StatefulSet
|
metadata:
|
||||||
metadata:
|
name: guac-mysql
|
||||||
name: guac-mysql
|
namespace: guacamole
|
||||||
namespace: guacamole
|
labels:
|
||||||
labels:
|
app: guac-mysql
|
||||||
app: guac-mysql
|
spec:
|
||||||
spec:
|
serviceName: guac-mysql
|
||||||
serviceName: guac-mysql
|
replicas: 1
|
||||||
replicas: 1
|
selector:
|
||||||
selector:
|
matchLabels:
|
||||||
matchLabels:
|
app: guac-mysql
|
||||||
app: guac-mysql
|
template:
|
||||||
template:
|
metadata:
|
||||||
metadata:
|
labels:
|
||||||
labels:
|
app: guac-mysql
|
||||||
app: guac-mysql
|
spec:
|
||||||
spec:
|
containers:
|
||||||
containers:
|
- name: mysql
|
||||||
- name: mysql
|
image: mysql:8.0
|
||||||
image: mysql:8.0
|
ports:
|
||||||
ports:
|
- containerPort: 3306
|
||||||
- containerPort: 3306
|
name: mysql
|
||||||
name: mysql
|
env:
|
||||||
env:
|
- name: MYSQL_ROOT_PASSWORD
|
||||||
- name: MYSQL_ROOT_PASSWORD
|
valueFrom:
|
||||||
valueFrom:
|
secretKeyRef:
|
||||||
secretKeyRef:
|
name: guacamole-credentials
|
||||||
name: guacamole-credentials
|
key: DB-Root-Password
|
||||||
key: DB-Root-Password
|
- name: MYSQL_DATABASE
|
||||||
- name: MYSQL_DATABASE
|
valueFrom:
|
||||||
valueFrom:
|
secretKeyRef:
|
||||||
secretKeyRef:
|
name: guacamole-credentials
|
||||||
name: guacamole-credentials
|
key: DB-Name
|
||||||
key: DB-Name
|
- name: MYSQL_USER
|
||||||
- name: MYSQL_USER
|
valueFrom:
|
||||||
valueFrom:
|
secretKeyRef:
|
||||||
secretKeyRef:
|
name: guacamole-credentials
|
||||||
name: guacamole-credentials
|
key: DB-User
|
||||||
key: DB-User
|
- name: MYSQL_PASSWORD
|
||||||
- name: MYSQL_PASSWORD
|
valueFrom:
|
||||||
valueFrom:
|
secretKeyRef:
|
||||||
secretKeyRef:
|
name: guacamole-credentials
|
||||||
name: guacamole-credentials
|
key: DB-Password
|
||||||
key: DB-Password
|
volumeMounts:
|
||||||
volumeMounts:
|
- name: guac-mysql-data
|
||||||
- name: guac-mysql-data
|
mountPath: /var/lib/mysql
|
||||||
mountPath: /var/lib/mysql
|
resources:
|
||||||
resources:
|
requests:
|
||||||
requests:
|
memory: 256Mi
|
||||||
memory: 256Mi
|
cpu: 100m
|
||||||
cpu: 100m
|
limits:
|
||||||
limits:
|
memory: 1Gi
|
||||||
memory: 1Gi
|
cpu: 500m
|
||||||
cpu: 500m
|
livenessProbe:
|
||||||
livenessProbe:
|
exec:
|
||||||
exec:
|
command:
|
||||||
command:
|
- mysqladmin
|
||||||
- mysqladmin
|
- ping
|
||||||
- ping
|
- -h
|
||||||
- -h
|
- localhost
|
||||||
- localhost
|
initialDelaySeconds: 60
|
||||||
initialDelaySeconds: 60
|
periodSeconds: 10
|
||||||
periodSeconds: 10
|
readinessProbe:
|
||||||
readinessProbe:
|
exec:
|
||||||
exec:
|
command:
|
||||||
command:
|
- mysqladmin
|
||||||
- mysqladmin
|
- ping
|
||||||
- ping
|
- -h
|
||||||
- -h
|
- localhost
|
||||||
- localhost
|
initialDelaySeconds: 30
|
||||||
initialDelaySeconds: 30
|
periodSeconds: 5
|
||||||
periodSeconds: 5
|
volumeClaimTemplates:
|
||||||
volumeClaimTemplates:
|
- metadata:
|
||||||
- metadata:
|
name: guac-mysql-data
|
||||||
name: guac-mysql-data
|
spec:
|
||||||
spec:
|
accessModes: [ReadWriteOnce]
|
||||||
accessModes: [ReadWriteOnce]
|
resources:
|
||||||
resources:
|
requests:
|
||||||
requests:
|
storage: 5Gi
|
||||||
storage: 5Gi
|
---
|
||||||
---
|
apiVersion: v1
|
||||||
apiVersion: v1
|
kind: Service
|
||||||
kind: Service
|
metadata:
|
||||||
metadata:
|
name: guac-mysql
|
||||||
name: guac-mysql
|
namespace: guacamole
|
||||||
namespace: guacamole
|
spec:
|
||||||
spec:
|
selector:
|
||||||
selector:
|
app: guac-mysql
|
||||||
app: guac-mysql
|
ports:
|
||||||
ports:
|
- port: 3306
|
||||||
- port: 3306
|
targetPort: 3306
|
||||||
targetPort: 3306
|
name: mysql
|
||||||
name: mysql
|
clusterIP: None
|
||||||
clusterIP: None
|
---
|
||||||
---
|
# DB schema init Job
|
||||||
# DB schema init Job
|
# Generates the MySQL schema and pipes it into the database
|
||||||
apiVersion: batch/v1
|
apiVersion: batch/v1
|
||||||
kind: Job
|
kind: Job
|
||||||
metadata:
|
metadata:
|
||||||
name: guacamole-initdb
|
name: guacamole-initdb
|
||||||
namespace: guacamole
|
namespace: guacamole
|
||||||
annotations:
|
annotations:
|
||||||
argocd.argoproj.io/hook: PostSync
|
argocd.argoproj.io/hook: PostSync
|
||||||
argocd.argoproj.io/hook-delete-policy: BeforeHookCreation
|
argocd.argoproj.io/hook-delete-policy: BeforeHookCreation
|
||||||
spec:
|
spec:
|
||||||
ttlSecondsAfterFinished: 300
|
ttlSecondsAfterFinished: 300
|
||||||
template:
|
template:
|
||||||
spec:
|
spec:
|
||||||
restartPolicy: OnFailure
|
restartPolicy: OnFailure
|
||||||
initContainers:
|
initContainers:
|
||||||
- name: wait-for-mysql
|
- name: wait-for-mysql
|
||||||
image: mysql:8.0
|
image: mysql:8.0
|
||||||
command:
|
command:
|
||||||
- sh
|
- sh
|
||||||
- -c
|
- -c
|
||||||
- |
|
- |
|
||||||
until mysqladmin ping -h guac-mysql --silent; do
|
until mysqladmin ping -h guac-mysql --silent; do
|
||||||
echo "Waiting for MySQL..."
|
echo "Waiting for MySQL..."
|
||||||
sleep 5
|
sleep 5
|
||||||
done
|
done
|
||||||
containers:
|
containers:
|
||||||
- name: initdb
|
- name: initdb
|
||||||
image: guacamole/guacamole:latest
|
image: guacamole/guacamole:latest
|
||||||
command:
|
command:
|
||||||
- sh
|
- sh
|
||||||
- -c
|
- -c
|
||||||
- |
|
- |
|
||||||
/opt/guacamole/bin/initdb.sh --mysql > /tmp/initdb.sql
|
# Generate schema SQL
|
||||||
mysql -h guac-mysql -u root -p"$MYSQL_ROOT_PASSWORD" "$MYSQL_DATABASE" < /tmp/initdb.sql || true
|
/opt/guacamole/bin/initdb.sh --mysql > /tmp/initdb.sql
|
||||||
env:
|
# Apply schema (ignore errors if tables already exist)
|
||||||
- name: MYSQL_ROOT_PASSWORD
|
mysql -h guac-mysql -u root -p"$MYSQL_ROOT_PASSWORD" "$MYSQL_DATABASE" < /tmp/initdb.sql || true
|
||||||
valueFrom:
|
env:
|
||||||
secretKeyRef:
|
- name: MYSQL_ROOT_PASSWORD
|
||||||
name: guacamole-credentials
|
valueFrom:
|
||||||
key: DB-Root-Password
|
secretKeyRef:
|
||||||
- name: MYSQL_DATABASE
|
name: guacamole-credentials
|
||||||
valueFrom:
|
key: DB-Root-Password
|
||||||
secretKeyRef:
|
- name: MYSQL_DATABASE
|
||||||
name: guacamole-credentials
|
valueFrom:
|
||||||
key: DB-Name
|
secretKeyRef:
|
||||||
---
|
name: guacamole-credentials
|
||||||
# guacd (Guacamole daemon)
|
key: DB-Name
|
||||||
apiVersion: apps/v1
|
---
|
||||||
kind: Deployment
|
# guacd (Guacamole daemon)
|
||||||
metadata:
|
apiVersion: apps/v1
|
||||||
name: guacd
|
kind: Deployment
|
||||||
namespace: guacamole
|
metadata:
|
||||||
labels:
|
name: guacd
|
||||||
app: guacd
|
namespace: guacamole
|
||||||
spec:
|
labels:
|
||||||
replicas: 1
|
app: guacd
|
||||||
selector:
|
spec:
|
||||||
matchLabels:
|
replicas: 1
|
||||||
app: guacd
|
selector:
|
||||||
template:
|
matchLabels:
|
||||||
metadata:
|
app: guacd
|
||||||
labels:
|
template:
|
||||||
app: guacd
|
metadata:
|
||||||
spec:
|
labels:
|
||||||
containers:
|
app: guacd
|
||||||
serviceAccountName: guacd-exec
|
spec:
|
||||||
- name: guacd
|
containers:
|
||||||
image: guacamole/guacd:latest
|
- name: guacd
|
||||||
ports:
|
image: guacamole/guacd:latest
|
||||||
- containerPort: 4822
|
ports:
|
||||||
name: guacd
|
- containerPort: 4822
|
||||||
resources:
|
name: guacd
|
||||||
requests:
|
resources:
|
||||||
memory: 128Mi
|
requests:
|
||||||
cpu: 100m
|
memory: 128Mi
|
||||||
limits:
|
cpu: 100m
|
||||||
memory: 512Mi
|
limits:
|
||||||
cpu: 500m
|
memory: 512Mi
|
||||||
livenessProbe:
|
cpu: 500m
|
||||||
tcpSocket:
|
livenessProbe:
|
||||||
port: 4822
|
tcpSocket:
|
||||||
initialDelaySeconds: 15
|
port: 4822
|
||||||
periodSeconds: 10
|
initialDelaySeconds: 15
|
||||||
---
|
periodSeconds: 10
|
||||||
apiVersion: v1
|
---
|
||||||
kind: Service
|
apiVersion: v1
|
||||||
metadata:
|
kind: Service
|
||||||
name: guacd
|
metadata:
|
||||||
namespace: guacamole
|
name: guacd
|
||||||
spec:
|
namespace: guacamole
|
||||||
selector:
|
spec:
|
||||||
app: guacd
|
selector:
|
||||||
ports:
|
app: guacd
|
||||||
- port: 4822
|
ports:
|
||||||
targetPort: 4822
|
- port: 4822
|
||||||
name: guacd
|
targetPort: 4822
|
||||||
---
|
name: guacd
|
||||||
# Guacamole Properties ConfigMap
|
---
|
||||||
apiVersion: v1
|
# Guacamole Web Application
|
||||||
kind: ConfigMap
|
apiVersion: apps/v1
|
||||||
metadata:
|
kind: Deployment
|
||||||
name: guacamole-properties
|
metadata:
|
||||||
namespace: guacamole
|
name: guacamole
|
||||||
labels:
|
namespace: guacamole
|
||||||
app: guacamole
|
labels:
|
||||||
data:
|
app: guacamole
|
||||||
guacamole.properties: |
|
spec:
|
||||||
# Blue Jay Remote Access — Guacamole Configuration
|
replicas: 1
|
||||||
# MySQL/guacd settings provided via env vars — do NOT duplicate here
|
selector:
|
||||||
|
matchLabels:
|
||||||
# 1Password Vault Integration
|
app: guacamole
|
||||||
1password-connect-url: http://onepassword-connect.onepassword-system.svc.cluster.local:8080
|
template:
|
||||||
1password-connect-token: placeholder-configure-via-secret
|
metadata:
|
||||||
1password-vault-id: qaphopopkryhbg353ukzhhuqoq
|
labels:
|
||||||
|
app: guacamole
|
||||||
# Extension Priority
|
spec:
|
||||||
extension-priority: mysql, ban, bluejay, 1password-vault, *
|
containers:
|
||||||
|
- name: guacamole
|
||||||
# Ban (brute force)
|
image: guacamole/guacamole:latest
|
||||||
ban-max-invalid-attempts: 5
|
ports:
|
||||||
ban-address-duration: 300000
|
- containerPort: 8080
|
||||||
ban-max-addresses: 1000
|
name: http
|
||||||
|
env:
|
||||||
# TOTP
|
- name: GUACD_HOSTNAME
|
||||||
totp-issuer: Blue Jay Remote Access
|
value: guacd
|
||||||
totp-digits: 6
|
- name: GUACD_PORT
|
||||||
totp-period: 30
|
value: "4822"
|
||||||
totp-mode: sha256
|
- name: MYSQL_HOSTNAME
|
||||||
|
value: guac-mysql
|
||||||
# Session Recording
|
- name: MYSQL_PORT
|
||||||
recording-search-path: /var/lib/guacamole/recordings
|
value: "3306"
|
||||||
|
- name: MYSQL_DATABASE
|
||||||
# Logging
|
valueFrom:
|
||||||
log-level: info
|
secretKeyRef:
|
||||||
|
name: guacamole-credentials
|
||||||
# API Token Expiry
|
key: DB-Name
|
||||||
api-session-timeout: 60
|
- name: MYSQL_USER
|
||||||
---
|
valueFrom:
|
||||||
# Guacamole Web Application — Blue Jay branded
|
secretKeyRef:
|
||||||
apiVersion: apps/v1
|
name: guacamole-credentials
|
||||||
kind: Deployment
|
key: DB-User
|
||||||
metadata:
|
- name: MYSQL_PASSWORD
|
||||||
name: guacamole
|
valueFrom:
|
||||||
namespace: guacamole
|
secretKeyRef:
|
||||||
labels:
|
name: guacamole-credentials
|
||||||
app: guacamole
|
key: DB-Password
|
||||||
spec:
|
resources:
|
||||||
replicas: 1
|
requests:
|
||||||
selector:
|
memory: 256Mi
|
||||||
matchLabels:
|
cpu: 100m
|
||||||
app: guacamole
|
limits:
|
||||||
template:
|
memory: 1Gi
|
||||||
metadata:
|
cpu: 500m
|
||||||
labels:
|
livenessProbe:
|
||||||
app: guacamole
|
httpGet:
|
||||||
spec:
|
path: /guacamole/
|
||||||
containers:
|
port: 8080
|
||||||
- name: guacamole
|
initialDelaySeconds: 120
|
||||||
image: localhost/fc-guacamole:bluejay
|
periodSeconds: 10
|
||||||
imagePullPolicy: Never
|
readinessProbe:
|
||||||
ports:
|
httpGet:
|
||||||
- containerPort: 8080
|
path: /guacamole/
|
||||||
name: http
|
port: 8080
|
||||||
env:
|
initialDelaySeconds: 60
|
||||||
- name: GUACD_HOSTNAME
|
periodSeconds: 5
|
||||||
value: guacd
|
---
|
||||||
- name: GUACD_PORT
|
apiVersion: v1
|
||||||
value: "4822"
|
kind: Service
|
||||||
- name: MYSQL_HOSTNAME
|
metadata:
|
||||||
value: guac-mysql
|
name: guacamole
|
||||||
- name: MYSQL_PORT
|
namespace: guacamole
|
||||||
value: "3306"
|
spec:
|
||||||
- name: MYSQL_DATABASE
|
selector:
|
||||||
valueFrom:
|
app: guacamole
|
||||||
secretKeyRef:
|
ports:
|
||||||
name: guacamole-credentials
|
- port: 8080
|
||||||
key: DB-Name
|
targetPort: 8080
|
||||||
- name: MYSQL_USER
|
name: http
|
||||||
valueFrom:
|
---
|
||||||
secretKeyRef:
|
# Traefik addPrefix middleware
|
||||||
name: guacamole-credentials
|
# External URL guac.iamworkin.lan/ gets prefix /guacamole added
|
||||||
key: DB-User
|
apiVersion: traefik.io/v1alpha1
|
||||||
- name: MYSQL_PASSWORD
|
kind: Middleware
|
||||||
valueFrom:
|
metadata:
|
||||||
secretKeyRef:
|
name: guac-add-prefix
|
||||||
name: guacamole-credentials
|
namespace: guacamole
|
||||||
key: DB-Password
|
spec:
|
||||||
volumeMounts:
|
addPrefix:
|
||||||
- name: guac-properties
|
prefix: /guacamole
|
||||||
mountPath: /etc/guacamole/guacamole.properties
|
---
|
||||||
subPath: guacamole.properties
|
# TLS Certificate via cert-manager
|
||||||
resources:
|
apiVersion: cert-manager.io/v1
|
||||||
requests:
|
kind: Certificate
|
||||||
memory: 256Mi
|
metadata:
|
||||||
cpu: 100m
|
name: guacamole-tls
|
||||||
limits:
|
namespace: guacamole
|
||||||
memory: 1Gi
|
spec:
|
||||||
cpu: 500m
|
secretName: guacamole-tls
|
||||||
livenessProbe:
|
issuerRef:
|
||||||
httpGet:
|
name: step-ca-acme
|
||||||
path: /guacamole/
|
kind: ClusterIssuer
|
||||||
port: 8080
|
dnsNames:
|
||||||
initialDelaySeconds: 120
|
- guac.iamworkin.lan
|
||||||
periodSeconds: 10
|
---
|
||||||
readinessProbe:
|
# Traefik IngressRoute
|
||||||
httpGet:
|
apiVersion: traefik.io/v1alpha1
|
||||||
path: /guacamole/
|
kind: IngressRoute
|
||||||
port: 8080
|
metadata:
|
||||||
initialDelaySeconds: 60
|
name: guacamole
|
||||||
periodSeconds: 5
|
namespace: guacamole
|
||||||
volumes:
|
spec:
|
||||||
- name: guac-properties
|
entryPoints:
|
||||||
configMap:
|
- websecure
|
||||||
name: guacamole-properties
|
routes:
|
||||||
---
|
- match: Host(`guac.iamworkin.lan`)
|
||||||
apiVersion: v1
|
kind: Rule
|
||||||
kind: Service
|
middlewares:
|
||||||
metadata:
|
- name: guac-add-prefix
|
||||||
name: guacamole
|
services:
|
||||||
namespace: guacamole
|
- name: guacamole
|
||||||
spec:
|
port: 8080
|
||||||
selector:
|
tls:
|
||||||
app: guacamole
|
secretName: guacamole-tls
|
||||||
ports:
|
---
|
||||||
- port: 8080
|
# 1Password secret sync — creates guacamole-credentials K8s Secret
|
||||||
targetPort: 8080
|
# Fields: username, password, DB-User, DB-Password, DB-Root-Password, DB-Name, URL
|
||||||
name: http
|
apiVersion: onepassword.com/v1
|
||||||
---
|
kind: OnePasswordItem
|
||||||
# Traefik addPrefix middleware
|
metadata:
|
||||||
apiVersion: traefik.io/v1alpha1
|
name: guacamole-credentials
|
||||||
kind: Middleware
|
namespace: guacamole
|
||||||
metadata:
|
spec:
|
||||||
name: guac-add-prefix
|
itemPath: vaults/IAmWorkin/items/Guacamole
|
||||||
namespace: guacamole
|
|
||||||
spec:
|
|
||||||
addPrefix:
|
|
||||||
prefix: /guacamole
|
|
||||||
---
|
|
||||||
# TLS Certificate via cert-manager
|
|
||||||
apiVersion: cert-manager.io/v1
|
|
||||||
kind: Certificate
|
|
||||||
metadata:
|
|
||||||
name: guacamole-tls
|
|
||||||
namespace: guacamole
|
|
||||||
spec:
|
|
||||||
secretName: guacamole-tls
|
|
||||||
issuerRef:
|
|
||||||
name: step-ca-acme
|
|
||||||
kind: ClusterIssuer
|
|
||||||
dnsNames:
|
|
||||||
- guac.iamworkin.lan
|
|
||||||
---
|
|
||||||
# Traefik IngressRoute
|
|
||||||
apiVersion: traefik.io/v1alpha1
|
|
||||||
kind: IngressRoute
|
|
||||||
metadata:
|
|
||||||
name: guacamole
|
|
||||||
namespace: guacamole
|
|
||||||
spec:
|
|
||||||
entryPoints:
|
|
||||||
- websecure
|
|
||||||
routes:
|
|
||||||
- match: Host(`guac.iamworkin.lan`)
|
|
||||||
kind: Rule
|
|
||||||
middlewares:
|
|
||||||
- name: guac-add-prefix
|
|
||||||
services:
|
|
||||||
- name: guacamole
|
|
||||||
port: 8080
|
|
||||||
tls:
|
|
||||||
secretName: guacamole-tls
|
|
||||||
---
|
|
||||||
# 1Password secret sync
|
|
||||||
apiVersion: onepassword.com/v1
|
|
||||||
kind: OnePasswordItem
|
|
||||||
metadata:
|
|
||||||
name: guacamole-credentials
|
|
||||||
namespace: guacamole
|
|
||||||
spec:
|
|
||||||
itemPath: vaults/IAmWorkin/items/Guacamole
|
|
||||||
---
|
|
||||||
# RBAC for guacd K8s exec protocol
|
|
||||||
apiVersion: v1
|
|
||||||
kind: ServiceAccount
|
|
||||||
metadata:
|
|
||||||
name: guacd-exec
|
|
||||||
namespace: guacamole
|
|
||||||
---
|
|
||||||
apiVersion: rbac.authorization.k8s.io/v1
|
|
||||||
kind: ClusterRole
|
|
||||||
metadata:
|
|
||||||
name: guacd-pod-exec
|
|
||||||
rules:
|
|
||||||
- apiGroups: [""]
|
|
||||||
resources: ["pods"]
|
|
||||||
verbs: ["get", "list"]
|
|
||||||
- apiGroups: [""]
|
|
||||||
resources: ["pods/exec"]
|
|
||||||
verbs: ["create"]
|
|
||||||
- apiGroups: [""]
|
|
||||||
resources: ["namespaces"]
|
|
||||||
verbs: ["list"]
|
|
||||||
---
|
|
||||||
apiVersion: rbac.authorization.k8s.io/v1
|
|
||||||
kind: ClusterRoleBinding
|
|
||||||
metadata:
|
|
||||||
name: guacd-pod-exec
|
|
||||||
subjects:
|
|
||||||
- kind: ServiceAccount
|
|
||||||
name: guacd-exec
|
|
||||||
namespace: guacamole
|
|
||||||
roleRef:
|
|
||||||
kind: ClusterRole
|
|
||||||
name: guacd-pod-exec
|
|
||||||
apiGroup: rbac.authorization.k8s.io
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
1362
apps/irc/irc.yaml
1362
apps/irc/irc.yaml
File diff suppressed because it is too large
Load Diff
@@ -1,259 +1,259 @@
|
|||||||
# docker-mailserver - Postfix + Dovecot + rspamd
|
# docker-mailserver - Postfix + Dovecot + rspamd
|
||||||
# ArgoCD managed - BlueJay Lab
|
# ArgoCD managed - BlueJay Lab
|
||||||
# Credentials: 1Password → OnePasswordItem CRD → K8s Secret
|
# Credentials: 1Password → OnePasswordItem CRD → K8s Secret
|
||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Namespace
|
kind: Namespace
|
||||||
metadata:
|
metadata:
|
||||||
name: mail
|
name: mail
|
||||||
labels:
|
labels:
|
||||||
app.kubernetes.io/part-of: bluejay-infra
|
app.kubernetes.io/part-of: bluejay-infra
|
||||||
---
|
---
|
||||||
# 1Password → K8s Secret sync for mail credentials
|
# 1Password → K8s Secret sync for mail credentials
|
||||||
apiVersion: onepassword.com/v1
|
apiVersion: onepassword.com/v1
|
||||||
kind: OnePasswordItem
|
kind: OnePasswordItem
|
||||||
metadata:
|
metadata:
|
||||||
name: mail-credentials
|
name: mail-credentials
|
||||||
namespace: mail
|
namespace: mail
|
||||||
spec:
|
spec:
|
||||||
itemPath: "vaults/IAmWorkin/items/Mail Postmaster"
|
itemPath: "vaults/IAmWorkin/items/Mail Postmaster"
|
||||||
---
|
---
|
||||||
# Mail data PVC
|
# Mail data PVC
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: PersistentVolumeClaim
|
kind: PersistentVolumeClaim
|
||||||
metadata:
|
metadata:
|
||||||
name: mail-data
|
name: mail-data
|
||||||
namespace: mail
|
namespace: mail
|
||||||
spec:
|
spec:
|
||||||
accessModes: [ReadWriteOnce]
|
accessModes: [ReadWriteOnce]
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
storage: 5Gi
|
storage: 5Gi
|
||||||
---
|
---
|
||||||
# Mail state PVC
|
# Mail state PVC
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: PersistentVolumeClaim
|
kind: PersistentVolumeClaim
|
||||||
metadata:
|
metadata:
|
||||||
name: mail-state
|
name: mail-state
|
||||||
namespace: mail
|
namespace: mail
|
||||||
spec:
|
spec:
|
||||||
accessModes: [ReadWriteOnce]
|
accessModes: [ReadWriteOnce]
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
storage: 1Gi
|
storage: 1Gi
|
||||||
---
|
---
|
||||||
# docker-mailserver Deployment
|
# docker-mailserver Deployment
|
||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
name: mailserver
|
name: mailserver
|
||||||
namespace: mail
|
namespace: mail
|
||||||
labels:
|
labels:
|
||||||
app: mailserver
|
app: mailserver
|
||||||
spec:
|
spec:
|
||||||
replicas: 1
|
replicas: 1
|
||||||
strategy:
|
strategy:
|
||||||
type: Recreate
|
type: Recreate
|
||||||
selector:
|
selector:
|
||||||
matchLabels:
|
matchLabels:
|
||||||
app: mailserver
|
app: mailserver
|
||||||
template:
|
template:
|
||||||
metadata:
|
metadata:
|
||||||
labels:
|
labels:
|
||||||
app: mailserver
|
app: mailserver
|
||||||
spec:
|
spec:
|
||||||
hostname: mail
|
hostname: mail
|
||||||
initContainers:
|
initContainers:
|
||||||
- name: inject-accounts
|
- name: inject-accounts
|
||||||
image: busybox:1.36
|
image: busybox:1.36
|
||||||
command:
|
command:
|
||||||
- sh
|
- sh
|
||||||
- -c
|
- -c
|
||||||
- |
|
- |
|
||||||
ADMIN_EMAIL=$(cat /credentials/Admin-Email)
|
ADMIN_EMAIL=$(cat /credentials/Admin-Email)
|
||||||
ADMIN_HASH=$(cat /credentials/Admin-Hash)
|
ADMIN_HASH=$(cat /credentials/Admin-Hash)
|
||||||
NOREPLY_EMAIL=$(cat /credentials/Noreply-Email)
|
NOREPLY_EMAIL=$(cat /credentials/Noreply-Email)
|
||||||
NOREPLY_HASH=$(cat /credentials/Noreply-Hash)
|
NOREPLY_HASH=$(cat /credentials/Noreply-Hash)
|
||||||
echo "${ADMIN_EMAIL}|${ADMIN_HASH}" > /accounts/postfix-accounts.cf
|
echo "${ADMIN_EMAIL}|${ADMIN_HASH}" > /accounts/postfix-accounts.cf
|
||||||
echo "${NOREPLY_EMAIL}|${NOREPLY_HASH}" >> /accounts/postfix-accounts.cf
|
echo "${NOREPLY_EMAIL}|${NOREPLY_HASH}" >> /accounts/postfix-accounts.cf
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
- name: mail-credentials
|
- name: mail-credentials
|
||||||
mountPath: /credentials
|
mountPath: /credentials
|
||||||
readOnly: true
|
readOnly: true
|
||||||
- name: mail-accounts-generated
|
- name: mail-accounts-generated
|
||||||
mountPath: /accounts
|
mountPath: /accounts
|
||||||
containers:
|
containers:
|
||||||
- name: mailserver
|
- name: mailserver
|
||||||
image: docker.io/mailserver/docker-mailserver:latest
|
image: docker.io/mailserver/docker-mailserver:latest
|
||||||
ports:
|
ports:
|
||||||
- containerPort: 25
|
- containerPort: 25
|
||||||
name: smtp
|
name: smtp
|
||||||
- containerPort: 465
|
- containerPort: 465
|
||||||
name: smtps
|
name: smtps
|
||||||
- containerPort: 587
|
- containerPort: 587
|
||||||
name: submission
|
name: submission
|
||||||
- containerPort: 143
|
- containerPort: 143
|
||||||
name: imap
|
name: imap
|
||||||
- containerPort: 993
|
- containerPort: 993
|
||||||
name: imaps
|
name: imaps
|
||||||
env:
|
env:
|
||||||
- name: ENABLE_SPAMASSASSIN
|
- name: ENABLE_SPAMASSASSIN
|
||||||
value: "1"
|
value: "1"
|
||||||
- name: ENABLE_CLAMAV
|
- name: ENABLE_CLAMAV
|
||||||
value: "0"
|
value: "0"
|
||||||
- name: ENABLE_RSPAMD
|
- name: ENABLE_RSPAMD
|
||||||
value: "1"
|
value: "1"
|
||||||
- name: TZ
|
- name: TZ
|
||||||
value: America/Chicago
|
value: America/Chicago
|
||||||
- name: POSTMASTER_ADDRESS
|
- name: POSTMASTER_ADDRESS
|
||||||
value: postmaster@iamwork.in
|
value: postmaster@iamwork.in
|
||||||
- name: OVERRIDE_HOSTNAME
|
- name: OVERRIDE_HOSTNAME
|
||||||
value: mail.iamwork.in
|
value: mail.iamwork.in
|
||||||
- name: ENABLE_FAIL2BAN
|
- name: ENABLE_FAIL2BAN
|
||||||
value: "0"
|
value: "0"
|
||||||
- name: ENABLE_POSTGREY
|
- name: ENABLE_POSTGREY
|
||||||
value: "0"
|
value: "0"
|
||||||
- name: ONE_DIR
|
- name: ONE_DIR
|
||||||
value: "1"
|
value: "1"
|
||||||
- name: PERMIT_DOCKER
|
- name: PERMIT_DOCKER
|
||||||
value: network
|
value: network
|
||||||
- name: SSL_TYPE
|
- name: SSL_TYPE
|
||||||
value: manual
|
value: manual
|
||||||
- name: SSL_CERT_PATH
|
- name: SSL_CERT_PATH
|
||||||
value: /etc/ssl/mail/tls.crt
|
value: /etc/ssl/mail/tls.crt
|
||||||
- name: SSL_KEY_PATH
|
- name: SSL_KEY_PATH
|
||||||
value: /etc/ssl/mail/tls.key
|
value: /etc/ssl/mail/tls.key
|
||||||
- name: ACCOUNT_PROVISIONER
|
- name: ACCOUNT_PROVISIONER
|
||||||
value: FILE
|
value: FILE
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
- name: mail-data
|
- name: mail-data
|
||||||
mountPath: /var/mail
|
mountPath: /var/mail
|
||||||
- name: mail-state
|
- name: mail-state
|
||||||
mountPath: /var/mail-state
|
mountPath: /var/mail-state
|
||||||
- name: mail-tls
|
- name: mail-tls
|
||||||
mountPath: /etc/ssl/mail
|
mountPath: /etc/ssl/mail
|
||||||
readOnly: true
|
readOnly: true
|
||||||
- name: mail-accounts-generated
|
- name: mail-accounts-generated
|
||||||
mountPath: /tmp/docker-mailserver/postfix-accounts.cf
|
mountPath: /tmp/docker-mailserver/postfix-accounts.cf
|
||||||
subPath: postfix-accounts.cf
|
subPath: postfix-accounts.cf
|
||||||
readOnly: true
|
readOnly: true
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
memory: 512Mi
|
memory: 512Mi
|
||||||
cpu: 200m
|
cpu: 200m
|
||||||
limits:
|
limits:
|
||||||
memory: 2Gi
|
memory: 2Gi
|
||||||
cpu: "1"
|
cpu: "1"
|
||||||
securityContext:
|
securityContext:
|
||||||
capabilities:
|
capabilities:
|
||||||
add:
|
add:
|
||||||
- NET_ADMIN
|
- NET_ADMIN
|
||||||
- SYS_PTRACE
|
- SYS_PTRACE
|
||||||
volumes:
|
volumes:
|
||||||
- name: mail-data
|
- name: mail-data
|
||||||
persistentVolumeClaim:
|
persistentVolumeClaim:
|
||||||
claimName: mail-data
|
claimName: mail-data
|
||||||
- name: mail-state
|
- name: mail-state
|
||||||
persistentVolumeClaim:
|
persistentVolumeClaim:
|
||||||
claimName: mail-state
|
claimName: mail-state
|
||||||
- name: mail-tls
|
- name: mail-tls
|
||||||
secret:
|
secret:
|
||||||
secretName: mail-tls
|
secretName: mail-tls
|
||||||
- name: mail-credentials
|
- name: mail-credentials
|
||||||
secret:
|
secret:
|
||||||
secretName: mail-credentials
|
secretName: mail-credentials
|
||||||
- name: mail-accounts-generated
|
- name: mail-accounts-generated
|
||||||
emptyDir: {}
|
emptyDir: {}
|
||||||
---
|
---
|
||||||
# SMTP LoadBalancer Service (external)
|
# SMTP LoadBalancer Service (external)
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Service
|
kind: Service
|
||||||
metadata:
|
metadata:
|
||||||
name: mail-smtp
|
name: mail-smtp
|
||||||
namespace: mail
|
namespace: mail
|
||||||
annotations:
|
annotations:
|
||||||
metallb.universe.tf/loadBalancerIPs: 10.0.56.202
|
metallb.universe.tf/loadBalancerIPs: 10.0.56.202
|
||||||
spec:
|
spec:
|
||||||
type: LoadBalancer
|
type: LoadBalancer
|
||||||
selector:
|
selector:
|
||||||
app: mailserver
|
app: mailserver
|
||||||
ports:
|
ports:
|
||||||
- port: 25
|
- port: 25
|
||||||
targetPort: 25
|
targetPort: 25
|
||||||
name: smtp
|
name: smtp
|
||||||
protocol: TCP
|
protocol: TCP
|
||||||
- port: 465
|
- port: 465
|
||||||
targetPort: 465
|
targetPort: 465
|
||||||
name: smtps
|
name: smtps
|
||||||
protocol: TCP
|
protocol: TCP
|
||||||
- port: 587
|
- port: 587
|
||||||
targetPort: 587
|
targetPort: 587
|
||||||
name: submission
|
name: submission
|
||||||
protocol: TCP
|
protocol: TCP
|
||||||
---
|
---
|
||||||
# IMAP ClusterIP Service (internal)
|
# IMAP ClusterIP Service (internal)
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Service
|
kind: Service
|
||||||
metadata:
|
metadata:
|
||||||
name: mail-imap
|
name: mail-imap
|
||||||
namespace: mail
|
namespace: mail
|
||||||
spec:
|
spec:
|
||||||
selector:
|
selector:
|
||||||
app: mailserver
|
app: mailserver
|
||||||
ports:
|
ports:
|
||||||
- port: 143
|
- port: 143
|
||||||
targetPort: 143
|
targetPort: 143
|
||||||
name: imap
|
name: imap
|
||||||
- port: 993
|
- port: 993
|
||||||
targetPort: 993
|
targetPort: 993
|
||||||
name: imaps
|
name: imaps
|
||||||
---
|
---
|
||||||
# TLS Certificate via cert-manager
|
# TLS Certificate via cert-manager
|
||||||
apiVersion: cert-manager.io/v1
|
apiVersion: cert-manager.io/v1
|
||||||
kind: Certificate
|
kind: Certificate
|
||||||
metadata:
|
metadata:
|
||||||
name: mail-tls
|
name: mail-tls
|
||||||
namespace: mail
|
namespace: mail
|
||||||
spec:
|
spec:
|
||||||
secretName: mail-tls
|
secretName: mail-tls
|
||||||
issuerRef:
|
issuerRef:
|
||||||
name: step-ca-acme
|
name: step-ca-acme
|
||||||
kind: ClusterIssuer
|
kind: ClusterIssuer
|
||||||
dnsNames:
|
dnsNames:
|
||||||
- mail.iamworkin.lan
|
- mail.iamworkin.lan
|
||||||
---
|
---
|
||||||
# Traefik IngressRoute - Webmail placeholder
|
# Traefik IngressRoute - Webmail placeholder
|
||||||
apiVersion: traefik.io/v1alpha1
|
apiVersion: traefik.io/v1alpha1
|
||||||
kind: IngressRoute
|
kind: IngressRoute
|
||||||
metadata:
|
metadata:
|
||||||
name: mail-webmail
|
name: mail-webmail
|
||||||
namespace: mail
|
namespace: mail
|
||||||
spec:
|
spec:
|
||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- match: Host(`mail.iamworkin.lan`)
|
- match: Host(`mail.iamworkin.lan`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
services:
|
services:
|
||||||
- name: mail-imap
|
- name: mail-imap
|
||||||
port: 993
|
port: 993
|
||||||
tls:
|
tls:
|
||||||
secretName: mail-tls
|
secretName: mail-tls
|
||||||
---
|
---
|
||||||
# Public IngressRoute - Webmail (flowercore.io with Cloudflare origin cert)
|
# Public IngressRoute - Webmail (flowercore.io with Cloudflare origin cert)
|
||||||
apiVersion: traefik.io/v1alpha1
|
apiVersion: traefik.io/v1alpha1
|
||||||
kind: IngressRoute
|
kind: IngressRoute
|
||||||
metadata:
|
metadata:
|
||||||
name: mail-webmail-public
|
name: mail-webmail-public
|
||||||
namespace: mail
|
namespace: mail
|
||||||
spec:
|
spec:
|
||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- match: Host(`webmail.flowercore.io`)
|
- match: Host(`webmail.flowercore.io`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
services:
|
services:
|
||||||
- name: mail-webmail
|
- name: mail-webmail
|
||||||
port: 8080
|
port: 8080
|
||||||
tls:
|
tls:
|
||||||
secretName: cf-origin-flowercore-io
|
secretName: cf-origin-flowercore-io
|
||||||
|
|||||||
@@ -1,495 +1,495 @@
|
|||||||
# Matrix Synapse + Element Web
|
# Matrix Synapse + Element Web
|
||||||
# PostgreSQL 16 + Synapse homeserver + Element Web client
|
# PostgreSQL 16 + Synapse homeserver + Element Web client
|
||||||
# ArgoCD managed - BlueJay Lab
|
# ArgoCD managed - BlueJay Lab
|
||||||
# DB credentials sourced from 1Password via OnePasswordItem CRD (matrix-credentials)
|
# DB credentials sourced from 1Password via OnePasswordItem CRD (matrix-credentials)
|
||||||
# Synapse homeserver.yaml DB password injected at runtime via init container
|
# Synapse homeserver.yaml DB password injected at runtime via init container
|
||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Namespace
|
kind: Namespace
|
||||||
metadata:
|
metadata:
|
||||||
name: matrix
|
name: matrix
|
||||||
labels:
|
labels:
|
||||||
app.kubernetes.io/part-of: bluejay-infra
|
app.kubernetes.io/part-of: bluejay-infra
|
||||||
---
|
---
|
||||||
# Synapse homeserver.yaml template ConfigMap
|
# Synapse homeserver.yaml template ConfigMap
|
||||||
# DB password placeholder __DB_PASSWORD__ is replaced at pod startup by init container
|
# DB password placeholder __DB_PASSWORD__ is replaced at pod startup by init container
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: ConfigMap
|
kind: ConfigMap
|
||||||
metadata:
|
metadata:
|
||||||
name: synapse-config
|
name: synapse-config
|
||||||
namespace: matrix
|
namespace: matrix
|
||||||
data:
|
data:
|
||||||
homeserver.yaml.template: |
|
homeserver.yaml.template: |
|
||||||
server_name: "iamworkin.lan"
|
server_name: "iamworkin.lan"
|
||||||
pid_file: /data/homeserver.pid
|
pid_file: /data/homeserver.pid
|
||||||
public_baseurl: "https://matrix.iamworkin.lan/"
|
public_baseurl: "https://matrix.iamworkin.lan/"
|
||||||
listeners:
|
listeners:
|
||||||
- port: 8008
|
- port: 8008
|
||||||
tls: false
|
tls: false
|
||||||
type: http
|
type: http
|
||||||
x_forwarded: true
|
x_forwarded: true
|
||||||
bind_addresses: ["0.0.0.0"]
|
bind_addresses: ["0.0.0.0"]
|
||||||
resources:
|
resources:
|
||||||
- names: [client, federation]
|
- names: [client, federation]
|
||||||
compress: false
|
compress: false
|
||||||
database:
|
database:
|
||||||
name: psycopg2
|
name: psycopg2
|
||||||
args:
|
args:
|
||||||
user: __DB_USER__
|
user: __DB_USER__
|
||||||
password: __DB_PASSWORD__
|
password: __DB_PASSWORD__
|
||||||
database: synapse
|
database: synapse
|
||||||
host: matrix-postgres
|
host: matrix-postgres
|
||||||
port: 5432
|
port: 5432
|
||||||
cp_min: 5
|
cp_min: 5
|
||||||
cp_max: 10
|
cp_max: 10
|
||||||
log_config: "/config/log.config"
|
log_config: "/config/log.config"
|
||||||
media_store_path: /data/media_store
|
media_store_path: /data/media_store
|
||||||
registration_shared_secret: "a208f2e4b260f6b7d6ff4566df49c56c8b73fa20b911ce4e617b791ee7868adc"
|
registration_shared_secret: "a208f2e4b260f6b7d6ff4566df49c56c8b73fa20b911ce4e617b791ee7868adc"
|
||||||
report_stats: false
|
report_stats: false
|
||||||
macaroon_secret_key: "9964f398e8b48a91469ad419d293c06db4562f49df8cc6e129fb3a801fd9052d"
|
macaroon_secret_key: "9964f398e8b48a91469ad419d293c06db4562f49df8cc6e129fb3a801fd9052d"
|
||||||
form_secret: "7b0a9dbaf9ee94450e0b3271c408dfc4d313a55843ce4eec2ac1bb0315ffeb76"
|
form_secret: "7b0a9dbaf9ee94450e0b3271c408dfc4d313a55843ce4eec2ac1bb0315ffeb76"
|
||||||
signing_key_path: "/data/signing.key"
|
signing_key_path: "/data/signing.key"
|
||||||
trusted_key_servers:
|
trusted_key_servers:
|
||||||
- server_name: "matrix.org"
|
- server_name: "matrix.org"
|
||||||
enable_registration: false
|
enable_registration: false
|
||||||
suppress_key_server_warning: true
|
suppress_key_server_warning: true
|
||||||
log.config: |
|
log.config: |
|
||||||
version: 1
|
version: 1
|
||||||
formatters:
|
formatters:
|
||||||
precise:
|
precise:
|
||||||
format: "%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s - %(message)s"
|
format: "%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s - %(message)s"
|
||||||
handlers:
|
handlers:
|
||||||
console:
|
console:
|
||||||
class: logging.StreamHandler
|
class: logging.StreamHandler
|
||||||
formatter: precise
|
formatter: precise
|
||||||
loggers:
|
loggers:
|
||||||
synapse.storage.SQL:
|
synapse.storage.SQL:
|
||||||
level: WARNING
|
level: WARNING
|
||||||
root:
|
root:
|
||||||
level: WARNING
|
level: WARNING
|
||||||
handlers: [console]
|
handlers: [console]
|
||||||
disable_existing_loggers: false
|
disable_existing_loggers: false
|
||||||
---
|
---
|
||||||
# PostgreSQL 16 StatefulSet
|
# PostgreSQL 16 StatefulSet
|
||||||
# Credentials from 1Password-synced matrix-credentials secret
|
# Credentials from 1Password-synced matrix-credentials secret
|
||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: StatefulSet
|
kind: StatefulSet
|
||||||
metadata:
|
metadata:
|
||||||
name: matrix-postgres
|
name: matrix-postgres
|
||||||
namespace: matrix
|
namespace: matrix
|
||||||
labels:
|
labels:
|
||||||
app: matrix-postgres
|
app: matrix-postgres
|
||||||
spec:
|
spec:
|
||||||
serviceName: matrix-postgres
|
serviceName: matrix-postgres
|
||||||
replicas: 1
|
replicas: 1
|
||||||
selector:
|
selector:
|
||||||
matchLabels:
|
matchLabels:
|
||||||
app: matrix-postgres
|
app: matrix-postgres
|
||||||
template:
|
template:
|
||||||
metadata:
|
metadata:
|
||||||
labels:
|
labels:
|
||||||
app: matrix-postgres
|
app: matrix-postgres
|
||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: postgres
|
- name: postgres
|
||||||
image: postgres:16-alpine
|
image: postgres:16-alpine
|
||||||
ports:
|
ports:
|
||||||
- containerPort: 5432
|
- containerPort: 5432
|
||||||
name: postgres
|
name: postgres
|
||||||
env:
|
env:
|
||||||
- name: POSTGRES_USER
|
- name: POSTGRES_USER
|
||||||
valueFrom:
|
valueFrom:
|
||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
name: matrix-credentials
|
name: matrix-credentials
|
||||||
key: DB-User
|
key: DB-User
|
||||||
- name: POSTGRES_PASSWORD
|
- name: POSTGRES_PASSWORD
|
||||||
valueFrom:
|
valueFrom:
|
||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
name: matrix-credentials
|
name: matrix-credentials
|
||||||
key: DB-Password
|
key: DB-Password
|
||||||
- name: POSTGRES_DB
|
- name: POSTGRES_DB
|
||||||
value: synapse
|
value: synapse
|
||||||
- name: POSTGRES_INITDB_ARGS
|
- name: POSTGRES_INITDB_ARGS
|
||||||
value: "--encoding=UTF-8 --lc-collate=C --lc-ctype=C"
|
value: "--encoding=UTF-8 --lc-collate=C --lc-ctype=C"
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
- name: matrix-postgres-data
|
- name: matrix-postgres-data
|
||||||
mountPath: /var/lib/postgresql/data
|
mountPath: /var/lib/postgresql/data
|
||||||
subPath: pgdata
|
subPath: pgdata
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
memory: 256Mi
|
memory: 256Mi
|
||||||
cpu: 100m
|
cpu: 100m
|
||||||
limits:
|
limits:
|
||||||
memory: 1Gi
|
memory: 1Gi
|
||||||
cpu: 500m
|
cpu: 500m
|
||||||
livenessProbe:
|
livenessProbe:
|
||||||
exec:
|
exec:
|
||||||
command: ["pg_isready", "-U", "synapse"]
|
command: ["pg_isready", "-U", "synapse"]
|
||||||
initialDelaySeconds: 30
|
initialDelaySeconds: 30
|
||||||
periodSeconds: 10
|
periodSeconds: 10
|
||||||
readinessProbe:
|
readinessProbe:
|
||||||
exec:
|
exec:
|
||||||
command: ["pg_isready", "-U", "synapse"]
|
command: ["pg_isready", "-U", "synapse"]
|
||||||
initialDelaySeconds: 5
|
initialDelaySeconds: 5
|
||||||
periodSeconds: 5
|
periodSeconds: 5
|
||||||
volumeClaimTemplates:
|
volumeClaimTemplates:
|
||||||
- metadata:
|
- metadata:
|
||||||
name: matrix-postgres-data
|
name: matrix-postgres-data
|
||||||
spec:
|
spec:
|
||||||
accessModes: [ReadWriteOnce]
|
accessModes: [ReadWriteOnce]
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
storage: 5Gi
|
storage: 5Gi
|
||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Service
|
kind: Service
|
||||||
metadata:
|
metadata:
|
||||||
name: matrix-postgres
|
name: matrix-postgres
|
||||||
namespace: matrix
|
namespace: matrix
|
||||||
spec:
|
spec:
|
||||||
selector:
|
selector:
|
||||||
app: matrix-postgres
|
app: matrix-postgres
|
||||||
ports:
|
ports:
|
||||||
- port: 5432
|
- port: 5432
|
||||||
targetPort: 5432
|
targetPort: 5432
|
||||||
name: postgres
|
name: postgres
|
||||||
clusterIP: None
|
clusterIP: None
|
||||||
---
|
---
|
||||||
# Synapse Data PVC
|
# Synapse Data PVC
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: PersistentVolumeClaim
|
kind: PersistentVolumeClaim
|
||||||
metadata:
|
metadata:
|
||||||
name: synapse-data
|
name: synapse-data
|
||||||
namespace: matrix
|
namespace: matrix
|
||||||
spec:
|
spec:
|
||||||
accessModes: [ReadWriteOnce]
|
accessModes: [ReadWriteOnce]
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
storage: 2Gi
|
storage: 2Gi
|
||||||
---
|
---
|
||||||
# Synapse Deployment
|
# Synapse Deployment
|
||||||
# Init container injects DB credentials from 1Password secret into homeserver.yaml
|
# Init container injects DB credentials from 1Password secret into homeserver.yaml
|
||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
name: synapse
|
name: synapse
|
||||||
namespace: matrix
|
namespace: matrix
|
||||||
labels:
|
labels:
|
||||||
app: synapse
|
app: synapse
|
||||||
spec:
|
spec:
|
||||||
replicas: 1
|
replicas: 1
|
||||||
strategy:
|
strategy:
|
||||||
type: Recreate
|
type: Recreate
|
||||||
selector:
|
selector:
|
||||||
matchLabels:
|
matchLabels:
|
||||||
app: synapse
|
app: synapse
|
||||||
template:
|
template:
|
||||||
metadata:
|
metadata:
|
||||||
labels:
|
labels:
|
||||||
app: synapse
|
app: synapse
|
||||||
spec:
|
spec:
|
||||||
initContainers:
|
initContainers:
|
||||||
- name: generate-signing-key
|
- name: generate-signing-key
|
||||||
image: matrixdotorg/synapse:latest
|
image: matrixdotorg/synapse:latest
|
||||||
securityContext:
|
securityContext:
|
||||||
runAsUser: 0
|
runAsUser: 0
|
||||||
command: ["sh", "-c"]
|
command: ["sh", "-c"]
|
||||||
args:
|
args:
|
||||||
- |
|
- |
|
||||||
if [ \! -f /data/signing.key ]; then
|
if [ \! -f /data/signing.key ]; then
|
||||||
python -m synapse.app.homeserver --generate-keys --config-path /config-template/homeserver.yaml.template 2>/dev/null || true
|
python -m synapse.app.homeserver --generate-keys --config-path /config-template/homeserver.yaml.template 2>/dev/null || true
|
||||||
# If key generation fails with template, create a minimal config for key gen
|
# If key generation fails with template, create a minimal config for key gen
|
||||||
if [ \! -f /data/signing.key ]; then
|
if [ \! -f /data/signing.key ]; then
|
||||||
echo server_name: iamworkin.lan > /tmp/minimal.yaml
|
echo server_name: iamworkin.lan > /tmp/minimal.yaml
|
||||||
echo signing_key_path: /data/signing.key >> /tmp/minimal.yaml
|
echo signing_key_path: /data/signing.key >> /tmp/minimal.yaml
|
||||||
python -c "from signedjson.key import generate_signing_key, write_signing_keys; import sys; key = generate_signing_key(a_auto); write_signing_keys(open(/data/signing.key,w), [key])" 2>/dev/null || true
|
python -c "from signedjson.key import generate_signing_key, write_signing_keys; import sys; key = generate_signing_key(a_auto); write_signing_keys(open(/data/signing.key,w), [key])" 2>/dev/null || true
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
chown 991:991 /data/signing.key 2>/dev/null || true
|
chown 991:991 /data/signing.key 2>/dev/null || true
|
||||||
chmod 644 /data/signing.key 2>/dev/null || true
|
chmod 644 /data/signing.key 2>/dev/null || true
|
||||||
mkdir -p /data/media_store
|
mkdir -p /data/media_store
|
||||||
chown -R 991:991 /data 2>/dev/null || true
|
chown -R 991:991 /data 2>/dev/null || true
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
- name: synapse-data
|
- name: synapse-data
|
||||||
mountPath: /data
|
mountPath: /data
|
||||||
- name: synapse-config-template
|
- name: synapse-config-template
|
||||||
mountPath: /config-template
|
mountPath: /config-template
|
||||||
- name: inject-credentials
|
- name: inject-credentials
|
||||||
image: busybox:latest
|
image: busybox:latest
|
||||||
command: ["sh", "-c"]
|
command: ["sh", "-c"]
|
||||||
args:
|
args:
|
||||||
- |
|
- |
|
||||||
# Copy template and substitute DB credentials from 1Password secret
|
# Copy template and substitute DB credentials from 1Password secret
|
||||||
cp /config-template/log.config /config/log.config
|
cp /config-template/log.config /config/log.config
|
||||||
sed -e "s/__DB_PASSWORD__/${DB_PASSWORD}/g" \
|
sed -e "s/__DB_PASSWORD__/${DB_PASSWORD}/g" \
|
||||||
-e "s/__DB_USER__/${DB_USER}/g" \
|
-e "s/__DB_USER__/${DB_USER}/g" \
|
||||||
/config-template/homeserver.yaml.template > /config/homeserver.yaml
|
/config-template/homeserver.yaml.template > /config/homeserver.yaml
|
||||||
echo "Credentials injected into homeserver.yaml"
|
echo "Credentials injected into homeserver.yaml"
|
||||||
env:
|
env:
|
||||||
- name: DB_PASSWORD
|
- name: DB_PASSWORD
|
||||||
valueFrom:
|
valueFrom:
|
||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
name: matrix-credentials
|
name: matrix-credentials
|
||||||
key: DB-Password
|
key: DB-Password
|
||||||
- name: DB_USER
|
- name: DB_USER
|
||||||
valueFrom:
|
valueFrom:
|
||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
name: matrix-credentials
|
name: matrix-credentials
|
||||||
key: DB-User
|
key: DB-User
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
- name: synapse-config-template
|
- name: synapse-config-template
|
||||||
mountPath: /config-template
|
mountPath: /config-template
|
||||||
- name: synapse-config-rendered
|
- name: synapse-config-rendered
|
||||||
mountPath: /config
|
mountPath: /config
|
||||||
containers:
|
containers:
|
||||||
- name: synapse
|
- name: synapse
|
||||||
image: matrixdotorg/synapse:latest
|
image: matrixdotorg/synapse:latest
|
||||||
ports:
|
ports:
|
||||||
- containerPort: 8008
|
- containerPort: 8008
|
||||||
name: http
|
name: http
|
||||||
env:
|
env:
|
||||||
- name: SYNAPSE_CONFIG_DIR
|
- name: SYNAPSE_CONFIG_DIR
|
||||||
value: /config
|
value: /config
|
||||||
- name: SYNAPSE_CONFIG_PATH
|
- name: SYNAPSE_CONFIG_PATH
|
||||||
value: /config/homeserver.yaml
|
value: /config/homeserver.yaml
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
- name: synapse-data
|
- name: synapse-data
|
||||||
mountPath: /data
|
mountPath: /data
|
||||||
- name: synapse-config-rendered
|
- name: synapse-config-rendered
|
||||||
mountPath: /config
|
mountPath: /config
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
memory: 512Mi
|
memory: 512Mi
|
||||||
cpu: 200m
|
cpu: 200m
|
||||||
limits:
|
limits:
|
||||||
memory: 2Gi
|
memory: 2Gi
|
||||||
cpu: "1"
|
cpu: "1"
|
||||||
livenessProbe:
|
livenessProbe:
|
||||||
httpGet:
|
httpGet:
|
||||||
path: /health
|
path: /health
|
||||||
port: 8008
|
port: 8008
|
||||||
initialDelaySeconds: 60
|
initialDelaySeconds: 60
|
||||||
periodSeconds: 10
|
periodSeconds: 10
|
||||||
readinessProbe:
|
readinessProbe:
|
||||||
httpGet:
|
httpGet:
|
||||||
path: /health
|
path: /health
|
||||||
port: 8008
|
port: 8008
|
||||||
initialDelaySeconds: 30
|
initialDelaySeconds: 30
|
||||||
periodSeconds: 5
|
periodSeconds: 5
|
||||||
volumes:
|
volumes:
|
||||||
- name: synapse-data
|
- name: synapse-data
|
||||||
persistentVolumeClaim:
|
persistentVolumeClaim:
|
||||||
claimName: synapse-data
|
claimName: synapse-data
|
||||||
- name: synapse-config-template
|
- name: synapse-config-template
|
||||||
configMap:
|
configMap:
|
||||||
name: synapse-config
|
name: synapse-config
|
||||||
- name: synapse-config-rendered
|
- name: synapse-config-rendered
|
||||||
emptyDir: {}
|
emptyDir: {}
|
||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Service
|
kind: Service
|
||||||
metadata:
|
metadata:
|
||||||
name: synapse
|
name: synapse
|
||||||
namespace: matrix
|
namespace: matrix
|
||||||
spec:
|
spec:
|
||||||
selector:
|
selector:
|
||||||
app: synapse
|
app: synapse
|
||||||
ports:
|
ports:
|
||||||
- port: 8008
|
- port: 8008
|
||||||
targetPort: 8008
|
targetPort: 8008
|
||||||
name: http
|
name: http
|
||||||
---
|
---
|
||||||
# Element Web ConfigMap
|
# Element Web ConfigMap
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: ConfigMap
|
kind: ConfigMap
|
||||||
metadata:
|
metadata:
|
||||||
name: element-web-config
|
name: element-web-config
|
||||||
namespace: matrix
|
namespace: matrix
|
||||||
data:
|
data:
|
||||||
config.json: |
|
config.json: |
|
||||||
{
|
{
|
||||||
"default_server_config": {
|
"default_server_config": {
|
||||||
"m.homeserver": {
|
"m.homeserver": {
|
||||||
"base_url": "https://matrix.iamworkin.lan",
|
"base_url": "https://matrix.iamworkin.lan",
|
||||||
"server_name": "iamworkin.lan"
|
"server_name": "iamworkin.lan"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"brand": "BlueJay Chat",
|
"brand": "BlueJay Chat",
|
||||||
"disable_guests": true,
|
"disable_guests": true,
|
||||||
"disable_3pid_login": true
|
"disable_3pid_login": true
|
||||||
}
|
}
|
||||||
---
|
---
|
||||||
# Element Web Deployment
|
# Element Web Deployment
|
||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
name: element-web
|
name: element-web
|
||||||
namespace: matrix
|
namespace: matrix
|
||||||
labels:
|
labels:
|
||||||
app: element-web
|
app: element-web
|
||||||
spec:
|
spec:
|
||||||
replicas: 1
|
replicas: 1
|
||||||
selector:
|
selector:
|
||||||
matchLabels:
|
matchLabels:
|
||||||
app: element-web
|
app: element-web
|
||||||
template:
|
template:
|
||||||
metadata:
|
metadata:
|
||||||
labels:
|
labels:
|
||||||
app: element-web
|
app: element-web
|
||||||
spec:
|
spec:
|
||||||
enableServiceLinks: false
|
enableServiceLinks: false
|
||||||
containers:
|
containers:
|
||||||
- name: element-web
|
- name: element-web
|
||||||
image: vectorim/element-web:latest
|
image: vectorim/element-web:latest
|
||||||
ports:
|
ports:
|
||||||
- containerPort: 80
|
- containerPort: 80
|
||||||
name: http
|
name: http
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
- name: element-config
|
- name: element-config
|
||||||
mountPath: /app/config.json
|
mountPath: /app/config.json
|
||||||
subPath: config.json
|
subPath: config.json
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
memory: 32Mi
|
memory: 32Mi
|
||||||
cpu: 10m
|
cpu: 10m
|
||||||
limits:
|
limits:
|
||||||
memory: 128Mi
|
memory: 128Mi
|
||||||
cpu: 100m
|
cpu: 100m
|
||||||
livenessProbe:
|
livenessProbe:
|
||||||
httpGet:
|
httpGet:
|
||||||
path: /
|
path: /
|
||||||
port: 80
|
port: 80
|
||||||
initialDelaySeconds: 10
|
initialDelaySeconds: 10
|
||||||
periodSeconds: 10
|
periodSeconds: 10
|
||||||
readinessProbe:
|
readinessProbe:
|
||||||
httpGet:
|
httpGet:
|
||||||
path: /
|
path: /
|
||||||
port: 80
|
port: 80
|
||||||
initialDelaySeconds: 5
|
initialDelaySeconds: 5
|
||||||
periodSeconds: 5
|
periodSeconds: 5
|
||||||
volumes:
|
volumes:
|
||||||
- name: element-config
|
- name: element-config
|
||||||
configMap:
|
configMap:
|
||||||
name: element-web-config
|
name: element-web-config
|
||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Service
|
kind: Service
|
||||||
metadata:
|
metadata:
|
||||||
name: element-web
|
name: element-web
|
||||||
namespace: matrix
|
namespace: matrix
|
||||||
spec:
|
spec:
|
||||||
selector:
|
selector:
|
||||||
app: element-web
|
app: element-web
|
||||||
ports:
|
ports:
|
||||||
- port: 80
|
- port: 80
|
||||||
targetPort: 80
|
targetPort: 80
|
||||||
name: http
|
name: http
|
||||||
---
|
---
|
||||||
# TLS Certificates via cert-manager
|
# TLS Certificates via cert-manager
|
||||||
apiVersion: cert-manager.io/v1
|
apiVersion: cert-manager.io/v1
|
||||||
kind: Certificate
|
kind: Certificate
|
||||||
metadata:
|
metadata:
|
||||||
name: matrix-tls
|
name: matrix-tls
|
||||||
namespace: matrix
|
namespace: matrix
|
||||||
spec:
|
spec:
|
||||||
secretName: matrix-tls
|
secretName: matrix-tls
|
||||||
issuerRef:
|
issuerRef:
|
||||||
name: step-ca-acme
|
name: step-ca-acme
|
||||||
kind: ClusterIssuer
|
kind: ClusterIssuer
|
||||||
dnsNames:
|
dnsNames:
|
||||||
- matrix.iamworkin.lan
|
- matrix.iamworkin.lan
|
||||||
---
|
---
|
||||||
apiVersion: cert-manager.io/v1
|
apiVersion: cert-manager.io/v1
|
||||||
kind: Certificate
|
kind: Certificate
|
||||||
metadata:
|
metadata:
|
||||||
name: element-tls
|
name: element-tls
|
||||||
namespace: matrix
|
namespace: matrix
|
||||||
spec:
|
spec:
|
||||||
secretName: element-tls
|
secretName: element-tls
|
||||||
issuerRef:
|
issuerRef:
|
||||||
name: step-ca-acme
|
name: step-ca-acme
|
||||||
kind: ClusterIssuer
|
kind: ClusterIssuer
|
||||||
dnsNames:
|
dnsNames:
|
||||||
- element.iamworkin.lan
|
- element.iamworkin.lan
|
||||||
---
|
---
|
||||||
# Traefik IngressRoute - Synapse
|
# Traefik IngressRoute - Synapse
|
||||||
apiVersion: traefik.io/v1alpha1
|
apiVersion: traefik.io/v1alpha1
|
||||||
kind: IngressRoute
|
kind: IngressRoute
|
||||||
metadata:
|
metadata:
|
||||||
name: synapse
|
name: synapse
|
||||||
namespace: matrix
|
namespace: matrix
|
||||||
spec:
|
spec:
|
||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- match: Host(`matrix.iamworkin.lan`)
|
- match: Host(`matrix.iamworkin.lan`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
services:
|
services:
|
||||||
- name: synapse
|
- name: synapse
|
||||||
port: 8008
|
port: 8008
|
||||||
tls:
|
tls:
|
||||||
secretName: matrix-tls
|
secretName: matrix-tls
|
||||||
---
|
---
|
||||||
# Traefik IngressRoute - Element Web
|
# Traefik IngressRoute - Element Web
|
||||||
apiVersion: traefik.io/v1alpha1
|
apiVersion: traefik.io/v1alpha1
|
||||||
kind: IngressRoute
|
kind: IngressRoute
|
||||||
metadata:
|
metadata:
|
||||||
name: element-web
|
name: element-web
|
||||||
namespace: matrix
|
namespace: matrix
|
||||||
spec:
|
spec:
|
||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- match: Host(`element.iamworkin.lan`)
|
- match: Host(`element.iamworkin.lan`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
services:
|
services:
|
||||||
- name: element-web
|
- name: element-web
|
||||||
port: 80
|
port: 80
|
||||||
tls:
|
tls:
|
||||||
secretName: element-tls
|
secretName: element-tls
|
||||||
---
|
---
|
||||||
# 1Password secret sync — creates matrix-credentials K8s Secret
|
# 1Password secret sync — creates matrix-credentials K8s Secret
|
||||||
# Fields: DB-User, DB-Password, Registration-Secret, username, password, URL
|
# Fields: DB-User, DB-Password, Registration-Secret, username, password, URL
|
||||||
apiVersion: onepassword.com/v1
|
apiVersion: onepassword.com/v1
|
||||||
kind: OnePasswordItem
|
kind: OnePasswordItem
|
||||||
metadata:
|
metadata:
|
||||||
name: matrix-credentials
|
name: matrix-credentials
|
||||||
namespace: matrix
|
namespace: matrix
|
||||||
spec:
|
spec:
|
||||||
itemPath: vaults/IAmWorkin/items/Matrix Synapse
|
itemPath: vaults/IAmWorkin/items/Matrix Synapse
|
||||||
---
|
---
|
||||||
# Public IngressRoute - Element Web (flowercore.io with Cloudflare origin cert)
|
# Public IngressRoute - Element Web (flowercore.io with Cloudflare origin cert)
|
||||||
apiVersion: traefik.io/v1alpha1
|
apiVersion: traefik.io/v1alpha1
|
||||||
kind: IngressRoute
|
kind: IngressRoute
|
||||||
metadata:
|
metadata:
|
||||||
name: element-public
|
name: element-public
|
||||||
namespace: matrix
|
namespace: matrix
|
||||||
spec:
|
spec:
|
||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- match: Host(`element.flowercore.io`)
|
- match: Host(`element.flowercore.io`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
services:
|
services:
|
||||||
- name: element-web
|
- name: element-web
|
||||||
port: 80
|
port: 80
|
||||||
tls:
|
tls:
|
||||||
secretName: cf-origin-flowercore-io
|
secretName: cf-origin-flowercore-io
|
||||||
---
|
---
|
||||||
# Public IngressRoute - Synapse (flowercore.io with Cloudflare origin cert)
|
# Public IngressRoute - Synapse (flowercore.io with Cloudflare origin cert)
|
||||||
apiVersion: traefik.io/v1alpha1
|
apiVersion: traefik.io/v1alpha1
|
||||||
kind: IngressRoute
|
kind: IngressRoute
|
||||||
metadata:
|
metadata:
|
||||||
name: synapse-public
|
name: synapse-public
|
||||||
namespace: matrix
|
namespace: matrix
|
||||||
spec:
|
spec:
|
||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- match: Host(`matrix.flowercore.io`)
|
- match: Host(`matrix.flowercore.io`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
services:
|
services:
|
||||||
- name: synapse
|
- name: synapse
|
||||||
port: 8008
|
port: 8008
|
||||||
tls:
|
tls:
|
||||||
secretName: cf-origin-flowercore-io
|
secretName: cf-origin-flowercore-io
|
||||||
|
|||||||
@@ -1,257 +1,257 @@
|
|||||||
# NOC Services - Traefik IngressRoutes for noc1 services
|
# NOC Services - Traefik IngressRoutes for noc1 services
|
||||||
# Proxies internal .iamworkin.lan hostnames to noc1 (10.0.56.10) via
|
# Proxies internal .iamworkin.lan hostnames to noc1 (10.0.56.10) via
|
||||||
# headless Service + manual Endpoints (standard K8s external proxy pattern)
|
# headless Service + manual Endpoints (standard K8s external proxy pattern)
|
||||||
# ArgoCD managed - BlueJay Lab
|
# ArgoCD managed - BlueJay Lab
|
||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Namespace
|
kind: Namespace
|
||||||
metadata:
|
metadata:
|
||||||
name: noc-proxy
|
name: noc-proxy
|
||||||
labels:
|
labels:
|
||||||
app.kubernetes.io/part-of: bluejay-infra
|
app.kubernetes.io/part-of: bluejay-infra
|
||||||
---
|
---
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# BasicAuth - shared across all NOC proxy IngressRoutes
|
# BasicAuth - shared across all NOC proxy IngressRoutes
|
||||||
# ============================================================
|
# ============================================================
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Secret
|
kind: Secret
|
||||||
metadata:
|
metadata:
|
||||||
name: noc-proxy-auth
|
name: noc-proxy-auth
|
||||||
namespace: noc-proxy
|
namespace: noc-proxy
|
||||||
type: Opaque
|
type: Opaque
|
||||||
data:
|
data:
|
||||||
users: YWRtaW46JDJiJDEwJEZjdlVFNWNpNkxvNi5rZ1k5L3hJV2V5M2tvM3VVY1U5YXJaSlQ4N29ZREtCSi5lNkoucXJD
|
users: YWRtaW46JDJiJDEwJEZjdlVFNWNpNkxvNi5rZ1k5L3hJV2V5M2tvM3VVY1U5YXJaSlQ4N29ZREtCSi5lNkoucXJD
|
||||||
---
|
---
|
||||||
apiVersion: traefik.io/v1alpha1
|
apiVersion: traefik.io/v1alpha1
|
||||||
kind: Middleware
|
kind: Middleware
|
||||||
metadata:
|
metadata:
|
||||||
name: noc-proxy-auth
|
name: noc-proxy-auth
|
||||||
namespace: noc-proxy
|
namespace: noc-proxy
|
||||||
spec:
|
spec:
|
||||||
basicAuth:
|
basicAuth:
|
||||||
secret: noc-proxy-auth
|
secret: noc-proxy-auth
|
||||||
---
|
---
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# Grafana - noc1:3000
|
# Grafana - noc1:3000
|
||||||
# ============================================================
|
# ============================================================
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Service
|
kind: Service
|
||||||
metadata:
|
metadata:
|
||||||
name: grafana-external
|
name: grafana-external
|
||||||
namespace: noc-proxy
|
namespace: noc-proxy
|
||||||
spec:
|
spec:
|
||||||
ports:
|
ports:
|
||||||
- port: 3000
|
- port: 3000
|
||||||
targetPort: 3000
|
targetPort: 3000
|
||||||
name: http
|
name: http
|
||||||
clusterIP: None
|
clusterIP: None
|
||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Endpoints
|
kind: Endpoints
|
||||||
metadata:
|
metadata:
|
||||||
name: grafana-external
|
name: grafana-external
|
||||||
namespace: noc-proxy
|
namespace: noc-proxy
|
||||||
subsets:
|
subsets:
|
||||||
- addresses:
|
- addresses:
|
||||||
- ip: 10.0.56.10
|
- ip: 10.0.56.10
|
||||||
ports:
|
ports:
|
||||||
- port: 3000
|
- port: 3000
|
||||||
name: http
|
name: http
|
||||||
---
|
---
|
||||||
apiVersion: cert-manager.io/v1
|
apiVersion: cert-manager.io/v1
|
||||||
kind: Certificate
|
kind: Certificate
|
||||||
metadata:
|
metadata:
|
||||||
name: grafana-tls
|
name: grafana-tls
|
||||||
namespace: noc-proxy
|
namespace: noc-proxy
|
||||||
spec:
|
spec:
|
||||||
secretName: grafana-tls
|
secretName: grafana-tls
|
||||||
issuerRef:
|
issuerRef:
|
||||||
name: step-ca-acme
|
name: step-ca-acme
|
||||||
kind: ClusterIssuer
|
kind: ClusterIssuer
|
||||||
dnsNames:
|
dnsNames:
|
||||||
- grafana.iamworkin.lan
|
- grafana.iamworkin.lan
|
||||||
---
|
---
|
||||||
apiVersion: traefik.io/v1alpha1
|
apiVersion: traefik.io/v1alpha1
|
||||||
kind: IngressRoute
|
kind: IngressRoute
|
||||||
metadata:
|
metadata:
|
||||||
name: grafana
|
name: grafana
|
||||||
namespace: noc-proxy
|
namespace: noc-proxy
|
||||||
spec:
|
spec:
|
||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- kind: Rule
|
- kind: Rule
|
||||||
match: Host(`grafana.iamworkin.lan`)
|
match: Host(`grafana.iamworkin.lan`)
|
||||||
middlewares:
|
middlewares:
|
||||||
- name: noc-proxy-auth
|
- name: noc-proxy-auth
|
||||||
services:
|
services:
|
||||||
- name: grafana-external
|
- name: grafana-external
|
||||||
port: 3000
|
port: 3000
|
||||||
tls:
|
tls:
|
||||||
secretName: grafana-tls
|
secretName: grafana-tls
|
||||||
---
|
---
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# Prometheus - noc1:9091
|
# Prometheus - noc1:9091
|
||||||
# ============================================================
|
# ============================================================
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Service
|
kind: Service
|
||||||
metadata:
|
metadata:
|
||||||
name: prometheus-external
|
name: prometheus-external
|
||||||
namespace: noc-proxy
|
namespace: noc-proxy
|
||||||
spec:
|
spec:
|
||||||
ports:
|
ports:
|
||||||
- port: 9091
|
- port: 9091
|
||||||
targetPort: 9091
|
targetPort: 9091
|
||||||
name: http
|
name: http
|
||||||
clusterIP: None
|
clusterIP: None
|
||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Endpoints
|
kind: Endpoints
|
||||||
metadata:
|
metadata:
|
||||||
name: prometheus-external
|
name: prometheus-external
|
||||||
namespace: noc-proxy
|
namespace: noc-proxy
|
||||||
subsets:
|
subsets:
|
||||||
- addresses:
|
- addresses:
|
||||||
- ip: 10.0.56.10
|
- ip: 10.0.56.10
|
||||||
ports:
|
ports:
|
||||||
- port: 9091
|
- port: 9091
|
||||||
name: http
|
name: http
|
||||||
---
|
---
|
||||||
apiVersion: cert-manager.io/v1
|
apiVersion: cert-manager.io/v1
|
||||||
kind: Certificate
|
kind: Certificate
|
||||||
metadata:
|
metadata:
|
||||||
name: prometheus-tls
|
name: prometheus-tls
|
||||||
namespace: noc-proxy
|
namespace: noc-proxy
|
||||||
spec:
|
spec:
|
||||||
secretName: prometheus-tls
|
secretName: prometheus-tls
|
||||||
issuerRef:
|
issuerRef:
|
||||||
name: step-ca-acme
|
name: step-ca-acme
|
||||||
kind: ClusterIssuer
|
kind: ClusterIssuer
|
||||||
dnsNames:
|
dnsNames:
|
||||||
- prometheus.iamworkin.lan
|
- prometheus.iamworkin.lan
|
||||||
---
|
---
|
||||||
apiVersion: traefik.io/v1alpha1
|
apiVersion: traefik.io/v1alpha1
|
||||||
kind: IngressRoute
|
kind: IngressRoute
|
||||||
metadata:
|
metadata:
|
||||||
name: prometheus
|
name: prometheus
|
||||||
namespace: noc-proxy
|
namespace: noc-proxy
|
||||||
spec:
|
spec:
|
||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- kind: Rule
|
- kind: Rule
|
||||||
match: Host(`prometheus.iamworkin.lan`)
|
match: Host(`prometheus.iamworkin.lan`)
|
||||||
middlewares:
|
middlewares:
|
||||||
- name: noc-proxy-auth
|
- name: noc-proxy-auth
|
||||||
services:
|
services:
|
||||||
- name: prometheus-external
|
- name: prometheus-external
|
||||||
port: 9091
|
port: 9091
|
||||||
tls:
|
tls:
|
||||||
secretName: prometheus-tls
|
secretName: prometheus-tls
|
||||||
---
|
---
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# Cockpit - noc1:9090
|
# Cockpit - noc1:9090
|
||||||
# ============================================================
|
# ============================================================
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Service
|
kind: Service
|
||||||
metadata:
|
metadata:
|
||||||
name: cockpit-external
|
name: cockpit-external
|
||||||
namespace: noc-proxy
|
namespace: noc-proxy
|
||||||
spec:
|
spec:
|
||||||
ports:
|
ports:
|
||||||
- port: 9090
|
- port: 9090
|
||||||
targetPort: 9090
|
targetPort: 9090
|
||||||
name: https
|
name: https
|
||||||
clusterIP: None
|
clusterIP: None
|
||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Endpoints
|
kind: Endpoints
|
||||||
metadata:
|
metadata:
|
||||||
name: cockpit-external
|
name: cockpit-external
|
||||||
namespace: noc-proxy
|
namespace: noc-proxy
|
||||||
subsets:
|
subsets:
|
||||||
- addresses:
|
- addresses:
|
||||||
- ip: 10.0.56.10
|
- ip: 10.0.56.10
|
||||||
ports:
|
ports:
|
||||||
- port: 9090
|
- port: 9090
|
||||||
name: https
|
name: https
|
||||||
---
|
---
|
||||||
apiVersion: cert-manager.io/v1
|
apiVersion: cert-manager.io/v1
|
||||||
kind: Certificate
|
kind: Certificate
|
||||||
metadata:
|
metadata:
|
||||||
name: cockpit-tls
|
name: cockpit-tls
|
||||||
namespace: noc-proxy
|
namespace: noc-proxy
|
||||||
spec:
|
spec:
|
||||||
secretName: cockpit-tls
|
secretName: cockpit-tls
|
||||||
issuerRef:
|
issuerRef:
|
||||||
name: step-ca-acme
|
name: step-ca-acme
|
||||||
kind: ClusterIssuer
|
kind: ClusterIssuer
|
||||||
dnsNames:
|
dnsNames:
|
||||||
- cockpit.iamworkin.lan
|
- cockpit.iamworkin.lan
|
||||||
---
|
---
|
||||||
# Cockpit uses self-signed HTTPS on 9090, so we need a ServersTransport
|
# Cockpit uses self-signed HTTPS on 9090, so we need a ServersTransport
|
||||||
# to skip backend TLS verification
|
# to skip backend TLS verification
|
||||||
apiVersion: traefik.io/v1alpha1
|
apiVersion: traefik.io/v1alpha1
|
||||||
kind: ServersTransport
|
kind: ServersTransport
|
||||||
metadata:
|
metadata:
|
||||||
name: cockpit-transport
|
name: cockpit-transport
|
||||||
namespace: noc-proxy
|
namespace: noc-proxy
|
||||||
spec:
|
spec:
|
||||||
insecureSkipVerify: true
|
insecureSkipVerify: true
|
||||||
---
|
---
|
||||||
apiVersion: traefik.io/v1alpha1
|
apiVersion: traefik.io/v1alpha1
|
||||||
kind: IngressRoute
|
kind: IngressRoute
|
||||||
metadata:
|
metadata:
|
||||||
name: cockpit
|
name: cockpit
|
||||||
namespace: noc-proxy
|
namespace: noc-proxy
|
||||||
spec:
|
spec:
|
||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- kind: Rule
|
- kind: Rule
|
||||||
match: Host(`cockpit.iamworkin.lan`)
|
match: Host(`cockpit.iamworkin.lan`)
|
||||||
middlewares:
|
middlewares:
|
||||||
- name: noc-proxy-auth
|
- name: noc-proxy-auth
|
||||||
services:
|
services:
|
||||||
- name: cockpit-external
|
- name: cockpit-external
|
||||||
port: 9090
|
port: 9090
|
||||||
serversTransport: cockpit-transport
|
serversTransport: cockpit-transport
|
||||||
tls:
|
tls:
|
||||||
secretName: cockpit-tls
|
secretName: cockpit-tls
|
||||||
---
|
---
|
||||||
# NetworkPolicy: allow Traefik ingress, allow egress to noc1
|
# NetworkPolicy: allow Traefik ingress, allow egress to noc1
|
||||||
apiVersion: networking.k8s.io/v1
|
apiVersion: networking.k8s.io/v1
|
||||||
kind: NetworkPolicy
|
kind: NetworkPolicy
|
||||||
metadata:
|
metadata:
|
||||||
name: noc-proxy-netpol
|
name: noc-proxy-netpol
|
||||||
namespace: noc-proxy
|
namespace: noc-proxy
|
||||||
spec:
|
spec:
|
||||||
podSelector: {}
|
podSelector: {}
|
||||||
policyTypes:
|
policyTypes:
|
||||||
- Ingress
|
- Ingress
|
||||||
- Egress
|
- Egress
|
||||||
ingress:
|
ingress:
|
||||||
- from:
|
- from:
|
||||||
- namespaceSelector:
|
- namespaceSelector:
|
||||||
matchLabels:
|
matchLabels:
|
||||||
kubernetes.io/metadata.name: traefik-system
|
kubernetes.io/metadata.name: traefik-system
|
||||||
egress:
|
egress:
|
||||||
- to:
|
- to:
|
||||||
- ipBlock:
|
- ipBlock:
|
||||||
cidr: 10.0.56.10/32
|
cidr: 10.0.56.10/32
|
||||||
ports:
|
ports:
|
||||||
- port: 3000
|
- port: 3000
|
||||||
protocol: TCP
|
protocol: TCP
|
||||||
- port: 9090
|
- port: 9090
|
||||||
protocol: TCP
|
protocol: TCP
|
||||||
- port: 9091
|
- port: 9091
|
||||||
protocol: TCP
|
protocol: TCP
|
||||||
- to:
|
- to:
|
||||||
- namespaceSelector:
|
- namespaceSelector:
|
||||||
matchLabels:
|
matchLabels:
|
||||||
kubernetes.io/metadata.name: kube-system
|
kubernetes.io/metadata.name: kube-system
|
||||||
ports:
|
ports:
|
||||||
- port: 53
|
- port: 53
|
||||||
protocol: UDP
|
protocol: UDP
|
||||||
- port: 53
|
- port: 53
|
||||||
protocol: TCP
|
protocol: TCP
|
||||||
|
|||||||
@@ -1,145 +1,145 @@
|
|||||||
# TeamSpeak 3 Server
|
# TeamSpeak 3 Server
|
||||||
# ArgoCD managed - BlueJay Lab
|
# ArgoCD managed - BlueJay Lab
|
||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Namespace
|
kind: Namespace
|
||||||
metadata:
|
metadata:
|
||||||
name: teamspeak
|
name: teamspeak
|
||||||
labels:
|
labels:
|
||||||
app.kubernetes.io/part-of: bluejay-infra
|
app.kubernetes.io/part-of: bluejay-infra
|
||||||
---
|
---
|
||||||
# 1Password secret sync - TeamSpeak credentials
|
# 1Password secret sync - TeamSpeak credentials
|
||||||
apiVersion: onepassword.com/v1
|
apiVersion: onepassword.com/v1
|
||||||
kind: OnePasswordItem
|
kind: OnePasswordItem
|
||||||
metadata:
|
metadata:
|
||||||
name: teamspeak-credentials
|
name: teamspeak-credentials
|
||||||
namespace: teamspeak
|
namespace: teamspeak
|
||||||
spec:
|
spec:
|
||||||
itemPath: "vaults/IAmWorkin/items/TeamSpeak 3"
|
itemPath: "vaults/IAmWorkin/items/TeamSpeak 3"
|
||||||
---
|
---
|
||||||
# TeamSpeak data PVC
|
# TeamSpeak data PVC
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: PersistentVolumeClaim
|
kind: PersistentVolumeClaim
|
||||||
metadata:
|
metadata:
|
||||||
name: teamspeak-data
|
name: teamspeak-data
|
||||||
namespace: teamspeak
|
namespace: teamspeak
|
||||||
spec:
|
spec:
|
||||||
accessModes: [ReadWriteOnce]
|
accessModes: [ReadWriteOnce]
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
storage: 1Gi
|
storage: 1Gi
|
||||||
---
|
---
|
||||||
# TeamSpeak license key
|
# TeamSpeak license key
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Secret
|
kind: Secret
|
||||||
metadata:
|
metadata:
|
||||||
name: teamspeak-license
|
name: teamspeak-license
|
||||||
namespace: teamspeak
|
namespace: teamspeak
|
||||||
type: Opaque
|
type: Opaque
|
||||||
data:
|
data:
|
||||||
licensekey.dat: Y29tcGFueSBuYW1lIDogQW5kcmV3IFN0b2x0egphZGRyZXNzICAgICAgOiA2NjI1IDE2Mm5kIHQKemlwY29kZSAgICAgIDogNTUwNjgKY2l0eSAgICAgICAgIDogTGFrZXZpbGxlCmNvdW50cnkgICAgICA6IFVuaXRlZCBTdGF0ZXMgb2YgQW1lcmljYQpwaG9uZSAgICAgICAgOiA5NTI5OTk2NDExCmZheCAgICAgICAgICA6IApzYWxlcyBjb250YWN0OiBBbmRyZXcgU3RvbHR6IChhc3RvbHR6QGlhbXdvcmsuaW4pCnRlY2ggY29udGFjdCA6IEFuZHJldyBTdG9sdHogKGFzdG9sdHpAaWFtd29yay5pbikKCnRzIHZlcnNpb24gICA6IDMKdHlwZSAgICAgICAgIDogQWN0aXZhdGlvbiBMaWNlbnNlCnN0YXJ0IGRhdGUgICA6IFN1biBNYXIgIDggMDA6MDA6MDAgMjAyNgplbmQgZGF0ZSAgICAgOiBNb24gTWFyICA4IDAwOjAwOjAwIDIwMjcKbWF4LiB2aXJ0dWFsIHNlcnZlcnM6IDEKbWF4LiBzbG90cyAgIDogMzIKZGVzY3JpcHRpb24gIDogVGVhbVNwZWFrIDMgQUwKCgo9PWtleTI9PQpDb0VDQ3NnQkFRQ3ZiSEZUUURZL3RlclBlaWxycC9FQ1U5eENINVUzeEM5MmxZVE5hWS8wS1FBSkZ1ZUFhemJzZ0FBQUFDVlVaV0Z0VTNCbFlXc2dVM2x6ZEdWdGN5QkhiV0pJQUFCTnozMW0vRVdKU2w4QjFtcjJ2anZvdjRIL2s2UE9KVGJLb2NzVnoxRTNCUUFZd1c3S1B0R0k4QUFBQUNSVVpXRnRVM0JsWVdzZ2MzbHpkR1Z0Y3lCSGJXSklBQUFXSlVXQkErRjQzTERsMzFxS0NpOWw4WWdpQmhyOXlIWW1rbTFvWVVTMlhnSVl5cFVBR3F2SWdBWUFBQUFBUVc1a2NtVjNJRk4wYjJ4MGVnQVNJTmp2OStDVDQwTTUvQWdlY0lLcW1Gb2hyZnAzd3dSbGVSL25Ia3kvdHRKcEdDQWdBU29PVkdWaGJWTndaV0ZySURNZ1FVd1N0UUVCQUs5c2NWTkFOaisxNnM5NktXdW44UUpUM0VJZmxUZkVMM2FWaE0xcGovUXBBQWtXNTRCck51eUFBQUFBSlZSbFlXMVRjR1ZoYXlCVGVYTjBaVzF6SUVkdFlrZ0FBRTNQZldiOFJZbEtYd0hXYXZhK08raS9nZitUbzg0bE5zcWh5eFhQVVRjRkFCakJic28rMFlqd0FBQUFKRlJsWVcxVGNHVmhheUJ6ZVhOMFpXMXpJRWR0WWtnQUFGTTFQT2YxY0VzclhjckFtMU9wS1RnN2cyaHlVNlROY093TFVJaXJpbnc4QlJqQmJzbyswWWp3R2tBRFpWRFRLVndEQTdqYWVFK0pqRFQ1WUFJc1hScWxpdlpTeTR1aUJSYlB0RUZ3d0VnVXR2RHg4TEJaQ29zOEhPTDI0bllBalZ0UFRCdHJnRWF0NHVBSgo9PWtleTI9PQoKPT1rZXk9PQpWRk16VEdsalpXNXpaV1l3WkFJd1JCL1VCTWQ0MnRnQmg4TkY0dnN4K2lsTmpFZHQzazdxbXZPamRYZUVtUWFjQ0J5S0tnelZ4T2MwMDlYanIrU09BakFjR2oxV1ZwTGpiNGxGYk1DaEpsU1FXZW5zYTJhNmJXK2JoN2lCdzF1Zk5WaXFnTk41YThpN1VFS29sNmhsSmExVFViQkVpTng2T1NjbHBBOENhNDhjVk5zS050N0wvandDaVhuZFBkV3BuUW5CdUlYeXFLUXkxM2ZsNDJWUWo0Rk90V2kzTHRoYkNpODlWWEQwYXRpNTNjQlRTWHN4QXdMUndzZFBqeWFobmFsNStXaiswUFdYOE4ySlEzMFZmalFQVnAyMFk2dmc0K29lcm1vV291QUc5RDFjQzRrQVJoQnlVRmU5VnUvM2VBTVRiNUlHbnllY1k0QUF0RjJmdTR1aG5NYUFYQ3Q3UWNHN1JSVEFLQnNjSVhyVlVLM1NnS3ZLR1p6T2RGeU0=
|
licensekey.dat: Y29tcGFueSBuYW1lIDogQW5kcmV3IFN0b2x0egphZGRyZXNzICAgICAgOiA2NjI1IDE2Mm5kIHQKemlwY29kZSAgICAgIDogNTUwNjgKY2l0eSAgICAgICAgIDogTGFrZXZpbGxlCmNvdW50cnkgICAgICA6IFVuaXRlZCBTdGF0ZXMgb2YgQW1lcmljYQpwaG9uZSAgICAgICAgOiA5NTI5OTk2NDExCmZheCAgICAgICAgICA6IApzYWxlcyBjb250YWN0OiBBbmRyZXcgU3RvbHR6IChhc3RvbHR6QGlhbXdvcmsuaW4pCnRlY2ggY29udGFjdCA6IEFuZHJldyBTdG9sdHogKGFzdG9sdHpAaWFtd29yay5pbikKCnRzIHZlcnNpb24gICA6IDMKdHlwZSAgICAgICAgIDogQWN0aXZhdGlvbiBMaWNlbnNlCnN0YXJ0IGRhdGUgICA6IFN1biBNYXIgIDggMDA6MDA6MDAgMjAyNgplbmQgZGF0ZSAgICAgOiBNb24gTWFyICA4IDAwOjAwOjAwIDIwMjcKbWF4LiB2aXJ0dWFsIHNlcnZlcnM6IDEKbWF4LiBzbG90cyAgIDogMzIKZGVzY3JpcHRpb24gIDogVGVhbVNwZWFrIDMgQUwKCgo9PWtleTI9PQpDb0VDQ3NnQkFRQ3ZiSEZUUURZL3RlclBlaWxycC9FQ1U5eENINVUzeEM5MmxZVE5hWS8wS1FBSkZ1ZUFhemJzZ0FBQUFDVlVaV0Z0VTNCbFlXc2dVM2x6ZEdWdGN5QkhiV0pJQUFCTnozMW0vRVdKU2w4QjFtcjJ2anZvdjRIL2s2UE9KVGJLb2NzVnoxRTNCUUFZd1c3S1B0R0k4QUFBQUNSVVpXRnRVM0JsWVdzZ2MzbHpkR1Z0Y3lCSGJXSklBQUFXSlVXQkErRjQzTERsMzFxS0NpOWw4WWdpQmhyOXlIWW1rbTFvWVVTMlhnSVl5cFVBR3F2SWdBWUFBQUFBUVc1a2NtVjNJRk4wYjJ4MGVnQVNJTmp2OStDVDQwTTUvQWdlY0lLcW1Gb2hyZnAzd3dSbGVSL25Ia3kvdHRKcEdDQWdBU29PVkdWaGJWTndaV0ZySURNZ1FVd1N0UUVCQUs5c2NWTkFOaisxNnM5NktXdW44UUpUM0VJZmxUZkVMM2FWaE0xcGovUXBBQWtXNTRCck51eUFBQUFBSlZSbFlXMVRjR1ZoYXlCVGVYTjBaVzF6SUVkdFlrZ0FBRTNQZldiOFJZbEtYd0hXYXZhK08raS9nZitUbzg0bE5zcWh5eFhQVVRjRkFCakJic28rMFlqd0FBQUFKRlJsWVcxVGNHVmhheUJ6ZVhOMFpXMXpJRWR0WWtnQUFGTTFQT2YxY0VzclhjckFtMU9wS1RnN2cyaHlVNlROY093TFVJaXJpbnc4QlJqQmJzbyswWWp3R2tBRFpWRFRLVndEQTdqYWVFK0pqRFQ1WUFJc1hScWxpdlpTeTR1aUJSYlB0RUZ3d0VnVXR2RHg4TEJaQ29zOEhPTDI0bllBalZ0UFRCdHJnRWF0NHVBSgo9PWtleTI9PQoKPT1rZXk9PQpWRk16VEdsalpXNXpaV1l3WkFJd1JCL1VCTWQ0MnRnQmg4TkY0dnN4K2lsTmpFZHQzazdxbXZPamRYZUVtUWFjQ0J5S0tnelZ4T2MwMDlYanIrU09BakFjR2oxV1ZwTGpiNGxGYk1DaEpsU1FXZW5zYTJhNmJXK2JoN2lCdzF1Zk5WaXFnTk41YThpN1VFS29sNmhsSmExVFViQkVpTng2T1NjbHBBOENhNDhjVk5zS050N0wvandDaVhuZFBkV3BuUW5CdUlYeXFLUXkxM2ZsNDJWUWo0Rk90V2kzTHRoYkNpODlWWEQwYXRpNTNjQlRTWHN4QXdMUndzZFBqeWFobmFsNStXaiswUFdYOE4ySlEzMFZmalFQVnAyMFk2dmc0K29lcm1vV291QUc5RDFjQzRrQVJoQnlVRmU5VnUvM2VBTVRiNUlHbnllY1k0QUF0RjJmdTR1aG5NYUFYQ3Q3UWNHN1JSVEFLQnNjSVhyVlVLM1NnS3ZLR1p6T2RGeU0=
|
||||||
---
|
---
|
||||||
# TeamSpeak 3 Deployment
|
# TeamSpeak 3 Deployment
|
||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
name: teamspeak
|
name: teamspeak
|
||||||
namespace: teamspeak
|
namespace: teamspeak
|
||||||
labels:
|
labels:
|
||||||
app: teamspeak
|
app: teamspeak
|
||||||
spec:
|
spec:
|
||||||
replicas: 1
|
replicas: 1
|
||||||
strategy:
|
strategy:
|
||||||
type: Recreate
|
type: Recreate
|
||||||
selector:
|
selector:
|
||||||
matchLabels:
|
matchLabels:
|
||||||
app: teamspeak
|
app: teamspeak
|
||||||
template:
|
template:
|
||||||
metadata:
|
metadata:
|
||||||
labels:
|
labels:
|
||||||
app: teamspeak
|
app: teamspeak
|
||||||
spec:
|
spec:
|
||||||
initContainers:
|
initContainers:
|
||||||
- name: copy-license
|
- name: copy-license
|
||||||
image: busybox:latest
|
image: busybox:latest
|
||||||
command: ['sh', '-c', 'cp /license/licensekey.dat /data/licensekey.dat']
|
command: ['sh', '-c', 'cp /license/licensekey.dat /data/licensekey.dat']
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
- name: teamspeak-data
|
- name: teamspeak-data
|
||||||
mountPath: /data
|
mountPath: /data
|
||||||
- name: license
|
- name: license
|
||||||
mountPath: /license
|
mountPath: /license
|
||||||
readOnly: true
|
readOnly: true
|
||||||
containers:
|
containers:
|
||||||
- name: teamspeak
|
- name: teamspeak
|
||||||
image: teamspeak:latest
|
image: teamspeak:latest
|
||||||
ports:
|
ports:
|
||||||
- containerPort: 9987
|
- containerPort: 9987
|
||||||
name: voice
|
name: voice
|
||||||
protocol: UDP
|
protocol: UDP
|
||||||
- containerPort: 30033
|
- containerPort: 30033
|
||||||
name: filetransfer
|
name: filetransfer
|
||||||
protocol: TCP
|
protocol: TCP
|
||||||
- containerPort: 10011
|
- containerPort: 10011
|
||||||
name: serverquery
|
name: serverquery
|
||||||
protocol: TCP
|
protocol: TCP
|
||||||
env:
|
env:
|
||||||
- name: TS3SERVER_LICENSE
|
- name: TS3SERVER_LICENSE
|
||||||
value: accept
|
value: accept
|
||||||
- name: TS3SERVER_SERVERADMIN_PASSWORD
|
- name: TS3SERVER_SERVERADMIN_PASSWORD
|
||||||
valueFrom:
|
valueFrom:
|
||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
name: teamspeak-credentials
|
name: teamspeak-credentials
|
||||||
key: ServerQuery-Password
|
key: ServerQuery-Password
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
- name: teamspeak-data
|
- name: teamspeak-data
|
||||||
mountPath: /var/ts3server
|
mountPath: /var/ts3server
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
memory: 128Mi
|
memory: 128Mi
|
||||||
cpu: 50m
|
cpu: 50m
|
||||||
limits:
|
limits:
|
||||||
memory: 512Mi
|
memory: 512Mi
|
||||||
cpu: 500m
|
cpu: 500m
|
||||||
readinessProbe:
|
readinessProbe:
|
||||||
tcpSocket:
|
tcpSocket:
|
||||||
port: 10011
|
port: 10011
|
||||||
initialDelaySeconds: 30
|
initialDelaySeconds: 30
|
||||||
periodSeconds: 10
|
periodSeconds: 10
|
||||||
livenessProbe:
|
livenessProbe:
|
||||||
tcpSocket:
|
tcpSocket:
|
||||||
port: 10011
|
port: 10011
|
||||||
initialDelaySeconds: 60
|
initialDelaySeconds: 60
|
||||||
periodSeconds: 15
|
periodSeconds: 15
|
||||||
volumes:
|
volumes:
|
||||||
- name: teamspeak-data
|
- name: teamspeak-data
|
||||||
persistentVolumeClaim:
|
persistentVolumeClaim:
|
||||||
claimName: teamspeak-data
|
claimName: teamspeak-data
|
||||||
- name: license
|
- name: license
|
||||||
secret:
|
secret:
|
||||||
secretName: teamspeak-license
|
secretName: teamspeak-license
|
||||||
---
|
---
|
||||||
# TeamSpeak LoadBalancer Service
|
# TeamSpeak LoadBalancer Service
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Service
|
kind: Service
|
||||||
metadata:
|
metadata:
|
||||||
name: teamspeak
|
name: teamspeak
|
||||||
namespace: teamspeak
|
namespace: teamspeak
|
||||||
annotations:
|
annotations:
|
||||||
metallb.universe.tf/loadBalancerIPs: 10.0.56.205
|
metallb.universe.tf/loadBalancerIPs: 10.0.56.205
|
||||||
spec:
|
spec:
|
||||||
type: LoadBalancer
|
type: LoadBalancer
|
||||||
selector:
|
selector:
|
||||||
app: teamspeak
|
app: teamspeak
|
||||||
ports:
|
ports:
|
||||||
- port: 9987
|
- port: 9987
|
||||||
targetPort: 9987
|
targetPort: 9987
|
||||||
name: voice
|
name: voice
|
||||||
protocol: UDP
|
protocol: UDP
|
||||||
- port: 30033
|
- port: 30033
|
||||||
targetPort: 30033
|
targetPort: 30033
|
||||||
name: filetransfer
|
name: filetransfer
|
||||||
protocol: TCP
|
protocol: TCP
|
||||||
- port: 10011
|
- port: 10011
|
||||||
targetPort: 10011
|
targetPort: 10011
|
||||||
name: serverquery
|
name: serverquery
|
||||||
protocol: TCP
|
protocol: TCP
|
||||||
|
|||||||
@@ -1,127 +1,127 @@
|
|||||||
# Twilio Voice Bridge - Traefik ingress to edge1
|
# Twilio Voice Bridge - Traefik ingress to edge1
|
||||||
# ArgoCD managed - BlueJay Lab
|
# ArgoCD managed - BlueJay Lab
|
||||||
# Routes voice.bluejay.dev (TwiML) and voice-ws.bluejay.dev (WebSocket)
|
# Routes voice.bluejay.dev (TwiML) and voice-ws.bluejay.dev (WebSocket)
|
||||||
# to edge1 Pi5 at 10.0.57.15 (PROD VLAN)
|
# to edge1 Pi5 at 10.0.57.15 (PROD VLAN)
|
||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Namespace
|
kind: Namespace
|
||||||
metadata:
|
metadata:
|
||||||
name: voice
|
name: voice
|
||||||
labels:
|
labels:
|
||||||
app.kubernetes.io/part-of: bluejay-infra
|
app.kubernetes.io/part-of: bluejay-infra
|
||||||
---
|
---
|
||||||
# Cloudflare origin cert for *.bluejay.dev
|
# Cloudflare origin cert for *.bluejay.dev
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Secret
|
kind: Secret
|
||||||
metadata:
|
metadata:
|
||||||
name: cf-origin-bluejay-dev
|
name: cf-origin-bluejay-dev
|
||||||
namespace: voice
|
namespace: voice
|
||||||
type: kubernetes.io/tls
|
type: kubernetes.io/tls
|
||||||
data:
|
data:
|
||||||
tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVvakNDQTRxZ0F3SUJBZ0lVTkxnemZ4UVRzMElyWWRaZUZKUGN5TjRyNmFjd0RRWUpLb1pJaHZjTkFRRUwKQlFBd2dZc3hDekFKQmdOVkJBWVRBbFZUTVJrd0Z3WURWUVFLRXhCRGJHOTFaRVpzWVhKbExDQkpibU11TVRRdwpNZ1lEVlFRTEV5dERiRzkxWkVac1lYSmxJRTl5YVdkcGJpQlRVMHdnUTJWeWRHbG1hV05oZEdVZ1FYVjBhRzl5CmFYUjVNUll3RkFZRFZRUUhFdzFUWVc0Z1JuSmhibU5wYzJOdk1STXdFUVlEVlFRSUV3cERZV3hwWm05eWJtbGgKTUI0WERUSTJNRE14TURBMU1USXdNRm9YRFRReE1ETXdOakExTVRJd01Gb3dZakVaTUJjR0ExVUVDaE1RUTJ4dgpkV1JHYkdGeVpTd2dTVzVqTGpFZE1Cc0dBMVVFQ3hNVVEyeHZkV1JHYkdGeVpTQlBjbWxuYVc0Z1EwRXhKakFrCkJnTlZCQU1USFVOc2IzVmtSbXhoY21VZ1QzSnBaMmx1SUVObGNuUnBabWxqWVhSbE1JSUJJakFOQmdrcWhraUcKOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQXlPODBJQ3dPV0RWTEpQNm9RenI3aXVENmtWMGNWZ01VbUx5VApKVnVYUlhZSEY3M2ZrM2pPbytCQVE1M2pmbERHUFVYc0UvNlV6VDRoUDVYTlVLaUNXaitvYy84eE1BSWsxcWwrClZnbFI1MDBUQ0FtZDliazNZVkxiZjBSejVMMUQ0WGJmOEVzamhOUVV2Z3Y0dTZoQzdnRmdrVGplc1dIZjg0K04KNERETDdmTjFQZHR4RVBiVWZrbGN1MUZSdXdlMk9QNkFEMlJvdkphNWZwODRHcVY2TDAzdjY2RjFtMnBST1VmRwpFdWpRNG4zSms2cUx5NHZTTENzOGJlOGRBRW5QcDgyZ2NRZk9mUVlIS2JTUWhiQnMwK01vK3lkTHpHSzFRdklRCnVPcDZRT1BtM0lac09Eb0VCdG5kMTh2amx6Y1JSdE94cjNzaFovdmNWY0o0YUJNZDVRSURBUUFCbzRJQkpEQ0MKQVNBd0RnWURWUjBQQVFIL0JBUURBZ1dnTUIwR0ExVWRKUVFXTUJRR0NDc0dBUVVGQndNQ0JnZ3JCZ0VGQlFjRApBVEFNQmdOVkhSTUJBZjhFQWpBQU1CMEdBMVVkRGdRV0JCVHgyYmFCUGlvWjZUd2U3THhnaTViUS82cUFkakFmCkJnTlZIU01FR0RBV2dCUWs2Rk5YWFh3MFFJZXA2NVRidXVFV2VQd3BwREJBQmdnckJnRUZCUWNCQVFRME1ESXcKTUFZSUt3WUJCUVVITUFHR0pHaDBkSEE2THk5dlkzTndMbU5zYjNWa1pteGhjbVV1WTI5dEwyOXlhV2RwYmw5agpZVEFsQmdOVkhSRUVIakFjZ2cwcUxtSnNkV1ZxWVhrdVpHVjJnZ3RpYkhWbGFtRjVMbVJsZGpBNEJnTlZIUjhFCk1UQXZNQzJnSzZBcGhpZG9kSFJ3T2k4dlkzSnNMbU5zYjNWa1pteGhjbVV1WTI5dEwyOXlhV2RwYmw5allTNWoKY213d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFDS0ZVRXhYbFB5KzlPRytJc1VWN1NXS09Udkk0b2JrUkd6bwpOckhudWZ3dGtxa0dzUGErUU5LbUk1UVNaYTVMS1YybWZJdWsrNE12U1FvZklmbUFUb1JEWEdQK041aWxEbWRSCk5rS2ttSUpZL242UzM3MGdZN0JQMjFwNjJKUnZkVUU5ZmV5RU1iMUdNbGNINjN6MUQxMzZZOWlvQ1FnYWNFZVUKOFZSVWFPZkJvby9sVzlYbXA1ZDZzcTBic2tybUhRN1ZSTjUxZCtsL0RvY2lkU2xZcHQxbXljSUN3c1F4U0dpMApYN1pMTXhHdCtDVG9jcFRFbkdrQ2t0NnhrKzVJUElXaHYvVnZuTnlQNUwxM0ZRN1d4QzFsaUIwcVdKMkEwcWpoCkR2cmxPNUpsclNWWEtNc0hwSWRFN3pJZ29JUUc2cnU1N1V4UjJyeko0d0VrSXcrd1ZyMD0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
|
tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVvakNDQTRxZ0F3SUJBZ0lVTkxnemZ4UVRzMElyWWRaZUZKUGN5TjRyNmFjd0RRWUpLb1pJaHZjTkFRRUwKQlFBd2dZc3hDekFKQmdOVkJBWVRBbFZUTVJrd0Z3WURWUVFLRXhCRGJHOTFaRVpzWVhKbExDQkpibU11TVRRdwpNZ1lEVlFRTEV5dERiRzkxWkVac1lYSmxJRTl5YVdkcGJpQlRVMHdnUTJWeWRHbG1hV05oZEdVZ1FYVjBhRzl5CmFYUjVNUll3RkFZRFZRUUhFdzFUWVc0Z1JuSmhibU5wYzJOdk1STXdFUVlEVlFRSUV3cERZV3hwWm05eWJtbGgKTUI0WERUSTJNRE14TURBMU1USXdNRm9YRFRReE1ETXdOakExTVRJd01Gb3dZakVaTUJjR0ExVUVDaE1RUTJ4dgpkV1JHYkdGeVpTd2dTVzVqTGpFZE1Cc0dBMVVFQ3hNVVEyeHZkV1JHYkdGeVpTQlBjbWxuYVc0Z1EwRXhKakFrCkJnTlZCQU1USFVOc2IzVmtSbXhoY21VZ1QzSnBaMmx1SUVObGNuUnBabWxqWVhSbE1JSUJJakFOQmdrcWhraUcKOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQXlPODBJQ3dPV0RWTEpQNm9RenI3aXVENmtWMGNWZ01VbUx5VApKVnVYUlhZSEY3M2ZrM2pPbytCQVE1M2pmbERHUFVYc0UvNlV6VDRoUDVYTlVLaUNXaitvYy84eE1BSWsxcWwrClZnbFI1MDBUQ0FtZDliazNZVkxiZjBSejVMMUQ0WGJmOEVzamhOUVV2Z3Y0dTZoQzdnRmdrVGplc1dIZjg0K04KNERETDdmTjFQZHR4RVBiVWZrbGN1MUZSdXdlMk9QNkFEMlJvdkphNWZwODRHcVY2TDAzdjY2RjFtMnBST1VmRwpFdWpRNG4zSms2cUx5NHZTTENzOGJlOGRBRW5QcDgyZ2NRZk9mUVlIS2JTUWhiQnMwK01vK3lkTHpHSzFRdklRCnVPcDZRT1BtM0lac09Eb0VCdG5kMTh2amx6Y1JSdE94cjNzaFovdmNWY0o0YUJNZDVRSURBUUFCbzRJQkpEQ0MKQVNBd0RnWURWUjBQQVFIL0JBUURBZ1dnTUIwR0ExVWRKUVFXTUJRR0NDc0dBUVVGQndNQ0JnZ3JCZ0VGQlFjRApBVEFNQmdOVkhSTUJBZjhFQWpBQU1CMEdBMVVkRGdRV0JCVHgyYmFCUGlvWjZUd2U3THhnaTViUS82cUFkakFmCkJnTlZIU01FR0RBV2dCUWs2Rk5YWFh3MFFJZXA2NVRidXVFV2VQd3BwREJBQmdnckJnRUZCUWNCQVFRME1ESXcKTUFZSUt3WUJCUVVITUFHR0pHaDBkSEE2THk5dlkzTndMbU5zYjNWa1pteGhjbVV1WTI5dEwyOXlhV2RwYmw5agpZVEFsQmdOVkhSRUVIakFjZ2cwcUxtSnNkV1ZxWVhrdVpHVjJnZ3RpYkhWbGFtRjVMbVJsZGpBNEJnTlZIUjhFCk1UQXZNQzJnSzZBcGhpZG9kSFJ3T2k4dlkzSnNMbU5zYjNWa1pteGhjbVV1WTI5dEwyOXlhV2RwYmw5allTNWoKY213d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFDS0ZVRXhYbFB5KzlPRytJc1VWN1NXS09Udkk0b2JrUkd6bwpOckhudWZ3dGtxa0dzUGErUU5LbUk1UVNaYTVMS1YybWZJdWsrNE12U1FvZklmbUFUb1JEWEdQK041aWxEbWRSCk5rS2ttSUpZL242UzM3MGdZN0JQMjFwNjJKUnZkVUU5ZmV5RU1iMUdNbGNINjN6MUQxMzZZOWlvQ1FnYWNFZVUKOFZSVWFPZkJvby9sVzlYbXA1ZDZzcTBic2tybUhRN1ZSTjUxZCtsL0RvY2lkU2xZcHQxbXljSUN3c1F4U0dpMApYN1pMTXhHdCtDVG9jcFRFbkdrQ2t0NnhrKzVJUElXaHYvVnZuTnlQNUwxM0ZRN1d4QzFsaUIwcVdKMkEwcWpoCkR2cmxPNUpsclNWWEtNc0hwSWRFN3pJZ29JUUc2cnU1N1V4UjJyeko0d0VrSXcrd1ZyMD0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
|
||||||
tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2UUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktjd2dnU2pBZ0VBQW9JQkFRREk3elFnTEE1WU5Vc2sKL3FoRE92dUs0UHFSWFJ4V0F4U1l2Sk1sVzVkRmRnY1h2ZCtUZU02ajRFQkRuZU4rVU1ZOVJld1QvcFROUGlFLwpsYzFRcUlKYVA2aHovekV3QWlUV3FYNVdDVkhuVFJNSUNaMzF1VGRoVXR0L1JIUGt2VVBoZHQvd1N5T0UxQlMrCkMvaTdxRUx1QVdDUk9ONnhZZC96ajQzZ01NdnQ4M1U5MjNFUTl0UitTVnk3VVZHN0I3WTQvb0FQWkdpOGxybCsKbnpnYXBYb3ZUZS9yb1hXYmFsRTVSOFlTNk5EaWZjbVRxb3ZMaTlJc0t6eHQ3eDBBU2MrbnphQnhCODU5QmdjcAp0SkNGc0d6VDR5ajdKMHZNWXJWQzhoQzQ2bnBBNCtiY2htdzRPZ1FHMmQzWHkrT1hOeEZHMDdHdmV5Rm4rOXhWCnduaG9FeDNsQWdNQkFBRUNnZ0VBRFpWeU9peVFTYkZNbzdNZGovSDRXR0t1UGM2RUlHSno3WUZ1Rnl2eWRZMHQKbkpMRy94Sy9NWC96Q0Q4dnhuWFNlUWoxbFVKMEw4M2Y5SXI5aHRMbGdSRmxvM1hnanVUT05iN2VuaFZpTnBkVQp6b25MNW5VL2c3SlV5VzFJd25GekdkWnQvREl3TkFZY1l0NnZVWXhsL2U0VTU2eG5EYW5XdUlIL2J1VU5uRWZtCjZNcnlIblhseDA0TzZzOElLSCtXNUxDam1ma1Jac0VveE9Damt6T2hucmdCTk4xSWxWSWhhMDhLOXBxRk5qM0wKaWd4MVNYZDhqaHNZUHJxaDNkak0rVUNKSitKMURuMjhaUmoyZUtqWDMvZmFDbGFpOEFzUVBtQTJScjZYZ3kzeApaR090dzRPL2Nxb1hnOUFDU05NanRNK3VtaXM3QzNncWp6VUZ4MWwvNFFLQmdRRFNvSGVDY1dXSUJQV3grR01hCnBSMENHejQ0eDNPRUhnNWYza2RvK3BDK0I3RnYxREV5bktqUUY4VFBYaWJXVGZVL1pBRG5DVmIvU1Z2L1QyNnkKT2NlaW44UGRqdXkraE05ZUxjWXU4QVZiK0VKOHFMUUsrZE5QZm1nYXZJMWR2V3U2Tm8wSTNSSzZWUkpiQXEyWgpLcjdsVEloMjdZMDRMajlaaUIxU01YZ0J0UUtCZ1FEME9EbEVCNHRHa1l2dTVLMkFoaDBmdnlIaUVoUTd5dWUzCmZXdG1VYnRxV0ZlM1R5UG9JTWJWMTM3MkNIdlh6MFNEMXRwYzJxa3hxN3c4d1BYM3RJZGk5NWxMbVMzZm8zWFoKdTNTYVo4enozTlAwR3JXK1Y0c3hHb1VnbWgwL2lzOXJoaWxXZGF5bU5SWEQ5U0MyUU5IdTU5NDY2UjFkczNnbgpiZlJlUkw4SmNRS0JnREptVjNLTk0rQmlYM0Jnb1VaRThEWUswczYvV3pMb0JrU0dhY3dDK1JPZnY2T2t3TWo5Cmw1K0RzSUoyWXhDd3d0aVNVMnoxWFMzbEhmQnZ6MnN5VEVUcnVmQ1FQTEl5RVhUVnV6Q01HcHd4UWFlV3JzNVoKaldqZU5JY0JTMHA5QXdRaC9ZbDdiUG5OVllFVm1QaW5zOW9tZ0JrRkt0K2dvV1FKSUFzRTcxUnBBb0dCQUxNSgphTW43c2RuNUo1bnA0VnhBZGFkcGFvQ2VlbURmUG9KaEd0UTNCT3RRZW5Xek9nS1p6TXJHSVpoaTNjOTNicVlzClk0Y0E4bHFzcU9IdElDVUpIdHVwNHFMdVdCZ0VjSWcvaVpzTWo4OFRTL3MvZlk5ZUJIZnFGa0N4V3RIVGhINHkKSzZucnVMZGNZV2w0RWhRcWJ2enkxUk5oQkp0Rno4Y3dMNTdRVFRDeEFvR0FjZFFkbzk3bzZmS0dQa3kvREpnNApoTGlLbHVkTjF3bmJaTHFVM0UwNzBwVDhJQkx3TFNpTUNpYXRXWWtScHFpdUQyMSsya1p4SE1NdnNoZWJXQmFmCmVqWU9jcHVvQ3VWdWc1K1dlbmc0cmUxSTl2c2czUE5WYkdrNW1xNmZDbndsbGFnMkEvSVBVRFFOaUpCVGM1WUQKc25udzhVTjNBTFBMSTlPVVd1eXJUckk9Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K
|
tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2UUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktjd2dnU2pBZ0VBQW9JQkFRREk3elFnTEE1WU5Vc2sKL3FoRE92dUs0UHFSWFJ4V0F4U1l2Sk1sVzVkRmRnY1h2ZCtUZU02ajRFQkRuZU4rVU1ZOVJld1QvcFROUGlFLwpsYzFRcUlKYVA2aHovekV3QWlUV3FYNVdDVkhuVFJNSUNaMzF1VGRoVXR0L1JIUGt2VVBoZHQvd1N5T0UxQlMrCkMvaTdxRUx1QVdDUk9ONnhZZC96ajQzZ01NdnQ4M1U5MjNFUTl0UitTVnk3VVZHN0I3WTQvb0FQWkdpOGxybCsKbnpnYXBYb3ZUZS9yb1hXYmFsRTVSOFlTNk5EaWZjbVRxb3ZMaTlJc0t6eHQ3eDBBU2MrbnphQnhCODU5QmdjcAp0SkNGc0d6VDR5ajdKMHZNWXJWQzhoQzQ2bnBBNCtiY2htdzRPZ1FHMmQzWHkrT1hOeEZHMDdHdmV5Rm4rOXhWCnduaG9FeDNsQWdNQkFBRUNnZ0VBRFpWeU9peVFTYkZNbzdNZGovSDRXR0t1UGM2RUlHSno3WUZ1Rnl2eWRZMHQKbkpMRy94Sy9NWC96Q0Q4dnhuWFNlUWoxbFVKMEw4M2Y5SXI5aHRMbGdSRmxvM1hnanVUT05iN2VuaFZpTnBkVQp6b25MNW5VL2c3SlV5VzFJd25GekdkWnQvREl3TkFZY1l0NnZVWXhsL2U0VTU2eG5EYW5XdUlIL2J1VU5uRWZtCjZNcnlIblhseDA0TzZzOElLSCtXNUxDam1ma1Jac0VveE9Damt6T2hucmdCTk4xSWxWSWhhMDhLOXBxRk5qM0wKaWd4MVNYZDhqaHNZUHJxaDNkak0rVUNKSitKMURuMjhaUmoyZUtqWDMvZmFDbGFpOEFzUVBtQTJScjZYZ3kzeApaR090dzRPL2Nxb1hnOUFDU05NanRNK3VtaXM3QzNncWp6VUZ4MWwvNFFLQmdRRFNvSGVDY1dXSUJQV3grR01hCnBSMENHejQ0eDNPRUhnNWYza2RvK3BDK0I3RnYxREV5bktqUUY4VFBYaWJXVGZVL1pBRG5DVmIvU1Z2L1QyNnkKT2NlaW44UGRqdXkraE05ZUxjWXU4QVZiK0VKOHFMUUsrZE5QZm1nYXZJMWR2V3U2Tm8wSTNSSzZWUkpiQXEyWgpLcjdsVEloMjdZMDRMajlaaUIxU01YZ0J0UUtCZ1FEME9EbEVCNHRHa1l2dTVLMkFoaDBmdnlIaUVoUTd5dWUzCmZXdG1VYnRxV0ZlM1R5UG9JTWJWMTM3MkNIdlh6MFNEMXRwYzJxa3hxN3c4d1BYM3RJZGk5NWxMbVMzZm8zWFoKdTNTYVo4enozTlAwR3JXK1Y0c3hHb1VnbWgwL2lzOXJoaWxXZGF5bU5SWEQ5U0MyUU5IdTU5NDY2UjFkczNnbgpiZlJlUkw4SmNRS0JnREptVjNLTk0rQmlYM0Jnb1VaRThEWUswczYvV3pMb0JrU0dhY3dDK1JPZnY2T2t3TWo5Cmw1K0RzSUoyWXhDd3d0aVNVMnoxWFMzbEhmQnZ6MnN5VEVUcnVmQ1FQTEl5RVhUVnV6Q01HcHd4UWFlV3JzNVoKaldqZU5JY0JTMHA5QXdRaC9ZbDdiUG5OVllFVm1QaW5zOW9tZ0JrRkt0K2dvV1FKSUFzRTcxUnBBb0dCQUxNSgphTW43c2RuNUo1bnA0VnhBZGFkcGFvQ2VlbURmUG9KaEd0UTNCT3RRZW5Xek9nS1p6TXJHSVpoaTNjOTNicVlzClk0Y0E4bHFzcU9IdElDVUpIdHVwNHFMdVdCZ0VjSWcvaVpzTWo4OFRTL3MvZlk5ZUJIZnFGa0N4V3RIVGhINHkKSzZucnVMZGNZV2w0RWhRcWJ2enkxUk5oQkp0Rno4Y3dMNTdRVFRDeEFvR0FjZFFkbzk3bzZmS0dQa3kvREpnNApoTGlLbHVkTjF3bmJaTHFVM0UwNzBwVDhJQkx3TFNpTUNpYXRXWWtScHFpdUQyMSsya1p4SE1NdnNoZWJXQmFmCmVqWU9jcHVvQ3VWdWc1K1dlbmc0cmUxSTl2c2czUE5WYkdrNW1xNmZDbndsbGFnMkEvSVBVRFFOaUpCVGM1WUQKc25udzhVTjNBTFBMSTlPVVd1eXJUckk9Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K
|
||||||
---
|
---
|
||||||
# Service (no selector) pointing to external edge1
|
# Service (no selector) pointing to external edge1
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Service
|
kind: Service
|
||||||
metadata:
|
metadata:
|
||||||
name: voice-bridge
|
name: voice-bridge
|
||||||
namespace: voice
|
namespace: voice
|
||||||
spec:
|
spec:
|
||||||
ports:
|
ports:
|
||||||
- name: twiml
|
- name: twiml
|
||||||
port: 8766
|
port: 8766
|
||||||
targetPort: 8766
|
targetPort: 8766
|
||||||
protocol: TCP
|
protocol: TCP
|
||||||
- name: websocket
|
- name: websocket
|
||||||
port: 8765
|
port: 8765
|
||||||
targetPort: 8765
|
targetPort: 8765
|
||||||
protocol: TCP
|
protocol: TCP
|
||||||
---
|
---
|
||||||
# Manual Endpoints for edge1 (outside K8s)
|
# Manual Endpoints for edge1 (outside K8s)
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Endpoints
|
kind: Endpoints
|
||||||
metadata:
|
metadata:
|
||||||
name: voice-bridge
|
name: voice-bridge
|
||||||
namespace: voice
|
namespace: voice
|
||||||
subsets:
|
subsets:
|
||||||
- addresses:
|
- addresses:
|
||||||
- ip: 10.0.57.15
|
- ip: 10.0.57.15
|
||||||
ports:
|
ports:
|
||||||
- name: twiml
|
- name: twiml
|
||||||
port: 8766
|
port: 8766
|
||||||
protocol: TCP
|
protocol: TCP
|
||||||
- name: websocket
|
- name: websocket
|
||||||
port: 8765
|
port: 8765
|
||||||
protocol: TCP
|
protocol: TCP
|
||||||
---
|
---
|
||||||
# TwiML webhook: voice.bluejay.dev -> edge1:8766
|
# TwiML webhook: voice.bluejay.dev -> edge1:8766
|
||||||
apiVersion: traefik.io/v1alpha1
|
apiVersion: traefik.io/v1alpha1
|
||||||
kind: IngressRoute
|
kind: IngressRoute
|
||||||
metadata:
|
metadata:
|
||||||
name: voice-twiml
|
name: voice-twiml
|
||||||
namespace: voice
|
namespace: voice
|
||||||
spec:
|
spec:
|
||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- kind: Rule
|
- kind: Rule
|
||||||
match: Host(`voice.bluejay.dev`)
|
match: Host(`voice.bluejay.dev`)
|
||||||
services:
|
services:
|
||||||
- name: voice-bridge
|
- name: voice-bridge
|
||||||
port: 8766
|
port: 8766
|
||||||
tls:
|
tls:
|
||||||
secretName: cf-origin-bluejay-dev
|
secretName: cf-origin-bluejay-dev
|
||||||
---
|
---
|
||||||
# WebSocket media stream: voice-ws.bluejay.dev -> edge1:8765
|
# WebSocket media stream: voice-ws.bluejay.dev -> edge1:8765
|
||||||
apiVersion: traefik.io/v1alpha1
|
apiVersion: traefik.io/v1alpha1
|
||||||
kind: IngressRoute
|
kind: IngressRoute
|
||||||
metadata:
|
metadata:
|
||||||
name: voice-ws
|
name: voice-ws
|
||||||
namespace: voice
|
namespace: voice
|
||||||
spec:
|
spec:
|
||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- kind: Rule
|
- kind: Rule
|
||||||
match: Host(`voice-ws.bluejay.dev`)
|
match: Host(`voice-ws.bluejay.dev`)
|
||||||
services:
|
services:
|
||||||
- name: voice-bridge
|
- name: voice-bridge
|
||||||
port: 8765
|
port: 8765
|
||||||
tls:
|
tls:
|
||||||
secretName: cf-origin-bluejay-dev
|
secretName: cf-origin-bluejay-dev
|
||||||
---
|
---
|
||||||
# NetworkPolicy: allow Traefik ingress only
|
# NetworkPolicy: allow Traefik ingress only
|
||||||
apiVersion: networking.k8s.io/v1
|
apiVersion: networking.k8s.io/v1
|
||||||
kind: NetworkPolicy
|
kind: NetworkPolicy
|
||||||
metadata:
|
metadata:
|
||||||
name: voice-netpol
|
name: voice-netpol
|
||||||
namespace: voice
|
namespace: voice
|
||||||
spec:
|
spec:
|
||||||
podSelector: {}
|
podSelector: {}
|
||||||
policyTypes:
|
policyTypes:
|
||||||
- Ingress
|
- Ingress
|
||||||
- Egress
|
- Egress
|
||||||
ingress:
|
ingress:
|
||||||
- from:
|
- from:
|
||||||
- namespaceSelector:
|
- namespaceSelector:
|
||||||
matchLabels:
|
matchLabels:
|
||||||
kubernetes.io/metadata.name: traefik-system
|
kubernetes.io/metadata.name: traefik-system
|
||||||
egress:
|
egress:
|
||||||
- to:
|
- to:
|
||||||
- ipBlock:
|
- ipBlock:
|
||||||
cidr: 10.0.57.15/32
|
cidr: 10.0.57.15/32
|
||||||
ports:
|
ports:
|
||||||
- port: 8765
|
- port: 8765
|
||||||
protocol: TCP
|
protocol: TCP
|
||||||
- port: 8766
|
- port: 8766
|
||||||
protocol: TCP
|
protocol: TCP
|
||||||
- to:
|
- to:
|
||||||
- namespaceSelector:
|
- namespaceSelector:
|
||||||
matchLabels:
|
matchLabels:
|
||||||
kubernetes.io/metadata.name: kube-system
|
kubernetes.io/metadata.name: kube-system
|
||||||
ports:
|
ports:
|
||||||
- port: 53
|
- port: 53
|
||||||
protocol: UDP
|
protocol: UDP
|
||||||
- port: 53
|
- port: 53
|
||||||
protocol: TCP
|
protocol: TCP
|
||||||
|
|||||||
@@ -1,360 +1,360 @@
|
|||||||
# Zabbix 7.2 Monitoring Stack
|
# Zabbix 7.2 Monitoring Stack
|
||||||
# PostgreSQL 16 + Zabbix Server + Zabbix Web (nginx)
|
# PostgreSQL 16 + Zabbix Server + Zabbix Web (nginx)
|
||||||
# ArgoCD managed - BlueJay Lab
|
# ArgoCD managed - BlueJay Lab
|
||||||
# Credentials sourced from 1Password via OnePasswordItem CRD (zabbix-credentials)
|
# Credentials sourced from 1Password via OnePasswordItem CRD (zabbix-credentials)
|
||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Namespace
|
kind: Namespace
|
||||||
metadata:
|
metadata:
|
||||||
name: zabbix
|
name: zabbix
|
||||||
labels:
|
labels:
|
||||||
app.kubernetes.io/part-of: bluejay-infra
|
app.kubernetes.io/part-of: bluejay-infra
|
||||||
---
|
---
|
||||||
# PostgreSQL 16 StatefulSet
|
# PostgreSQL 16 StatefulSet
|
||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: StatefulSet
|
kind: StatefulSet
|
||||||
metadata:
|
metadata:
|
||||||
name: zabbix-postgres
|
name: zabbix-postgres
|
||||||
namespace: zabbix
|
namespace: zabbix
|
||||||
labels:
|
labels:
|
||||||
app: zabbix-postgres
|
app: zabbix-postgres
|
||||||
spec:
|
spec:
|
||||||
serviceName: zabbix-postgres
|
serviceName: zabbix-postgres
|
||||||
replicas: 1
|
replicas: 1
|
||||||
selector:
|
selector:
|
||||||
matchLabels:
|
matchLabels:
|
||||||
app: zabbix-postgres
|
app: zabbix-postgres
|
||||||
template:
|
template:
|
||||||
metadata:
|
metadata:
|
||||||
labels:
|
labels:
|
||||||
app: zabbix-postgres
|
app: zabbix-postgres
|
||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: postgres
|
- name: postgres
|
||||||
image: postgres:16-alpine
|
image: postgres:16-alpine
|
||||||
args:
|
args:
|
||||||
- "-c"
|
- "-c"
|
||||||
- "shared_buffers=256MB"
|
- "shared_buffers=256MB"
|
||||||
- "-c"
|
- "-c"
|
||||||
- "effective_cache_size=512MB"
|
- "effective_cache_size=512MB"
|
||||||
- "-c"
|
- "-c"
|
||||||
- "work_mem=16MB"
|
- "work_mem=16MB"
|
||||||
- "-c"
|
- "-c"
|
||||||
- "maintenance_work_mem=128MB"
|
- "maintenance_work_mem=128MB"
|
||||||
- "-c"
|
- "-c"
|
||||||
- "random_page_cost=1.1"
|
- "random_page_cost=1.1"
|
||||||
- "-c"
|
- "-c"
|
||||||
- "effective_io_concurrency=200"
|
- "effective_io_concurrency=200"
|
||||||
- "-c"
|
- "-c"
|
||||||
- "max_connections=50"
|
- "max_connections=50"
|
||||||
- "-c"
|
- "-c"
|
||||||
- "checkpoint_completion_target=0.9"
|
- "checkpoint_completion_target=0.9"
|
||||||
- "-c"
|
- "-c"
|
||||||
- "wal_buffers=8MB"
|
- "wal_buffers=8MB"
|
||||||
ports:
|
ports:
|
||||||
- containerPort: 5432
|
- containerPort: 5432
|
||||||
name: postgres
|
name: postgres
|
||||||
env:
|
env:
|
||||||
- name: POSTGRES_USER
|
- name: POSTGRES_USER
|
||||||
valueFrom:
|
valueFrom:
|
||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
name: zabbix-credentials
|
name: zabbix-credentials
|
||||||
key: DB-User
|
key: DB-User
|
||||||
- name: POSTGRES_PASSWORD
|
- name: POSTGRES_PASSWORD
|
||||||
valueFrom:
|
valueFrom:
|
||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
name: zabbix-credentials
|
name: zabbix-credentials
|
||||||
key: DB-Password
|
key: DB-Password
|
||||||
- name: POSTGRES_DB
|
- name: POSTGRES_DB
|
||||||
value: zabbix
|
value: zabbix
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
- name: zabbix-postgres-data
|
- name: zabbix-postgres-data
|
||||||
mountPath: /var/lib/postgresql/data
|
mountPath: /var/lib/postgresql/data
|
||||||
subPath: pgdata
|
subPath: pgdata
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
memory: 512Mi
|
memory: 512Mi
|
||||||
cpu: 200m
|
cpu: 200m
|
||||||
limits:
|
limits:
|
||||||
memory: 1Gi
|
memory: 1Gi
|
||||||
cpu: "1"
|
cpu: "1"
|
||||||
livenessProbe:
|
livenessProbe:
|
||||||
exec:
|
exec:
|
||||||
command:
|
command:
|
||||||
- pg_isready
|
- pg_isready
|
||||||
- -U
|
- -U
|
||||||
- zabbix
|
- zabbix
|
||||||
initialDelaySeconds: 30
|
initialDelaySeconds: 30
|
||||||
periodSeconds: 10
|
periodSeconds: 10
|
||||||
readinessProbe:
|
readinessProbe:
|
||||||
exec:
|
exec:
|
||||||
command:
|
command:
|
||||||
- pg_isready
|
- pg_isready
|
||||||
- -U
|
- -U
|
||||||
- zabbix
|
- zabbix
|
||||||
initialDelaySeconds: 5
|
initialDelaySeconds: 5
|
||||||
periodSeconds: 5
|
periodSeconds: 5
|
||||||
volumeClaimTemplates:
|
volumeClaimTemplates:
|
||||||
- metadata:
|
- metadata:
|
||||||
name: zabbix-postgres-data
|
name: zabbix-postgres-data
|
||||||
spec:
|
spec:
|
||||||
accessModes: [ReadWriteOnce]
|
accessModes: [ReadWriteOnce]
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
storage: 10Gi
|
storage: 10Gi
|
||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Service
|
kind: Service
|
||||||
metadata:
|
metadata:
|
||||||
name: zabbix-postgres
|
name: zabbix-postgres
|
||||||
namespace: zabbix
|
namespace: zabbix
|
||||||
spec:
|
spec:
|
||||||
selector:
|
selector:
|
||||||
app: zabbix-postgres
|
app: zabbix-postgres
|
||||||
ports:
|
ports:
|
||||||
- port: 5432
|
- port: 5432
|
||||||
targetPort: 5432
|
targetPort: 5432
|
||||||
name: postgres
|
name: postgres
|
||||||
clusterIP: None
|
clusterIP: None
|
||||||
---
|
---
|
||||||
# Zabbix Server
|
# Zabbix Server
|
||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
name: zabbix-server
|
name: zabbix-server
|
||||||
namespace: zabbix
|
namespace: zabbix
|
||||||
labels:
|
labels:
|
||||||
app: zabbix-server
|
app: zabbix-server
|
||||||
spec:
|
spec:
|
||||||
replicas: 1
|
replicas: 1
|
||||||
selector:
|
selector:
|
||||||
matchLabels:
|
matchLabels:
|
||||||
app: zabbix-server
|
app: zabbix-server
|
||||||
template:
|
template:
|
||||||
metadata:
|
metadata:
|
||||||
labels:
|
labels:
|
||||||
app: zabbix-server
|
app: zabbix-server
|
||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: zabbix-server
|
- name: zabbix-server
|
||||||
image: zabbix/zabbix-server-pgsql:7.2-alpine-latest
|
image: zabbix/zabbix-server-pgsql:7.2-alpine-latest
|
||||||
ports:
|
ports:
|
||||||
- containerPort: 10051
|
- containerPort: 10051
|
||||||
name: trapper
|
name: trapper
|
||||||
env:
|
env:
|
||||||
- name: DB_SERVER_HOST
|
- name: DB_SERVER_HOST
|
||||||
value: zabbix-postgres
|
value: zabbix-postgres
|
||||||
- name: DB_SERVER_PORT
|
- name: DB_SERVER_PORT
|
||||||
value: "5432"
|
value: "5432"
|
||||||
- name: POSTGRES_USER
|
- name: POSTGRES_USER
|
||||||
valueFrom:
|
valueFrom:
|
||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
name: zabbix-credentials
|
name: zabbix-credentials
|
||||||
key: DB-User
|
key: DB-User
|
||||||
- name: POSTGRES_PASSWORD
|
- name: POSTGRES_PASSWORD
|
||||||
valueFrom:
|
valueFrom:
|
||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
name: zabbix-credentials
|
name: zabbix-credentials
|
||||||
key: DB-Password
|
key: DB-Password
|
||||||
- name: POSTGRES_DB
|
- name: POSTGRES_DB
|
||||||
value: zabbix
|
value: zabbix
|
||||||
- name: ZBX_CACHESIZE
|
- name: ZBX_CACHESIZE
|
||||||
value: "64M"
|
value: "64M"
|
||||||
- name: ZBX_VALUECACHESIZE
|
- name: ZBX_VALUECACHESIZE
|
||||||
value: "64M"
|
value: "64M"
|
||||||
- name: ZBX_HISTORYCACHESIZE
|
- name: ZBX_HISTORYCACHESIZE
|
||||||
value: "32M"
|
value: "32M"
|
||||||
- name: ZBX_TRENDCACHESIZE
|
- name: ZBX_TRENDCACHESIZE
|
||||||
value: "8M"
|
value: "8M"
|
||||||
- name: ZBX_STARTPOLLERS
|
- name: ZBX_STARTPOLLERS
|
||||||
value: "10"
|
value: "10"
|
||||||
- name: ZBX_STARTPOLLERSUNREACHABLE
|
- name: ZBX_STARTPOLLERSUNREACHABLE
|
||||||
value: "3"
|
value: "3"
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
memory: 256Mi
|
memory: 256Mi
|
||||||
cpu: 100m
|
cpu: 100m
|
||||||
limits:
|
limits:
|
||||||
memory: 1Gi
|
memory: 1Gi
|
||||||
cpu: "1"
|
cpu: "1"
|
||||||
livenessProbe:
|
livenessProbe:
|
||||||
tcpSocket:
|
tcpSocket:
|
||||||
port: 10051
|
port: 10051
|
||||||
initialDelaySeconds: 60
|
initialDelaySeconds: 60
|
||||||
periodSeconds: 10
|
periodSeconds: 10
|
||||||
readinessProbe:
|
readinessProbe:
|
||||||
tcpSocket:
|
tcpSocket:
|
||||||
port: 10051
|
port: 10051
|
||||||
initialDelaySeconds: 30
|
initialDelaySeconds: 30
|
||||||
periodSeconds: 5
|
periodSeconds: 5
|
||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Service
|
kind: Service
|
||||||
metadata:
|
metadata:
|
||||||
name: zabbix-server
|
name: zabbix-server
|
||||||
namespace: zabbix
|
namespace: zabbix
|
||||||
spec:
|
spec:
|
||||||
selector:
|
selector:
|
||||||
app: zabbix-server
|
app: zabbix-server
|
||||||
ports:
|
ports:
|
||||||
- port: 10051
|
- port: 10051
|
||||||
targetPort: 10051
|
targetPort: 10051
|
||||||
name: trapper
|
name: trapper
|
||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Service
|
kind: Service
|
||||||
metadata:
|
metadata:
|
||||||
name: zabbix-trapper
|
name: zabbix-trapper
|
||||||
namespace: zabbix
|
namespace: zabbix
|
||||||
annotations:
|
annotations:
|
||||||
metallb.universe.tf/loadBalancerIPs: 10.0.56.203
|
metallb.universe.tf/loadBalancerIPs: 10.0.56.203
|
||||||
spec:
|
spec:
|
||||||
type: LoadBalancer
|
type: LoadBalancer
|
||||||
selector:
|
selector:
|
||||||
app: zabbix-server
|
app: zabbix-server
|
||||||
ports:
|
ports:
|
||||||
- port: 10051
|
- port: 10051
|
||||||
targetPort: 10051
|
targetPort: 10051
|
||||||
name: trapper
|
name: trapper
|
||||||
protocol: TCP
|
protocol: TCP
|
||||||
---
|
---
|
||||||
# Zabbix Web (nginx + PostgreSQL)
|
# Zabbix Web (nginx + PostgreSQL)
|
||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
name: zabbix-web
|
name: zabbix-web
|
||||||
namespace: zabbix
|
namespace: zabbix
|
||||||
labels:
|
labels:
|
||||||
app: zabbix-web
|
app: zabbix-web
|
||||||
spec:
|
spec:
|
||||||
replicas: 1
|
replicas: 1
|
||||||
selector:
|
selector:
|
||||||
matchLabels:
|
matchLabels:
|
||||||
app: zabbix-web
|
app: zabbix-web
|
||||||
template:
|
template:
|
||||||
metadata:
|
metadata:
|
||||||
labels:
|
labels:
|
||||||
app: zabbix-web
|
app: zabbix-web
|
||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: zabbix-web
|
- name: zabbix-web
|
||||||
image: zabbix/zabbix-web-nginx-pgsql:7.2-alpine-latest
|
image: zabbix/zabbix-web-nginx-pgsql:7.2-alpine-latest
|
||||||
ports:
|
ports:
|
||||||
- containerPort: 8080
|
- containerPort: 8080
|
||||||
name: http
|
name: http
|
||||||
env:
|
env:
|
||||||
- name: ZBX_SERVER_HOST
|
- name: ZBX_SERVER_HOST
|
||||||
value: zabbix-server
|
value: zabbix-server
|
||||||
- name: ZBX_SERVER_NAME
|
- name: ZBX_SERVER_NAME
|
||||||
value: "BlueJay NOC"
|
value: "BlueJay NOC"
|
||||||
- name: PHP_TZ
|
- name: PHP_TZ
|
||||||
value: America/Chicago
|
value: America/Chicago
|
||||||
- name: DB_SERVER_HOST
|
- name: DB_SERVER_HOST
|
||||||
value: zabbix-postgres
|
value: zabbix-postgres
|
||||||
- name: DB_SERVER_PORT
|
- name: DB_SERVER_PORT
|
||||||
value: "5432"
|
value: "5432"
|
||||||
- name: POSTGRES_USER
|
- name: POSTGRES_USER
|
||||||
valueFrom:
|
valueFrom:
|
||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
name: zabbix-credentials
|
name: zabbix-credentials
|
||||||
key: DB-User
|
key: DB-User
|
||||||
- name: POSTGRES_PASSWORD
|
- name: POSTGRES_PASSWORD
|
||||||
valueFrom:
|
valueFrom:
|
||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
name: zabbix-credentials
|
name: zabbix-credentials
|
||||||
key: DB-Password
|
key: DB-Password
|
||||||
- name: POSTGRES_DB
|
- name: POSTGRES_DB
|
||||||
value: zabbix
|
value: zabbix
|
||||||
- name: ZBX_ADMIN_PASSWORD
|
- name: ZBX_ADMIN_PASSWORD
|
||||||
valueFrom:
|
valueFrom:
|
||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
name: zabbix-credentials
|
name: zabbix-credentials
|
||||||
key: password
|
key: password
|
||||||
- name: ZBX_MEMORYLIMIT
|
- name: ZBX_MEMORYLIMIT
|
||||||
value: "256M"
|
value: "256M"
|
||||||
- name: PHP_FPM_PM_MAX_CHILDREN
|
- name: PHP_FPM_PM_MAX_CHILDREN
|
||||||
value: "10"
|
value: "10"
|
||||||
- name: PHP_FPM_PM_START_SERVERS
|
- name: PHP_FPM_PM_START_SERVERS
|
||||||
value: "3"
|
value: "3"
|
||||||
- name: PHP_FPM_PM_MIN_SPARE_SERVERS
|
- name: PHP_FPM_PM_MIN_SPARE_SERVERS
|
||||||
value: "2"
|
value: "2"
|
||||||
- name: PHP_FPM_PM_MAX_SPARE_SERVERS
|
- name: PHP_FPM_PM_MAX_SPARE_SERVERS
|
||||||
value: "5"
|
value: "5"
|
||||||
- name: PHP_FPM_PM_MAX_REQUESTS
|
- name: PHP_FPM_PM_MAX_REQUESTS
|
||||||
value: "500"
|
value: "500"
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
memory: 256Mi
|
memory: 256Mi
|
||||||
cpu: 100m
|
cpu: 100m
|
||||||
limits:
|
limits:
|
||||||
memory: 768Mi
|
memory: 768Mi
|
||||||
cpu: 500m
|
cpu: 500m
|
||||||
livenessProbe:
|
livenessProbe:
|
||||||
httpGet:
|
httpGet:
|
||||||
path: /
|
path: /
|
||||||
port: 8080
|
port: 8080
|
||||||
initialDelaySeconds: 60
|
initialDelaySeconds: 60
|
||||||
timeoutSeconds: 5
|
timeoutSeconds: 5
|
||||||
periodSeconds: 10
|
periodSeconds: 10
|
||||||
readinessProbe:
|
readinessProbe:
|
||||||
httpGet:
|
httpGet:
|
||||||
path: /
|
path: /
|
||||||
port: 8080
|
port: 8080
|
||||||
initialDelaySeconds: 30
|
initialDelaySeconds: 30
|
||||||
periodSeconds: 5
|
periodSeconds: 5
|
||||||
timeoutSeconds: 5
|
timeoutSeconds: 5
|
||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Service
|
kind: Service
|
||||||
metadata:
|
metadata:
|
||||||
name: zabbix-web
|
name: zabbix-web
|
||||||
namespace: zabbix
|
namespace: zabbix
|
||||||
spec:
|
spec:
|
||||||
selector:
|
selector:
|
||||||
app: zabbix-web
|
app: zabbix-web
|
||||||
ports:
|
ports:
|
||||||
- port: 8080
|
- port: 8080
|
||||||
targetPort: 8080
|
targetPort: 8080
|
||||||
name: http
|
name: http
|
||||||
---
|
---
|
||||||
# TLS Certificate via cert-manager
|
# TLS Certificate via cert-manager
|
||||||
apiVersion: cert-manager.io/v1
|
apiVersion: cert-manager.io/v1
|
||||||
kind: Certificate
|
kind: Certificate
|
||||||
metadata:
|
metadata:
|
||||||
name: zabbix-tls
|
name: zabbix-tls
|
||||||
namespace: zabbix
|
namespace: zabbix
|
||||||
spec:
|
spec:
|
||||||
secretName: zabbix-tls
|
secretName: zabbix-tls
|
||||||
issuerRef:
|
issuerRef:
|
||||||
name: step-ca-acme
|
name: step-ca-acme
|
||||||
kind: ClusterIssuer
|
kind: ClusterIssuer
|
||||||
dnsNames:
|
dnsNames:
|
||||||
- zabbix.iamworkin.lan
|
- zabbix.iamworkin.lan
|
||||||
---
|
---
|
||||||
# Traefik IngressRoute
|
# Traefik IngressRoute
|
||||||
apiVersion: traefik.io/v1alpha1
|
apiVersion: traefik.io/v1alpha1
|
||||||
kind: IngressRoute
|
kind: IngressRoute
|
||||||
metadata:
|
metadata:
|
||||||
name: zabbix-web
|
name: zabbix-web
|
||||||
namespace: zabbix
|
namespace: zabbix
|
||||||
spec:
|
spec:
|
||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- match: Host(`zabbix.iamworkin.lan`)
|
- match: Host(`zabbix.iamworkin.lan`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
services:
|
services:
|
||||||
- name: zabbix-web
|
- name: zabbix-web
|
||||||
port: 8080
|
port: 8080
|
||||||
tls:
|
tls:
|
||||||
secretName: zabbix-tls
|
secretName: zabbix-tls
|
||||||
---
|
---
|
||||||
# 1Password secret sync — creates zabbix-credentials K8s Secret
|
# 1Password secret sync — creates zabbix-credentials K8s Secret
|
||||||
# Fields: DB-User, DB-Password, username, password, URL
|
# Fields: DB-User, DB-Password, username, password, URL
|
||||||
apiVersion: onepassword.com/v1
|
apiVersion: onepassword.com/v1
|
||||||
kind: OnePasswordItem
|
kind: OnePasswordItem
|
||||||
metadata:
|
metadata:
|
||||||
name: zabbix-credentials
|
name: zabbix-credentials
|
||||||
namespace: zabbix
|
namespace: zabbix
|
||||||
spec:
|
spec:
|
||||||
itemPath: vaults/IAmWorkin/items/Zabbix Admin
|
itemPath: vaults/IAmWorkin/items/Zabbix Admin
|
||||||
|
|||||||
Reference in New Issue
Block a user