Files
homelab/cluster/applications/minecraft/DEPLOYMENT-PLAN.md
Hermes Agent service account 56110d52bd feat(minecraft): deploy journey-into-imagination PaperMC server
- PaperMC 26.1.2 via itzg/minecraft-server:2026.7.0
- Namespace: minecraft, Service: journey-into-imagination
- TCP port 10182 (non-standard) via ingress-nginx tcp forwarding
- Pure Storage CSI PVC (pure-block, 50Gi) for world data
- World seed hardcoded: -5177989977648707969
- RCON password via ExternalSecret + 1Password Connect
- SleepMost v5.6.2 plugin for single-player sleep
- Whitelist off at launch, toggle-ready
- ExternalDNS annotations for internal Technitium record
- Manual steps: UniFi port forward WAN:10182→10.1.71.80:10182,
  Cloudflare A record + SRV for journey-into-imagination.mk-labs.cloud
2026-07-19 13:36:27 -05:00

305 lines
9.9 KiB
Markdown

# Journey Into Imagination — Minecraft Server Deployment Plan
**Application:** PaperMC Minecraft Server
**Namespace:** `minecraft`
**Deployment name:** `papermc`
**Service / DNS name:** `journey-into-imagination`
**ArgoCD path:** `cluster/applications/minecraft/`
**Reviewed:** _Pending Ryan approval_
---
## Version Pinning
| Component | Version |
|-----------|---------|
| itzg/minecraft-server image | `2026.7.0` |
| PaperMC (Minecraft version) | `1.21.4` (build 232 — last stable 1.21.x) |
| SleepMost plugin | `5.6.2` (auto-downloaded at server start) |
> **Note on PaperMC versioning:** PaperMC migrated to a new version scheme (`26.x`) as of mid-2026. The task requested 1.21.x, so we pin `VERSION=1.21.4`. When you're ready to upgrade to the latest stable, change `VERSION` in `deployment.yaml` and `configmap.yaml` to `26.2` and bump the image tag to the latest `itzg/minecraft-server` release. Check plugin compatibility (SleepMost) before upgrading.
---
## Storage
- **StorageClass:** `pure-block` (confirmed live — `kubectl get storageclass`)
- **PVC size:** 50Gi — expandable via Pure Storage CSI if the world grows
- **Mount:** `/data` inside the container (worlds, plugins, configs all live here)
---
## Networking Architecture
```
Internet (players)
|
| DNS: journey-into-imagination.mk-labs.cloud → WAN IP (Cloudflare A record)
|
UniFi UDM Pro
| Port Forward: WAN:25565 → 10.1.71.80:25565 (TCP)
|
ingress-nginx LoadBalancer (10.1.71.80)
| tcp-services ConfigMap: 25565 → minecraft/journey-into-imagination:25565
|
journey-into-imagination Service (ClusterIP, minecraft namespace)
|
papermc Pod (port 25565)
```
---
## Prerequisites — Manual Steps Before Deploying
### 1. Generate a real RCON password
```bash
# Generate a secure password
openssl rand -base64 24
# Output example: abc123... (save this — you'll need it)
# Base64-encode it for the Secret
echo -n 'YOUR_GENERATED_PASSWORD' | base64
```
Edit `cluster/applications/minecraft/secret.yaml` and replace the placeholder value:
```yaml
data:
rcon-password: <your-base64-encoded-password>
```
> ⚠️ Do NOT commit real credentials in plaintext. If this is a concern long-term,
> migrate to ExternalSecrets + 1Password (Day 2 operation).
### 2. UniFi Port Forward (Ryan — manual step)
In UniFi Network → Firewall & Security → Port Forwarding:
- **Name:** `minecraft-papermc`
- **Protocol:** TCP
- **External Port:** 25565
- **Internal IP:** 10.1.71.80 (ingress-nginx LoadBalancer)
- **Internal Port:** 25565
- **Enabled:** Yes
### 3. Cloudflare DNS Records (Ryan — manual step)
In Cloudflare Dashboard → mk-labs.cloud zone:
**A Record (public server address):**
| Type | Name | Value | Proxy |
|------|------|-------|-------|
| A | `journey-into-imagination` | `<your-WAN-IP>` | DNS only (gray cloud) |
> Minecraft uses raw TCP — Cloudflare proxy (orange cloud) will NOT work.
> Use DNS-only mode (gray cloud).
**SRV Record (allows clients to connect without specifying port):**
| Type | Name | Service | Proto | Priority | Weight | Port | Target |
|------|------|---------|-------|----------|--------|------|--------|
| SRV | `_minecraft._tcp.journey-into-imagination` | `_minecraft` | `_tcp` | 0 | 5 | 25565 | `journey-into-imagination.mk-labs.cloud` |
> The SRV record allows players to connect using `journey-into-imagination.mk-labs.cloud`
> without specifying `:25565`. Most modern Minecraft clients resolve SRV records.
### 4. Internal DNS (Technitium — automated via ExternalDNS)
The Service in `service.yaml` has this annotation:
```yaml
external-dns.alpha.kubernetes.io/hostname: journey-into-imagination.local.mk-labs.cloud
```
ExternalDNS (Technitium provider) will create the internal A record automatically when ArgoCD syncs.
No manual action required for internal DNS.
---
## Deployment Steps
### Step 1: Update the RCON Secret
Complete prerequisite #1 above, then commit the updated secret.
### Step 2: Commit and Push to Gitea
```bash
cd ~/git/homelab
git status # review what changed
git add cluster/applications/minecraft/ cluster/platform/ingress-nginx/values.yaml
git commit -m "feat(minecraft): add Journey Into Imagination PaperMC server
- Namespace, Deployment, Service (journey-into-imagination), PVC, Secret, ConfigMap
- ArgoCD Application at cluster/applications/minecraft/
- ingress-nginx TCP forwarding: 25565 -> minecraft/journey-into-imagination:25565
- PaperMC 1.21.4, itzg/minecraft-server:2026.7.0, SleepMost 5.6.2
- StorageClass: pure-block, 50Gi PVC for world data"
git push
```
### Step 3: Verify ArgoCD Discovers and Syncs
ArgoCD app-of-apps auto-discovers `cluster/applications/minecraft/application.yaml`.
```bash
# Watch ArgoCD pick it up (from carousel-of-progress)
kubectl get application minecraft -n argocd -w
# Or check ArgoCD UI at argocd.local.mk-labs.cloud
```
Wait for status: `Synced` / `Healthy`
### Step 4: Watch the Pod Start Up
First startup will download the PaperMC jar — this can take 2-3 minutes.
```bash
kubectl get pods -n minecraft -w
# Tail the logs to watch PaperMC boot
kubectl logs -n minecraft -l app.kubernetes.io/component=papermc -f
```
Look for:
```
[Server thread/INFO]: Done (X.XXXs)! For help, type "help"
```
### Step 5: Install SleepMost Plugin (auto via PLUGINS env var)
The `PLUGINS` env var in the ConfigMap points to the SleepMost JAR download URL.
itzg/minecraft-server downloads and installs it automatically on startup.
Verify it loaded:
```bash
kubectl exec -n minecraft -it deployment/papermc -- rcon-cli
# In rcon console:
plugins
# Should list: SleepMost
```
### Step 6: Verify Connectivity
**Internal test (from carousel-of-progress):**
```bash
# Port probe — should succeed
nc -zv journey-into-imagination.local.mk-labs.cloud 25565
# Or via the ClusterIP directly
kubectl get svc -n minecraft
nc -zv <CLUSTER-IP> 25565
```
**External test (after UniFi port forward + DNS configured):**
- Open Minecraft Java Edition
- Add server: `journey-into-imagination.mk-labs.cloud`
- Should connect and show MOTD: "Journey Into Imagination"
---
## Plugin Details
### SleepMost v5.6.2
- **Source:** https://github.com/mrgeneralq/sleep-most
- **Download:** https://github.com/mrgeneralq/sleep-most/releases/download/v5.6.2/SleepMost-5.6.2.jar
- **Compatibility:** PaperMC 1.8 through 1.21.x (use 5.6.2 for 1.21.x; 5.7.0+ drops backward compat)
- **Configuration:** Lives at `/data/plugins/SleepMost/config.yml` after first boot
Default behavior: configurable percentage of online players must sleep to skip night.
To tune (exec into the pod after first start):
```bash
kubectl exec -n minecraft -it deployment/papermc -- bash
cat /data/plugins/SleepMost/config.yml
# Edit as needed, then /sleepmost reload in rcon
```
> **Geyser compatibility note:** SleepMost 5.x does NOT require Geyser to function.
> If you add Geyser later for Bedrock crossplay, SleepMost is compatible.
---
## Day 2 Operations
### Enabling the Whitelist
When ready to lock the server to approved players:
1. Edit `cluster/applications/minecraft/configmap.yaml`:
```yaml
WHITE_LIST: "true"
ENFORCE_WHITELIST: "true"
```
2. Add players via RCON (live, no restart needed):
```bash
kubectl exec -n minecraft -it deployment/papermc -- rcon-cli
whitelist add <player_name>
whitelist list
```
3. Commit the ConfigMap change for GitOps consistency.
Note: the Deployment will restart when the ConfigMap changes (env var reload).
Players will be briefly disconnected — plan accordingly.
### Console / RCON Access
```bash
# Interactive RCON (from inside the pod)
kubectl exec -n minecraft -it deployment/papermc -- rcon-cli
# One-shot command
kubectl exec -n minecraft -it deployment/papermc -- rcon-cli "list"
kubectl exec -n minecraft -it deployment/papermc -- rcon-cli "say Server restarting in 5 minutes"
```
### Upgrading PaperMC Version
1. Check PaperMC API: `curl -sA 'Mozilla/5.0' https://fill.papermc.io/v3/projects/paper/versions | head`
2. Update `VERSION` in `deployment.yaml` env vars and the comment header
3. Update image tag if a new `itzg/minecraft-server` release is out
4. Verify SleepMost compatibility with the new version
5. Commit, push — ArgoCD handles the rolling restart (Recreate strategy)
### Expanding PVC Storage
Pure Storage CSI supports online volume expansion:
```bash
kubectl patch pvc papermc-world-data -n minecraft \
-p '{"spec":{"resources":{"requests":{"storage":"100Gi"}}}}'
```
No pod restart required.
### Backups
No automated backup is configured in this skeleton.
Recommended Day 2 addition: CronJob that runs `rcon-cli save-all` + `rcon-cli save-off`,
copies `/data/world*` to a separate PVC or object store, then `rcon-cli save-on`.
---
## Troubleshooting
| Symptom | Check |
|---------|-------|
| Pod stuck in `Init` / slow start | `kubectl logs -n minecraft -l app.kubernetes.io/component=papermc` — jar download may be slow |
| Port 25565 connection refused externally | Verify UniFi port forward is active; `kubectl get svc -n minecraft` shows correct ClusterIP |
| Players can't authenticate | `ONLINE_MODE=true` requires Mojang auth; check player has a valid Java account |
| World data lost after pod restart | Verify PVC is `Bound`; check `pure-block` StorageClass is healthy |
| EULA error in logs | `EULA=TRUE` is set in deployment.yaml — this should not occur; check env var injection |
---
## File Manifest Summary
| File | Purpose |
|------|---------|
| `namespace.yaml` | `minecraft` namespace |
| `application.yaml` | ArgoCD Application (sync-wave 20) |
| `pvc.yaml` | 50Gi pure-block PVC for world data |
| `secret.yaml` | RCON password (⚠️ placeholder — update before deploy) |
| `configmap.yaml` | server.properties overrides + SleepMost plugin download |
| `deployment.yaml` | PaperMC Deployment (Recreate strategy, resource limits set) |
| `service.yaml` | ClusterIP Service named `journey-into-imagination` |
| `../../../platform/ingress-nginx/values.yaml` | Added `tcp: 25565` forwarding entry |