diff --git a/.vagrant/machines/default/virtualbox/action_set_name b/.vagrant/machines/default/virtualbox/action_set_name index 15b8df30fc..d20e1353ef 100644 --- a/.vagrant/machines/default/virtualbox/action_set_name +++ b/.vagrant/machines/default/virtualbox/action_set_name @@ -1 +1 @@ -1775761002 \ No newline at end of file +1778158287 \ No newline at end of file diff --git a/.vagrant/machines/default/virtualbox/id b/.vagrant/machines/default/virtualbox/id index eed431def4..8304196f84 100644 --- a/.vagrant/machines/default/virtualbox/id +++ b/.vagrant/machines/default/virtualbox/id @@ -1 +1 @@ -71b90015-a795-4129-b975-f4d5a0796f1e \ No newline at end of file +78bdca32-96b1-4c68-a8e2-722642a70cdd \ No newline at end of file diff --git a/.vagrant/machines/default/virtualbox/index_uuid b/.vagrant/machines/default/virtualbox/index_uuid index 68fbc553bd..94cf10c36e 100644 --- a/.vagrant/machines/default/virtualbox/index_uuid +++ b/.vagrant/machines/default/virtualbox/index_uuid @@ -1 +1 @@ -412210d4f6ce475a9f760bed593913cd \ No newline at end of file +515b21fc17394b05b2c07f3a03b39268 \ No newline at end of file diff --git a/Vagrantfile b/Vagrantfile index 42c7b75ef7..0f6f99ed18 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -1,6 +1,6 @@ Vagrant.configure("2") do |config| config.vm.box = "ubuntu/jammy64" - config.vm.hostname = "lab11" + config.vm.hostname = "lab15-statefulset" # Disable project folder sharing inside the VM. # This avoids common Windows path issues (spaces, Cyrillic characters) @@ -21,7 +21,7 @@ Vagrant.configure("2") do |config| config.ssh.insert_key = true config.vm.provider "virtualbox" do |vb| - vb.name = "lab11" + vb.name = "lab15-statefulset" vb.memory = 6144 vb.cpus = 2 end diff --git a/a.txt b/a.txt new file mode 100644 index 0000000000..72ba179ea4 --- /dev/null +++ b/a.txt @@ -0,0 +1,181 @@ +1000 +/tp Dorley 1000 300 1000 +/tp Dorley 1000 300 1000 +/tp Dorley 1000 300 1000 +/tp Dorley 1000 300 1000 +/tp Dorley 1000 300 1000 +[02:07:42] [Server thread/INFO] [fastsuite/]: Constructed recipe list for minecraft:smithing in 80.13 μs. 174/224 recipes are parallelized. +[02:07:42] [Server thread/INFO] [minecraft/MinecraftServer]: Teleported Dorley to 1000.500000, 300.000000, 1000.500000 +[02:07:42] [Server thread/INFO] [minecraft/MinecraftServer]: Teleported Dorley to 1000.500000, 300.000000, 1000.500000 +[02:07:42] [Server thread/INFO] [minecraft/MinecraftServer]: Teleported Dorley to 1000.500000, 300.000000, 1000.500000 +[02:07:42] [Server thread/INFO] [minecraft/MinecraftServer]: Teleported Dorley to 1000.500000, 300.000000, 1000.500000 +[02:07:42] [Server thread/INFO] [minecraft/MinecraftServer]: Teleported Dorley to 1000.500000, 300.000000, 1000.500000 +[02:07:42] [Server thread/INFO] [minecraft/MinecraftServer]: Teleported Dorley to 1000.500000, 300.000000, 1000.500000 +[02:07:42] [Server thread/INFO] [minecraft/MinecraftServer]: Teleported Dorley to 1000.500000, 300.000000, 1000.500000 +[02:07:42] [Server thread/INFO] [minecraft/MinecraftServer]: Teleported Dorley to 1000.500000, 300.000000, 1000.500000 +[02:07:42] [Server thread/INFO] [minecraft/MinecraftServer]: Teleported Dorley to 1000.500000, 300.000000, 1000.500000 +[02:07:42] [Server thread/INFO] [minecraft/MinecraftServer]: Teleported Dorley to 1000.500000, 300.000000, 1000.500000 +[02:07:42] [Server thread/INFO] [minecraft/MinecraftServer]: Teleported Dorley to 1000.500000, 300.000000, 1000.500000 +[02:07:42] [Server thread/INFO] [minecraft/MinecraftServer]: Teleported Dorley to 1000.500000, 300.000000, 1000.500000 +/tp Dorley 1000 300 1000 +[02:07:42] [Server thread/INFO] [pingwheel/]: Channel update: Dorley -> default +[02:07:42] [Server thread/INFO] [co.al.pa.ParCool/]: Limitation of 5e117944-90b0-3107-8e22-76dfcc7b8c63 was loaded +[02:07:42] [Server thread/WARN] [minecraft/MinecraftServer]: Can't keep up! Is the server overloaded? Running 2320ms or 46 ticks behind +[02:07:43] [Server thread/INFO] [minecraft/MinecraftServer]: Teleported Dorley to 1000.500000, 300.000000, 1000.500000 +/tp Dorley 1000 300 1000 +[02:07:43] [Server thread/INFO] [minecraft/MinecraftServer]: Teleported Dorley to 1000.500000, 300.000000, 1000.500000 +/tp Dorley 1000 300 1000 +/tp Dorley 1000 300 1000 +[02:07:43] [Server thread/INFO] [minecraft/MinecraftServer]: Teleported Dorley to 1000.500000, 300.000000, 1000.500000 +[02:07:43] [Server thread/INFO] [minecraft/MinecraftServer]: Teleported Dorley to 1000.500000, 300.000000, 1000.500000 +[02:07:44] [Server thread/ERROR] [minecraft/MinecraftServer]: Encountered an unexpected exception +net.minecraft.ReportedException: Ticking block entity + at TRANSFORMER/minecraft@1.21.1/net.minecraft.server.MinecraftServer.tickChildren(MinecraftServer.java:1041) ~[server-1.21.1-20240808.144430-srg.jar%23475!/:?] {re:mixin,pl:accesstransformer:B,pl:connector_pre_launch:A,re:classloading,pl:accesstransformer:B,pl:mixin:APP:modernfix-modernfix.mixins.json:perf.fix_loop_spin_waiting.MinecraftServerMixin from mod modernfix,pl:mixin:APP:openpartiesandclaims.mixins.json:MixinMinecraftServer from mod openpartiesandclaims,pl:mixin:APP:modernfix-modernfix.mixins.json:core.MinecraftServerMixin from mod modernfix,pl:mixin:APP:modernfix-modernfix.mixins.json:perf.dedicated_reload_executor.MinecraftServerMixin from mod modernfix,pl:mixin:APP:veil.scheduler.mixins.json:MinecraftServerMixin from mod veil,pl:mixin:APP:rechiseled.mixins.json:MinecraftServerMixin from mod rechiseled,pl:mixin:APP:lootr-common.mixins.json:accessor.AccessorMixinMinecraftServer from mod lootr,pl:mixin:APP:fabric-message-api-v1.mixins.json:MinecraftServerMixin from mod fabric_message_api_v1,pl:mixin:APP:structureessentials.mixins.json:LevelCreatedCallback from mod structureessentials,pl:mixin:APP:fabric-resource-loader-v0.mixins.json:MinecraftServerMixin from mod fabric_resource_loader_v0,pl:mixin:APP:ponder-common.mixins.json:accessor.MinecraftServerAccessor from mod ponder,pl:mixin:APP:balm.neoforge.mixins.json:MinecraftServerMixin from mod balm,pl:mixin:APP:xaerohud.mixins.json:MixinMinecraftServer from mod xaerominimap,pl:mixin:APP:aether.mixins.json:common.accessor.MinecraftServerAccessor from mod aether,pl:mixin:APP:xaeroworldmap.mixins.json:MixinMinecraftServer from mod xaeroworldmap,pl:mixin:APP:fabric-lifecycle-events-v1.mixins.json:MinecraftServerMixin from mod fabric_lifecycle_events_v1,pl:mixin:APP:kubejs.mixins.json:MinecraftServerMixin from mod kubejs,pl:mixin:APP:sable.mixins.json:udp.MinecraftServerMixin from mod sable,pl:mixin:APP:moonlight.mixins.json:MinecraftServerMixin from mod moonlight,pl:mixin:APP:c2me-fixes-general-threading-issues.mixins.json:asynccatchers.MixinMinecraftServer from mod c2me_fixes_general_threading_issues,pl:mixin:APP:c2me-opts-scheduling.mixins.json:idle_tasks.autosave.enhanced_autosave.MixinMinecraftServer from mod c2me_opts_scheduling,pl:mixin:APP:c2me-opts-scheduling.mixins.json:mid_tick_chunk_tasks.MixinMinecraftServer from mod c2me_opts_scheduling,pl:mixin:APP:c2me-opts-scheduling.mixins.json:shutdown.MixinMinecraftServer from mod c2me_opts_scheduling,pl:mixin:APP:c2me-rewrites-chunk-system.mixins.json:MixinMinecraftServer from mod c2me_rewrites_chunk_system,pl:mixin:APP:c2me-notickvd.mixins.json:MixinMinecraftServer from mod c2me_notickvd,pl:mixin:A,pl:connector_pre_launch:A} + at TRANSFORMER/minecraft@1.21.1/net.minecraft.server.dedicated.DedicatedServer.tickChildren(DedicatedServer.java:317) ~[server-1.21.1-20240808.144430-srg.jar%23475!/:?] {re:mixin,pl:connector_pre_launch:A,re:classloading,pl:mixin:A,pl:connector_pre_launch:A} + at TRANSFORMER/minecraft@1.21.1/net.minecraft.server.MinecraftServer.tickServer(MinecraftServer.java:917) ~[server-1.21.1-20240808.144430-srg.jar%23475!/:?] {re:mixin,pl:accesstransformer:B,pl:connector_pre_launch:A,re:classloading,pl:accesstransformer:B,pl:mixin:APP:modernfix-modernfix.mixins.json:perf.fix_loop_spin_waiting.MinecraftServerMixin from mod modernfix,pl:mixin:APP:openpartiesandclaims.mixins.json:MixinMinecraftServer from mod openpartiesandclaims,pl:mixin:APP:modernfix-modernfix.mixins.json:core.MinecraftServerMixin from mod modernfix,pl:mixin:APP:modernfix-modernfix.mixins.json:perf.dedicated_reload_executor.MinecraftServerMixin from mod modernfix,pl:mixin:APP:veil.scheduler.mixins.json:MinecraftServerMixin from mod veil,pl:mixin:APP:rechiseled.mixins.json:MinecraftServerMixin from mod rechiseled,pl:mixin:APP:lootr-common.mixins.json:accessor.AccessorMixinMinecraftServer from mod lootr,pl:mixin:APP:fabric-message-api-v1.mixins.json:MinecraftServerMixin from mod fabric_message_api_v1,pl:mixin:APP:structureessentials.mixins.json:LevelCreatedCallback from mod structureessentials,pl:mixin:APP:fabric-resource-loader-v0.mixins.json:MinecraftServerMixin from mod fabric_resource_loader_v0,pl:mixin:APP:ponder-common.mixins.json:accessor.MinecraftServerAccessor from mod ponder,pl:mixin:APP:balm.neoforge.mixins.json:MinecraftServerMixin from mod balm,pl:mixin:APP:xaerohud.mixins.json:MixinMinecraftServer from mod xaerominimap,pl:mixin:APP:aether.mixins.json:common.accessor.MinecraftServerAccessor from mod aether,pl:mixin:APP:xaeroworldmap.mixins.json:MixinMinecraftServer from mod xaeroworldmap,pl:mixin:APP:fabric-lifecycle-events-v1.mixins.json:MinecraftServerMixin from mod fabric_lifecycle_events_v1,pl:mixin:APP:kubejs.mixins.json:MinecraftServerMixin from mod kubejs,pl:mixin:APP:sable.mixins.json:udp.MinecraftServerMixin from mod sable,pl:mixin:APP:moonlight.mixins.json:MinecraftServerMixin from mod moonlight,pl:mixin:APP:c2me-fixes-general-threading-issues.mixins.json:asynccatchers.MixinMinecraftServer from mod c2me_fixes_general_threading_issues,pl:mixin:APP:c2me-opts-scheduling.mixins.json:idle_tasks.autosave.enhanced_autosave.MixinMinecraftServer from mod c2me_opts_scheduling,pl:mixin:APP:c2me-opts-scheduling.mixins.json:mid_tick_chunk_tasks.MixinMinecraftServer from mod c2me_opts_scheduling,pl:mixin:APP:c2me-opts-scheduling.mixins.json:shutdown.MixinMinecraftServer from mod c2me_opts_scheduling,pl:mixin:APP:c2me-rewrites-chunk-system.mixins.json:MixinMinecraftServer from mod c2me_rewrites_chunk_system,pl:mixin:APP:c2me-notickvd.mixins.json:MixinMinecraftServer from mod c2me_notickvd,pl:mixin:A,pl:connector_pre_launch:A} + at TRANSFORMER/minecraft@1.21.1/net.minecraft.server.MinecraftServer.runServer(MinecraftServer.java:707) ~[server-1.21.1-20240808.144430-srg.jar%23475!/:?] {re:mixin,pl:accesstransformer:B,pl:connector_pre_launch:A,re:classloading,pl:accesstransformer:B,pl:mixin:APP:modernfix-modernfix.mixins.json:perf.fix_loop_spin_waiting.MinecraftServerMixin from mod modernfix,pl:mixin:APP:openpartiesandclaims.mixins.json:MixinMinecraftServer from mod openpartiesandclaims,pl:mixin:APP:modernfix-modernfix.mixins.json:core.MinecraftServerMixin from mod modernfix,pl:mixin:APP:modernfix-modernfix.mixins.json:perf.dedicated_reload_executor.MinecraftServerMixin from mod modernfix,pl:mixin:APP:veil.scheduler.mixins.json:MinecraftServerMixin from mod veil,pl:mixin:APP:rechiseled.mixins.json:MinecraftServerMixin from mod rechiseled,pl:mixin:APP:lootr-common.mixins.json:accessor.AccessorMixinMinecraftServer from mod lootr,pl:mixin:APP:fabric-message-api-v1.mixins.json:MinecraftServerMixin from mod fabric_message_api_v1,pl:mixin:APP:structureessentials.mixins.json:LevelCreatedCallback from mod structureessentials,pl:mixin:APP:fabric-resource-loader-v0.mixins.json:MinecraftServerMixin from mod fabric_resource_loader_v0,pl:mixin:APP:ponder-common.mixins.json:accessor.MinecraftServerAccessor from mod ponder,pl:mixin:APP:balm.neoforge.mixins.json:MinecraftServerMixin from mod balm,pl:mixin:APP:xaerohud.mixins.json:MixinMinecraftServer from mod xaerominimap,pl:mixin:APP:aether.mixins.json:common.accessor.MinecraftServerAccessor from mod aether,pl:mixin:APP:xaeroworldmap.mixins.json:MixinMinecraftServer from mod xaeroworldmap,pl:mixin:APP:fabric-lifecycle-events-v1.mixins.json:MinecraftServerMixin from mod fabric_lifecycle_events_v1,pl:mixin:APP:kubejs.mixins.json:MinecraftServerMixin from mod kubejs,pl:mixin:APP:sable.mixins.json:udp.MinecraftServerMixin from mod sable,pl:mixin:APP:moonlight.mixins.json:MinecraftServerMixin from mod moonlight,pl:mixin:APP:c2me-fixes-general-threading-issues.mixins.json:asynccatchers.MixinMinecraftServer from mod c2me_fixes_general_threading_issues,pl:mixin:APP:c2me-opts-scheduling.mixins.json:idle_tasks.autosave.enhanced_autosave.MixinMinecraftServer from mod c2me_opts_scheduling,pl:mixin:APP:c2me-opts-scheduling.mixins.json:mid_tick_chunk_tasks.MixinMinecraftServer from mod c2me_opts_scheduling,pl:mixin:APP:c2me-opts-scheduling.mixins.json:shutdown.MixinMinecraftServer from mod c2me_opts_scheduling,pl:mixin:APP:c2me-rewrites-chunk-system.mixins.json:MixinMinecraftServer from mod c2me_rewrites_chunk_system,pl:mixin:APP:c2me-notickvd.mixins.json:MixinMinecraftServer from mod c2me_notickvd,pl:mixin:A,pl:connector_pre_launch:A} + at TRANSFORMER/minecraft@1.21.1/net.minecraft.server.MinecraftServer.lambda$spin$2(MinecraftServer.java:267) ~[server-1.21.1-20240808.144430-srg.jar%23475!/:?] {re:mixin,pl:accesstransformer:B,pl:connector_pre_launch:A,re:classloading,pl:accesstransformer:B,pl:mixin:APP:modernfix-modernfix.mixins.json:perf.fix_loop_spin_waiting.MinecraftServerMixin from mod modernfix,pl:mixin:APP:openpartiesandclaims.mixins.json:MixinMinecraftServer from mod openpartiesandclaims,pl:mixin:APP:modernfix-modernfix.mixins.json:core.MinecraftServerMixin from mod modernfix,pl:mixin:APP:modernfix-modernfix.mixins.json:perf.dedicated_reload_executor.MinecraftServerMixin from mod modernfix,pl:mixin:APP:veil.scheduler.mixins.json:MinecraftServerMixin from mod veil,pl:mixin:APP:rechiseled.mixins.json:MinecraftServerMixin from mod rechiseled,pl:mixin:APP:lootr-common.mixins.json:accessor.AccessorMixinMinecraftServer from mod lootr,pl:mixin:APP:fabric-message-api-v1.mixins.json:MinecraftServerMixin from mod fabric_message_api_v1,pl:mixin:APP:structureessentials.mixins.json:LevelCreatedCallback from mod structureessentials,pl:mixin:APP:fabric-resource-loader-v0.mixins.json:MinecraftServerMixin from mod fabric_resource_loader_v0,pl:mixin:APP:ponder-common.mixins.json:accessor.MinecraftServerAccessor from mod ponder,pl:mixin:APP:balm.neoforge.mixins.json:MinecraftServerMixin from mod balm,pl:mixin:APP:xaerohud.mixins.json:MixinMinecraftServer from mod xaerominimap,pl:mixin:APP:aether.mixins.json:common.accessor.MinecraftServerAccessor from mod aether,pl:mixin:APP:xaeroworldmap.mixins.json:MixinMinecraftServer from mod xaeroworldmap,pl:mixin:APP:fabric-lifecycle-events-v1.mixins.json:MinecraftServerMixin from mod fabric_lifecycle_events_v1,pl:mixin:APP:kubejs.mixins.json:MinecraftServerMixin from mod kubejs,pl:mixin:APP:sable.mixins.json:udp.MinecraftServerMixin from mod sable,pl:mixin:APP:moonlight.mixins.json:MinecraftServerMixin from mod moonlight,pl:mixin:APP:c2me-fixes-general-threading-issues.mixins.json:asynccatchers.MixinMinecraftServer from mod c2me_fixes_general_threading_issues,pl:mixin:APP:c2me-opts-scheduling.mixins.json:idle_tasks.autosave.enhanced_autosave.MixinMinecraftServer from mod c2me_opts_scheduling,pl:mixin:APP:c2me-opts-scheduling.mixins.json:mid_tick_chunk_tasks.MixinMinecraftServer from mod c2me_opts_scheduling,pl:mixin:APP:c2me-opts-scheduling.mixins.json:shutdown.MixinMinecraftServer from mod c2me_opts_scheduling,pl:mixin:APP:c2me-rewrites-chunk-system.mixins.json:MixinMinecraftServer from mod c2me_rewrites_chunk_system,pl:mixin:APP:c2me-notickvd.mixins.json:MixinMinecraftServer from mod c2me_notickvd,pl:mixin:A,pl:connector_pre_launch:A} + at java.base/java.lang.Thread.run(Thread.java:1583) [?:?] {re:mixin} +Caused by: java.lang.UnsupportedOperationException + at java.base/java.util.ImmutableCollections.uoe(ImmutableCollections.java:142) ~[?:?] {} + at java.base/java.util.ImmutableCollections$AbstractImmutableCollection.clear(ImmutableCollections.java:149) ~[?:?] {} + at TRANSFORMER/create@6.0.10/com.simibubi.create.content.kinetics.RotationPropagator.handler$cak000$create_connected$forwardConnection(RotationPropagator.java:1055) ~[create-1.21.1-6.0.10.jar%23548!/:6.0.10] {re:mixin,re:classloading,pl:mixin:APP:create_connected.mixins.json:RotationPropagatorAccessor from mod create_connected,pl:mixin:APP:create_connected.mixins.json:RotationPropagatorMixin from mod create_connected,pl:mixin:APP:create_connected.mixins.json:chaincogwheel.RotationPropagatorMixin from mod create_connected,pl:mixin:APP:createbigcannons.mixins.json:compat.create.rotation_propagation.RotationPropagatorMixin from mod createbigcannons,pl:mixin:APP:offroad.mixins.json:RotationPropagatorMixin from mod offroad,pl:mixin:APP:simulated.mixins.json:extra_kinetics.RotationPropagatorMixin from mod simulated,pl:mixin:APP:createcasing.mixins.json:create.RotationPropagatorMixin from mod createcasing,pl:mixin:APP:simulated.mixins.json:flicker_tally_removal.RotationPropagatorMixin from mod simulated,pl:mixin:A} + at TRANSFORMER/create@6.0.10/com.simibubi.create.content.kinetics.RotationPropagator.getPotentialNeighbourLocations(RotationPropagator.java:439) ~[create-1.21.1-6.0.10.jar%23548!/:6.0.10] {re:mixin,re:classloading,pl:mixin:APP:create_connected.mixins.json:RotationPropagatorAccessor from mod create_connected,pl:mixin:APP:create_connected.mixins.json:RotationPropagatorMixin from mod create_connected,pl:mixin:APP:create_connected.mixins.json:chaincogwheel.RotationPropagatorMixin from mod create_connected,pl:mixin:APP:createbigcannons.mixins.json:compat.create.rotation_propagation.RotationPropagatorMixin from mod createbigcannons,pl:mixin:APP:offroad.mixins.json:RotationPropagatorMixin from mod offroad,pl:mixin:APP:simulated.mixins.json:extra_kinetics.RotationPropagatorMixin from mod simulated,pl:mixin:APP:createcasing.mixins.json:create.RotationPropagatorMixin from mod createcasing,pl:mixin:APP:simulated.mixins.json:flicker_tally_removal.RotationPropagatorMixin from mod simulated,pl:mixin:A} + at TRANSFORMER/create@6.0.10/com.simibubi.create.content.kinetics.RotationPropagator.getConnectedNeighbours(RotationPropagator.java:412) ~[create-1.21.1-6.0.10.jar%23548!/:6.0.10] {re:mixin,re:classloading,pl:mixin:APP:create_connected.mixins.json:RotationPropagatorAccessor from mod create_connected,pl:mixin:APP:create_connected.mixins.json:RotationPropagatorMixin from mod create_connected,pl:mixin:APP:create_connected.mixins.json:chaincogwheel.RotationPropagatorMixin from mod create_connected,pl:mixin:APP:createbigcannons.mixins.json:compat.create.rotation_propagation.RotationPropagatorMixin from mod createbigcannons,pl:mixin:APP:offroad.mixins.json:RotationPropagatorMixin from mod offroad,pl:mixin:APP:simulated.mixins.json:extra_kinetics.RotationPropagatorMixin from mod simulated,pl:mixin:APP:createcasing.mixins.json:create.RotationPropagatorMixin from mod createcasing,pl:mixin:APP:simulated.mixins.json:flicker_tally_removal.RotationPropagatorMixin from mod simulated,pl:mixin:A} + at TRANSFORMER/create@6.0.10/com.simibubi.create.content.kinetics.RotationPropagator.propagateNewSource(RotationPropagator.java:223) ~[create-1.21.1-6.0.10.jar%23548!/:6.0.10] {re:mixin,re:classloading,pl:mixin:APP:create_connected.mixins.json:RotationPropagatorAccessor from mod create_connected,pl:mixin:APP:create_connected.mixins.json:RotationPropagatorMixin from mod create_connected,pl:mixin:APP:create_connected.mixins.json:chaincogwheel.RotationPropagatorMixin from mod create_connected,pl:mixin:APP:createbigcannons.mixins.json:compat.create.rotation_propagation.RotationPropagatorMixin from mod createbigcannons,pl:mixin:APP:offroad.mixins.json:RotationPropagatorMixin from mod offroad,pl:mixin:APP:simulated.mixins.json:extra_kinetics.RotationPropagatorMixin from mod simulated,pl:mixin:APP:createcasing.mixins.json:create.RotationPropagatorMixin from mod createcasing,pl:mixin:APP:simulated.mixins.json:flicker_tally_removal.RotationPropagatorMixin from mod simulated,pl:mixin:A} + at TRANSFORMER/create@6.0.10/com.simibubi.create.content.kinetics.RotationPropagator.mixinextras$bridge$propagateNewSource$48(RotationPropagator.java) ~[create-1.21.1-6.0.10.jar%23548!/:6.0.10] {re:mixin,re:classloading,pl:mixin:APP:create_connected.mixins.json:RotationPropagatorAccessor from mod create_connected,pl:mixin:APP:create_connected.mixins.json:RotationPropagatorMixin from mod create_connected,pl:mixin:APP:create_connected.mixins.json:chaincogwheel.RotationPropagatorMixin from mod create_connected,pl:mixin:APP:createbigcannons.mixins.json:compat.create.rotation_propagation.RotationPropagatorMixin from mod createbigcannons,pl:mixin:APP:offroad.mixins.json:RotationPropagatorMixin from mod offroad,pl:mixin:APP:simulated.mixins.json:extra_kinetics.RotationPropagatorMixin from mod simulated,pl:mixin:APP:createcasing.mixins.json:create.RotationPropagatorMixin from mod createcasing,pl:mixin:APP:simulated.mixins.json:flicker_tally_removal.RotationPropagatorMixin from mod simulated,pl:mixin:A} + at TRANSFORMER/create@6.0.10/com.simibubi.create.content.kinetics.RotationPropagator.wrapOperation$deg000$createbigcannons$handleAdded(RotationPropagator.java:2037) ~[create-1.21.1-6.0.10.jar%23548!/:6.0.10] {re:mixin,re:classloading,pl:mixin:APP:create_connected.mixins.json:RotationPropagatorAccessor from mod create_connected,pl:mixin:APP:create_connected.mixins.json:RotationPropagatorMixin from mod create_connected,pl:mixin:APP:create_connected.mixins.json:chaincogwheel.RotationPropagatorMixin from mod create_connected,pl:mixin:APP:createbigcannons.mixins.json:compat.create.rotation_propagation.RotationPropagatorMixin from mod createbigcannons,pl:mixin:APP:offroad.mixins.json:RotationPropagatorMixin from mod offroad,pl:mixin:APP:simulated.mixins.json:extra_kinetics.RotationPropagatorMixin from mod simulated,pl:mixin:APP:createcasing.mixins.json:create.RotationPropagatorMixin from mod createcasing,pl:mixin:APP:simulated.mixins.json:flicker_tally_removal.RotationPropagatorMixin from mod simulated,pl:mixin:A} + at TRANSFORMER/create@6.0.10/com.simibubi.create.content.kinetics.RotationPropagator.handleAdded(RotationPropagator.java:211) ~[create-1.21.1-6.0.10.jar%23548!/:6.0.10] {re:mixin,re:classloading,pl:mixin:APP:create_connected.mixins.json:RotationPropagatorAccessor from mod create_connected,pl:mixin:APP:create_connected.mixins.json:RotationPropagatorMixin from mod create_connected,pl:mixin:APP:create_connected.mixins.json:chaincogwheel.RotationPropagatorMixin from mod create_connected,pl:mixin:APP:createbigcannons.mixins.json:compat.create.rotation_propagation.RotationPropagatorMixin from mod createbigcannons,pl:mixin:APP:offroad.mixins.json:RotationPropagatorMixin from mod offroad,pl:mixin:APP:simulated.mixins.json:extra_kinetics.RotationPropagatorMixin from mod simulated,pl:mixin:APP:createcasing.mixins.json:create.RotationPropagatorMixin from mod createcasing,pl:mixin:APP:simulated.mixins.json:flicker_tally_removal.RotationPropagatorMixin from mod simulated,pl:mixin:A} + at TRANSFORMER/create@6.0.10/com.simibubi.create.content.kinetics.base.KineticBlockEntity.attachKinetics(KineticBlockEntity.java:365) ~[create-1.21.1-6.0.10.jar%23548!/:6.0.10] {re:mixin,pl:runtimedistcleaner:A,re:computing_frames,pl:runtimedistcleaner:A,re:classloading,pl:mixin:A,pl:runtimedistcleaner:A} + at TRANSFORMER/create@6.0.10/com.simibubi.create.content.kinetics.base.KineticBlockEntity.tick(KineticBlockEntity.java:100) ~[create-1.21.1-6.0.10.jar%23548!/:6.0.10] {re:mixin,pl:runtimedistcleaner:A,re:computing_frames,pl:runtimedistcleaner:A,re:classloading,pl:mixin:A,pl:runtimedistcleaner:A} + at TRANSFORMER/createbigcannons@5.11.2/rbasamoyai.createbigcannons.cannon_control.cannon_mount.CannonMountBlockEntity.tick(CannonMountBlockEntity.java:108) ~[createbigcannons-5.11.2+mc.1.21.1.jar%23575!/:?] {re:classloading} + at TRANSFORMER/create@6.0.10/com.simibubi.create.foundation.blockEntity.SmartBlockEntityTicker.tick(SmartBlockEntityTicker.java:15) ~[create-1.21.1-6.0.10.jar%23548!/:6.0.10] {re:classloading} + at TRANSFORMER/minecraft@1.21.1/net.minecraft.world.level.chunk.LevelChunk$BoundTickingBlockEntity.tick(LevelChunk.java:711) ~[server-1.21.1-20240808.144430-srg.jar%23475!/:?] {re:mixin,pl:connector_pre_launch:A,re:classloading,pl:mixin:APP:lithium.mixins.json:minimal_nonvanilla.world.block_entity_ticking.support_cache.DirectBlockEntityTickInvokerMixin from mod lithium,pl:mixin:APP:lithium.mixins.json:world.block_entity_ticking.world_border.DirectBlockEntityTickInvokerMixin from mod lithium,pl:mixin:APP:polymorph.mixins.json:MixinLevelChunk from mod polymorph,pl:mixin:A,pl:connector_pre_launch:A} + at TRANSFORMER/minecraft@1.21.1/net.minecraft.world.level.chunk.LevelChunk$RebindableTickingBlockEntityWrapper.tick(LevelChunk.java:788) ~[server-1.21.1-20240808.144430-srg.jar%23475!/:?] {re:mixin,pl:connector_pre_launch:A,re:classloading,pl:mixin:APP:lithium.mixins.json:world.block_entity_ticking.sleeping.WrappedBlockEntityTickInvokerAccessor from mod lithium,pl:mixin:A,pl:connector_pre_launch:A} + at TRANSFORMER/minecraft@1.21.1/net.minecraft.world.level.Level.redirect$cea000$observable$redirectTick(Level.java:6324) ~[server-1.21.1-20240808.144430-srg.jar%23475!/:?] {re:computing_frames,pl:accesstransformer:B,xf:fml:default,pl:connector_pre_launch:A,re:mixin,pl:accesstransformer:B,xf:fml:default,pl:connector_pre_launch:A,re:classloading,pl:accesstransformer:B,xf:fml:default,pl:mixin:APP:lithium.mixins.json:alloc.chunk_random.LevelMixin from mod lithium,pl:mixin:APP:lithium.mixins.json:entity.collisions.intersection.LevelMixin from mod lithium,pl:mixin:APP:lithium.mixins.json:minimal_nonvanilla.collisions.empty_space.LevelMixin from mod lithium,pl:mixin:APP:lithium.mixins.json:util.accessors.LevelAccessor from mod lithium,pl:mixin:APP:lithium.mixins.json:util.block_entity_retrieval.LevelMixin from mod lithium,pl:mixin:APP:lithium.mixins.json:util.data_storage.LevelMixin from mod lithium,pl:mixin:APP:lithium.mixins.json:world.block_entity_ticking.chunk_tickable.LevelMixin from mod lithium,pl:mixin:APP:lithium.mixins.json:world.block_entity_ticking.sleeping.LevelMixin from mod lithium,pl:mixin:APP:lithium.mixins.json:world.inline_block_access.LevelMixin from mod lithium,pl:mixin:APP:lithium-neoforge.mixins.json:block.hopper.LevelMixin from mod lithium,pl:mixin:APP:observable.common.json:LevelMixin from mod observable,pl:mixin:APP:irons_spellbooks.mixins.json:LevelMixin from mod irons_spellbooks,pl:mixin:APP:aether.mixins.json:common.accessor.LevelAccessor from mod aether,pl:mixin:APP:refurbished_furniture.common.mixins.json:LevelMixin from mod refurbished_furniture,pl:mixin:APP:fabric-lifecycle-events-v1.mixins.json:WorldMixin from mod fabric_lifecycle_events_v1,pl:mixin:APP:kubejs.mixins.json:LevelMixin from mod kubejs,pl:mixin:APP:sliceanddice.mixins.json:LevelMixin from mod sliceanddice,pl:mixin:APP:sable.mixins.json:entity.entity_sublevel_collision.LevelMixin from mod sable,pl:mixin:APP:sable.mixins.json:world_border.LevelMixin from mod sable,pl:mixin:APP:sable-neoforge.mixins.json:compatibility.create.super_glue.LevelAccessor from mod sable,pl:mixin:APP:c2me-opts-scheduling.mixins.json:mid_tick_chunk_tasks.MixinWorld from mod c2me_opts_scheduling,pl:mixin:APP:c2me-fixes-worldgen-threading-issues.mixins.json:threading_detections.random_instances.MixinWorld from mod c2me_fixes_worldgen_threading_issues,pl:mixin:APP:c2me-notickvd.mixins.json:MixinWorld from mod c2me_notickvd,pl:mixin:APP:openpartiesandclaims.mixins.json:MixinLevel from mod openpartiesandclaims,pl:mixin:A,pl:connector_pre_launch:A} + at TRANSFORMER/minecraft@1.21.1/net.minecraft.world.level.Level.tickBlockEntities(Level.java:565) ~[server-1.21.1-20240808.144430-srg.jar%23475!/:?] {re:computing_frames,pl:accesstransformer:B,xf:fml:default,pl:connector_pre_launch:A,re:mixin,pl:accesstransformer:B,xf:fml:default,pl:connector_pre_launch:A,re:classloading,pl:accesstransformer:B,xf:fml:default,pl:mixin:APP:lithium.mixins.json:alloc.chunk_random.LevelMixin from mod lithium,pl:mixin:APP:lithium.mixins.json:entity.collisions.intersection.LevelMixin from mod lithium,pl:mixin:APP:lithium.mixins.json:minimal_nonvanilla.collisions.empty_space.LevelMixin from mod lithium,pl:mixin:APP:lithium.mixins.json:util.accessors.LevelAccessor from mod lithium,pl:mixin:APP:lithium.mixins.json:util.block_entity_retrieval.LevelMixin from mod lithium,pl:mixin:APP:lithium.mixins.json:util.data_storage.LevelMixin from mod lithium,pl:mixin:APP:lithium.mixins.json:world.block_entity_ticking.chunk_tickable.LevelMixin from mod lithium,pl:mixin:APP:lithium.mixins.json:world.block_entity_ticking.sleeping.LevelMixin from mod lithium,pl:mixin:APP:lithium.mixins.json:world.inline_block_access.LevelMixin from mod lithium,pl:mixin:APP:lithium-neoforge.mixins.json:block.hopper.LevelMixin from mod lithium,pl:mixin:APP:observable.common.json:LevelMixin from mod observable,pl:mixin:APP:irons_spellbooks.mixins.json:LevelMixin from mod irons_spellbooks,pl:mixin:APP:aether.mixins.json:common.accessor.LevelAccessor from mod aether,pl:mixin:APP:refurbished_furniture.common.mixins.json:LevelMixin from mod refurbished_furniture,pl:mixin:APP:fabric-lifecycle-events-v1.mixins.json:WorldMixin from mod fabric_lifecycle_events_v1,pl:mixin:APP:kubejs.mixins.json:LevelMixin from mod kubejs,pl:mixin:APP:sliceanddice.mixins.json:LevelMixin from mod sliceanddice,pl:mixin:APP:sable.mixins.json:entity.entity_sublevel_collision.LevelMixin from mod sable,pl:mixin:APP:sable.mixins.json:world_border.LevelMixin from mod sable,pl:mixin:APP:sable-neoforge.mixins.json:compatibility.create.super_glue.LevelAccessor from mod sable,pl:mixin:APP:c2me-opts-scheduling.mixins.json:mid_tick_chunk_tasks.MixinWorld from mod c2me_opts_scheduling,pl:mixin:APP:c2me-fixes-worldgen-threading-issues.mixins.json:threading_detections.random_instances.MixinWorld from mod c2me_fixes_worldgen_threading_issues,pl:mixin:APP:c2me-notickvd.mixins.json:MixinWorld from mod c2me_notickvd,pl:mixin:APP:openpartiesandclaims.mixins.json:MixinLevel from mod openpartiesandclaims,pl:mixin:A,pl:connector_pre_launch:A} + at TRANSFORMER/minecraft@1.21.1/net.minecraft.server.level.ServerLevel.tick(ServerLevel.java:428) ~[server-1.21.1-20240808.144430-srg.jar%23475!/:?] {re:mixin,pl:accesstransformer:B,pl:connector_pre_launch:A,re:classloading,pl:accesstransformer:B,pl:mixin:APP:cupboard.mixins.json:ServerAddEntityMixin from mod cupboard,pl:mixin:APP:immersive_melodies.mixins.json:ServerWorldMixin from mod immersive_melodies,pl:mixin:APP:supplementaries-common.mixins.json:ServerLevelMixin from mod supplementaries,pl:mixin:APP:lithium.mixins.json:alloc.chunk_random.ServerLevelMixin from mod lithium,pl:mixin:APP:lithium.mixins.json:entity.inactive_navigations.ServerLevelMixin from mod lithium,pl:mixin:APP:lithium.mixins.json:minimal_nonvanilla.spawning.ServerLevelAccessor from mod lithium,pl:mixin:APP:lithium.mixins.json:util.accessors.ServerLevelAccessor from mod lithium,pl:mixin:APP:lithium.mixins.json:util.entity_movement_tracking.ServerLevelAccessor from mod lithium,pl:mixin:APP:lithium.mixins.json:world.block_entity_ticking.sleeping.ServerLevelMixin from mod lithium,pl:mixin:APP:fabric-api-lookup-api-v1.mixins.json:ServerWorldMixin from mod fabric_api_lookup_api_v1,pl:mixin:APP:observable.common.json:ServerLevelMixin from mod observable,pl:mixin:APP:bettercaves.mixins.json:ServerLevelMixin from mod bettercaves,pl:mixin:APP:createbigcannons.mixins.json:ServerLevelMixin from mod createbigcannons,pl:mixin:APP:revive_me.mixins.json:ServerLevelMixin from mod revive_me,pl:mixin:APP:pehkui.mixins.json:compat117plus.ServerWorldMixin from mod pehkui,pl:mixin:APP:glitchcore.mixins.json:MixinServerLevel from mod glitchcore,pl:mixin:APP:polymorph.mixins.json:MixinServerLevel from mod polymorph,pl:mixin:APP:aether.mixins.json:common.accessor.ServerLevelAccessor from mod aether,pl:mixin:APP:refurbished_furniture.common.mixins.json:ServerLevelMixin from mod refurbished_furniture,pl:mixin:APP:fabric-lifecycle-events-v1.mixins.json:ServerWorldMixin from mod fabric_lifecycle_events_v1,pl:mixin:APP:kubejs.mixins.json:ServerLevelMixin from mod kubejs,pl:mixin:APP:create.mixins.json:accessor.ServerLevelAccessor from mod create,pl:mixin:APP:sable.mixins.json:block_decal_render.ServerLevelMixin from mod sable,pl:mixin:APP:sable.mixins.json:entity.entity_aabb_lookup.LevelsMixin from mod sable,pl:mixin:APP:sable.mixins.json:entity.entity_kicking.ServerLevelMixin from mod sable,pl:mixin:APP:sable.mixins.json:entity.server_entities_tick.ServerLevelMixin from mod sable,pl:mixin:APP:sable.mixins.json:explosion.ServerLevelMixin from mod sable,pl:mixin:APP:sable.mixins.json:particle.ServerLevelMixin from mod sable,pl:mixin:APP:sable.mixins.json:physics.ServerLevelMixin from mod sable,pl:mixin:APP:sable.mixins.json:plot.LevelsMixin from mod sable,pl:mixin:APP:sable.mixins.json:plot.ServerLevelMixin from mod sable,pl:mixin:APP:sable.mixins.json:water_occlusion.LevelsMixin from mod sable,pl:mixin:APP:yungscavebiomes.mixins.json:accessor.ServerLevelAccessor from mod yungscavebiomes,pl:mixin:APP:yungscavebiomes.mixins.json:lost_caves.ServerLevelMixin from mod yungscavebiomes,pl:mixin:APP:comforts.mixins.json:MixinServerSleepStatus from mod comforts,pl:mixin:APP:betterdeserttemples.mixins.json:ServerLevelMixin from mod betterdeserttemples,pl:mixin:APP:moonlight-common.mixins.json:ServerLevelMixin from mod moonlight,pl:mixin:APP:yawp.mixins.json:ServerWorldMixin from mod yawp,pl:mixin:APP:c2me-opts-scheduling.mixins.json:mid_tick_chunk_tasks.MixinServerWorld from mod c2me_opts_scheduling,pl:mixin:APP:c2me-opts-scheduling.mixins.json:shutdown.MixinServerWorld from mod c2me_opts_scheduling,pl:mixin:APP:openpartiesandclaims.mixins.json:MixinServerLevel from mod openpartiesandclaims,pl:mixin:A,pl:connector_pre_launch:A} + at TRANSFORMER/minecraft@1.21.1/net.minecraft.server.MinecraftServer.tickChildren(MinecraftServer.java:1037) ~[server-1.21.1-20240808.144430-srg.jar%23475!/:?] {re:mixin,pl:accesstransformer:B,pl:connector_pre_launch:A,re:classloading,pl:accesstransformer:B,pl:mixin:APP:modernfix-modernfix.mixins.json:perf.fix_loop_spin_waiting.MinecraftServerMixin from mod modernfix,pl:mixin:APP:openpartiesandclaims.mixins.json:MixinMinecraftServer from mod openpartiesandclaims,pl:mixin:APP:modernfix-modernfix.mixins.json:core.MinecraftServerMixin from mod modernfix,pl:mixin:APP:modernfix-modernfix.mixins.json:perf.dedicated_reload_executor.MinecraftServerMixin from mod modernfix,pl:mixin:APP:veil.scheduler.mixins.json:MinecraftServerMixin from mod veil,pl:mixin:APP:rechiseled.mixins.json:MinecraftServerMixin from mod rechiseled,pl:mixin:APP:lootr-common.mixins.json:accessor.AccessorMixinMinecraftServer from mod lootr,pl:mixin:APP:fabric-message-api-v1.mixins.json:MinecraftServerMixin from mod fabric_message_api_v1,pl:mixin:APP:structureessentials.mixins.json:LevelCreatedCallback from mod structureessentials,pl:mixin:APP:fabric-resource-loader-v0.mixins.json:MinecraftServerMixin from mod fabric_resource_loader_v0,pl:mixin:APP:ponder-common.mixins.json:accessor.MinecraftServerAccessor from mod ponder,pl:mixin:APP:balm.neoforge.mixins.json:MinecraftServerMixin from mod balm,pl:mixin:APP:xaerohud.mixins.json:MixinMinecraftServer from mod xaerominimap,pl:mixin:APP:aether.mixins.json:common.accessor.MinecraftServerAccessor from mod aether,pl:mixin:APP:xaeroworldmap.mixins.json:MixinMinecraftServer from mod xaeroworldmap,pl:mixin:APP:fabric-lifecycle-events-v1.mixins.json:MinecraftServerMixin from mod fabric_lifecycle_events_v1,pl:mixin:APP:kubejs.mixins.json:MinecraftServerMixin from mod kubejs,pl:mixin:APP:sable.mixins.json:udp.MinecraftServerMixin from mod sable,pl:mixin:APP:moonlight.mixins.json:MinecraftServerMixin from mod moonlight,pl:mixin:APP:c2me-fixes-general-threading-issues.mixins.json:asynccatchers.MixinMinecraftServer from mod c2me_fixes_general_threading_issues,pl:mixin:APP:c2me-opts-scheduling.mixins.json:idle_tasks.autosave.enhanced_autosave.MixinMinecraftServer from mod c2me_opts_scheduling,pl:mixin:APP:c2me-opts-scheduling.mixins.json:mid_tick_chunk_tasks.MixinMinecraftServer from mod c2me_opts_scheduling,pl:mixin:APP:c2me-opts-scheduling.mixins.json:shutdown.MixinMinecraftServer from mod c2me_opts_scheduling,pl:mixin:APP:c2me-rewrites-chunk-system.mixins.json:MixinMinecraftServer from mod c2me_rewrites_chunk_system,pl:mixin:APP:c2me-notickvd.mixins.json:MixinMinecraftServer from mod c2me_notickvd,pl:mixin:A,pl:connector_pre_launch:A} + ... 5 more +[02:07:44] [Server thread/FATAL] [ne.ne.ne.co.NeoForgeMod/]: Preparing crash report with UUID a36e0fc1-7ce8-4171-9789-461a00445944 +[02:07:44] [Server thread/ERROR] [minecraft/MinecraftServer]: This crash report has been saved to: /home/container/crash-reports/crash-2026-05-01_02.07.44-server.txt +[02:07:44] [Server thread/INFO] [minecraft/MinecraftServer]: Stopping server +[02:07:44] [Server thread/INFO] [minecraft/MinecraftServer]: Saving players +[02:07:46] [Server thread/INFO] [minecraft/MinecraftServer]: Saving worlds +[02:07:46] [Server thread/INFO] [minecraft/MinecraftServer]: ServerLevel[world]/minecraft:overworld: waiting for 4823 chunks to unload +[02:07:48] [Server thread/INFO] [minecraft/MinecraftServer]: ServerLevel[world]/minecraft:overworld: waiting for 1365 chunks to unload +[02:07:50] [Server thread/INFO] [minecraft/MinecraftServer]: ServerLevel[world]/minecraft:overworld: waiting for 1843 chunks to unload +[02:07:52] [Server thread/INFO] [minecraft/MinecraftServer]: ServerLevel[world]/minecraft:overworld: waiting for 2018 chunks to unload +[02:07:54] [Server thread/INFO] [minecraft/MinecraftServer]: ServerLevel[world]/minecraft:overworld: waiting for 588 chunks to unload +[02:07:55] [Server thread/INFO] [minecraft/MinecraftServer]: Saving chunks for level 'ServerLevel[world]'/minecraft:overworld +[02:07:55] [Server thread/INFO] [de.ry.sa.Sable/]: Saving sub-levels for level 'ServerLevel[world]'/minecraft:overworld +[02:07:55] [Server thread/INFO] [YAWP-DataManager/]: Requested save. Saving region data for all levels +[02:07:55] [Server thread/INFO] [minecraft/MinecraftServer]: Saving chunks for level 'ServerLevel[world]'/irons_spellbooks:pocket_dimension +[02:07:55] [Server thread/INFO] [de.ry.sa.Sable/]: Saving sub-levels for level 'ServerLevel[world]'/irons_spellbooks:pocket_dimension +[02:07:55] [Server thread/INFO] [YAWP-DataManager/]: Requested save. Saving region data for all levels +[02:07:55] [Server thread/INFO] [minecraft/MinecraftServer]: Saving chunks for level 'ServerLevel[world]'/twilightforest:twilight_forest +[02:07:55] [Server thread/INFO] [de.ry.sa.Sable/]: Saving sub-levels for level 'ServerLevel[world]'/twilightforest:twilight_forest +[02:07:55] [Server thread/INFO] [YAWP-DataManager/]: Requested save. Saving region data for all levels +[02:07:55] [Server thread/INFO] [minecraft/MinecraftServer]: Saving chunks for level 'ServerLevel[world]'/aether:the_aether +[02:07:55] [Server thread/INFO] [de.ry.sa.Sable/]: Saving sub-levels for level 'ServerLevel[world]'/aether:the_aether +[02:07:55] [Server thread/INFO] [YAWP-DataManager/]: Requested save. Saving region data for all levels +[02:07:55] [Server thread/INFO] [minecraft/MinecraftServer]: Saving chunks for level 'ServerLevel[world]'/javd:void +[02:07:55] [Server thread/INFO] [de.ry.sa.Sable/]: Saving sub-levels for level 'ServerLevel[world]'/javd:void +[02:07:55] [Server thread/INFO] [YAWP-DataManager/]: Requested save. Saving region data for all levels +[02:07:55] [Server thread/INFO] [minecraft/MinecraftServer]: Saving chunks for level 'ServerLevel[world]'/minecraft:the_end +[02:07:55] [Server thread/INFO] [de.ry.sa.Sable/]: Saving sub-levels for level 'ServerLevel[world]'/minecraft:the_end +[02:07:55] [Server thread/INFO] [YAWP-DataManager/]: Requested save. Saving region data for all levels +[02:07:55] [Server thread/INFO] [minecraft/MinecraftServer]: Saving chunks for level 'ServerLevel[world]'/minecraft:the_nether +[02:07:55] [Server thread/INFO] [de.ry.sa.Sable/]: Saving sub-levels for level 'ServerLevel[world]'/minecraft:the_nether +[02:07:55] [Server thread/INFO] [YAWP-DataManager/]: Requested save. Saving region data for all levels +[02:07:55] [Server thread/INFO] [minecraft/MinecraftServer]: ThreadedAnvilChunkStorage (world): All chunks are saved +[02:07:55] [Server thread/INFO] [minecraft/MinecraftServer]: ThreadedAnvilChunkStorage (pocket_dimension): All chunks are saved +[02:07:55] [Server thread/INFO] [minecraft/MinecraftServer]: ThreadedAnvilChunkStorage (twilight_forest): All chunks are saved +[02:07:55] [Server thread/INFO] [minecraft/MinecraftServer]: ThreadedAnvilChunkStorage (the_aether): All chunks are saved +[02:07:55] [Server thread/INFO] [minecraft/MinecraftServer]: ThreadedAnvilChunkStorage (void): All chunks are saved +[02:07:55] [Server thread/INFO] [minecraft/MinecraftServer]: ThreadedAnvilChunkStorage (DIM1): All chunks are saved +[02:07:55] [Server thread/INFO] [minecraft/MinecraftServer]: ThreadedAnvilChunkStorage (DIM-1): All chunks are saved +[02:07:55] [Server thread/INFO] [minecraft/MinecraftServer]: ThreadedAnvilChunkStorage: All dimensions are saved +[02:07:55] [Server thread/INFO] [YAWP-DataManager/]: Unloading level 'minecraft:overworld'. Saving region data +[02:07:55] [Server thread/INFO] [YAWP-DataManager/]: Saving region data for level 'minecraft:overworld' +[02:07:55] [Server thread/INFO] [Di.se.di.co.ge.qu.WorldGenerationQueue/]: Closing world gen queue +[02:07:55] [Server thread/INFO] [Di.se.di.co.ge.qu.WorldGenerationQueue/]: Closing WorldGenerationQueue... +[02:07:55] [Server thread/INFO] [Di.se.di.co.ge.qu.WorldGenerationQueue/]: Shutting down world generator thread pool... +[02:07:55] [Server thread/INFO] [Di.se.di.co.ge.qu.WorldGenerationQueue/]: World generator thread pool shutdown with [0] incomplete tasks. +[02:07:55] [Server thread/INFO] [Di.se.di.co.ge.BatchGenerator/]: [BatchGenerator] shutting down... +[02:07:55] [Server thread/INFO] [DistantHorizons-LOD World Gen/]: Closing [BatchGenerationEnvironment_neoforge] +[02:07:55] [Server thread/INFO] [Di.se.di.co.ge.qu.WorldGenerationQueue/]: Finished closing WorldGenerationQueue +[02:07:55] [Server thread/INFO] [Di.se.di.co.le.AbstractDhServerLevel/]: Closed DHLevel for [Wrapped{ServerLevel[world]@minecraft:overworld}]. +[02:07:55] [C2ME Storage #3/INFO] [C2ME Storage/]: Storage thread Thread[#120,C2ME Storage #3,8,SERVER] stopped +[02:07:55] [C2ME Storage #2/INFO] [C2ME Storage/]: Storage thread Thread[#119,C2ME Storage #2,8,SERVER] stopped +[02:07:55] [C2ME Storage #1/INFO] [C2ME Storage/]: Storage thread Thread[#118,C2ME Storage #1,8,SERVER] stopped +[02:07:55] [Server thread/INFO] [Di.se.di.co.ge.qu.WorldGenerationQueue/]: Closing world gen queue +[02:07:55] [Server thread/INFO] [Di.se.di.co.ge.qu.WorldGenerationQueue/]: Closing WorldGenerationQueue... +[02:07:55] [Server thread/INFO] [Di.se.di.co.ge.qu.WorldGenerationQueue/]: Shutting down world generator thread pool... +[02:07:55] [Server thread/INFO] [Di.se.di.co.ge.qu.WorldGenerationQueue/]: World generator thread pool shutdown with [0] incomplete tasks. +[02:07:55] [Server thread/INFO] [Di.se.di.co.ge.BatchGenerator/]: [BatchGenerator] shutting down... +[02:07:55] [Server thread/INFO] [DistantHorizons-LOD World Gen/]: Closing [BatchGenerationEnvironment_neoforge] +[02:07:55] [Server thread/INFO] [Di.se.di.co.ge.qu.WorldGenerationQueue/]: Finished closing WorldGenerationQueue +[02:07:55] [Server thread/INFO] [Di.se.di.co.le.AbstractDhServerLevel/]: Closed DHLevel for [Wrapped{ServerLevel[world]@irons_spellbooks:pocket_dimension}]. +[02:07:55] [C2ME Storage #6/INFO] [C2ME Storage/]: Storage thread Thread[#141,C2ME Storage #6,8,SERVER] stopped +[02:07:55] [C2ME Storage #5/INFO] [C2ME Storage/]: Storage thread Thread[#140,C2ME Storage #5,8,SERVER] stopped +[02:07:55] [C2ME Storage #4/INFO] [C2ME Storage/]: Storage thread Thread[#139,C2ME Storage #4,8,SERVER] stopped +[02:07:55] [Server thread/INFO] [YAWP-DataManager/]: Unloading level 'twilightforest:twilight_forest'. Saving region data +[02:07:55] [Server thread/INFO] [YAWP-DataManager/]: Saving region data for level 'twilightforest:twilight_forest' +[02:07:55] [Server thread/INFO] [Di.se.di.co.ge.qu.WorldGenerationQueue/]: Closing world gen queue +[02:07:55] [Server thread/INFO] [Di.se.di.co.ge.qu.WorldGenerationQueue/]: Closing WorldGenerationQueue... +[02:07:55] [Server thread/INFO] [Di.se.di.co.ge.qu.WorldGenerationQueue/]: Shutting down world generator thread pool... +[02:07:55] [Server thread/INFO] [Di.se.di.co.ge.qu.WorldGenerationQueue/]: World generator thread pool shutdown with [0] incomplete tasks. +[02:07:55] [Server thread/INFO] [Di.se.di.co.ge.BatchGenerator/]: [BatchGenerator] shutting down... +[02:07:55] [Server thread/INFO] [DistantHorizons-LOD World Gen/]: Closing [BatchGenerationEnvironment_neoforge] +[02:07:55] [Server thread/INFO] [Di.se.di.co.ge.qu.WorldGenerationQueue/]: Finished closing WorldGenerationQueue +[02:07:55] [Server thread/INFO] [Di.se.di.co.le.AbstractDhServerLevel/]: Closed DHLevel for [Wrapped{ServerLevel[world]@twilightforest:twilight_forest}]. +[02:07:55] [C2ME Storage #9/INFO] [C2ME Storage/]: Storage thread Thread[#152,C2ME Storage #9,8,SERVER] stopped +[02:07:55] [C2ME Storage #8/INFO] [C2ME Storage/]: Storage thread Thread[#151,C2ME Storage #8,8,SERVER] stopped +[02:07:55] [Server thread/INFO] [YAWP-DataManager/]: Unloading level 'aether:the_aether'. Saving region data +[02:07:55] [C2ME Storage #7/INFO] [C2ME Storage/]: Storage thread Thread[#150,C2ME Storage #7,8,SERVER] stopped +[02:07:55] [Server thread/INFO] [YAWP-DataManager/]: Saving region data for level 'aether:the_aether' +[02:07:55] [Server thread/INFO] [Di.se.di.co.ge.qu.WorldGenerationQueue/]: Closing world gen queue +[02:07:55] [Server thread/INFO] [Di.se.di.co.ge.qu.WorldGenerationQueue/]: Closing WorldGenerationQueue... +[02:07:55] [Server thread/INFO] [Di.se.di.co.ge.qu.WorldGenerationQueue/]: Shutting down world generator thread pool... +[02:07:55] [Server thread/INFO] [Di.se.di.co.ge.qu.WorldGenerationQueue/]: World generator thread pool shutdown with [0] incomplete tasks. +[02:07:55] [Server thread/INFO] [Di.se.di.co.ge.BatchGenerator/]: [BatchGenerator] shutting down... +[02:07:55] [Server thread/INFO] [DistantHorizons-LOD World Gen/]: Closing [BatchGenerationEnvironment_neoforge] +[02:07:55] [Server thread/INFO] [Di.se.di.co.ge.qu.WorldGenerationQueue/]: Finished closing WorldGenerationQueue +[02:07:55] [Server thread/INFO] [Di.se.di.co.le.AbstractDhServerLevel/]: Closed DHLevel for [Wrapped{ServerLevel[world]@aether:the_aether}]. +[02:07:55] [C2ME Storage #12/INFO] [C2ME Storage/]: Storage thread Thread[#162,C2ME Storage #12,8,SERVER] stopped +[02:07:55] [C2ME Storage #11/INFO] [C2ME Storage/]: Storage thread Thread[#161,C2ME Storage #11,8,SERVER] stopped +[02:07:55] [C2ME Storage #10/INFO] [C2ME Storage/]: Storage thread Thread[#160,C2ME Storage #10,8,SERVER] stopped +[02:07:55] [Server thread/INFO] [Di.se.di.co.ge.qu.WorldGenerationQueue/]: Closing world gen queue +[02:07:55] [Server thread/INFO] [Di.se.di.co.ge.qu.WorldGenerationQueue/]: Closing WorldGenerationQueue... +[02:07:55] [Server thread/INFO] [Di.se.di.co.ge.qu.WorldGenerationQueue/]: Shutting down world generator thread pool... +[02:07:55] [Server thread/INFO] [Di.se.di.co.ge.qu.WorldGenerationQueue/]: World generator thread pool shutdown with [0] incomplete tasks. +[02:07:55] [Server thread/INFO] [Di.se.di.co.ge.BatchGenerator/]: [BatchGenerator] shutting down... +[02:07:55] [Server thread/INFO] [DistantHorizons-LOD World Gen/]: Closing [BatchGenerationEnvironment_neoforge] +[02:07:55] [Server thread/INFO] [Di.se.di.co.ge.qu.WorldGenerationQueue/]: Finished closing WorldGenerationQueue +[02:07:55] [Server thread/INFO] [Di.se.di.co.le.AbstractDhServerLevel/]: Closed DHLevel for [Wrapped{ServerLevel[world]@javd:void}]. +[02:07:55] [C2ME Storage #15/INFO] [C2ME Storage/]: Storage thread Thread[#172,C2ME Storage #15,8,SERVER] stopped +[02:07:55] [C2ME Storage #14/INFO] [C2ME Storage/]: Storage thread Thread[#171,C2ME Storage #14,8,SERVER] stopped +[02:07:55] [C2ME Storage #13/INFO] [C2ME Storage/]: Storage thread Thread[#170,C2ME Storage #13,8,SERVER] stopped +[02:07:55] [Server thread/INFO] [YAWP-DataManager/]: Unloading level 'minecraft:the_end'. Saving region data +[02:07:55] [Server thread/INFO] [YAWP-DataManager/]: Saving region data for level 'minecraft:the_end' +[02:07:55] [Server thread/INFO] [Di.se.di.co.ge.qu.WorldGenerationQueue/]: Closing world gen queue +[02:07:55] [Server thread/INFO] [Di.se.di.co.ge.qu.WorldGenerationQueue/]: Closing WorldGenerationQueue... +[02:07:55] [Server thread/INFO] [Di.se.di.co.ge.qu.WorldGenerationQueue/]: Shutting down world generator thread pool... +[02:07:55] [Server thread/INFO] [Di.se.di.co.ge.qu.WorldGenerationQueue/]: World generator thread pool shutdown with [0] incomplete tasks. +[02:07:55] [Server thread/INFO] [Di.se.di.co.ge.BatchGenerator/]: [BatchGenerator] shutting down... +[02:07:55] [Server thread/INFO] [DistantHorizons-LOD World Gen/]: Closing [BatchGenerationEnvironment_neoforge] +[02:07:55] [Server thread/INFO] [Di.se.di.co.ge.qu.WorldGenerationQueue/]: Finished closing WorldGenerationQueue +[02:07:55] [Server thread/INFO] [Di.se.di.co.le.AbstractDhServerLevel/]: Closed DHLevel for [Wrapped{ServerLevel[world]@minecraft:the_end}]. +[02:07:55] [C2ME Storage #18/INFO] [C2ME Storage/]: Storage thread Thread[#182,C2ME Storage #18,8,SERVER] stopped +[02:07:55] [C2ME Storage #17/INFO] [C2ME Storage/]: Storage thread Thread[#181,C2ME Storage #17,8,SERVER] stopped +[02:07:55] [C2ME Storage #16/INFO] [C2ME Storage/]: Storage thread Thread[#180,C2ME Storage #16,8,SERVER] stopped +[02:07:55] [Server thread/INFO] [YAWP-DataManager/]: Unloading level 'minecraft:the_nether'. Saving region data +[02:07:55] [Server thread/INFO] [YAWP-DataManager/]: Saving region data for level 'minecraft:the_nether' +[02:07:55] [Server thread/INFO] [Di.se.di.co.ge.qu.WorldGenerationQueue/]: Closing world gen queue +[02:07:55] [Server thread/INFO] [Di.se.di.co.ge.qu.WorldGenerationQueue/]: Closing WorldGenerationQueue... +[02:07:55] [Server thread/INFO] [Di.se.di.co.ge.qu.WorldGenerationQueue/]: Shutting down world generator thread pool... +[02:07:55] [Server thread/INFO] [Di.se.di.co.ge.qu.WorldGenerationQueue/]: World generator thread pool shutdown with [0] incomplete tasks. +[02:07:55] [Server thread/INFO] [Di.se.di.co.ge.BatchGenerator/]: [BatchGenerator] shutting down... +[02:07:55] [Server thread/INFO] [DistantHorizons-LOD World Gen/]: Closing [BatchGenerationEnvironment_neoforge] +[02:07:55] [Server thread/INFO] [Di.se.di.co.ge.qu.WorldGenerationQueue/]: Finished closing WorldGenerationQueue diff --git a/k8s/STATEFULSET.md b/k8s/STATEFULSET.md new file mode 100644 index 0000000000..dff1f391dc --- /dev/null +++ b/k8s/STATEFULSET.md @@ -0,0 +1,413 @@ +# StatefulSet & Persistent Storage + +## 1. StatefulSet Overview + +A StatefulSet is a Kubernetes workload controller designed for applications that require stable identity and persistent state. It provides: + +- stable and predictable pod names, such as `devops-info-service-0`, `devops-info-service-1`, and `devops-info-service-2` +- stable per-pod DNS names through a headless service +- persistent storage assigned independently to each replica through `volumeClaimTemplates` +- ordered creation, update, scaling, and deletion behavior + +For the DevOps Info Service, StatefulSet is useful because the application stores the visit counter in `/data/visits`. With a StatefulSet, each pod receives its own persistent volume, so every replica can keep an independent counter that survives pod recreation. + +### Deployment vs StatefulSet + +| Characteristic | Deployment | StatefulSet | +|---|---|---| +| Pod identity | Random pod names with generated suffixes | Stable ordinal names like `pod-0`, `pod-1`, `pod-2` | +| Network identity | No stable identity for each replica | Stable DNS identity for each pod | +| Storage | Usually stateless or shared externally | One persistent volume claim per pod | +| Scaling behavior | Unordered | Ordered by default | +| Best use case | Stateless web applications and APIs | Databases, queues, and stateful services | + +### Examples of stateful workloads + +Typical workloads that benefit from StatefulSets include PostgreSQL, MySQL, MongoDB, Kafka, RabbitMQ, Cassandra, and Elasticsearch. + +### Headless service + +A headless service is a Kubernetes Service with `clusterIP: None`. It does not load-balance traffic through a virtual ClusterIP. Instead, it creates DNS records that allow clients to reach individual StatefulSet pods directly. + +The DNS naming pattern used in this lab is: + +```text +...svc.cluster.local +``` + +For this deployment, examples are: + +```text +devops-info-service-0.devops-info-service-headless.default.svc.cluster.local +devops-info-service-1.devops-info-service-headless.default.svc.cluster.local +devops-info-service-2.devops-info-service-headless.default.svc.cluster.local +``` + +## 2. Implementation Summary + +The Helm chart was updated to deploy the application as a StatefulSet instead of a Deployment or Argo Rollout. + +### Files changed or added + +- `k8s/devops-info-service/values.yaml` + - `statefulset.enabled` was set to `true` + - `rollout.enabled` was set to `false` + - persistence remained enabled with a 100Mi volume size + - image repository uses the GitHub/DockerHub namespace `dorley174` + +- `k8s/devops-info-service/templates/statefulset.yaml` + - defines the `StatefulSet` + - sets `serviceName` to the headless service + - mounts `/data` from a per-pod PVC + - defines `volumeClaimTemplates` for independent persistent storage + +- `k8s/devops-info-service/templates/headless-service.yaml` + - defines a headless service with `clusterIP: None` + - selects the StatefulSet pods using the same selector labels + +- `k8s/devops-info-service/templates/pvc.yaml` + - kept for reference, but the StatefulSet uses `volumeClaimTemplates` for per-pod PVCs + +The bonus/extra credit update strategy task was not implemented. + +## 3. Resource Verification + +### Commands used + +```bash +kubectl get nodes +``` + +```bash +minikube image build -t dorley174/devops-info-service:lab15-local /home/vagrant/app_python +``` + +```bash +helm upgrade --install devops-info-service /home/vagrant/k8s/devops-info-service \ + --wait \ + --timeout 5m \ + --no-hooks \ + --set image.repository=dorley174/devops-info-service \ + --set image.tag=lab15-local \ + --set image.pullPolicy=IfNotPresent +``` + +If an old pod was already stuck with the previous image tag, it was recreated with: + +```bash +kubectl delete pod devops-info-service-0 +``` + +Then the resources were verified with: + +```bash +kubectl rollout status statefulset/devops-info-service --timeout=180s +``` + +```bash +kubectl get po,sts,svc,pvc -o wide +``` + +```bash +kubectl get svc devops-info-service-headless -o yaml | grep -E "name:|clusterIP:|publishNotReadyAddresses:" +``` + +### Output + +```text +$ kubectl get nodes +NAME STATUS ROLES AGE VERSION +minikube Ready control-plane 2h v1.34.2 + +$ minikube image build -t dorley174/devops-info-service:lab15-local /home/vagrant/app_python +#0 building with "default" instance using docker driver +#1 [internal] load build definition from Dockerfile +#1 DONE +#2 [internal] load metadata for docker.io/library/python:3.13.1-slim +#2 DONE +#9 [5/6] RUN pip install --no-cache-dir -r requirements.txt +#9 DONE +#11 exporting to image +#11 writing image sha256:3cc8dc1a899e58fc7e0a11b5de360965595c4de997ec5921bbe0f6a92fd7cff1 done +#11 naming to docker.io/dorley174/devops-info-service:lab15-local done +#11 DONE + +$ helm upgrade --install devops-info-service /home/vagrant/k8s/devops-info-service --wait --timeout 5m --no-hooks --set image.repository=dorley174/devops-info-service --set image.tag=lab15-local --set image.pullPolicy=IfNotPresent +Release "devops-info-service" does not exist. Installing it now. +NAME: devops-info-service +LAST DEPLOYED: Thu May 7 15:52:00 2026 +NAMESPACE: default +STATUS: deployed +REVISION: 1 +TEST SUITE: None + +$ kubectl rollout status statefulset/devops-info-service --timeout=180s +Waiting for 3 pods to be ready... +partitioned roll out complete: 3 new pods have been updated... + +$ kubectl get po,sts,svc,pvc -o wide +NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES +pod/devops-info-service-0 1/1 Running 0 3m10s 10.244.0.5 minikube +pod/devops-info-service-1 1/1 Running 0 2m35s 10.244.0.6 minikube +pod/devops-info-service-2 1/1 Running 0 2m02s 10.244.0.7 minikube + +NAME READY AGE CONTAINERS IMAGES +statefulset.apps/devops-info-service 3/3 3m10s devops-info-service dorley174/devops-info-service:lab15-local + +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR +service/devops-info-service NodePort 10.108.129.253 80:30083/TCP 3m11s app.kubernetes.io/instance=devops-info-service,app.kubernetes.io/name=devops-info-service +service/devops-info-service-headless ClusterIP None 80/TCP 3m11s app.kubernetes.io/instance=devops-info-service,app.kubernetes.io/name=devops-info-service +service/kubernetes ClusterIP 10.96.0.1 443/TCP 2h + +NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE VOLUMEMODE +persistentvolumeclaim/data-volume-devops-info-service-0 Bound pvc-58f1c9dc-3436-458a-af2c-9c326059ca6f 100Mi RWO standard 3m11s Filesystem +persistentvolumeclaim/data-volume-devops-info-service-1 Bound pvc-6d16b9ec-3b64-4a79-9d25-413a66f80341 100Mi RWO standard 2m36s Filesystem +persistentvolumeclaim/data-volume-devops-info-service-2 Bound pvc-f0975d83-6c16-4b33-9672-b222a13b218a 100Mi RWO standard 2m03s Filesystem + +$ kubectl get svc devops-info-service-headless -o yaml | grep -E "name:|clusterIP:|publishNotReadyAddresses:" + name: devops-info-service-headless + namespace: default + clusterIP: None +``` + +### Verification summary + +The expected result is: + +- one StatefulSet named `devops-info-service` +- three pods named `devops-info-service-0`, `devops-info-service-1`, and `devops-info-service-2` +- one regular service named `devops-info-service` +- one headless service named `devops-info-service-headless` with `clusterIP: None` +- one PVC per StatefulSet pod, for example: + - `data-volume-devops-info-service-0` + - `data-volume-devops-info-service-1` + - `data-volume-devops-info-service-2` + +## 4. Network Identity + +The headless service was used to verify stable DNS records for each StatefulSet pod. + +### Commands used + +```bash +kubectl run dns-check --image=busybox:1.36 --restart=Never --command -- sleep 300 +``` + +```bash +kubectl wait --for=condition=Ready pod/dns-check --timeout=60s +``` + +```bash +kubectl exec dns-check -- nslookup devops-info-service-0.devops-info-service-headless.default.svc.cluster.local +``` + +```bash +kubectl exec dns-check -- nslookup devops-info-service-1.devops-info-service-headless.default.svc.cluster.local +``` + +```bash +kubectl exec dns-check -- nslookup devops-info-service-2.devops-info-service-headless.default.svc.cluster.local +``` + +```bash +kubectl delete pod dns-check +``` + +### Output + +```text +$ kubectl run dns-check --image=busybox:1.36 --restart=Never --command -- sleep 300 +pod/dns-check created + +$ kubectl wait --for=condition=Ready pod/dns-check --timeout=60s +pod/dns-check condition met + +$ kubectl exec dns-check -- nslookup devops-info-service-0.devops-info-service-headless.default.svc.cluster.local +Server: 10.96.0.10 +Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local + +Name: devops-info-service-0.devops-info-service-headless.default.svc.cluster.local +Address 1: 10.244.0.5 devops-info-service-0.devops-info-service-headless.default.svc.cluster.local + +$ kubectl exec dns-check -- nslookup devops-info-service-1.devops-info-service-headless.default.svc.cluster.local +Server: 10.96.0.10 +Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local + +Name: devops-info-service-1.devops-info-service-headless.default.svc.cluster.local +Address 1: 10.244.0.6 devops-info-service-1.devops-info-service-headless.default.svc.cluster.local + +$ kubectl exec dns-check -- nslookup devops-info-service-2.devops-info-service-headless.default.svc.cluster.local +Server: 10.96.0.10 +Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local + +Name: devops-info-service-2.devops-info-service-headless.default.svc.cluster.local +Address 1: 10.244.0.7 devops-info-service-2.devops-info-service-headless.default.svc.cluster.local + +$ kubectl delete pod dns-check +pod "dns-check" deleted +``` + +### Verification summary + +Successful DNS lookup confirms that StatefulSet pods have stable network identities through the headless service. + +## 5. Per-Pod Storage Evidence + +Each pod was accessed directly through a separate port-forward. This verifies that the replicas do not share the same visit counter file. + +### Port-forward commands + +Run these in separate terminals: + +```bash +kubectl port-forward pod/devops-info-service-0 8080:5000 +``` + +```bash +kubectl port-forward pod/devops-info-service-1 8081:5000 +``` + +```bash +kubectl port-forward pod/devops-info-service-2 8082:5000 +``` + +### Request commands + +```bash +curl http://127.0.0.1:8080/visits +curl http://127.0.0.1:8080/visits +``` + +```bash +curl http://127.0.0.1:8081/visits +``` + +```bash +curl http://127.0.0.1:8082/visits +curl http://127.0.0.1:8082/visits +curl http://127.0.0.1:8082/visits +``` + +### Counter verification commands + +```bash +kubectl exec devops-info-service-0 -- cat /data/visits +``` + +```bash +kubectl exec devops-info-service-1 -- cat /data/visits +``` + +```bash +kubectl exec devops-info-service-2 -- cat /data/visits +``` + +### Output + +```text +Terminal 1: +$ kubectl port-forward pod/devops-info-service-0 8080:5000 +Forwarding from 127.0.0.1:8080 -> 5000 +Forwarding from [::1]:8080 -> 5000 + +Terminal 2: +$ kubectl port-forward pod/devops-info-service-1 8081:5000 +Forwarding from 127.0.0.1:8081 -> 5000 +Forwarding from [::1]:8081 -> 5000 + +Terminal 3: +$ kubectl port-forward pod/devops-info-service-2 8082:5000 +Forwarding from 127.0.0.1:8082 -> 5000 +Forwarding from [::1]:8082 -> 5000 + +$ curl http://127.0.0.1:8080/visits +{"visits":1} +$ curl http://127.0.0.1:8080/visits +{"visits":2} + +$ curl http://127.0.0.1:8081/visits +{"visits":1} + +$ curl http://127.0.0.1:8082/visits +{"visits":1} +$ curl http://127.0.0.1:8082/visits +{"visits":2} +$ curl http://127.0.0.1:8082/visits +{"visits":3} + +$ kubectl exec devops-info-service-0 -- cat /data/visits +2 + +$ kubectl exec devops-info-service-1 -- cat /data/visits +1 + +$ kubectl exec devops-info-service-2 -- cat /data/visits +3 +``` + +### Verification summary + +Different counter values in `/data/visits` prove that every pod uses its own persistent volume. This confirms per-pod storage isolation. + +## 6. Persistence Test + +Persistence was tested by deleting one StatefulSet pod and checking that its data remained available after Kubernetes recreated it. + +### Commands used + +```bash +kubectl exec devops-info-service-0 -- cat /data/visits +``` + +```bash +kubectl delete pod devops-info-service-0 +``` + +```bash +kubectl rollout status statefulset/devops-info-service --timeout=180s +``` + +```bash +kubectl exec devops-info-service-0 -- cat /data/visits +``` + +### Output + +```text +$ kubectl exec devops-info-service-0 -- cat /data/visits +2 + +$ kubectl delete pod devops-info-service-0 +pod "devops-info-service-0" deleted + +$ kubectl rollout status statefulset/devops-info-service --timeout=180s +Waiting for 1 pods to be ready... +partitioned roll out complete: 3 new pods have been updated... + +$ kubectl get pod devops-info-service-0 -o wide +NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES +devops-info-service-0 1/1 Running 0 52s 10.244.0.8 minikube + +$ kubectl exec devops-info-service-0 -- cat /data/visits +2 +``` + +### Verification summary + +The expected result is that the value before and after deleting `devops-info-service-0` is the same. This proves that: + +- the pod was recreated with the same stable ordinal identity +- the existing PVC `data-volume-devops-info-service-0` was reused +- the `/data/visits` file persisted across pod deletion and recreation + +## 7. Cleanup Commands + +These commands can be used after the lab is checked: + +```bash +helm uninstall devops-info-service +``` + +```bash +kubectl delete pvc -l app.kubernetes.io/instance=devops-info-service +``` diff --git a/k8s/devops-info-service/templates/deployment.yaml b/k8s/devops-info-service/templates/deployment.yaml index 231e68b0dc..34941da9f7 100644 --- a/k8s/devops-info-service/templates/deployment.yaml +++ b/k8s/devops-info-service/templates/deployment.yaml @@ -1,4 +1,4 @@ -{{- if not .Values.rollout.enabled }} +{{- if and (not .Values.rollout.enabled) (not .Values.statefulset.enabled) }} apiVersion: apps/v1 kind: Deployment metadata: diff --git a/k8s/devops-info-service/templates/headless-service.yaml b/k8s/devops-info-service/templates/headless-service.yaml new file mode 100644 index 0000000000..f85f62aadb --- /dev/null +++ b/k8s/devops-info-service/templates/headless-service.yaml @@ -0,0 +1,18 @@ +{{- if .Values.statefulset.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "devops-info-service.fullname" . }}-headless + labels: + {{- include "devops-info-service.labels" . | nindent 4 }} + app.kubernetes.io/role: headless +spec: + clusterIP: None + selector: + {{- include "devops-info-service.selectorLabels" . | nindent 4 }} + ports: + - name: http + protocol: TCP + port: {{ .Values.service.port }} + targetPort: {{ .Values.service.targetPort }} +{{- end }} diff --git a/k8s/devops-info-service/templates/pvc.yaml b/k8s/devops-info-service/templates/pvc.yaml index 862717f000..b3e8a54d0c 100644 --- a/k8s/devops-info-service/templates/pvc.yaml +++ b/k8s/devops-info-service/templates/pvc.yaml @@ -1,4 +1,4 @@ -{{- if .Values.persistence.enabled }} +{{- if and .Values.persistence.enabled (not .Values.statefulset.enabled) }} apiVersion: v1 kind: PersistentVolumeClaim metadata: diff --git a/k8s/devops-info-service/templates/statefulset.yaml b/k8s/devops-info-service/templates/statefulset.yaml new file mode 100644 index 0000000000..081cc0bf9f --- /dev/null +++ b/k8s/devops-info-service/templates/statefulset.yaml @@ -0,0 +1,135 @@ +{{- if .Values.statefulset.enabled }} +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: {{ include "devops-info-service.fullname" . }} + labels: + {{- include "devops-info-service.labels" . | nindent 4 }} +spec: + serviceName: {{ include "devops-info-service.fullname" . }}-headless + replicas: {{ .Values.replicaCount }} + revisionHistoryLimit: {{ .Values.revisionHistoryLimit }} + selector: + matchLabels: + {{- include "devops-info-service.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + {{- include "devops-info-service.labels" . | nindent 8 }} + {{- if or .Values.podAnnotations .Values.vault.enabled }} + annotations: + {{- with .Values.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- if .Values.vault.enabled }} + vault.hashicorp.com/agent-inject: "true" + vault.hashicorp.com/role: {{ .Values.vault.role | quote }} + vault.hashicorp.com/auth-path: {{ .Values.vault.authPath | quote }} + vault.hashicorp.com/agent-inject-secret-app-config: {{ .Values.vault.secrets.appConfig.path | quote }} + vault.hashicorp.com/secret-volume-path-app-config: {{ .Values.vault.secrets.appConfig.mountPath | quote }} + vault.hashicorp.com/agent-inject-file-app-config: {{ .Values.vault.secrets.appConfig.fileName | quote }} + {{- if .Values.vault.service }} + vault.hashicorp.com/service: {{ .Values.vault.service | quote }} + {{- end }} + {{- end }} + {{- end }} + spec: + serviceAccountName: {{ include "devops-info-service.serviceAccountName" . }} + automountServiceAccountToken: true + securityContext: + seccompProfile: + type: RuntimeDefault + fsGroup: 10001 + containers: + - name: {{ .Chart.Name }} + image: "{{ required "image.repository is required" .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - name: http + containerPort: {{ .Values.containerPort }} + protocol: TCP + env: + - name: PORT + value: {{ .Values.env.port | quote }} + - name: DEBUG + value: {{ .Values.env.debug | quote }} + - name: APP_VARIANT + value: {{ .Values.env.appVariant | quote }} + - name: APP_MESSAGE + value: {{ .Values.env.appMessage | quote }} + - name: SERVICE_VERSION + value: {{ .Values.env.serviceVersion | quote }} + - name: VISITS_FILE + value: {{ .Values.env.visitsFile | quote }} + {{- if .Values.secrets.enabled }} + - name: APP_USERNAME + valueFrom: + secretKeyRef: + name: {{ include "devops-info-service.secretName" . }} + key: username + - name: APP_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "devops-info-service.secretName" . }} + key: password + {{- end }} + envFrom: + - configMapRef: + name: {{ include "devops-info-service.fullname" . }}-env + volumeMounts: + - name: config-volume + mountPath: {{ .Values.config.mountPath }} + readOnly: true + - name: data-volume + mountPath: {{ .Values.persistence.mountPath }} + resources: + {{- toYaml .Values.resources | nindent 12 }} + readinessProbe: + httpGet: + path: {{ .Values.readinessProbe.path }} + port: {{ .Values.readinessProbe.port }} + initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.readinessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }} + failureThreshold: {{ .Values.readinessProbe.failureThreshold }} + livenessProbe: + httpGet: + path: {{ .Values.livenessProbe.path }} + port: {{ .Values.livenessProbe.port }} + initialDelaySeconds: {{ .Values.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.livenessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.livenessProbe.timeoutSeconds }} + failureThreshold: {{ .Values.livenessProbe.failureThreshold }} + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + runAsNonRoot: true + runAsUser: 10001 + runAsGroup: 10001 + volumes: + - name: config-volume + configMap: + name: {{ include "devops-info-service.fullname" . }}-config + {{- if not .Values.persistence.enabled }} + - name: data-volume + emptyDir: {} + {{- end }} + {{- if .Values.persistence.enabled }} + volumeClaimTemplates: + - metadata: + name: data-volume + labels: + {{- include "devops-info-service.labels" . | nindent 10 }} + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: {{ .Values.persistence.size }} + {{- if .Values.persistence.storageClass }} + storageClassName: {{ .Values.persistence.storageClass | quote }} + {{- end }} + {{- end }} +{{- end }} diff --git a/k8s/devops-info-service/values.yaml b/k8s/devops-info-service/values.yaml index 3c58852c3d..e792a987a5 100644 --- a/k8s/devops-info-service/values.yaml +++ b/k8s/devops-info-service/values.yaml @@ -19,8 +19,11 @@ strategy: maxSurge: 1 maxUnavailable: 0 -rollout: +statefulset: enabled: true + +rollout: + enabled: false strategy: canary canary: maxSurge: 1 @@ -72,8 +75,8 @@ env: port: "5000" debug: "False" appVariant: app1 - appMessage: "Lab 14 progressive delivery deployment" - serviceVersion: "lab14-canary-v1" + appMessage: "Lab 15 StatefulSet with per-pod persistent storage" + serviceVersion: "lab15-statefulset-v1" visitsFile: "/data/visits" config: