diff --git a/minecraft/mc-router.yaml b/minecraft/mc-router.yaml new file mode 100644 index 0000000..e33ba06 --- /dev/null +++ b/minecraft/mc-router.yaml @@ -0,0 +1,193 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: mc-router + namespace: minecraft +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: services-watcher + namespace: minecraft +rules: + - apiGroups: [""] + resources: ["services"] + verbs: ["watch", "list"] + - apiGroups: ["apps"] + resources: ["statefulsets", "statefulsets/scale"] + verbs: ["watch", "list", "get", "update"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: mc-router-services-watcher + namespace: minecraft +subjects: + - kind: ServiceAccount + name: mc-router + namespace: minecraft +roleRef: + kind: ClusterRole + name: services-watcher + apiGroup: rbac.authorization.k8s.io +--- +apiVersion: v1 +kind: Service +metadata: + name: mc-router + namespace: minecraft +spec: + type: NodePort + selector: + run: mc-router + ports: + - targetPort: web + name: web + port: 8080 + nodePort: 30001 + - targetPort: proxy + name: proxy + port: 25565 + nodePort: 25565 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: mc-router + namespace: minecraft + labels: + run: mc-router +spec: + selector: + matchLabels: + run: mc-router + strategy: + type: Recreate + template: + metadata: + namespace: minecraft + labels: + run: mc-router + spec: + serviceAccountName: mc-router + containers: + - image: itzg/mc-router + imagePullPolicy: Always + name: mc-router + args: + [ + "--api-binding", + ":8080", + "--in-kube-cluster", + "--auto-scale-up", + "--debug", + ] + env: + - name: AUTO_SCALE_UP + value: "true" + ports: + - name: proxy + containerPort: 25565 + - name: web + containerPort: 8080 + resources: + requests: + memory: 50Mi + cpu: "100m" + limits: + memory: 100Mi + cpu: "250m" + +# Cron job for stopping empty servers +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: mc-shutdown + namespace: minecraft +rules: + - apiGroups: ["apps"] + resources: ["statefulsets", "statefulsets/scale"] + verbs: ["list", "get", "update", "patch"] + - apiGroups: [""] + resources: ["pods", "pods/log"] + verbs: ["get", "list"] + - apiGroups: [""] + resources: ["pods/exec"] + verbs: ["create"] +--- +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: mc-shutdown + namespace: minecraft +subjects: + - kind: ServiceAccount + name: mc-shutdown + namespace: default +roleRef: + kind: ClusterRole + name: mc-shutdown + apiGroup: "rbac.authorization.k8s.io" +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: mc-shutdown + namespace: minecraft +--- +apiVersion: batch/v1 +kind: CronJob +metadata: + name: mc-shutdown + namespace: minecraft +spec: + schedule: "*/5 * * * *" + concurrencyPolicy: Forbid + jobTemplate: + spec: + template: + spec: + serviceAccountName: mc-shutdown + restartPolicy: OnFailure + containers: + - name: shutdown + image: bitnami/kubectl:latest + imagePullPolicy: IfNotPresent + command: + - /bin/bash + - -c + - source shutdown-script.sh + volumeMounts: + - name: shutdown-script + mountPath: /shutdown-script.sh + subPath: shutdown-script.sh + readOnly: true + volumes: + - name: shutdown-script + configMap: + name: shutdown-script + items: + - key: shutdown-script.sh + path: shutdown-script.sh +# uses container label containertype=minecraft-server to find running servers +# TODO: get ownerReferences link to StatefulSet/name from pod metadate instead of sed string manipulation +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: shutdown-script + namespace: minecraft +data: + shutdown-script.sh: | + #!/bin/bash + MC_PODS=$(kubectl get pods -l containertype=minecraft-server -o=jsonpath="{range .items[*]}{.metadata.name},"| sed 's/,/\n/g') + for p in $MC_PODS; do + echo "found minecraft pod $p, sleeping 120 seconds to prevent shutdown before login" + sleep 120 + deployment=$(echo $p |sed 's/-0//g') + # check online player count in the mc server + if [[ $(kubectl exec -i $p -- /usr/local/bin/mc-monitor status) == *"online=0"* ]] ;then + kubectl scale statefulset $deployment --replicas=0 + fi + done diff --git a/minecraft/tfg-deployment.yaml b/minecraft/tfg-deployment.yaml index 944c966..2558806 100644 --- a/minecraft/tfg-deployment.yaml +++ b/minecraft/tfg-deployment.yaml @@ -1,26 +1,32 @@ apiVersion: apps/v1 -kind: Deployment +kind: StatefulSet metadata: name: tfg namespace: minecraft labels: app.kubernetes.io/name: tfg spec: - replicas: 1 selector: matchLabels: app.kubernetes.io/name: tfg - strategy: - type: Recreate + replicas: 1 template: metadata: + namespace: minecraft labels: app.kubernetes.io/name: tfg + containertype: minecraft-server spec: containers: - name: tfg image: itzg/minecraft-server:java21-graalvm env: + # Let jvm figure out memory based on limits + - name: MEMORY + value: "" + - name: JVM_XX_OPTS + value: "-XX:MaxRAMPercentage=75" + - name: ALLOW_FLIGHT value: "true" - name: CF_API_KEY @@ -38,8 +44,7 @@ spec: value: "TRUE" - name: MAX_TICK_TIME value: "-1" - - name: MEMORY - value: 12G + - name: MOD_PLATFORM value: AUTO_CURSEFORGE - name: ONLINE_MODE @@ -48,6 +53,7 @@ spec: value: "true" - name: SPAWN_PROTECTION value: "0" + - name: OPS value: | RoyalCat33 @@ -56,16 +62,32 @@ spec: ports: - containerPort: 25565 protocol: TCP + resources: + requests: + cpu: "1" + memory: "2Gi" + limits: + cpu: "4" + memory: "10Gi" + readinessProbe: + exec: + command: + ["/usr/local/bin/mc-monitor", "status", "--host", "localhost"] + # Give it i + p * f seconds to be ready, so 120 seconds + initialDelaySeconds: 20 + periodSeconds: 5 + failureThreshold: 20 + # Monitor ongoing liveness + livenessProbe: + exec: + command: + ["/usr/local/bin/mc-monitor", "status", "--host", "localhost"] + initialDelaySeconds: 120 + periodSeconds: 60 volumeMounts: - mountPath: /data name: tfg-data - - mountPath: /downloads - name: curseforge-downloads - restartPolicy: Always volumes: - name: tfg-data persistentVolumeClaim: claimName: tfg-data - - name: curseforge-downloads - persistentVolumeClaim: - claimName: curseforge-downloads diff --git a/minecraft/tfg-service.yaml b/minecraft/tfg-service.yaml index 1a771ee..c2b3cd0 100644 --- a/minecraft/tfg-service.yaml +++ b/minecraft/tfg-service.yaml @@ -5,6 +5,21 @@ metadata: namespace: minecraft labels: app.kubernetes.io/name: tfg + annotations: + mc-router.itzg.me/externalServerName: "tfg.mc.konfa.ch" +spec: + selector: + app.kubernetes.io/name: tfg + ports: + - port: 25565 +--- +apiVersion: v1 +kind: Service +metadata: + name: tfg-port + namespace: minecraft + labels: + app.kubernetes.io/name: tfg spec: type: NodePort selector: @@ -14,3 +29,12 @@ spec: port: 25565 targetPort: 25565 nodePort: 32565 +--- +apiVersion: externaldns.k8s.io/v1alpha1 +kind: DNSEndpoint +metadata: + name: tfg-dns-record + namespace: minecraft +spec: + endpoints: + - dnsName: tfg.mc.konfa.ch