Last time, I said that in the next entry in this series I would do something fun (and likely impractical) with kubernetes. I lied; sorry. Since then, I received several great questions that I didn’t manage to cover, so I thought that I’d address a couple of them now. This entry will be rather piecemeal, but hopefully much shorter than the prior ones!

Customizing the server.properties file

The start of accidental PVP harm

Minecraft uses a simple configuration file to store many of its default settings. This is called the server.properties file. Let’s take a look at the one running in our Docker container:

ftb-server $ sudo docker exec -ti <container name> /bin/bash
root@baea2dfbd18f:/opt/ftb# more server.properties
#Minecraft server properties
< snip! >
server-port=25565
level-type=DEFAULT
enable-rcon=false
level-seed=
force-gamemode=false
server-ip=
max-build-height=256
spawn-npcs=true
white-list=false
spawn-animals=true
hardcore=false
snooper-enabled=true
online-mode=true
resource-pack=
pvp=true
difficulty=1
< snip! >

We can see some pretty interesting settings in there. Some have to do with gameplay (e.g. difficulty), and some have to do with server management (e.g. server-port). What if we want to change it up a bit? That configuration file came from the zip file that we unpacked in our Dockerfile. We have a few different options:

  • Make the change in the running container
  • Update the Dockerfile
  • Pull in the server.properties file when running the container

The first option is going to be our winner. What we really want is to modify the config file, and have that change persist in the image. We already have a command prompt inside the container, so let’s modify the server.properties file such that the difficulty is normal, and different players on the server can’t kill each other:

pvp=false
difficulty=2
root@baea2dfbd18f:/opt/ftb# echo "<full modified content of server.properties>" \
                                 > server.properties

Now, we need to exit the container and commit the changes with a message and author:

root@baea2dfbd18f:/opt/ftb# exit
ftb-server $ sudo docker commit -m "customized the server.properties" \
                                -a "Jane Doe" \
                                 <container id> <docker user>/ftb:v2

You can verify that the image has been updated by listing all the images:

ftb-server $ sudo docker images
REPOSITORY            TAG     IMAGE ID        CREATED         VIRTUAL SIZE
<docker user>/ftb     v2      9ead6660604b    7 seconds ago   1.013 GB

Great! Now the different players on the server can’t kill each other. But if we start another server with the image in the registry, `pvp` will become true again. How do we persist it?

Once we have the change committed, we push the changes to Google Container Registry so that we can pull them down onto new servers:

ftb-server $ sudo docker tag <docker user>/ftb:v2 gcr.io/<project id>/ftb-v2
ftb-server $ sudo gcloud docker push gcr.io/<project id>/ftb-v2

We’re done! If we want to test it, we just start a new container like we have before, using this updated image (make sure to stop the old one, since we’re using the same port mapping for both).

Creeping up on a Creeper

However, we should be asking some questions about our updated image. What does it actually include? And didn’t we commit all of the progress we’ve made in the game?

The image now contains all changes to the container we committed. That includes the changes we made to server.properties, as well as all the extracted files that the Minecraft server requires to run. It does not mean that the world files have been committed for one simple reason: our world is stored on a data volume, and data volumes are exempt when you commit a container.

Pricing out the Minecraft server

One of the most common questions about running a Minecraft server is that of cost. How much is it going to set us back? Unfortunately, answering that question is not as straightforward as if we’d bought physical hardware to use as a server. Still, while our monthly bill will depend on a number of factors, we can get a rough estimate.

I run my server for just a few people, and shut it down when we’re not playing (though anyone can start it for a little solitary game time). Both of these factors keep my costs down. In fact, my costs are so low that I’ve gotten bills for approximately $0.05 on more than one occasion. Here’s a more typical monthly bill for me, from March 2015:

Network Internet Egress:        1982.657    Mebibytes       $0.23   $0.23
Standard Intel N1 1 VCPU:       2990        Minutes         $3.14   $3.37
Storage Pd Capacity:            7430        Gibibyte-hours  $0.40   $3.77
Storage Pd Snapshot:            2192.33     Gibibyte-hours  $0.08   $3.85
Storage:                        167.94      Gibibyte-hours  $0.01   $3.86
Sales tax (on $3.37)                                        $0.32   $4.18
"Totals for Mar 1, 2015 - Mar 31, 2015"                     $4.18   $4.18

As you can see, I’m running an n1-standard1 instance, and I played for almost 50 hours that month. This was after the point that I started taking semi-regular snapshots, which accounts for a fraction of the total bill. However, my usage isn’t necessarily representative of everyone’s, which is why there are tools to help us estimate cost. To get a really detailed estimate of costs, we can use the pricing calculator.

Or, we can make a rough estimate by looking at the big ticket items (in our case, the virtual machine) to understand what our pricing options are. If our n1-standard1 runs for more than 25% of the month, we can take advantage of a sustained use discount. The discount starts at 20% and goes up the more we use the instance. If we run the instance for an entire month, the hourly price is discounted by 30%.

If this is our first time using Google Compute Engine, then we can use the free trial, which gives us $300 to spend over the course of 60 days – and that’s a lot of Minecraft!

Next time

Interlude over, now back to our regularly scheduled programming. We’ll tackle Minecraft, Kubernetes, and absurdity in the conclusion (?!) to this series.

You can see the files we used in this blog entry on GitHub.