Skip to content

Media stack

Status: Current | Last reviewed: 2026-06-03

The five containers (or pods) that move audio around. None of them have managed-cloud equivalents — operators run them, end of story.

What runs

Service Role Default ports Where it runs
asterisk PBX, call control via PJSIP + ARI 5060 (SIP), 8087 (ARI WebSocket), 8088 (HTTP) Container (Vanguard) / hostNetwork pod (cluster)
kamailio SIP proxy, TLS termination, dial-plan 5060 (UDP/TCP), 5061 (TLS) Same
janus WebRTC gateway with SIP plugin 8088 (HTTP), 8188 (WS), 7088 (admin), 20000-20499 (RTP) Same
rtpengine RTP/SRTP media proxy, codec transcode 22222 (control), 20000-20499 (RTP) Same
coturn STUN/TURN for NAT traversal 3478 (UDP), 5349 (TLS) Same

Why hostNetwork in cluster

Media services need:

  1. Predictable IPs for SIP REGISTER, RTP packet rewriting, and ICE candidate generation. Pod IPs change.
  2. Raw socket access for fast packet handling.
  3. Wide port ranges that Kubernetes Services cannot expose efficiently.

The answer is hostNetwork: true. The pod gets the node's IP and port space directly. The trade-off is that pods are pinned to nodes one-to-one — no Service abstraction.

Charts that use this pattern: charts/asterisk/templates/deployment.yaml, charts/kamailio/, charts/janus/, charts/rtpengine/, charts/coturn/.

Per-cloud media node pools

The media pods need dedicated nodes (kernel tuning, dedicated NICs, no preemption). Each cloud's values file pins them:

  • GCP: nodeSelector: cloud.google.com/gke-nodepool: media-pool. Operators provision the pool with kernel tuning and sysctl overrides.
  • AWS: tolerations + labels matching dedicated EC2 instances. See media-pool-tuning.md.
  • Azure: same tolerations approach with AKS node pools.

kernel module unavailable in cluster

rtpengine performs best with its kernel module loaded — packet forwarding happens in-kernel without a userspace round-trip. In GKE, EKS, and AKS, container nodes do not allow loading kernel modules. The chart enforces userspace forwarding with table = -1 (see charts/rtpengine/templates/configmap.yaml).

Userspace works fine for hundreds of concurrent calls per node. If a customer needs thousands per node, they need bare-metal or self-managed VMs where the module can load.

Global Accelerator and dual-interface RTP

When AWS Global Accelerator fronts the SIP/media plane, it DNATs the public anycast IP to the regional LAN IP before delivery. Single-interface rtpengine config (interface = ${PUBLIC_IP}) breaks because rtpengine's listening socket binds the public IP, but inbound packets arrive on the LAN IP — kernel returns ICMP port-unreachable.

Fix: dual-interface in docker-compose.media.yml and the chart values:

interface = lan/${LAN_IP}!${PUBLIC_IP}
interface = pub/${PUBLIC_IP}

Sentinel and any GA-fronted environment must use this form. Direct IP environments can keep the single-interface config.

kamailio per-city TLS

Each city dev environment ships with a dedicated kamailio TLS cert. The cert maps to a Genesys BYOC trunk; the trunk has an ACL allowlisting the city's NAT egress IP. Three-way constraint: GA TCP :5065, per-city cert, trunk ACL — all three must align or Genesys transfers 404.

See city-dev-environments.md.

Janus WebSocket header rules

The nginx ingress for Janus's /ws endpoint must strip Cookie, User-Agent, and Referer, and re-declare Upgrade, Connection, and Host. nginx's header inheritance rules mean partial declarations get clobbered. See configs/nginx/trueserve-vanguard.conf.

Symptom of getting it wrong: Chrome 502 on SIP registration.

Where each one fits in the call path

Caller / Carrier (SIP)
  → kamailio       (TLS, ACL, dial-plan, inter-city routing)
  → asterisk       (PJSIP B2BUA, dialplan, ARI handoff)
  → ari-controller (Stasis app; orchestrates the call)
  → media-proxy    (carries audio between Asterisk and Pipeline)

Web caller (WebRTC)
  → coturn         (STUN/TURN for NAT traversal)
  → janus          (WebRTC ↔ SIP bridge)
  → asterisk       (rest of the path same as above)

For SRTP:
  rtpengine sits between asterisk and the outside world,
  rewriting SDP and forwarding packets.

See also