The previous post explains how to get up and running with Docker machine. This one will be a quick tutorial on setting up a Minecraft server using Machine.
Create a new Digital Ocean Machine. We need a 1gb
server
due to Java’s requirements, so we’ll specify the 1gb DO
variant:
> machine-docker create -d digitalocean --digitalocean-access-token=$DO_TOKEN --digitalocean-size=1gbbiscarch-minecraft INFO[0000] Creating SSH key... INFO[0000] CreatingDigital Ocean droplet... INFO[0003] Waiting for SSH... INFO[0155]"biscarch-minecraft" has been created and is now the activemachine. To point Docker at this machine, run: exportDOCKER_HOST=$(machine url) DOCKER_AUTH=identity
Run the command suggested to activate the Digital Ocean machine. Remember that we re-named our binaries, so our command will look slightly different:
export DOCKER_HOST=$(machine-docker url) DOCKER_AUTH=identity
After creating the machine, we can run a Minecraft server. Notice that we’ve accepted the EULA using an environment variable.
> machine-docker-1.3.1-dev-identity-auth run -itp 25565:25565 -e EULA=true itzg/minecraft-serverThe authenticity of host "$ip:2376" can't be established.Remote key ID XXXXAre you sure you want to continue connecting (yes/no)? yesUnable to find image 'itzg/minecraft-server:latest' locallyPulling repository itzg/minecraft-servercf3280236048: Download complete511136ea3c5a: Download complete97fd97495e49: Download complete2dcbbf65536c: Download complete6a459d727ebb: Download complete8f321fc43180: Download complete03db2b23cf03: Download complete9cbaf023786c: Download completec40e36cb3ec9: Download complete894f65ff66bd: Download completee82301eb9615: Download complete1dbf91539513: Download completee545342bf796: Download complete59bc57df4d1e: Download complete553afa5133d9: Download complete75c3ad818b79: Download complete0b0acc66bc64: Download complete978ce1e3b993: Download complete54fead2b8d41: Download complete2bb3b9314ae2: Download completeaf46a2317b29: Download complete0b1b3214a72a: Download completec68e5b97cc3f: Download completef08ca66bb473: Download complete36a596d541f4: Download complete5c1156fb886b: Download complete59349c103e38: Download complete1d5073dd8949: Download complete250469004d09: Download complete78a77d27bdfa: Download completeStatus: Downloaded newer image for itzg/minecraft-server:latest--2014-12-27 06:06:21-- https://s3.amazonaws.com/Minecraft.Download/versions/versions.jsonResolving s3.amazonaws.com (s3.amazonaws.com)... 54.231.244.4Connecting to s3.amazonaws.com (s3.amazonaws.com)|54.231.244.4|:443... connected.HTTP request sent, awaiting response... 200 OKLength: 20681 (20K) [application/octet-stream]Saving to: 'STDOUT'100%[====================================================================================>] 20,681 --.-K/s in 0.1s2014-12-27 06:06:22 (149 KB/s) - written to stdout [20681/20681]Downloading minecraft_server.1.8.1.jar ...[06:06:33] [Server thread/INFO]: Starting minecraft server version 1.8.1[06:06:33] [Server thread/INFO]: Loading properties[06:06:33] [Server thread/INFO]: Default game type: SURVIVAL[06:06:33] [Server thread/INFO]: Generating keypair[06:06:33] [Server thread/INFO]: Starting Minecraft server on *:25565[06:06:33] [Server thread/INFO]: Using epoll channel type[06:06:34] [Server thread/WARN]: Failed to load user banlist:java.io.FileNotFoundException: banned-players.json (No such file or directory)at java.io.FileInputStream.open(Native Method) ~[?:1.7.0_65]at java.io.FileInputStream.<init>(FileInputStream.java:146) ~[?:1.7.0_65]at com.google.common.io.Files.newReader(Files.java:86) ~[minecraft_server.1.8.1.jar:?]at su.g(SourceFile:124) ~[minecraft_server.1.8.1.jar:?]at po.z(SourceFile:99) [minecraft_server.1.8.1.jar:?]at po.<init>(SourceFile:25) [minecraft_server.1.8.1.jar:?]at pp.i(SourceFile:172) [minecraft_server.1.8.1.jar:?]at net.minecraft.server.MinecraftServer.run(SourceFile:418) [minecraft_server.1.8.1.jar:?]at java.lang.Thread.run(Thread.java:745) [?:1.7.0_65][06:06:34] [Server thread/WARN]: Failed to load ip banlist:java.io.FileNotFoundException: banned-ips.json (No such file or directory)at java.io.FileInputStream.open(Native Method) ~[?:1.7.0_65]at java.io.FileInputStream.<init>(FileInputStream.java:146) ~[?:1.7.0_65]at com.google.common.io.Files.newReader(Files.java:86) ~[minecraft_server.1.8.1.jar:?]at su.g(SourceFile:124) ~[minecraft_server.1.8.1.jar:?]at po.y(SourceFile:91) [minecraft_server.1.8.1.jar:?]at po.<init>(SourceFile:27) [minecraft_server.1.8.1.jar:?]at pp.i(SourceFile:172) [minecraft_server.1.8.1.jar:?]at net.minecraft.server.MinecraftServer.run(SourceFile:418) [minecraft_server.1.8.1.jar:?]at java.lang.Thread.run(Thread.java:745) [?:1.7.0_65][06:06:34] [Server thread/WARN]: Failed to load operators list:java.io.FileNotFoundException: ops.json (No such file or directory)at java.io.FileInputStream.open(Native Method) ~[?:1.7.0_65]at java.io.FileInputStream.<init>(FileInputStream.java:146) ~[?:1.7.0_65]at com.google.common.io.Files.newReader(Files.java:86) ~[minecraft_server.1.8.1.jar:?]at su.g(SourceFile:124) ~[minecraft_server.1.8.1.jar:?]at po.A(SourceFile:107) [minecraft_server.1.8.1.jar:?]at po.<init>(SourceFile:29) [minecraft_server.1.8.1.jar:?]at pp.i(SourceFile:172) [minecraft_server.1.8.1.jar:?]at net.minecraft.server.MinecraftServer.run(SourceFile:418) [minecraft_server.1.8.1.jar:?]at java.lang.Thread.run(Thread.java:745) [?:1.7.0_65][06:06:34] [Server thread/WARN]: Failed to load white-list:java.io.FileNotFoundException: whitelist.json (No such file or directory)at java.io.FileInputStream.open(Native Method) ~[?:1.7.0_65]at java.io.FileInputStream.<init>(FileInputStream.java:146) ~[?:1.7.0_65]at com.google.common.io.Files.newReader(Files.java:86) ~[minecraft_server.1.8.1.jar:?]at su.g(SourceFile:124) ~[minecraft_server.1.8.1.jar:?]at po.C(SourceFile:123) [minecraft_server.1.8.1.jar:?]at po.<init>(SourceFile:30) [minecraft_server.1.8.1.jar:?]at pp.i(SourceFile:172) [minecraft_server.1.8.1.jar:?]at net.minecraft.server.MinecraftServer.run(SourceFile:418) [minecraft_server.1.8.1.jar:?]at java.lang.Thread.run(Thread.java:745) [?:1.7.0_65][06:06:34] [Server thread/INFO]: Preparing level "world"[06:06:34] [Server thread/INFO]: Preparing start region for level 0[06:06:35] [Server thread/INFO]: Preparing spawn area: 4%[06:06:36] [Server thread/INFO]: Preparing spawn area: 7%[06:06:37] [Server thread/INFO]: Preparing spawn area: 9%[06:06:38] [Server thread/INFO]: Preparing spawn area: 11%[06:06:39] [Server thread/INFO]: Preparing spawn area: 15%[06:06:40] [Server thread/INFO]: Preparing spawn area: 17%[06:06:41] [Server thread/INFO]: Preparing spawn area: 20%[06:06:42] [Server thread/INFO]: Preparing spawn area: 29%[06:06:43] [Server thread/INFO]: Preparing spawn area: 40%[06:06:44] [Server thread/INFO]: Preparing spawn area: 55%[06:06:46] [Server thread/INFO]: Preparing spawn area: 70%[06:06:47] [Server thread/INFO]: Preparing spawn area: 82%[06:06:48] [Server thread/INFO]: Preparing spawn area: 95%[06:06:48] [Server thread/INFO]: Done (14.248s)! For help, type "help" or "?"
If we ignore the files that we didn’t create for things like the banned players list, that’s all we have to do to run the server! Launch Minecraft and select Multiplayer:
To get the server address, run machine-docker url
.
> machine-docker urltcp://nnn.nnn.nn.nn:2376
After clicking done
, we should see our server:
After clicking play the server, we get a nice new world!
Spawning servers is cool, but how do we keep the data around after the container is killed?
Let’s take a look inside a running Minecraft container.
> machine-docker-1.3.1-dev-identity-auth psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES94cf3f854fd8 itzg/minecraft-server:latest "/start-minecraft" About a minute ago Up About a minute 0.0.0.0:25565->25565/tcp sad_pare> machine-docker-1.3.1-dev-identity-auth exec -it 94c bash>> minecraft@94cf3f854fd8:/data$ lsbanned-ips.json banned-players.json eula.txt logs minecraft_server.1.8.1.jar ops.json server.properties usercache.json whitelist.json world
kill
the old server (we ran it using -it
so Control-C
should kill it. If you chose to run it with -d
, just use
machine-docker-1.3.1-dev-identity-auth ps
and
machine-docker-1.3.1-dev-identity-auth kill $container_id
After killing the server, we will get kicked from the game:
We can see that there were quite a few files in the /data
directory. We’re going to mount a volume there using
/opt/craft
on the host.
Notice that we’ve also set the Message of the Day (MOTD).
machine-docker-1.3.1-dev-identity-auth run -dp 25565:25565 -e EULA=true -e 'MOTD=Crafty Crafting!' -v /opt/craft:/data itzg/minecraft-server
Let’s ssh in to the Digital Ocean host and see if we have any files:
> machine-docker sshroot@docker:~# ls /opt/craft/banned-ips.json banned-players.json eula.txt logs minecraft_server.1.8.1.jar ops.json server.properties usercache.json whitelist.json world
Voila! We have a bunch of files. Now we reconnect to the server (using the Minecraft app) and spend some time doing something (say, chopping down a tree). After that, kill the server as before. The files will stay on the Digital Ocean machine, so we can just restart the server using the same volume mount:
machine-docker-1.3.1-dev-identity-auth run -dp 25565:25565 -e EULA=true -e 'MOTD=Crafty Crafting!' -v /opt/craft:/data itzg/minecraft-server
And look at that, we’ve still cutting down our tree! The server was saved!
Now we’ll re-run our server with a level seed. It should be
added to /opt/craft/server.properties
and we can do that
through ssh and vi:
> machine-docker ssh biscarch/minecraftroot@docker:~# vi /opt/craft/server.properties
server.properties looks something like this (we’ve just
changed the level-seed
)
root@docker:~# cat /opt/craft/server.properties#Minecraft server properties#Sat Dec 27 10:00:14 UTC 2014spawn-protection=16max-tick-time=60000generator-settings=force-gamemode=falseallow-nether=truegamemode=0enable-query=falseplayer-idle-timeout=0difficulty=1spawn-monsters=trueop-permission-level=4resource-pack-hash=announce-player-achievements=truepvp=truesnooper-enabled=truelevel-type=DEFAULThardcore=falseenable-command-block=falsemax-players=20network-compression-threshold=256max-world-size=29999984server-port=25565texture-pack=server-ip=spawn-npcs=trueallow-flight=falselevel-name=worldview-distance=10resource-pack=spawn-animals=truewhite-list=falsegenerate-structures=trueonline-mode=truemax-build-height=256level-seed=1785852800490497919use-native-transport=trueenable-rcon=falsemotd=Crafty Crafting!
Now we should be able to blow away /opt/craft/world
(if it
exists in the container) and our world will get rebuilt:
rm -rf /opt/craft/world
run the server with the volume attached:
machine-docker-1.3.1-dev-identity-auth run -dp 25565:25565 -e EULA=true -e 'MOTD=Crafty Crafting!' -v /opt/craft:/data itzg/minecraft-server
After starting the server with the new seed, just play the server as before (it should still be listed). Turn around and you should see:
We can use docker machine to ssh into the server and edit
/opt/craft/server.properties
, which holds
a bunch of data
we may want to edit. Then just restart the container :)
Happy Crafting!