Here I explain how to run Minecraft Java server on Azure Container Instance.
You need container deployment configuraiton yaml file called server-env.yaml. In this file you define how to deploy container instance. For example:
apiVersion: 2023-05-01
location: swedencentral
name: minecraft
properties:
containers:
- name: minecraft
properties:
environmentVariables:
- name: 'EULA'
value: 'TRUE'
- name: 'DIFFICULTY'
value: 'easy'
- name: 'GAMEMODE'
value: 'survival'
- name: 'HARDCORE'
value: 'false'
image: itzg/minecraft-server
volumeMounts:
- mountPath: /data
name: filesharevolume
ports:
- port: 25565
protocol: TCP
resources:
requests:
cpu: 1.0
memoryInGB: 1.5
ipAddress:
type: Public
ports:
- protocol: tcp
port: '25565'
dnsNameLabel: minecraft
autoGeneratedDomainNameLabelScope: TenantReuse
osType: Linux
restartPolicy: OnFailure
volumes:
- name: filesharevolume
azureFile:
sharename: minecraftdata
storageAccountName: stminecraftcontainerdata
storageAccountKey: #{storagekey}#
tags: null
type: Microsoft.ContainerInstance/containerGroups
You can test deploying container with the following command. NOTE! In the above example the storageAccountKey needs to be configured if testing manually. In this exmaple it is tokenized and Azure DevOps pipeline uses Token Replace task to configure it from secret varable during the pipeline run.
az container create --resource-group rg-minecraft-container --file server-env.yaml
You can create Azure DevOps CI/CD pipeline for deploying and managing Azure Container Instance.
First of all the trigger is defined to be none, because we want to manually tell what operation we want to do with the pipeline.
For example you decide to play Minecraft server with friends only 2 hours today, you can create new container for the server and destroy it after the gaming session.
This way you keep costs to a minimumm.
With parametes you can define what options you have for operations.
Deployment uses external yaml configuration file server-env.yaml and secret values are tokenized.
This means that you can store for example storage account key secret with secret value variable and grab it during the pipeline run and replace with template token.
You can also integrate Azure Key Vault to Azure DevOps library variables.
Then there is just different Azure CLI commands for operations. Operations could be also done with statefull Terrafomr IaC tool, but in this simple example I decided just to create and destroy without worrying about the configuraitons. Those are still in the version control.
If container will be destroyed, the persisten server data still exists in the Azure storage accoount file share as difined in the container volume configuration. And when recreating the container, it reads the same data and you can continue your game where you left off.
Here is example how I can create, start, stop, destroy and check status of container instance.
Pipeline run looks like this:
Example of azure-pipeline.yaml file:
trigger: none
pr: none
parameters:
- name: operation
type: string
default: start
values:
- create
- start
- stop
- destroy
- status
variables:
- group: Minecraft
pool:
vmImage: ubuntu-latest
jobs:
- job: containerjob
displayName: Operating Container
steps:
- checkout: self
- task: replacetokens@5
inputs:
rootDirectory: 'container'
targetFiles: '**/*.yaml'
encoding: 'auto'
tokenPattern: 'default'
writeBOM: true
actionOnMissing: 'warn'
keepToken: false
actionOnNoFiles: 'continue'
enableTransforms: false
enableRecursion: false
useLegacyPattern: false
enableTelemetry: true
tokenPrefix: '#{'
tokenSuffix: '}#'
- task: AzureCLI@2
displayName: running operation for container
inputs:
azureSubscription: 'TuomasAzureSub'
scriptType: 'pscore'
scriptLocation: 'inlineScript'
${{ if eq(parameters.operation, 'create') }}:
inlineScript: |
az container create --resource-group rg-minecraft-container --file container/server-env.yaml
echo "Minecraft server address: $(az container show --resource-group rg-minecraft-container --name minecraft |jq -r '.ipAddress.fqdn'):$(az container show --resource-group rg-minecraft-container --name minecraft |jq '.ipAddress.ports[].port')"
${{ if eq(parameters.operation, 'start') }}:
inlineScript: |
az container start --resource-group rg-minecraft-container --name minecraft
echo "Minecraft server address: $(az container show --resource-group rg-minecraft-container --name minecraft |jq -r '.ipAddress.fqdn'):$(az container show --resource-group rg-minecraft-container --name minecraft |jq '.ipAddress.ports[].port')"
${{ if eq(parameters.operation, 'stop') }}:
inlineScript: |
az container stop --resource-group rg-minecraft-container --name minecraft
${{ if eq(parameters.operation, 'destroy') }}:
inlineScript: |
az container delete --resource-group rg-minecraft-container --name minecraft --yes
${{ if eq(parameters.operation, 'status') }}:
inlineScript: |
az container logs --resource-group rg-minecraft-container --name minecraft
echo "Minecraft server address: $(az container show --resource-group rg-minecraft-container --name minecraft |jq -r '.ipAddress.fqdn'):$(az container show --resource-group rg-minecraft-container --name minecraft |jq '.ipAddress.ports[].port')"
With Azure Container Instance, you can simply run, for example, a Java server at a very low cost.
When you need a server you spin it up or create it and when you don't need it you can destroy it.
You only pay for the CPU seconds you use.
The only permanent expences are coming from the file share files of the server data.
There are many advantages of using containers. For example, if you used a virtual machine to run same Java server, you should install the server and update the OS.
You should configure linux/windows services to restart Java server during the reboot and manage persistent data files inside the server.
With virtual machines you can easily shut it down and start, but with containers it is as easy to just destroy and recreate.
Every time you spin up the container you can define how much it can take CPU and memory.
Scaling up of the virtual machine is slower and harder.
Running virtual machines are more expensive, at least if you need a Windows license.
If you do not need statefull deployment, for example, playing new server world some hours and never come back to same map, you can forget the Azure storage account, file share and volume mapping.
Then deployment is even simplier and you do not need to pay storage costs.
This example covers only simple single container deployment.
If you need scalable environment, you need application gateway and load balancer with virtual networking.
Or if you need more complex microservice architecture I recommend to check Azure Kubernetes Services (AKS).