While this post will end up with a running Teamspeak server, it is very hard on the resources of the Raspberry Pi and might not be suitable for everyday use.
To deploy a teamspeak server on raspberry pi a few things need to be done:
- (optional) Get a Kubernetes cluster up and running (this is not required, if
you just want to run the 
dockercontainer directly). - Get Teamspeak to run on 
ARM. - Setup an ingress controller to make the Teamspeak server accessible from the outside world (in this case this will be the Nginx Ingress).
 
Setting up a kubernetes cluster
To setup a kubernetes cluster on Raspberry Pis K3S is very good approach, as the cluster will be more lightweight that simply installing upstream kubernetes.
As a base I recommend using HypriotOS or Ubuntu Server1 as those allow configuring the images using Cloud-Init.
Make sure to follow the instructions to use the the legacy backend for
iptables if installing kubernetes v1.17 or lower: kubeadm instructions.
When installing k3s to run Teamspeak Traefik should not be installed,
as only the 2.x version supports UDP ingresses - so instead nginx-ingress
will be installed later:
1curl -sfL https://get.k3s.io | sh -s - --no-deploy=traefik
Deploy Teamspeak
Build an ARM image for Teamspeak
Teamspeak does not provide a binary for ARM.
It is however possible to run it using Qemu - I have already prepared an
ARM image that will run the Teamspeak server through qemu that you can
find on my Dockerhub - or if you want to see the source checkout the
repository on Github.
The image is using the same entrypoint.sh as the official image - so if
you are already using that one you should be able to use it exactly the same
way (if not - feel free to open an issue).
Deploy the image
Now - if you do not want to use kubernetes, you can simply use the image
using docker and expose the required Teamspeak ports as you would with
docker:
1docker run -p 9987:9987/udp -p 10011:10011 -p 30033:30033 -e TS3SERVER_LICENSE=accept monadt/teamspeak3-server
This way is a lot easier on the resources and will likely run more reliable on a Raspberry PI with < 2 GB of RAM.
Setup nginx-ingress
Get nginx-ingress to run on ARM
Setting up the nginx-ingress on a cluster running on ARM needs a few extra
steps when using the official documentation.
The images used in the manifests are not compatible with armv7 (that is
used when running a cluster on a bunch of Raspberry Pis).
First the mandatory.yaml has to be updated to use the images for the arm
architecture2:
1wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.30.0/deploy/static/mandatory.yaml
2sed -i 's/nginx-ingress-controller:0/nginx-ingress-controller-arm:0/' mandatory.yaml
The resulting mandatory.yaml file can now be applied to the cluster:
1kubectl apply -f mandatory.yaml
In my local cluster I am using the NodePort approach, so the service for
that can be applied next:
1kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.30.0/deploy/static/provider/baremetal/service-nodeport.yaml
Setup a Teamspeak deployment
With all pieces in place the Teamspeak container can now be deployed onto
the cluster:
Save the following yaml into a file (e.g. teamspeak.yaml).
 1---
 2apiVersion: v1
 3kind: Namespace
 4metadata:
 5  name: teamspeak
 6---
 7apiVersion: v1
 8kind: PersistentVolumeClaim
 9metadata:
10  name: teamspeak-pvc
11  namespace: teamspeak
12spec:
13  accessModes:
14    - ReadWriteOnce
15  storageClassName: local-path
16  resources:
17    requests:
18      storage: 256Mi
19---
20apiVersion: apps/v1
21kind: Deployment
22metadata:
23  name: teamspeak-deployment
24  namespace: teamspeak
25  labels:
26    app: teamspeak
27spec:
28  replicas: 1
29  selector:
30    matchLabels:
31      app: teamspeak
32  template:
33    metadata:
34      namespace: teamspeak
35      labels:
36        app: teamspeak
37    spec:
38      containers:
39        - name: teamspeak-server
40          image: monadt/teamspeak3-server:3.11.0
41          ports:
42            - name: ts
43              containerPort: 9987
44              protocol: UDP
45          resources:
46          env:
47          - name: TS3SERVER_LICENSE
48            value: accept
49          volumeMounts:
50          - mountPath: /var/ts3server/
51            name: teamspeak-data
52      volumes:
53        - name: teamspeak-data
54          persistentVolumeClaim:
55            claimName: teamspeak-pvc
56---
57apiVersion: v1
58kind: Service
59metadata:
60  name: teamspeak-service
61  namespace: teamspeak
62  labels:
63    app: teamspeak
64spec:
65  type: ClusterIP
66  ports:
67    - port: 9987
68      targetPort: ts
69      protocol: UDP
70      name: ts
71  selector:
72    app: teamspeak
73---
74apiVersion: v1
75kind: ConfigMap
76metadata:
77  name: udp-services
78  namespace: ingress-nginx
79data:
80  9987: "teamspeak/teamspeak-service:9987"
Apply this using kubectl:
1kubectl apply -f teamspeak.yaml
The 9987 udp port will also need to be added to the ingress service.
In the ports section of the service add the following snippet:
1kubectl edit svc ingress-nginx -n ingress-nginx
1- name: teamspeak
2  port: 9987
3  protocol: UDP
4  targetPort: 9987
Forwarding traffic to the ingress
The final step depends a lot on the setup you are deploying the cluster in.
If it is behind your local router, you have to check which port was bound to
the 9987 udp port and forward this to one of your cluster-nodes:
1kubectl describe svc ingress-nginx -n ingress-nginx
 1Name:                     ingress-nginx
 2Namespace:                ingress-nginx
 3Labels:                   app.kubernetes.io/name=ingress-nginx
 4                          app.kubernetes.io/part-of=ingress-nginx
 5Annotations:              Selector:  app.kubernetes.io/name=ingress-nginx,app.kubernetes.io/part-of=ingress-nginx
 6Type:                     NodePort
 7IP:                       10.43.33.70
 8Port:                     http  80/TCP
 9TargetPort:               80/TCP
10NodePort:                 http  32224/TCP
11Endpoints:
12Port:                     https  443/TCP
13TargetPort:               443/TCP
14NodePort:                 https  31955/TCP
15Endpoints:
16Port:                     teamspeak  9987/UDP
17TargetPort:               9987/UDP
18NodePort:                 teamspeak  31222/UDP
19Endpoints:
20Session Affinity:         None
21External Traffic Policy:  Cluster
22Events:                   <none>
In this case the port that needs to be forwarded is the 31222 port (the
NodePort for the 9987 UDP port).
- 
For Ubuntu you will have to edit the file
/boot/firmware/cmdline.txtand add the optionscgroup_memory=1 cgroup_enable=memoryat the end of the line fork3s(orcontainersin general) to work. ↩︎ - 
See https://github.com/kubernetes/ingress-nginx/pull/3852 ↩︎