- namespace: PodSecurity privileged, needed for /dev/kvm + privileged QEMU - storageclass: 1 replica, strict-local, WaitForFirstConsumer - deployment: nodeSelector workload=imessage + matching NoSchedule toleration, Recreate strategy (two QEMU procs on one qcow2 corrupts it), no readiness probe (guest install is interactive and takes many minutes) - services: ClusterIP only; VNC is an unauthenticated console, reach it with port-forward, never an Ingress - networkpolicy: default-deny, opt-in via sms-client=true on port 1234
116 lines
5.0 KiB
YAML
116 lines
5.0 KiB
YAML
# macOS VM (Docker-OSX) hosting the BlueBubbles server.
|
|
#
|
|
# ── Why a VM and not a container ────────────────────────────────────────────
|
|
# Containers share the host kernel. macOS binaries are Mach-O and need XNU plus
|
|
# Cocoa/IOKit, which a Linux kernel cannot provide, so no macOS container exists
|
|
# or can exist. Docker-OSX is QEMU running a macOS guest, packaged in a
|
|
# container — a VM in a box, not a macOS container.
|
|
#
|
|
# ── Why this works on worker-2 ──────────────────────────────────────────────
|
|
# Verified on the existing hardware: amd64, `vmx` (Intel VT-x) present, and
|
|
# /dev/kvm exists on Talos nodes (KVM is compiled into Talos' kernel, not a
|
|
# module). Bare metal, so no nested virtualisation needed.
|
|
#
|
|
# ── Read this before relying on it ──────────────────────────────────────────
|
|
# 1. Setup is INTERACTIVE. First boot runs the macOS installer: connect over
|
|
# VNC (:5999), erase the disk in Disk Utility, install, create a user, sign
|
|
# into iMessage, THEN install BlueBubbles inside the guest. This manifest
|
|
# only provides the machine; it does not provision macOS.
|
|
# 2. iMessage activation on non-Apple hardware is a coin flip. BlueBubbles'
|
|
# own guidance: "test sending an iMessage to yourself. If it does not
|
|
# succeed, it's likely best to restart from the beginning."
|
|
# 3. Apple's macOS licence permits virtualisation only on Apple hardware. This
|
|
# is a Hackintosh. Use a throwaway Apple ID, not a primary one.
|
|
# 4. BlueBubbles labels this path "not for beginners", "no guarantees or
|
|
# warranty".
|
|
#
|
|
# Private API (reactions, typing indicators, edit/unsend) needs SIP disabled
|
|
# inside the guest and is NOT required for plain send/receive. Skip it.
|
|
apiVersion: apps/v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: macos-bluebubbles
|
|
labels:
|
|
app.kubernetes.io/name: macos-bluebubbles
|
|
app.kubernetes.io/part-of: sms
|
|
spec:
|
|
replicas: 1
|
|
# Recreate: the qcow2 disk is RWO and a second pod must never attach it
|
|
# concurrently — two QEMU processes on one image corrupts it.
|
|
strategy:
|
|
type: Recreate
|
|
selector:
|
|
matchLabels:
|
|
app.kubernetes.io/name: macos-bluebubbles
|
|
template:
|
|
metadata:
|
|
labels:
|
|
app.kubernetes.io/name: macos-bluebubbles
|
|
app.kubernetes.io/part-of: sms
|
|
spec:
|
|
# Dedicated node. The taint keeps everything else off worker-2; this
|
|
# toleration is what lets the VM on. Both halves are required.
|
|
nodeSelector:
|
|
workload: imessage
|
|
tolerations:
|
|
- key: workload
|
|
operator: Equal
|
|
value: imessage
|
|
effect: NoSchedule
|
|
containers:
|
|
- name: macos
|
|
image: sickcodes/docker-osx:latest@sha256:3a3c82c79bc4e73531f819ccdfa4053b3084efd7c1f645678dbf8b4b3a24369c
|
|
# QEMU needs /dev/kvm; Talos enforces `baseline` cluster-wide, so this
|
|
# only schedules because the sms namespace is labelled privileged.
|
|
securityContext:
|
|
privileged: true
|
|
env:
|
|
# Generates a unique serial / board-serial / UUID / MAC and persists
|
|
# them to bootdisk.qcow2. This synthetic identity is what iMessage
|
|
# activates against — it must stay stable across restarts, which is
|
|
# why the PVC matters.
|
|
- name: GENERATE_UNIQUE
|
|
value: "true"
|
|
# Identity is only plausible if it matches a real product line.
|
|
- name: DEVICE_MODEL
|
|
value: "iMacPro1,1"
|
|
- name: RAM
|
|
value: "12"
|
|
- name: CORES
|
|
value: "6"
|
|
- name: EXTRA
|
|
# Expose the BlueBubbles server port from the guest to the pod.
|
|
# Guest :1234 (BlueBubbles default) -> pod :1234.
|
|
value: "-device virtio-net-pci,netdev=net0 -netdev user,id=net0,hostfwd=tcp::1234-:1234"
|
|
ports:
|
|
- name: vnc
|
|
containerPort: 5999
|
|
protocol: TCP
|
|
- name: bluebubbles
|
|
containerPort: 1234
|
|
protocol: TCP
|
|
resources:
|
|
requests:
|
|
cpu: "6"
|
|
memory: 14Gi
|
|
limits:
|
|
cpu: "12"
|
|
memory: 20Gi
|
|
volumeMounts:
|
|
- name: macos-disk
|
|
mountPath: /home/arch/OSX-KVM/disk
|
|
- name: kvm
|
|
mountPath: /dev/kvm
|
|
# No readiness probe on purpose. The guest takes many minutes to boot,
|
|
# and until macOS + BlueBubbles are installed BY HAND there is nothing
|
|
# listening on 1234. A probe here would crash-loop the pod through the
|
|
# entire interactive install.
|
|
volumes:
|
|
- name: macos-disk
|
|
persistentVolumeClaim:
|
|
claimName: macos-disk
|
|
- name: kvm
|
|
hostPath:
|
|
path: /dev/kvm
|
|
type: CharDevice
|