4 minutes
Run a minecraft server in Kubernetes
Overview
Running your own Minecraft server in Kubernetes is relatively easy and quick to implement.
The following steps are necessary:
- Create a corresponding Docker image (optional, as there are also ready-made images)
- Create entry points in Traefik
- Create deployment, service and ingress route in Kubernetes
Image create
Even if there are already ready-made Docker images for Minecraft servers (such as itzg/minecraft-server which loads the latest version with every build), you can create this yourself with little effort and can thus also specify which version you want, for example.
Get the latest version of server.jar from off. Minecraft website
Create a Dockerfile
FROM openjdk:25-jdk-slim
LABEL maintainer="docker-images@localhost.local" Description="minecraft server (java)"
WORKDIR /app
COPY server.jar /app/
COPY eula.txt /app/
CMD ["java", "-Xmx1024M", "-Xms512M", "-jar", "server.jar", "nogui"]
and a file eula.txt
#By changing the setting below to TRUE you are indicating your agreement to our EULA (https://aka.ms/MinecraftEULA).
#Thu Jan 02 14:10:22 CET 2025
eula=true
in the same directory where the downloaded server.jar is located.
Build image minecraft-server:latest with docker build -t minecraft-server:latest .
within this directory.
Kubernetes
traefik entrypoint
Since traefik is used as an ingress controller in the current setup, the corresponding entry points must be created here.
- minecraft-tcp (listens to TCP port 25565)
- minecraft-udp (listens on the UDP port 25565)
This can usually be done by adding the following lines to the corresponding configuration of traefik (located e.g. in K3S under /var/lib/rancher/k3s/server/manifests/traefik.yaml)
minecraft-tcp:
port: 25565
expose:
default: true
exposedPort: 25565
protocol: TCP
minecraft-udp:
port: 25565
expose:
default: true
exposedPort: 25565
protocol: UDP
After the redeployment (should be done automatically by traefik) you can find two new entrypoints in your Dashboard
Deployment
In the following case, all deployments are carried out in namespace minecraft, if this does not yet exist, it can be created with kubectl create namespace minecraft
to create it.
Create deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: minecraft-server
namespace: minecraft
spec:
replicas: 1
selector:
matchLabels:
app: minecraft-server
template:
metadata:
labels:
app: minecraft-server
spec:
containers:
- name: minecraft-server
image: minecraft-server:latest
imagePullPolicy: Always
env:
- name: EULA
value: "TRUE"
- name: PVP
value: "false"
- name: SPAWN_MONSTERS
value: "true"
ports:
- containerPort: 25565
and a service.yaml
apiVersion: v1
kind: Service
metadata:
name: minecraft-server
namespace: minecraft
spec:
selector:
app: minecraft-server
ports:
- name: minecraft-server
protocol: TCP
port: 25565
targetPort: 25565
type: ClusterIP
apply both
kubectl -n minecraft apply -f deployment.yaml
kubectl -n minecraft apply -f service.yaml
check the pod is up and running with describe pod minecraft-server
Name: minecraft-server-784649cf4c-k28zr
Namespace: minecraft
Priority: 0
Service Account: default
Node: node01/192.168.1.1
Start Time: Thu, 02 Jan 2025 14:13:58 +0100
Labels: app=minecraft-server
pod-template-hash=784649cf4c
Annotations: <none>
Status: Running
IP: 10.42.1.93
IPs:
IP: 10.42.1.93
Controlled By: ReplicaSet/minecraft-server-784649cf4c
Containers:
minecraft-server:
Container ID: containerd://c77881ef45cd8276f1075f61390d862f5fb34b7810d476287bc09457dedcdd91
Image: minecraft-server:latest
Image ID: minecraft-server@sha256:74929e07102927b214b320fe59d03ad508a130aad1f7bae8ae9ff6ba3a031998
Port: 25565/TCP
Host Port: 0/TCP
State: Running
Started: Thu, 02 Jan 2025 14:13:59 +0100
Ready: True
Restart Count: 0
Environment:
EULA: TRUE
PVP: false
SPAWN_MONSTERS: true
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-5gphn (ro)
Conditions:
Type Status
PodReadyToStartContainers True
Initialized True
Ready True
ContainersReady True
PodScheduled True
Volumes:
kube-api-access-5gphn:
Type: Projected (a volume that contains injected data from multiple sources)
TokenExpirationSeconds: 3607
ConfigMapName: kube-root-ca.crt
ConfigMapOptional: <nil>
DownwardAPI: true
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events: <none>
and the service exists minecraft describe service minecraft-server
Name: minecraft-server
Namespace: minecraft
Labels: app.kubernetes.io/instance=minecraft-server
Annotations: <none>
Selector: app=minecraft-server
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.43.170.9
IPs: 10.43.170.9
Port: minecraft-server 25565/TCP
TargetPort: 25565/TCP
Endpoints: 10.42.1.93:25565
Session Affinity: None
Internal Traffic Policy: Cluster
Events: <none>
TCP-Routing (traefik)
To enable network traffic from the minecraft-server entry point to the corresponding service, TCP routing is required as follows.
Create ingress-routing.yaml
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRouteTCP
metadata:
name: minecraftservertcp
namespace: minecraft
spec:
entryPoints:
- minecraft-tcp
routes:
- match: HostSNI(`*`)
services:
- name: minecraft-server
port: 25565
and apply it kubectl -n minecraft apply -f ingress-routing.yaml
Adding server in Minecraft
After adding the server within Minecraft
the server is available