Skip to content

Kubernetes Deployment

Deploy the Lumo Minecraft server on Kubernetes for high availability and easy scaling.

  • Kubernetes cluster (1.19+)
  • kubectl configured
  • Persistent volume support (or dynamic provisioning)
  • LoadBalancer support (for external access) or NodePort

Create a dedicated namespace:

apiVersion: v1
kind: Namespace
metadata:
name: minecraft

Apply:

Terminal window
kubectl apply -f namespace.yaml

Create PVCs for data and backups:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: minecraft-data
namespace: minecraft
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: minecraft-backups
namespace: minecraft
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 20Gi
apiVersion: apps/v1
kind: Deployment
metadata:
name: lumo-server
namespace: minecraft
spec:
replicas: 1 # Minecraft servers must have exactly 1 replica
strategy:
type: Recreate # Important: Do not use RollingUpdate
selector:
matchLabels:
app: lumo-server
template:
metadata:
labels:
app: lumo-server
spec:
containers:
- name: minecraft
image: ghcr.io/lucasilverentand/lumo-server:latest
ports:
- containerPort: 25565
name: minecraft
protocol: TCP
- containerPort: 8100
name: bluemap
protocol: TCP
- containerPort: 25575
name: rcon
protocol: TCP
- containerPort: 24454
name: voicechat
protocol: UDP
env:
- name: EULA
value: "true"
- name: MEMORY
value: "4G"
- name: ENABLE_AUTOPAUSE
value: "false" # Disable in Kubernetes (health checks conflict)
- name: BACKUP_ENABLED
value: "true"
- name: RCON_PASSWORD
valueFrom:
secretKeyRef:
name: minecraft-secrets
key: rcon-password
resources:
requests:
memory: "4Gi"
cpu: "2000m"
limits:
memory: "6Gi"
cpu: "4000m"
volumeMounts:
- name: data
mountPath: /data
- name: backups
mountPath: /backups
livenessProbe:
tcpSocket:
port: 25565
initialDelaySeconds: 300
periodSeconds: 30
readinessProbe:
tcpSocket:
port: 25565
initialDelaySeconds: 60
periodSeconds: 10
volumes:
- name: data
persistentVolumeClaim:
claimName: minecraft-data
- name: backups
persistentVolumeClaim:
claimName: minecraft-backups

Expose the server using LoadBalancer or NodePort:

apiVersion: v1
kind: Service
metadata:
name: lumo-server
namespace: minecraft
spec:
type: LoadBalancer
selector:
app: lumo-server
ports:
- name: minecraft
port: 25565
targetPort: 25565
protocol: TCP
- name: bluemap
port: 8100
targetPort: 8100
protocol: TCP
- name: rcon
port: 25575
targetPort: 25575
protocol: TCP
- name: voicechat
port: 24454
targetPort: 24454
protocol: UDP
apiVersion: v1
kind: Service
metadata:
name: lumo-server
namespace: minecraft
spec:
type: NodePort
selector:
app: lumo-server
ports:
- name: minecraft
port: 25565
targetPort: 25565
nodePort: 30565 # Access on <node-ip>:30565
protocol: TCP
- name: bluemap
port: 8100
targetPort: 8100
nodePort: 30100
protocol: TCP

Store sensitive configuration:

Terminal window
kubectl create secret generic minecraft-secrets \
--from-literal=rcon-password='your-strong-password' \
-n minecraft

For environment variables, use a ConfigMap:

apiVersion: v1
kind: ConfigMap
metadata:
name: minecraft-config
namespace: minecraft
data:
MEMORY: "4G"
DIFFICULTY: "hard"
MAX_PLAYERS: "20"
MOTD: "Welcome to Lumo Server on Kubernetes!"
OPS: "YourMinecraftUsername"

Reference in deployment:

envFrom:
- configMapRef:
name: minecraft-config

Create secret with AWS credentials:

Terminal window
kubectl create secret generic aws-credentials \
--from-literal=AWS_ACCESS_KEY_ID='your-key' \
--from-literal=AWS_SECRET_ACCESS_KEY='your-secret' \
-n minecraft

Add to deployment env:

- name: S3_ENABLED
value: "true"
- name: S3_BUCKET
value: "minecraft-backups"
- name: AWS_DEFAULT_REGION
value: "us-east-1"
- name: AWS_ACCESS_KEY_ID
valueFrom:
secretKeyRef:
name: aws-credentials
key: AWS_ACCESS_KEY_ID
- name: AWS_SECRET_ACCESS_KEY
valueFrom:
secretKeyRef:
name: aws-credentials
key: AWS_SECRET_ACCESS_KEY

For easier management, consider creating a Helm chart:

values.yaml
image:
repository: ghcr.io/lucasilverentand/lumo-server
tag: latest
pullPolicy: Always
minecraft:
eula: true
memory: "4G"
ops: "YourUsername"
motd: "Lumo Server"
service:
type: LoadBalancer
ports:
minecraft: 25565
bluemap: 8100
rcon: 25575
persistence:
data:
enabled: true
size: 10Gi
backups:
enabled: true
size: 20Gi
resources:
requests:
memory: 4Gi
cpu: 2
limits:
memory: 6Gi
cpu: 4

Add Prometheus metrics exporter sidecar:

- name: minecraft-exporter
image: joshi425/minecraft_exporter:latest
ports:
- containerPort: 9150
name: metrics
env:
- name: MC_RCON_ADDRESS
value: "localhost:25575"
- name: MC_RCON_PASSWORD
valueFrom:
secretKeyRef:
name: minecraft-secrets
key: rcon-password

For multiple servers:

  • Deploy separate instances with different names
  • Use different namespaces or selectors
  • Each needs its own PVC
  1. Local PVC: Automated backups to /backups volume
  2. S3: Offsite backups for disaster recovery
  3. PVC Snapshots: Use your cluster’s volume snapshot feature

Example snapshot:

apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
name: minecraft-data-snapshot
namespace: minecraft
spec:
source:
persistentVolumeClaimName: minecraft-data

Check PVC binding:

Terminal window
kubectl get pvc -n minecraft
kubectl describe pvc minecraft-data -n minecraft

Check service external IP:

Terminal window
kubectl get svc -n minecraft

View pod logs:

Terminal window
kubectl logs -f deployment/lumo-server -n minecraft

Increase resources in deployment:

resources:
requests:
memory: "6Gi"
cpu: "3000m"
limits:
memory: "8Gi"
cpu: "6000m"

Save all manifests in minecraft-k8s.yaml:

Terminal window
kubectl apply -f minecraft-k8s.yaml

Monitor deployment:

Terminal window
kubectl get all -n minecraft
kubectl logs -f deployment/lumo-server -n minecraft

Get external IP:

Terminal window
kubectl get svc lumo-server -n minecraft

Connect to the server using the EXTERNAL-IP shown in the service.