1.准备工作
需要以下基础
- Kubernetes基础概念
Kubernetes集群(当前集群版本 version 1.23.4)
#当前环境版本 Client Version: version.Info{Major:"1", Minor:"23", GitVersion:"v1.23.4", GitCommit:"e6c093d87ea4cbb530a7b2ae91e54c0842d8308a", GitTreeState:"clean", BuildDate:"2022-02-16T12:38:05Z", GoVersion:"go1.17.7", Compiler:"gc", Platform:"linux/amd64"} Server Version: version.Info{Major:"1", Minor:"23", GitVersion:"v1.23.4", GitCommit:"e6c093d87ea4cbb530a7b2ae91e54c0842d8308a", GitTreeState:"clean", BuildDate:"2022-02-16T12:32:02Z", GoVersion:"go1.17.7", Compiler:"gc", Platform:"linux/amd64"}
helm服务
#当前环境版本 version.BuildInfo{Version:"v3.8.1", GitCommit:"5cb9af4b1b271d11d7a97a71df3ac337dd94ad37", GitTreeState:"clean", GoVersion:"go1.17.5"}
Minecraft helm chart包
在Artifact hub下载并解压对应的Minecraft chart包到当前目录 (chart version 4.3.0)
2.配置基础Values文件
先把服务端跑起来,体验一把
由于values文件内容较多,我们只需要修改如下地方就可以把服务端跑起来.
修改如下地方,在values文件中搜索即可找到:
服务端版本类型以及服务端属性文件的地方
minecraftServer:
#同意EULA,搭建过mc服务器的童鞋应该都知道这个地方 This must be overridden, since we can't accept this for the user.
eula: "TRUE"
# 服务端的版本,例如填入版本1.12.2或者1.16.5... One of: LATEST, SNAPSHOT, or a specific version (ie: "1.7.9").
version: "1.12.2"
# 服务端类型,默认是原版VANILLA,也就是官方服务端 This can be one of "VANILLA", "FORGE", "SPIGOT", "BUKKIT", "PAPER", "FTBA", "SPONGEVANILLA", "CURSEFORGE"
type: "VANILLA"
# 服务端内存限制 If you adjust this, you may need to adjust resources.requests above to match.
memory: 1024M
# 如果需要离线登录,请关闭online mode Check accounts against Minecraft account service.
onlineMode: false
这个地方是选择k8s集群的存储驱动,我这里使用的是nfs的动态provisioner,大家可以自寻选择自己合适的CSI插件作为自己的Minecraft后端存储
注意层级关系,value中有两处persistence的配置地方,选择最外层的persistence进行配置
persistence:
annotations: {}
## minecraft data Persistent Volume Storage Class
## If defined, storageClassName: <storageClass>
## If set to "-", storageClassName: "", which disables dynamic provisioning
## If undefined (the default) or set to null, no storageClassName spec is
## set, choosing the default provisioner. (gp2 on AWS, standard on
## GKE, AWS & OpenStack)
##
storageClass: "填入你的storage class的名称"
dataDir:
# Set this to false if you don't care to persist state between restarts.
enabled: true
Size: 1Gi
# existingClaim: nil
## specify a subpath in the volume where the data is. Useful when sharing volumes with other apps.
# subPath: /path/to/dataDir
设置你服务端需要k8s集群为你分配多少CPU和Memory,个人建议加上limit限制,否则有可能服务端request的资源过大,影响集群内其他服务
注意如果加了limits限制,必须要和前面你的定义的memory的值一样
## Configure resource requests and limits
## ref: http://kubernetes.io/docs/user-guide/compute-resources/
##
resources:
requests:
memory: 512Mi
cpu: 500m
#limits:
#cpu: 500m
#memory: 1024Mi
存活探针设置,个人建议将 initialDelaySeconds 的时间设置长一些,个人是改为300+秒,留给服务端足够启动时间.
livenessProbe:
initialDelaySeconds: 300
periodSeconds: 5
failureThreshold: 20
successThreshold: 1
timeoutSeconds: 1
完整Values文件:
# ref: https://hub.docker.com/r/itzg/minecraft-server/
image:
repository: itzg/minecraft-server
tag: latest
pullPolicy: IfNotPresent
pullSecret: ""
# ### WARNING ###
# Minecraft is not horizontally scalable, adjusting this will most likely break your setup.
# ### WARNING ###
replicaCount: 1
## Configure resource requests and limits
## ref: http://kubernetes.io/docs/user-guide/compute-resources/
##
resources:
requests:
memory: 512Mi
cpu: 500m
# upgrade strategy type (e.g. Recreate or RollingUpdate)
strategyType: Recreate
nodeSelector: {}
tolerations: []
affinity: {}
securityContext:
# Security context settings
runAsUser: 1000
fsGroup: 2000
# Most of these map to environment variables. See Minecraft for details:
# https://hub.docker.com/r/itzg/minecraft-server/
livenessProbe:
initialDelaySeconds: 30
periodSeconds: 5
failureThreshold: 20
successThreshold: 1
timeoutSeconds: 1
readinessProbe:
initialDelaySeconds: 30
periodSeconds: 5
failureThreshold: 20
successThreshold: 1
timeoutSeconds: 1
startupProbe:
enabled: false
failureThreshold: 30
periodSeconds: 10
# initContainers:
# - name: do-something
# image: busybox
# command: ['do', 'something']
# volumesMounts:
# - name: nfs
# mountPath: /mnt/volume
# readOnly: true
initContainers: []
# sidecarContainers:
# - name: do-something
# image: busybox
# command: ['do', 'something']
# volumesMounts:
# - name: nfs
# mountPath: /mnt/volume
# readOnly: true
sidecarContainers: []
# extraVolumes:
# - volumeMounts:
# - name: nfs
# mountPath: /mnt/volume
# readOnly: true
# volumes:
# - name: nfs
# server: some.nfs.server.com
# path: /
# mountOptions:
# - port=2049
# - hard
# - vers=4
extraVolumes: []
minecraftServer:
# This must be overridden, since we can't accept this for the user.
eula: "FALSE"
# One of: LATEST, SNAPSHOT, or a specific version (ie: "1.7.9").
version: "LATEST"
# This can be one of "VANILLA", "FORGE", "SPIGOT", "BUKKIT", "PAPER", "FTBA", "SPONGEVANILLA", "CURSEFORGE"
type: "VANILLA"
# If type is set to FORGE, this sets the version; this is ignored if forgeInstallerUrl is set
forgeVersion:
# If type is set to SPONGEVANILLA, this sets the version
spongeVersion:
# If type is set to FORGE, this sets the URL to download the Forge installer
forgeInstallerUrl:
# If type is set to BUKKIT, this sets the URL to download the Bukkit package
bukkitDownloadUrl:
# If type is set to SPIGOT, this sets the URL to download the Spigot package
spigotDownloadUrl:
# If type is set to PAPER, this sets the URL to download the PaperSpigot package
paperDownloadUrl:
# If type is set to FTBA, this sets the modpack to run
ftbModpackId:
# If type is set to FTBA and a modpack is set, this sets the version to run
ftbModpackVersionId:
# If type is set to CURSEFORGE, this sets the server mod to run. Can also provide url to curseforge package.
cfServerMod:
# Set to true if running Feed The Beast and get an error like "unable to launch forgemodloader"
ftbLegacyJavaFixer: false
# One of: peaceful, easy, normal, and hard
difficulty: easy
# A comma-separated list of player names to whitelist.
whitelist:
# A comma-separated list of player names who should be admins.
ops:
# A server icon URL for server listings. Auto-scaled and transcoded.
icon:
# Max connected players.
maxPlayers: 20
# This sets the maximum possible size in blocks, expressed as a radius, that the world border can obtain.
maxWorldSize: 10000
# Allows players to travel to the Nether.
allowNether: true
# Allows server to announce when a player gets an achievement.
announcePlayerAchievements: true
# Enables command blocks.
enableCommandBlock: true
# If true, players will always join in the default gameMode even if they were previously set to something else.
forcegameMode: false
# Defines whether structures (such as villages) will be generated.
generateStructures: true
# If set to true, players will be set to spectator mode if they die.
hardcore: false
# The maximum height in which building is allowed.
maxBuildHeight: 256
# The maximum number of milliseconds a single tick may take before the server watchdog stops the server with the message. -1 disables this entirely.
maxTickTime: 60000
# Determines if animals will be able to spawn.
spawnAnimals: true
# Determines if monsters will be spawned.
spawnMonsters: true
# Determines if villagers will be spawned.
spawnNPCs: true
# Sets the area that non-ops can not edit (0 to disable)
spawnProtection: 16
# Max view distance (in chunks).
viewDistance: 10
# Define this if you want a specific map generation seed.
levelSeed:
# One of: creative, survival, adventure, spectator
gameMode: survival
# Message of the Day
motd: "Welcome to Minecraft on Kubernetes!"
# If true, enable player-vs-player damage.
pvp: false
# One of: DEFAULT, FLAT, LARGEBIOMES, AMPLIFIED, CUSTOMIZED
levelType: DEFAULT
# When levelType == FLAT or CUSTOMIZED, this can be used to further customize map generation.
# ref: https://hub.docker.com/r/itzg/minecraft-server/
generatorSettings:
worldSaveName: world
# If set, this URL will be downloaded at startup and used as a starting point
downloadWorldUrl:
# force re-download of server file
forceReDownload: false
# If set, the modpack at this URL will be downloaded at startup
downloadModpackUrl:
# If true, old versions of downloaded mods will be replaced with new ones from downloadModpackUrl
removeOldMods: false
# A list of VanillaTweaks Share Codes to download. (https://vanillatweaks.net/share#wUq1iz => "wUq1iz")
vanillaTweaksShareCodes: []
# Optional URI to a resource pack. The player may choose to use it.
resourcePackUrl:
# Optional SHA-1 digest of the resource pack, in lowercase hexadecimal.
# It is recommended to specify this, because it is used to verify the integrity of the resource pack.
resourcePackSha:
# When true, players will be prompted for a response and will be disconnected if they decline the required pack
resourcePackEnforce: false
# Check accounts against Minecraft account service.
onlineMode: true
# If you adjust this, you may need to adjust resources.requests above to match.
memory: 1024M
# General JVM options to be passed to the Minecraft server invocation
jvmOpts: ""
# Options like -X that need to proceed general JVM options
jvmXXOpts: ""
# By default, the server configuration will be created and set based on the following environment variables, but only the first time the server is started
# If you would like to override the server configuration each time the container starts up, you can set this to true
# see https://github.com/itzg/docker-minecraft-server#server-configuration
overrideServerProperties: false
# DEPRECATED: use top-level rconServiceAnnotations instead
serviceAnnotations: {}
serviceType: ClusterIP
## Set the port used if the serviceType is NodePort
nodePort:
# Set the external port of the service, usefull when using the LoadBalancer service type
servicePort: 25565
clusterIP:
loadBalancerIP:
# loadBalancerSourceRanges: []
## Set the externalTrafficPolicy in the Service to either Cluster or Local
# externalTrafficPolicy: Cluster
externalIPs:
# A list of Spigot resources/plugins IDs to download.
spigetResources: []
rcon:
# If you enable this, make SURE to change your password below.
enabled: false
port: 25575
password: "CHANGEME!"
existingSecret:
secretKey: rcon-password
serviceType: ClusterIP
## Set the external port if the rcon serviceType is NodePort
nodePort:
clusterIP:
loadBalancerIP:
# loadBalancerSourceRanges: []
## Set the externalTrafficPolicy in the Service to either Cluster or Local
# externalTrafficPolicy: Cluster
extraPorts:
[]
# These options allow you to expose another port from the Minecraft server, plugins such
# as dynmap (8123) and bluemap (8100) will require this for access to their web interfaces
#
# - name: map
# containerPort: 8123
# protocol: TCP
# service:
# enabled: false
# embedded: false
# annotations: {}
# type: ClusterIP
# ## Set the external port if the rcon serviceType is NodePort
## nodePort:
# loadBalancerIP: ""
# loadBalancerSourceRanges: []
# externalTrafficPolicy: Cluster
# port: 8123
# ingress:
# ingressClassName: nginx
# enabled: false
# annotations:
## Deprecated way for specifying the ingressClass. Kube.version < 1.18
## kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: "true"
# hosts:
# - name: map.local
# path: /
# tls:
# - secretName: map-tls
# hosts:
# - map.local
query:
# If you enable this, your server will be "published" to Gamespy
enabled: false
port: 25565
## Additional minecraft container environment variables
## Values can be either variable values or `valueFrom` yaml
##
extraEnv:
{}
# some_variable: some value
# another_variable:
# valueFrom:
# fieldRef:
# fieldPath: status.hostIP
## Additional environment variables to add to the minecraft container from
## ConfigMaps and Secrets
##
envFrom: []
persistence:
annotations: {}
## minecraft data Persistent Volume Storage Class
## If defined, storageClassName: <storageClass>
## If set to "-", storageClassName: "", which disables dynamic provisioning
## If undefined (the default) or set to null, no storageClassName spec is
## set, choosing the default provisioner. (gp2 on AWS, standard on
## GKE, AWS & OpenStack)
##
# storageClass: "-"
dataDir:
# Set this to false if you don't care to persist state between restarts.
enabled: false
Size: 1Gi
# existingClaim: nil
## specify a subpath in the volume where the data is. Useful when sharing volumes with other apps.
# subPath: /path/to/dataDir
podAnnotations: {}
deploymentAnnotations: {}
serviceAnnotations: {}
rconServiceAnnotations: {}
# PLEASE NOTE! rcon must be enabled above! It does NOT require a nodePort or loadBalancerIP
mcbackup:
enabled: false
image:
repository: itzg/mc-backup
tag: latest
pullPolicy: IfNotPresent
# wait 2 minutes before starting
initialDelay: 2m
# ***set to 0 or smaller, script will run once and exit. DO NOT SET TO 0 or smaller, this will cause K8s to kill your pod!***
# backupInterval="1.5d" -> backup every one and a half days (36 hours)
# backupInterval="2h 30m" -> backup every two and a half hours
backupInterval: 24h
# option lets you pause backups if no players are online.
pauseIfNoPlayers: "false"
# is set to a positive number, it'll delete old .tgz backup files from DEST_DIR. By default deletes backups older than a week.
pruneBackupsDays: 7
# Set to a negative value to retry indefinitely
rconRetries: 5
rconRetryInterval: 10s
# is a comma-separated list of glob(3) patterns to exclude from backups. By default excludes all jar files (plugins, server files),
# logs folder and cache (used by i.e. PaperMC server).
excludes: "*.jar,cache,logs"
# backup methods, see https://github.com/itzg/docker-mc-backup e.g. tar, rclone, restic
backupMethod: tar
# tar and rclone methods
destDir: /backups
# is a true/false flag that creates a symbolic link to the latest backup
linkLatest: "false"
# is the compression method used by tar. Valid value: gzip bzip2 zstd
compressMethod: "gzip"
# sets the parameters for zstd compression. The --long parameter affects RAM requirements for both compression and decompression
# (the default of 25 means 2^25 bytes = 32 MB).
zstdParameters: "-3 --long=25 --single-thread"
# the name of the remote you've configured in your rclone.conf
rcloneRemote:
rcloneDestDir:
rcloneCompressMethod: gzip
# see https://rclone.org/ for details
# this value is evaluated as a template
rcloneConfig:
# [remote]
# type = google cloud storage
# client_id =
# client_secret =
# token = {"AccessToken":"super","RefreshToken":"secret","Expiry":"date","Extra":null}
# project_number = 12345678
# object_acl = private
# bucket_acl = private
# if you prefer to create a secret from file (e.g. kubectl create secret generic my-rclone-config --from-file=~/.config/rclone/rclone.conf)
# rcloneConfigExistingSecret: my-rclone-config
resticRepository:
# variable to define a space separated list of additional restic tags. see https://hub.docker.com/r/itzg/mc-backup
resticAdditionalTags: "mc_backups"
# see https://restic.readthedocs.io/en/latest/060_forget.html
pruneResticRetention: "--keep-daily 7 --keep-weekly 5 --keep-monthly 12 --keep-yearly 75"
# At least one of RESTIC_PASSWORD* env variables need to be defined, see https://restic.readthedocs.io/en/latest/030_preparing_a_new_repo.html
resticEnvs:
[]
# RESTIC_PASSWORD: restic-password
extraEnvs:
[]
# Can be set to the timezone to use for logging
# tz:
resources:
requests:
memory: 512Mi
cpu: 500m
persistence:
annotations: {}
## minecraft data Persistent Volume Storage Class
## If defined, storageClassName: <storageClass>
## If set to "-", storageClassName: "", which disables dynamic provisioning
## If undefined (the default) or set to null, no storageClassName spec is
## set, choosing the default provisioner. (gp2 on AWS, standard on
## GKE, AWS & OpenStack)
##
# storageClass: "-"
backupDir:
# Set this to false if you don't care to persist state between restarts.
enabled: false
# existingClaim: nil
Size: 1Gi
3.开始部署
3.1 使用helm部署改好的value文件:
helm install -n <namespace> minecraft-test -f minecraft-values.yaml minecraft-4.3.0.tgz
预期输出结果:
NAME: minecraft-test
LAST DEPLOYED: Mon Sep 26 21:03:41 2022
NAMESPACE: lab
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
Get the IP address of your Minecraft server by running these commands in the
same shell:
export POD_NAME=$(kubectl get pods \
--namespace lab \
-l "component=minecraft-test-minecraft" \
-o jsonpath="{.items[0].metadata.name}")
kubectl port-forward $POD_NAME 25565:25565
echo "Point your Minecraft client at 127.0.0.1:25565"
[root@director minecraft]#
3.2 查看部署状态:
[root@director minecraft]# helm list -n lab
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
minecraft-test lab 1 2022-09-26 21:03:41.687369562 +0800 CST deployed minecraft-4.3.0 SeeValues
kubectl get pod -n <namespace>
NAME READY STATUS RESTARTS AGE
minecraft-test-minecraft-7cb4f8df9b-jnvwb 2/2 Running 0 10m
[root@director minecraft]#
[root@director minecraft]# k logs -n <namespace> -f minecraft-test-minecraft-67579d447-xcssb minecraft-test-minecraft
chmod: changing permissions of '/data': Operation not permitted
[init] Running as uid=1000 gid=1000 with /data as 'drwxrwxrwx 5 0 0 4096 Sep 26 13:31 /data'
[init] Resolved version given 1.12.2 into 1.12.2 and major version 1.12
[init] Resolving type given VANILLA
[init] server.properties already created, skipping
[init] Checking for JSON files.
[init] Setting initial memory to 1024M and max to 1024M
[init] Starting the Minecraft server...
2022-09-26 13:31:54,476 main ERROR Error processing element Queue ([Appenders: null]): CLASS_NOT_FOUND
2022-09-26 13:31:54,674 main ERROR Unable to locate appender "ServerGuiConsole" for logger config "root"
[13:31:59] [Server thread/INFO]: Starting minecraft server version 1.12.2
[13:31:59] [Server thread/INFO]: Loading properties
[13:31:59] [Server thread/INFO]: Default game type: SURVIVAL
[13:31:59] [Server thread/INFO]: Generating keypair
[13:32:00] [Server thread/INFO]: Starting Minecraft server on *:25565
[13:32:01] [Server thread/INFO]: Using epoll channel type
[13:32:01] [Server thread/INFO]: Preparing level "world"
[13:32:02] [Server thread/INFO]: Loaded 488 advancements
[13:32:02] [Server thread/INFO]: Preparing start region for level 0
[13:32:04] [Server thread/INFO]: Preparing spawn area: 0%
[13:32:05] [Server thread/INFO]: Preparing spawn area: 12%
[13:32:06] [Server thread/INFO]: Preparing spawn area: 32%
[13:32:07] [Server thread/INFO]: Preparing spawn area: 61%
[13:32:08] [Server thread/INFO]: Preparing spawn area: 96%
[13:32:09] [Server thread/INFO]: Done (7.591s)! For help, type "help" or "?"
[13:32:09] [Server thread/INFO]: Starting remote control listener
[13:32:09] [RCON Listener #1/INFO]: RCON running on 0.0.0.0:25575
[13:32:11] [RCON Listener #1/INFO]: Rcon connection from: /127.0.0.1
4.暴露服务给外部客户端
4.1 port-forward快速访问
使用kubectl port-forward将 minecraft的api server监听在使用这条命令的主机的25565端口将流量送到pod的25565端口kubectl -n lab port-forward minecraft-test-minecraft-7cb4f8df9b-jnvwb --address 0.0.0.0 25565:25565
[root@director minecraft]# kubectl -n lab port-forward minecraft-test-minecraft-67579d447-xcssb --address 0.0.0.0 25565:25565
Forwarding from 0.0.0.0:25565 -> 25565
打开Minecraft客户端,输入当前主机Ip,即可访问 PS:如果不是默认25565端口号,请在Ip后面跟上你自己指定的端口号,即
这时候,我们会发现服务器成功被发现,接下来就双击进入服务器吧!
成功以survivor模式登入服务器,happy gaming:):
4.2 补充说明:
- 获取服务器op权限
kubectl exec -it minecraft-test-minecraft-546d85dbff-mgtdj -n lab -- rcon-cli
[root@director minecraft]# k exec -it minecraft-test-minecraft-5667f8bffd-j9p8g -n lab -- rcon-cli
Defaulted container "minecraft-test-minecraft-mc-backup" out of: minecraft-test-minecraft-mc-backup, minecraft-test-minecraft
> help
--- Showing help page 1 of 10 (/help <page>) ---/advancement <grant|revoke|test> <player>/ban <name> [reason ...]/ban-ip <address|name> [reason ...]/banlist [ips|players]/blockdata <x> <y> <z> <dataTag>/clear [player] [item] [data] [maxCount] [dataTag]/clone <x1> <y1> <z1> <x2> <y2> <z2> <x> <y> <z> [maskMode] [cloneMode]Tip: Use the <tab> key while typing a command to auto-complete the command or its arguments
> list
There are 1/20 players online:wllo
> op wllo
Opped wllo
>
上帝模式,起飞!
- 关闭online mode
如果是离线模式的话,记得把on-line mode设置为false,否则就会如下图登录失败:
可以使用helm upgrade将更新好的values进行进行in-service重新部署
helm upgrade -n lab --atomic minecraft-test -f minecraft-values.yaml minecraft-4.3.0.tgz
[root@director minecraft]# helm upgrade -n lab --atomic minecraft-test -f minecraft-values.yaml minecraft-4.3.0.tgz
Release "minecraft-test" has been upgraded. Happy Helming!
NAME: minecraft-test
LAST DEPLOYED: Mon Sep 26 22:30:05 2022
NAMESPACE: lab
STATUS: deployed
REVISION: 2
TEST SUITE: None
NOTES:
Get the IP address of your Minecraft server by running these commands in the
same shell:
export POD_NAME=$(kubectl get pods \
--namespace lab \
-l "component=minecraft-test-minecraft" \
-o jsonpath="{.items[0].metadata.name}")
kubectl port-forward $POD_NAME 25565:25565
echo "Point your Minecraft client at 127.0.0.1:25565"
[root@director minecraft]# k get pod -n lab
NAME READY STATUS RESTARTS AGE
minecraft-test-minecraft-5667f8bffd-4qq5n 2/2 Running 0 3m36s
[root@director minecraft]#
4.2 通过service服务的Node port方式访问
宿主机+高端口号进行访问,不再赘述
5.结语
上述部署方式只是一个快速的Minecraft部署的Demo演示,具体详细进阶,大家可以参考value文件进行深入部署研究,欢迎交流分享经验!
这份chart包还有很多功能值得探索,比如,部署forge,spigot,paperspigot等服务端需要设置的参数,还有全栈大佬(作者)提供的mc-backup自动备份的功能(默认关闭)。
也可以使用作者开发的其他项目进行搭配使用,比如docker版的bungeecord,mc-router,mc-monitor,以及k8s的helm chart版的minecraft-bedrock,rcon-web-admin