Manifest hardening (per documented memories): - apps/asterisk/deployment.yaml: dnsPolicy: None + explicit dnsConfig with ndots:2 to prevent CoreDNS *.iamworkin.lan template from hijacking external egress (downloads.asterisk.org). - apps/fc-llm-bridge/fc-llm-bridge.yaml: same dnsConfig pattern for api.anthropic.com egress. - apps/fc-ttsreader/fc-ttsreader.yaml: same dnsConfig pattern for huggingface.co model seeding. - apps/fc-messageboard/fc-messageboard.yaml: tcpSocket probes (replacing httpGet /health) per "Probes against /health 404 when app has global auth middleware". - apps/fc-signalcontrol/fc-signalcontrol.yaml: same tcpSocket probe fix. New lint project: - tests/bluejay-infra-lint/BluejayInfraLint.Tests.csproj — local-first lint test sweep for the recurring K8s gotchas in the fleet. - tests/bluejay-infra-lint/FleetManifestLintTests.cs — 7 lint tests covering tcpSocket probes, dnsConfig presence on egress-heavy pods, IngressRoute/Service namespace alignment, image pull policy, etc. - tests/bluejay-infra-lint/conftest.dev/ — matching conftest policies for environments with conftest/opa. - .gitignore — adds bin/ + obj/ + DS_Store/swp. README.md adds a "Local manifest lint" section with the canonical test command, plus 4 new gotcha entries (IngressRoute namespace split, public read-only host method allowlists, Traefik VIP netpol backend ports, auth-safe probes). Tests: 7 / 7 lint tests passed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
201 lines
6.9 KiB
YAML
201 lines
6.9 KiB
YAML
apiVersion: apps/v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: asterisk
|
|
namespace: telephony
|
|
labels:
|
|
app: asterisk
|
|
spec:
|
|
replicas: 1
|
|
strategy:
|
|
type: Recreate
|
|
selector:
|
|
matchLabels:
|
|
app: asterisk
|
|
template:
|
|
metadata:
|
|
labels:
|
|
app: asterisk
|
|
spec:
|
|
nodeSelector:
|
|
kubernetes.io/hostname: rke2-agent1
|
|
hostNetwork: true
|
|
# Keep the search list free of iamworkin.lan so CoreDNS's wildcard
|
|
# template cannot hijack public egress like downloads.asterisk.org.
|
|
dnsPolicy: None
|
|
dnsConfig:
|
|
nameservers:
|
|
- 10.43.0.10
|
|
searches:
|
|
- telephony.svc.cluster.local
|
|
- svc.cluster.local
|
|
- cluster.local
|
|
options:
|
|
- name: ndots
|
|
value: "2"
|
|
securityContext:
|
|
fsGroup: 0
|
|
# CoreDNS in this cluster has an iamworkin.lan wildcard that catches
|
|
# any unresolved name and returns 10.0.56.200 (Traefik VIP), which
|
|
# means downloads.asterisk.org inside the pod resolves to Traefik and
|
|
# returns 404. Pin the real address so the init container can fetch
|
|
# the sounds tarball.
|
|
hostAliases:
|
|
- ip: 165.22.184.19
|
|
hostnames:
|
|
- downloads.asterisk.org
|
|
initContainers:
|
|
- name: install-sounds
|
|
# Downloads Asterisk core sounds (en, ulaw) into the sounds emptyDir
|
|
# volume so the base Asterisk image (which ships no sounds) can play
|
|
# vm-advopts, vm-goodbye, digits/*, characters/*, beep, etc. Skips
|
|
# the download if the directory already contains sound files —
|
|
# re-running the pod after a hot image reload reuses the unpack.
|
|
image: alpine:3.20
|
|
command:
|
|
- sh
|
|
- -c
|
|
- |
|
|
set -eu
|
|
if [ -f /sounds/en/vm-goodbye.ulaw ] || [ -f /sounds/en/vm-goodbye.gsm ]; then
|
|
echo "Sounds already present — skipping download."
|
|
exit 0
|
|
fi
|
|
echo "Installing curl + tar..."
|
|
apk add --no-cache curl tar gzip >/dev/null
|
|
cd /tmp
|
|
echo "Downloading Asterisk core sounds (en, ulaw) 1.6.1..."
|
|
# -k: cluster egress goes through a step-ca MITM for outbound TLS
|
|
# that this pod does not trust. The tarball is a public artifact —
|
|
# integrity is checked downstream by Asterisk at playback time.
|
|
curl -fksSLO https://downloads.asterisk.org/pub/telephony/sounds/releases/asterisk-core-sounds-en-ulaw-1.6.1.tar.gz
|
|
echo "Extracting to /sounds/en ..."
|
|
mkdir -p /sounds/en
|
|
tar -xzf asterisk-core-sounds-en-ulaw-1.6.1.tar.gz -C /sounds/en
|
|
echo "Done — $(ls /sounds/en | wc -l) files installed."
|
|
volumeMounts:
|
|
- name: sounds
|
|
mountPath: /sounds/en
|
|
containers:
|
|
- name: asterisk
|
|
image: localhost/andrius/asterisk:latest
|
|
imagePullPolicy: Never
|
|
ports:
|
|
- name: sip-udp
|
|
containerPort: 5060
|
|
protocol: UDP
|
|
- name: sip-tcp
|
|
containerPort: 5060
|
|
protocol: TCP
|
|
- name: ari
|
|
containerPort: 8088
|
|
protocol: TCP
|
|
volumeMounts:
|
|
- name: config-modules
|
|
mountPath: /etc/asterisk/modules.conf
|
|
subPath: modules.conf
|
|
- name: config-http
|
|
mountPath: /etc/asterisk/http.conf
|
|
subPath: http.conf
|
|
- name: config-ari
|
|
mountPath: /etc/asterisk/ari.conf
|
|
subPath: ari.conf
|
|
- name: config-manager
|
|
mountPath: /etc/asterisk/manager.conf
|
|
subPath: manager.conf
|
|
- name: config-pjsip
|
|
mountPath: /etc/asterisk/pjsip.conf
|
|
subPath: pjsip.conf
|
|
- name: config-extensions
|
|
mountPath: /etc/asterisk/extensions.conf
|
|
subPath: extensions.conf
|
|
- name: config-rtp
|
|
mountPath: /etc/asterisk/rtp.conf
|
|
subPath: rtp.conf
|
|
- name: asterisk-data
|
|
mountPath: /var/spool/asterisk
|
|
- name: asterisk-logs
|
|
mountPath: /var/log/asterisk
|
|
- name: sounds
|
|
mountPath: /var/lib/asterisk/sounds/en
|
|
# Shared TTS audio — telephony-web writes .sln16 files here (as
|
|
# /shared-tts), Asterisk plays them via `sound:tts/<name>` which
|
|
# resolves to this mount. Both pods are pinned to rke2-agent1.
|
|
- name: shared-tts
|
|
mountPath: /var/lib/asterisk/sounds/tts
|
|
resources:
|
|
requests:
|
|
cpu: 100m
|
|
memory: 128Mi
|
|
limits:
|
|
cpu: "1"
|
|
memory: 512Mi
|
|
livenessProbe:
|
|
tcpSocket:
|
|
port: 8088
|
|
initialDelaySeconds: 15
|
|
periodSeconds: 10
|
|
readinessProbe:
|
|
httpGet:
|
|
path: /ari/asterisk/info
|
|
port: 8088
|
|
httpHeaders:
|
|
- name: Authorization
|
|
value: "Basic Zmxvd2VyY29yZTpibHVlamF5LWFzdGVyaXNrLWFyaQ=="
|
|
initialDelaySeconds: 10
|
|
periodSeconds: 5
|
|
volumes:
|
|
- name: config-modules
|
|
configMap:
|
|
name: asterisk-config
|
|
items:
|
|
- key: modules.conf
|
|
path: modules.conf
|
|
- name: config-http
|
|
configMap:
|
|
name: asterisk-config
|
|
items:
|
|
- key: http.conf
|
|
path: http.conf
|
|
- name: config-ari
|
|
configMap:
|
|
name: asterisk-config
|
|
items:
|
|
- key: ari.conf
|
|
path: ari.conf
|
|
- name: config-manager
|
|
configMap:
|
|
name: asterisk-config
|
|
items:
|
|
- key: manager.conf
|
|
path: manager.conf
|
|
- name: config-pjsip
|
|
configMap:
|
|
name: asterisk-config
|
|
items:
|
|
- key: pjsip.conf
|
|
path: pjsip.conf
|
|
- name: config-extensions
|
|
configMap:
|
|
name: asterisk-config
|
|
items:
|
|
- key: extensions.conf
|
|
path: extensions.conf
|
|
- name: config-rtp
|
|
configMap:
|
|
name: asterisk-config
|
|
items:
|
|
- key: rtp.conf
|
|
path: rtp.conf
|
|
- name: asterisk-data
|
|
persistentVolumeClaim:
|
|
claimName: asterisk-data
|
|
- name: asterisk-logs
|
|
emptyDir: {}
|
|
- name: sounds
|
|
emptyDir: {}
|
|
- name: shared-tts
|
|
hostPath:
|
|
path: /tmp/tts-audio
|
|
type: DirectoryOrCreate
|