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

traefik 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

adding server

the server is available

server