Introduction
This post outlines the process of deploying a Minecraft server on a Kubernetes cluster, managed through GitOps principles using ArgoCD. This setup ensures that your Minecraft server infrastructure is declarative, version-controlled, and easily reproducible.
Project Overview
The minecraft project demonstrates a robust and resilient approach to hosting a single Minecraft server, featuring:
- Minecraft Server: Running the popular game server within a Kubernetes pod.
- Kubernetes: Orchestrating the deployment, scaling, and management of the server.
- ArgoCD: Implementing GitOps by continuously synchronizing the desired state defined in Git repositories with the live state of the Kubernetes cluster.
- Persistent Storage: Ensuring game world data persists across restarts and upgrades.
Architecture and Components
The deployment consists of several key Kubernetes resources, all defined as YAML manifests and managed through ArgoCD:
1. Namespace
A dedicated minecraft namespace is created to logically isolate the application’s resources within the Kubernetes cluster.
1
2
3
4
5
6
apiVersion: v1
kind: Namespace
metadata:
annotations:
argocd.argoproj.io/sync-wave: "0"
name: minecraft
2. Services
Two NodePort services are defined to expose the Minecraft game port and the RCON (Remote Console) port for management.
Minecraft Service
Exposes the standard Minecraft port (25565) as a NodePort.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
apiVersion: v1
kind: Service
metadata:
annotations:
argocd.argoproj.io/sync-wave: "0"
name: minecraft-service
namespace: minecraft
spec:
type: NodePort
selector:
app: minecraft
ports:
- protocol: TCP
port: 25565
targetPort: 25565
nodePort: 32565
RCON Service
Exposes the RCON port (25575) for remote administration of the Minecraft server.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
apiVersion: v1
kind: Service
metadata:
annotations:
argocd.argoproj.io/sync-wave: "0"
name: rcon-service
namespace: minecraft
spec:
type: NodePort
selector:
app: minecraft
ports:
- protocol: TCP
port: 25575 # Changed from 27015
targetPort: 25575
nodePort: 32575 # Changed from 32015 for consistency
RCON (Remote Console) is a protocol that allows server administrators to remotely execute commands on the Minecraft server. With the `rcon-service` configured as a `NodePort`, you can connect to your Minecraft server's RCON port (e.g., `NodeIP:32015`) using any RCON client or programmatically to manage the server, execute commands, broadcast messages, and more, without needing to be directly in the game or on the server's console. This is crucial for automation and remote administration.
3. Minecraft StatefulSet
To provide resilience and ensure persistent storage is correctly managed for our stateful Minecraft server, we deploy it as a Kubernetes StatefulSet. A StatefulSet is ideal for applications that require stable, unique network identifiers, stable persistent storage, and ordered, graceful deployment/scaling.
Key changes from a standard Deployment include:
kind: StatefulSet: Designates it as a StatefulSet.serviceName: minecraft-service: Associates the StatefulSet with a Headless Service (whichminecraft-serviceimplicitly acts as for stable network identities).nodeSelectorremoval: The pod is no longer pinned to a specific worker node, allowing Kubernetes to reschedule it on any healthy node if the current node fails.volumeClaimTemplates: Instead of a standalonePersistentVolumeClaim, the storage is now dynamically provisioned and managed by the StatefulSet itself. This ensures that the persistent volume for the Minecraft world is automatically created and re-attached on failover. TheaccessModesis set toReadWriteMany(RWX), indicating the underlying storage supports multiple readers/writers; however, it’s crucial to remember that the Minecraft server itself can only safely have one writer to the world data at a time to prevent corruption.
The Minecraft server uses the itzg/minecraft-server image, a flexible Docker image. Configurations include accepting the EULA, setting the server version and type (Paper recommended for performance), and allocating 1G of memory.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: minecraft
namespace: minecraft
labels:
app: minecraft
spec:
replicas: 1
selector:
matchLabels:
app: minecraft
serviceName: minecraft-service # Important for StatefulSets
template:
metadata:
labels:
app: minecraft
spec:
# nodeSelector removed to allow scheduling on any available node
containers:
- name: minecraft
image: itzg/minecraft-server:latest
imagePullPolicy: Always
ports:
# Game Port
- containerPort: 25565
name: minecraft
protocol: TCP
# 🟢 RCON Port
- containerPort: 25575
name: rcon
protocol: TCP
env:
# 1. Accept the License (Mandatory)
- name: EULA
value: "TRUE"
# 2. Set the Version (Defaults to LATEST if removed)
- name: VERSION
value: "LATEST"
# 3. Choose your flavor (VANILLA, PAPER, FORGE, FABRIC)
# PAPER is highly recommended for performance!
- name: TYPE
value: "PAPER"
# 4. Set Memory Limits (Java loves RAM)
- name: MEMORY
value: "1G"
- name: ENABLE_RCON # Explicitly enable RCON
value: "true"
- name: RCON_PASSWORD # Reference RCON password from a Kubernetes Secret
valueFrom:
secretKeyRef:
name: minecraft-rcon-secret # Name of the Secret
key: RCON_PASSWORD # Key within the Secret
volumeMounts:
- name: data
mountPath: /data
volumeClaimTemplates:
- metadata:
name: data # This name must match the volumeMounts.name in the container spec
spec:
accessModes:
- ReadWriteMany # Allows multiple pods to mount the volume simultaneously
storageClassName: kubenfs # <--- Your specific storage class
resources:
requests:
storage: 10Gi # Adjust size as needed (10GB is plenty for a start)
Note on RCON_PASSWORD:
For security best practices, the RCON_PASSWORD should be stored in a Kubernetes Secret rather than hardcoded in the manifest. You would create this secret using a command similar to the following:
1
kubectl create secret generic minecraft-rcon-secret --from-literal=RCON_PASSWORD='your-strong-password' -n minecraft
Remember to replace 'your-strong-password' with an actual strong, unique password.
5. GitOps with ArgoCD
The entire application configuration is stored in a Git repository. ArgoCD is configured to continuously monitor this repository and automatically synchronize the desired state with the Kubernetes cluster. The basic-application.yaml defines how ArgoCD points to the Minecraft server’s manifest.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: minecraft
namespace: argocd
spec:
project: default
source:
repoURL: git@github.com:<your-username>/minecraft.git
targetRevision: HEAD
path: gitops/basic
destination:
server: https://kubernetes.default.svc
namespace: minecraft
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
Conclusion
This setup provides a robust and manageable Minecraft server on Kubernetes. By leveraging a StatefulSet, removing the nodeSelector, and utilizing persistent storage, your game worlds are safe and the server instance benefits from automatic rescheduling and re-attachment of its persistent data, significantly improving its resilience. The entire deployment is managed through GitOps with ArgoCD for declarative infrastructure management.