Design¶
This document covers the system architecture and design decisions of Minecraft Operator.
Full Design Document
For the complete design document, see DESIGN.md in the repository.
Goals¶
- Version Control — Automatic tracking of PaperMC server and plugin updates
- Compatibility Guarantee — Constraint solver finds newest compatible versions
- Predictable Updates — Updates only during defined maintenance windows
- Graceful Updates — Proper RCON shutdown before updates
Non-Goals¶
- High Availability — 5-10 minute downtime during updates is acceptable
- World backups (separate tooling)
- Update rollbacks (world format changes are destructive)
- Performance monitoring (TPS, lag)
- Horizontal scaling
- Zero-downtime updates
System Architecture¶
┌─────────────────────────────────────────────────┐
│ K8s API Server │
│ │
│ ┌──────────────┐ ┌──────────────────┐ │
│ │ Plugin CRD │ │ PaperMCServer │ │
│ │ │ │ CRD │ │
│ └──────────────┘ └──────────────────┘ │
└────────────────┬────────────┬───────────────────┘
│ │
│ Watch │
│ │
┌────────────────▼────────────▼───────────────────┐
│ Minecraft Operator │
│ │
│ ┌─────────────────────────────────────────┐ │
│ │ Plugin Controller │ │
│ │ - Match servers via selector │ │
│ │ - Fetch from plugin APIs │ │
│ │ - Run solver for all matched servers │ │
│ └─────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────┐ │
│ │ PaperMCServer Controller │ │
│ │ - Find matched plugins │ │
│ │ - Ensure StatefulSet exists │ │
│ │ - Run solver for Paper version │ │
│ └─────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────┐ │
│ │ Update Controller │ │
│ │ - Watch cron schedule │ │
│ │ - Graceful shutdown via RCON │ │
│ │ - Update JARs and restart │ │
│ └─────────────────────────────────────────┘ │
└────────────────┬────────────┬───────────────────┘
│ │
┌────────┴────────┐ │
│ │ │
┌───────▼──────┐ ┌──────▼───▼───────┐
│ Plugin APIs │ │ Minecraft Pods │
│ - Hangar │ │ + RCON │
│ - Modrinth │ │ + StatefulSet │
└──────────────┘ └───────────────────┘
Component Interactions¶
Plugin → PaperMCServer (Declarative)¶
- Plugin defines
instanceSelectorlabels - Plugin Controller finds all matched servers
- Solver calculates best version for all matched servers
- PaperMCServer Controller reads resolved versions from Plugin.status
PaperMCServer → Plugin (Reactive)¶
- When labels change on PaperMCServer
- Plugin Controller recalculates matching
- May trigger new solver solution
Update Flow¶
- Trigger: Cron in
PaperMCServer.spec.updateSchedule - Update Controller coordinates:
- Reads resolved versions from all matched Plugins
- Reads
availableUpdatefrom PaperMCServer.status - Performs graceful shutdown via RCON
- Updates JARs in
plugins/update/directory - Deletes pod for StatefulSet recreation
Controller Details¶
Plugin Controller¶
Watches: Plugin CRDs
Reconciliation loop:
- Fetch metadata from plugin repository (Hangar)
- Find all PaperMCServer instances matching
instanceSelector - Run constraint solver to find best compatible version
- Update Plugin.status with resolved version and matched instances
- Trigger reconciliation on matched PaperMCServer resources
PaperMCServer Controller¶
Watches: PaperMCServer CRDs, matched Plugin CRDs
Reconciliation loop:
- Ensure StatefulSet exists with correct configuration
- Ensure Service exists for server access
- Find all Plugin resources that match this server
- Based on
updateStrategy: latest: Query Docker Hub for newest versionauto: Run solver for plugin compatibilitypin/build-pin: Validate pinned version- Update status with current/desired versions
Update Controller¶
Watches: PaperMCServer CRDs (cron-triggered)
Update process:
- Check if maintenance window is active
- Check if update is available and
updateDelaysatisfied - Download plugin JARs to
/data/plugins/update/ - Send RCON
save-allcommand - Send RCON
stopcommand - Wait for graceful shutdown
- Update StatefulSet image tag
- Delete pod → StatefulSet recreates with new version
Resource Relationships¶
erDiagram
Plugin ||--|{ PaperMCServer : "matches via selector"
PaperMCServer ||--|| StatefulSet : "creates"
PaperMCServer ||--|| Service : "creates"
StatefulSet ||--|| Pod : "manages"
Pod ||--|| PVC : "uses" Selector Conflict Resolution¶
When multiple Plugins match the same server:
- If any has
updateStrategy: latest: solver picks optimal version - If all have
updateStrategy: pinned: highest semver wins (with warning)
Version Resolution¶
Paper Version Resolution¶
Based on updateStrategy:
| Strategy | Resolution |
|---|---|
latest | Newest from Docker Hub (ignores plugins) |
auto | Solver finds compatible version |
pin | Specified version, latest build |
build-pin | Exact version and build |
Plugin Version Resolution¶
Based on updateStrategy:
| Strategy | Resolution |
|---|---|
latest | Newest compatible with ALL matched servers |
auto | Solver picks optimal version |
pin | Specified version |
build-pin | Exact version and build |
Edge Cases¶
Repository Unavailable¶
- Use cached
status.availableVersions - Mark
repositoryStatus: orphaned - Log warning
Plugin Without Version Metadata¶
- Assume compatibility with warning
- Use
compatibilityOverrideif set
No Compatible Version Found¶
- Emit warning in Plugin.status conditions
- Keep current version installed
- Set
updateBlocked: trueon server
See Also¶
- Constraint Solver — Version resolution algorithm
- Update Strategies — Detailed strategy guide
- DESIGN.md — Full design document