バージョン確認
ここまでに使用した主なアプリのバージョンを整理してみる。
Ubuntu Server(VM) : 22.04.3
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 22.04.3 LTS
Release: 22.04
Codename: jammy
Kubernetes : 1.28.3
$ kubectl version
Client Version: v1.28.3
Kustomize Version: v5.0.4-0.20230601165947-6ce0bf390ce3
Server Version: v1.28.3
CRI-O(CRI:Container Runtime Interface) : 1.28.1-0
$ sudo apt-show-versions cri-o
cri-o:amd64/unknown 1.28.1~0 uptodate
cri-o:arm64 not installed
cri-o:armhf not installed
cri-o:s390x not installed
Flannel(CNI:Container Network Interface) : 0.23.0
Flannel plugin : 1.2.0
$ kubectl get pods -n kube-flannel | grep flannel
kube-flannel-ds-97gjk 1/1 Running 0 9m9s
kube-flannel-ds-j8kt9 1/1 Running 0 9m40s
kube-flannel-ds-q88kf 1/1 Running 0 9m19s
kube-flannel-ds-wmb87 1/1 Running 0 9m30s
$ kubectl describe pod kube-flannel-ds-97gjk -n kube-flannel | grep Image
Image: docker.io/flannel/flannel-cni-plugin:v1.2.0
Image ID: a55d1bad692b776e7c632739dfbeffab2984ef399e1fa633e0751b1662ea8bb4
Image: docker.io/flannel/flannel:v0.23.0
Image ID: 01cdfa8dd262f793cedbb1561d574a180c0fe09e795ca641445566ca32840830
Image: docker.io/flannel/flannel:v0.23.0
Image ID: 01cdfa8dd262f793cedbb1561d574a180c0fe09e795ca641445566ca32840830
MetalLB(load balancers) : 0.13.12 ※指定してインストール
$ kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.13.12/config/manifests/metallb-native.yaml
Helm : 3.13.1
$ helm version
version.BuildInfo{Version:"v3.13.1", GitCommit:"3547a4b5bf5edb5478ce352e18858d8a552a4110", GitTreeState:"clean", GoVersion:"go1.20.8"}
kubernetes-dashboard : 6.0.8 ※ダッシュボード画面から確認
NFS CSI Driver(Provisioner) : 4.4.0 ※指定してインストール
helm install csi-driver-nfs csi-driver-nfs/csi-driver-nfs --namespace kube-system --version v4.4.0
itzg/minecraft-server : 2023.10.1 ※github.comより
https://github.com/itzg/docker-minecraft-server
マニフェストを作る
いよいよ Minecraft をデプロイする。
何はともあれマニフェストを用意する。既に多くの人たちが作っているものを活用させてもらおう。
次のサイトがわかり易かった。
使用するイメージは定番?の itzg/minecraft-server。
頻繁にアップデートされている docker image で利用者も多い。
永続ボリューム用の pvc も pod に含めたもの。pv は先にデプロイ済みの nfs-pv-java.yaml を使用している。
サーバーの詳細設定は README.md を参照。
$ vi mc-java.yaml
apiVersion: v1
kind: Namespace
metadata:
name: minecraft
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: minecraft
namespace: minecraft
spec:
selector:
matchLabels:
app: minecraft
template:
metadata:
labels:
app: minecraft
spec:
volumes:
- name: minecraft-volumes
persistentVolumeClaim:
claimName: nfs-pvc-java
containers:
- name: minecraft
image: itzg/minecraft-server
env:
- name: EULA
value: "TRUE"
- name: OPS
value: "user_name" # OP権限持ちのユーザ名を記述。複数の場合は「,」で区切る。
- name: WHITELIST
value: "user_name" # 接続可能ユーザ名を記述。複数の場合は「,」で区切る。
- name: LEVEL
value: "1.20.2" # マイクラのバージョン。
- name: MOTD
value: "MC-Kuvernetes" # マイクラのランチャーでサーバリストに表示するサーバの説明。
- name: TZ
value: "Asia/Tokyo"
- name: SERVER_NAME
value: "mc.jisaba.life" # サーバのドメイン名。
- name: MEMORY
value: "4G" # 割り当てるメモリ。resourcelimitと同じ値にしておくこと。
- name: SPAWN_PROTECTION
value: "0"
- name: MODE
value: "survival" # World生成時のゲームモード。
- name: DIFFICULTY
value: "easy" # World生成時の難易度。
# - name: SEED
# value: '3427891657823464' # World生成時のseed値を指定する場合はコメントイン。
resources:
limits:
memory: "4Gi" # worker node内で割り当ててもらうメモリの上限。worker nodeに積んでる以上のメモリサイズは不可。
ports:
- containerPort: 25565 # コンテナ側で開けてるポートを明示。
volumeMounts:
- name: minecraft-volumes
mountPath: "/data"
---
# 以下はロードバランサーを使用している場合。
apiVersion: v1
kind: Service
metadata:
name: minecraft
namespace: minecraft
labels:
app: minecraft
spec:
type: LoadBalancer
ports:
- name: minecraft-port
port: 25565
protocol: TCP
targetPort: 25565
selector:
app: minecraft
---
# 以下は永続ボリュームを適用する場合。pvは作成済みとします。
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nfs-pvc-java
namespace: minecraft
spec:
accessModes:
- ReadWriteMany
storageClassName: ""
resources:
requests:
storage: 5Gi
volumeName: nfs-pv-java
デプロイする
kubectl apply -f mc-java.yaml でデプロイして確認する。
$ kubectl get pods --namespace=minecraft
NAME READY STATUS RESTARTS AGE
minecraft-5d4d97bcd4-m76jv 1/1 Running 0 6m36s
詳細はこんな感じ。
お一人さま用の自鯖だから namespace も default で良いとは思いつつ、マイクラ用に分けている。
$ kubectl get pods --namespace=minecraft
NAME READY STATUS RESTARTS AGE
minecraft-5fd8ccd9bf-7lxvm 1/1 Running 0 17m
$ kubectl -n minecraft describe pod minecraft-5fd8ccd9bf-7lxvm
Name: minecraft-5fd8ccd9bf-7lxvm
Namespace: minecraft
Priority: 0
Service Account: default
Node: k8s-node4/10.1.1.6
Start Time: Sat, 04 Nov 2023 11:09:45 +0900
Labels: app=minecraft
pod-template-hash=5fd8ccd9bf
Annotations: <none>
Status: Running
IP: 10.244.1.13
IPs:
IP: 10.244.1.13
Controlled By: ReplicaSet/minecraft-5fd8ccd9bf
Containers:
minecraft:
Container ID: cri-o://71d73cc60f52692a30a21e2578e21caa5783c7595eb7243f711f33d19f1f9d91
Image: itzg/minecraft-server
Image ID: f73dab1b631c716f0e7d464bd54518123455ecd0edd7789fad057831fdf4e0c6
Port: 25565/TCP
Host Port: 0/TCP
State: Running
Started: Sat, 04 Nov 2023 11:09:48 +0900
Ready: True
Restart Count: 0
Limits:
memory: 4Gi
Requests:
memory: 4Gi
Environment:
EULA: TRUE
OPS: user_name
LEVEL: 1.20.2
MOTD: MC-Kuvernetes
TZ: Asia/Tokyo
SERVER_NAME: mc.jisaba.life
MEMORY: 4G
SPAWN_PROTECTION: 0
MODE: survival
DIFFICULTY: easy
Mounts:
/data from minecraft-volumes (rw)
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-7xsng (ro)
Conditions:
Type Status
Initialized True
Ready True
ContainersReady True
PodScheduled True
Volumes:
minecraft-volumes:
Type: PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)
ClaimName: nfs-pvc-java
ReadOnly: false
kube-api-access-7xsng:
Type: Projected (a volume that contains injected data from multiple sources)
TokenExpirationSeconds: 3607
ConfigMapName: kube-root-ca.crt
ConfigMapOptional: <nil>
DownwardAPI: true
QoS Class: Burstable
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 18m default-scheduler Successfully assigned minecraft/minecraft-5fd8ccd9bf-7lxvm to k8s-node4
Normal Pulling 18m kubelet Pulling image "itzg/minecraft-server"
Normal Pulled 18m kubelet Successfully pulled image "itzg/minecraft-server" in 2.067s (2.067s including waiting)
Normal Created 18m kubelet Created container minecraft
Normal Started 18m kubelet Started container minecraft
クラスター外から接続するための service/minecraft のアドレスを固定するのを忘れてた。
service に loadBalancerIP: 10.1.11.11 を追加する。
〜〜〜(省略)〜〜〜
---
apiVersion: v1
kind: Service
metadata:
name: minecraft
namespace: minecraft
labels:
app: minecraft
spec:
type: LoadBalancer
loadBalancerIP: 10.1.11.11 # IPアドレスの固定化
ports:
- name: minecraft-port
port: 25565
protocol: TCP
targetPort: 25565
selector:
app: minecraft
---
〜〜〜(省略)〜〜〜
現時点の最終的なクラスターの様子は次の通り。
$ kubectl get all -A
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-flannel pod/kube-flannel-ds-gz2hk 1/1 Running 2 6d18h
kube-flannel pod/kube-flannel-ds-hg2jv 1/1 Running 2 6d18h
kube-flannel pod/kube-flannel-ds-pcv8v 1/1 Running 1 6d18h
kube-flannel pod/kube-flannel-ds-vb5gr 1/1 Running 9 6d18h
kube-system pod/coredns-5dd5756b68-67dvx 1/1 Running 9 6d19h
kube-system pod/coredns-5dd5756b68-qtd4k 1/1 Running 9 6d19h
kube-system pod/csi-nfs-controller-c544c88c-k5hdt 4/4 Running 6 (141m ago) 12h
kube-system pod/csi-nfs-node-cvvfx 3/3 Running 0 12h
kube-system pod/csi-nfs-node-tv7sc 3/3 Running 0 12h
kube-system pod/csi-nfs-node-x6shz 3/3 Running 0 12h
kube-system pod/csi-nfs-node-xzqjm 3/3 Running 3 12h
kube-system pod/etcd-k8s-node1 1/1 Running 14 6d19h
kube-system pod/kube-apiserver-k8s-node1 1/1 Running 13 6d19h
kube-system pod/kube-controller-manager-k8s-node1 1/1 Running 35 6d19h
kube-system pod/kube-proxy-2vhl6 1/1 Running 2 6d18h
kube-system pod/kube-proxy-ddnxk 1/1 Running 9 6d19h
kube-system pod/kube-proxy-fjmft 1/1 Running 1 6d18h
kube-system pod/kube-proxy-w2x8c 1/1 Running 1 6d18h
kube-system pod/kube-scheduler-k8s-node1 1/1 Running 36 6d19h
kube-system pod/snapshot-controller-6597bcc578-2tw98 1/1 Running 5 (140m ago) 12h
kubernetes-dashboard pod/kubernetes-dashboard-798dd48467-bssc9 1/1 Running 9 (140m ago) 6d2h
metallb-system pod/controller-786f9df989-7fm7n 1/1 Running 0 16h
metallb-system pod/speaker-568dn 1/1 Running 16 (140m ago) 6d18h
metallb-system pod/speaker-5h8rf 1/1 Running 4 (15h ago) 6d18h
metallb-system pod/speaker-vxr4n 1/1 Running 2 (2d15h ago) 6d18h
metallb-system pod/speaker-wqpkz 1/1 Running 2 (2d15h ago) 6d18h
minecraft pod/minecraft-5fd8ccd9bf-7lxvm 1/1 Terminating 0 73m
minecraft pod/minecraft-6b854f7d5c-hc264 1/1 Running 0 4s
NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
default service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 6d19h
kube-system service/kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 6d19h
kubernetes-dashboard service/kubernetes-dashboard ClusterIP 10.96.253.32 <none> 443/TCP 6d2h
metallb-system service/webhook-service ClusterIP 10.106.140.148 <none> 443/TCP 6d18h
minecraft service/minecraft LoadBalancer 10.107.254.76 10.1.11.11 25565:32739/TCP 93m
NAMESPACE NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
kube-flannel daemonset.apps/kube-flannel-ds 4 4 4 4 4 <none> 6d18h
kube-system daemonset.apps/csi-nfs-node 4 4 4 4 4 kubernetes.io/os=linux 12h
kube-system daemonset.apps/kube-proxy 4 4 4 4 4 kubernetes.io/os=linux 6d19h
metallb-system daemonset.apps/speaker 4 4 4 4 4 kubernetes.io/os=linux 6d18h
NAMESPACE NAME READY UP-TO-DATE AVAILABLE AGE
kube-system deployment.apps/coredns 2/2 2 2 6d19h
kube-system deployment.apps/csi-nfs-controller 1/1 1 1 12h
kube-system deployment.apps/snapshot-controller 1/1 1 1 12h
kubernetes-dashboard deployment.apps/kubernetes-dashboard 1/1 1 1 6d2h
metallb-system deployment.apps/controller 1/1 1 1 6d18h
minecraft deployment.apps/minecraft 1/1 1 1 93m
NAMESPACE NAME DESIRED CURRENT READY AGE
kube-system replicaset.apps/coredns-5dd5756b68 2 2 2 6d19h
kube-system replicaset.apps/csi-nfs-controller-c544c88c 1 1 1 12h
kube-system replicaset.apps/snapshot-controller-6597bcc578 1 1 1 12h
kubernetes-dashboard replicaset.apps/kubernetes-dashboard-798dd48467 1 1 1 6d2h
metallb-system replicaset.apps/controller-786f9df989 1 1 1 6d18h
minecraft replicaset.apps/minecraft-5fd8ccd9bf 0 0 0 73m
minecraft replicaset.apps/minecraft-668448c6ff 0 0 0 93m
minecraft replicaset.apps/minecraft-6b854f7d5c 1 1 1 4s
minecraft replicaset.apps/minecraft-7b4d9f849f 0 0 0 75m
Minecraft が動作している node が故障したとき
replicaset: 1(または未設定)の場合
mc-java.yaml に replicas: 1 を追加してデプロイ(kubectl apply -f mc-java.yaml)してから、ノード k8s-node5 を Proxmox VE 管理画面からシャットダウンする。もちろん ssh でノードにログインして shutdown でも同じ。
〜〜〜(省略)〜〜〜
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: minecraft
namespace: minecraft
spec:
replicas: 1 # これが無い、または1の場合
selector:
matchLabels:
app: minecraft
template:
metadata:
labels:
app: minecraft
spec:
〜〜〜(省略)〜〜〜
ノードの停止直後 $ kubectl get pods -o wide -n minecraft は変化が無い。でも実際には Minecraft のランチャーから接続できなくなっている(pod は落ちている)。
数分すると、次のよ���にシャットダウンしたノードの pod は Terminating になる。併せて別のノード(k8s-node4)に新しい pod が生えてくる。
$ kubectl get pods -o wide -n minecraft
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
minecraft-6b854f7d5c-tvnsh 1/1 Terminating 0 42m 10.244.2.21 k8s-node5 <none> <none>
minecraft-6b854f7d5c-wpp4w 1/1 Running 0 45s 10.244.1.16 k8s-node4 <none> <none>
改めて k8s-node5 を立ち上げると、
$ kubectl get pods -o wide -n minecraft
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
minecraft-6b854f7d5c-wpp4w 1/1 Running 0 4m18s 10.244.1.16 k8s-node4 <none> <none>
このとおり、Terminating だった pod は解消されて、k8s-node4 の pod が引き続き動作する。
replicaset: 2 以上の場合
replicaset を2にすると、pod の一つは STATUS が CrashLoopBackOff となって、リスタートを繰り返す。
$ kubectl get pods -o wide -n minecraft
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
minecraft-6b854f7d5c-hc264 1/1 Running 2 45m 10.244.2.19 k8s-node5 <none> <none>
minecraft-6b854f7d5c-hpcvk 0/1 CrashLoopBackOff 6 (62s ago) 9m22s 10.244.1.14 k8s-node4 <none> <none>
リスタートを繰り返す方の pod のログを見るとこんな感じ。
$ kubectl logs -n minecraft minecraft-6b854f7d5c-hpcvk
[init] Running as uid=1000 gid=1000 with /data as 'drwxrwxr-x 7 1000 1000 4096 Nov 4 10:49 /data'
[init] Resolving type given VANILLA
[init] Resolved version given LATEST into 1.20.2
[init] Enabling whitelist functionality
[init] Setting mode
[mc-image-helper] 13:40:11.265 INFO : Created/updated 1 property in /data/server.properties
[mc-image-helper] 13:40:12.404 INFO : The file ./ops.json already exists, so no changes will be made
[mc-image-helper] 13:40:13.570 INFO : The file ./whitelist.json already exists, so no changes will be made
[init] Setting initial memory to 4G and max to 4G
[init] Starting the Minecraft server...
Starting net.minecraft.server.Main
[13:40:26] [ServerMain/INFO]: Environment: Environment[accountsHost=https://api.mojang.com, sessionHost=https://sessionserver.mojang.com, servicesHost=https://api.minecraftservices.com, name=PROD]
[13:40:26] [ServerMain/ERROR]: Failed to start the minecraft server
ard$a: /data/./1.20.2/session.lock: already locked (possibly by other Minecraft instance?)
at ard$a.a(SourceFile:95) ~[server-1.20.2.jar:?]
at ard.a(SourceFile:41) ~[server-1.20.2.jar:?]
at ecg$c.<init>(SourceFile:419) ~[server-1.20.2.jar:?]
at ecg.d(SourceFile:398) ~[server-1.20.2.jar:?]
at net.minecraft.server.Main.main(SourceFile:133) ~[server-1.20.2.jar:?]
at net.minecraft.bundler.Main.lambda$run$0(Main.java:54) ~[?:?]
at java.lang.Thread.run(Unknown Source) ~[?:?]
/data/1.20.2/session.lock されているから2つ目が起動できないらしい。
これは、Minecraft の仕様で、最初にサーバーが起動されたときに session.lock ファイルが作られて、以降常に監視しているため。
/data 内を、中身は同じでも別の pod(minecraft) で共有しているから2つ目は起動できない。
(参考)https://minecraft.fandom.com/wiki/Java_Edition_level_format#session.lock_format
ただし、あくまでも永続ボリュームに異なる pod(replica)が同時アクセスする場合は注意が必要、という話。
外部からの接続
自宅の LAN 内ではなく、インターネットから接続のこと。
ここまでの設定で、Minecraft には 10.1.11.11 で接続できることを確認している。
あとは、ルーターのポート開放で、service/minecraft のアドレス(10.1.11.11)に向ければ外部からも接続できる。
終わりに
とりあえず Minecraft が遊べる状態にはなった。
以降はセキュリティアップデート(Image: itzg/minecraft-server の更新)や Kubernetes 関係のアップグレードを適宜、実行する。
慣れた人なら Kubernetes の環境構築から Minecraft のデプロイまで半日も要しないかな。
コメント