# Document issues
TODO(juh) add a colorized version of these yamls that indicates which things are linked together?
# Full working example: Minecraft server
As promised, here is my solution to serving a single instance of a Minecraft server. There are five files (descriptions after, [tgz here](https://juh.gay/files/mcd.tgz)). Pages 301-309 cover various non-stuff-in-the-files things; 310-350 cover the contents of the files; 380 describes various maintenance and debugging operations.
> [!file]- [10-ns.yaml](310-namespace)
> ```yaml
> apiVersion: v1
> kind: Namespace
> metadata:
> name: mcd
> ```
> [!file]- [20-pvc.yaml](320-pvc)
> ```yaml
> apiVersion: v1
> kind: PersistentVolumeClaim
> metadata:
> name: smp-164-pvc
> namespace: mcd
> spec:
> accessModes:
> - ReadWriteOnce
> storageClassName: longhorn
> resources:
> requests:
> storage: 5Gi
> ```
> [!file]- [25-configmap.yaml](330-configmap)
> ```yaml
> apiVersion: v1
> kind: ConfigMap
> metadata:
> name: smp-164-config
> namespace: mcd
> labels:
> app: mcd
> style: smp # gamemode=0
> version: 1.6.4
> data:
> server.properties: |
> allow-flight=false
> allow-nether=true
> difficulty=1
> enable-query=false
> enable-rcon=true
> force-gamemode=false
> gamemode=0
> generate-structures=true
> generator-settings=
> hardcore=false
> level-name=world
> level-seed=
> level-type=DEFAULT
> max-build-height=256
> max-players=20
> motd=four legs good, two legs better
> online-mode=true
> player-idle-timeout=0
> pvp=true
> rcon.password=eebydeeby
> rcon.port=25575
> server-ip=
> server-port=25565
> snooper-enabled=true
> spawn-animals=true
> spawn-monsters=true
> spawn-npcs=true
> spawn-protection=16
> texture-pack=
> view-distance=10
> white-list=false
> ```
> [!file]- [30-deployment.yaml](340-deployment)
> ```yaml
> apiVersion: apps/v1
> kind: Deployment
> metadata:
> name: smp-164-deployment
> namespace: mcd
> labels:
> app: mcd
> style: smp
> version: 1.6.4
> spec:
> replicas: 1
> selector:
> matchLabels:
> app: mcd
> style: smp
> version: 1.6.4
> strategy:
> type: Recreate
> template:
> metadata:
> labels:
> app: mcd
> style: smp
> version: 1.6.4
> spec:
> initContainers:
> - name: init-config-files
> image: busybox:1.36
> command: ["/bin/sh", "-c"]
> args:
> - |
> yes n | cp -Lri /tmp/config/. /data/
> volumeMounts:
> - mountPath: /data
> name: smp-164-vol
> - mountPath: /tmp/config
> name: smp-164-config
> #- name: init-compare-files
> # image: busybox:1.36
> # command:
> # - "find"
> # - "/data"
> # - "/tmp/config"
> # volumeMounts:
> # - mountPath: /data
> # name: smp-164-vol
> # - mountPath: /tmp/config
> # name: smp-164-config
> #- name: init-sleep
> # image: busybox:1.36
> # command:
> # - "sleep"
> # - "infinity"
> # volumeMounts:
> # - mountPath: /data
> # name: smp-164-vol
> # - mountPath: /tmp/config
> # name: smp-164-config
> containers:
> - name: smp-164
> image: itzg/minecraft-server
> stdin: true
> tty: true
> ports:
> - containerPort: 25565
> hostPort: 25565
> protocol: TCP
> volumeMounts:
> - mountPath: /data
> name: smp-164-vol
> env:
> # things the ct won't run without
> - name: EULA
> value: "true"
>
> # jvm options
> - name: INIT_MEMORY
> value: 1G
> - name: MAX_MEMORY
> value: 3G
> - name: JVM_XX_OPTS
> value: -XX:+UseG1GC -XX:+UnlockExperimentalVMOptions -XX:MaxGCPauseMillis=100 -XX:+DisableExplicitGC -XX:TargetSurvivorRatio=90 -XX:G1NewSizePercent=50 -XX:G1MaxNewSizePercent=80 -XX:G1MixedGCLiveThresholdPercent=50 -XX:+AlwaysPreTouch -XX:+UseLargePages -XX:LargePageSizeInBytes=2m
>
> # game info
> - name: TYPE
> value: VANILLA
> - name: VERSION
> value: 1.6.4
>
> # game server options
> - name: ENABLE_ROLLING_LOGS
> value: "true"
> - name: TZ
> value: America/Vancouver
>
> restartPolicy: Always
> volumes:
> - name: smp-164-vol
> persistentVolumeClaim:
> claimName: smp-164-pvc
> - name: smp-164-config
> configMap:
> name: smp-164-config
> ```
> [!file]- [40-service.yaml](350-service)
> ```yaml
> apiVersion: v1
> kind: Service
> metadata:
> name: smp-164-svc
> namespace: mcd
> spec:
> type: NodePort
> selector:
> app: mcd
> ports:
> - name: mc
> port: 25565
> targetPort: 25565
> nodePort: 32565
> protocol: TCP
> ```
> [!config]- DNS records
> ```
> mc.example.org. 300 IN A 1.2.3.4
> _minecraft._tcp.example.org. 300 IN SRV 0 0 32565 mc.example.org.
> ```
Set the DNS records (substituting in your domain and IP), put all the yamls in the same directory, and then from that directory, run `kubectl create -f .`. This will attempt to create resources on the server for every yaml file in `.`. You can also run this from the parent dir and use the name of the directory, or supply a single filename to just create whatever's in that file (useful for testing). To delete everything, you could either delete the namespace (`kubectl delete -f 10-ns.yaml` or `kubectl delete ns mcd`), or just undo what we did above (`kubectl delete -f .`). They all have the same end result, since destroying the namespace destroys everything inside it.
Note that create and destroy operations take some time, on the order of tens of seconds in this example. **Don't kill them!** They are thinking :) just let them sit for a few minutes to simmer. Once the command returns, your resources are probably still not ready, they'll take some more time to fully spin up (order of minutes). I use [Infra](https://infra.app/download) to monitor what the cluster is doing, and it's very nice because it lets me see that yes, the namespace was created, yes, there's a pod, it's just not fully initialized yet, etc.
# Summary of parts
1. Namespace: a way of containing all the stuff for this project, separately from things for other projects
2. PersistentVolumeClaim (PVC): says "I would like to take a 5 GiB chunk of space from Longhorn and name it `smp-164-pvc`"
3. ConfigMap: some files we want to initialize in the storage volume before we start the server
4. Deployment: basically a docker compose specification, with some extra info to tell the cluster how to initialize and scale things properly, which is more complex because you can have multiple versions of the same app running together
5. Service: connect the containers' serving ports to the outside world and/or other internal services
I struggled a lot with the question, "what is the difference between a deployment and a service?" The deployment is about keeping the containers running, healthy, and in the right quantity. The service connects the deployment to other stuff. A deployment might have a database and a web backend and a web frontend, all scaled to match your load, and then the Service says "ok so we need to expose the frontend to the internet for our users, but not the backend and definitely not the database".