Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 43 additions & 10 deletions .github/workflows/docker_build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,9 @@ on:
pull_request:
branches: [ master, united ]

# Builds images and pushes nothing, so read is all the token ever needs -- at the
# workflow level and again on the job, because a job may widen what the workflow grants
# but never the other way round.
permissions:
contents: read
packages: write

concurrency:
group: docker-build-${{ github.ref }}
Expand All @@ -21,13 +19,44 @@ jobs:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write # Appliqué aussi au niveau du job

steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
submodules: recursive
fetch-depth: 1
# 0 = full history + tags, required so `git describe` below can see
# the release tags (v21.9.29, ...). A shallow depth omits tags and
# `describe` would fall back to a bare short hash.
fetch-depth: 0

- name: Determine release version
id: version
# Same command GenRevision.cmake uses, so the image tag matches the
# revision string the compiled server reports at startup.
run: |
SHA="$(git rev-parse --short HEAD)"
# A tag on this exact commit wins outright -> e.g. "v22.04.245"
if VERSION="$(git describe --tags --exact-match 2>/dev/null)"; then
echo "Tagged release: ${VERSION}"
# master with no tag on the commit -> e.g. "master-4ff44ff1a"
elif [ "${{ github.ref }}" = "refs/heads/master" ]; then
VERSION="master-${SHA}"
echo "master build: ${VERSION}"
# any other branch -> e.g. "beta-4ff44ff1a"
else
VERSION="beta-${SHA}"
echo "non-master build: ${VERSION}"
fi
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"

- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
Expand All @@ -36,18 +65,22 @@ jobs:
uses: docker/build-push-action@v6
with:
context: .
file: extra/docker/DockerFile-mangosd
tags: mangosd:latest
push: false
file: extra/docker/mangosd.Dockerfile
tags: |
ghcr.io/${{ github.repository_owner }}/mangosd:latest
ghcr.io/${{ github.repository_owner }}/mangosd:${{ steps.version.outputs.version }}
push: ${{ github.ref == 'refs/heads/master' }}
cache-from: type=gha,scope=mangosd
cache-to: type=gha,scope=mangosd,mode=max

- name: Build realmd image
uses: docker/build-push-action@v6
with:
context: .
file: extra/docker/DockerFile-realmd
tags: realmd:latest
push: false
file: extra/docker/realmd.Dockerfile
tags: |
ghcr.io/${{ github.repository_owner }}/realmd:latest
ghcr.io/${{ github.repository_owner }}/realmd:${{ steps.version.outputs.version }}
push: ${{ github.ref == 'refs/heads/master' }}
cache-from: type=gha,scope=realmd
cache-to: type=gha,scope=realmd,mode=max
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,7 @@ docs/superpowers/
# "working tree is clean" guard fails on the cache rather than on a real change.
.ccache/
.sccache/

# Local docker environment overrides (may hold credentials); keep the example.
.env
!.env.example
64 changes: 64 additions & 0 deletions extra/docker/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Copy this file to ".env" (in this extra/docker folder) and adjust as needed.
# docker compose reads .env automatically; every value below is optional and
# falls back to the default shown if left unset.

################################################################################
# Image selection (docker-compose.yml only; ignored by the local build file)
################################################################################

# GitHub Container Registry owner the images were published under.
REGISTRY_OWNER=mangostwo
# Image tag to pull. Matches the docker_build.yml workflow output:
# a git tag (v22.04.245), master-<sha>, beta-<sha>, or latest.
MANGOS_TAG=latest

################################################################################
# Database connection used by mangosd / realmd
#
# On first start the entrypoint seeds mangosd.conf / realmd.conf from these
# values. If a .conf already exists in the mounted etc folder it is left
# untouched, so these are ignored once the files exist.
################################################################################

# Host of the MySQL server. Inside compose this is the "mysqldb" service name.
DB_HOST=mysqldb
DB_PORT=3306
# Credentials mangosd/realmd log in with. Defaulted to root because the bundled
# mysql image only grants full DB access to root (the mangos user has none).
DB_USER=root
DB_PASS=mangos
# Database (schema) names.
DB_REALMD=realmd
DB_WORLD=mangos2
DB_CHARS=character2

# Bring your own config: an existing mangosd.conf / realmd.conf in the mounted
# etc folder is ALWAYS left untouched. When true (default) a .conf is seeded
# from the template if none exists; set to false to disable seeding entirely
# (nothing generated even when no .conf is present).
INIT_ENV_CONFIG=true

################################################################################
# Bundled MySQL container
################################################################################

MYSQL_USER=mangos
MYSQL_PASSWORD=mangos
MYSQL_ROOT_PASSWORD=mangos
# Host mask the root account may connect from. "%" = any host, required so the
# mangosd/realmd containers can reach it over the compose network.
MYSQL_ROOT_HOST=%

################################################################################
# Public address players connect to (NOT set here — see note)
#
# The address the game client connects to is stored in the realmd database, in
# the `realmlist` table's `address` column, NOT in any .conf file or env var.
# After the databases are initialised, set it manually, e.g.:
#
# UPDATE realmd.realmlist SET address = '203.0.113.10' WHERE id = 1;
#
# Use the server's public IP or DNS name (127.0.0.1 only works for a client on
# the same machine). realmd's BindIP in the conf stays 0.0.0.0 (listen on all
# interfaces) and does not need changing for containers.
################################################################################
158 changes: 158 additions & 0 deletions extra/docker/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
# Running MangosTwo with Docker

This folder contains everything needed to run the world server (`mangosd`) and
login server (`realmd`) in containers, backed by a MySQL container.

There are two compose files:

| File | Use |
| --------------------------- | -------------------------------------------------------------- |
| `docker-compose.yml` | Pull prebuilt images from GitHub Container Registry (default). |
| `docker-compose.build.yml` | Build the images locally from the Dockerfiles here. |

`docker-compose.build.yml` is an *override* layered on top of the base file.

## 1. Configure

Copy the example environment file and edit it:

```sh
cp .env.example .env
```

`docker compose` reads `.env` automatically. Every value is optional and falls
back to a sensible default; see `.env.example` for the full list. The common
ones:

- `REGISTRY_OWNER` / `MANGOS_TAG` — which image and tag to pull (registry mode).
- `DB_HOST`, `DB_PORT`, `DB_USER`, `DB_PASS`, `DB_REALMD`, `DB_WORLD`, `DB_CHARS`
— the database connection the servers use.
- `MYSQL_USER`, `MYSQL_PASSWORD`, `MYSQL_ROOT_PASSWORD`, `MYSQL_ROOT_HOST`
— the bundled MySQL container.
- `INIT_ENV_CONFIG` — whether the entrypoint seeds a `.conf` from the template
when none exists (default `true`; see "Bringing your own configuration").

### Config files are generated for you

On first start each container seeds its config from the shipped template:

- If `mangosd.conf` / `realmd.conf` does **not** exist in the mounted `etc`
folder, it is created from the `.conf.dist` and the database connection lines
are filled in from the `DB_*` variables above.
- If the `.conf` already exists, it is left untouched — edit it by hand for
anything the environment variables do not cover.

### Bringing your own configuration

Mount your own `mangosd.conf` / `realmd.conf` into `/mangos/etc` and the
entrypoint will detect it and run it as-is, without generating or rewriting
anything. To turn off seeding altogether (even when no `.conf` is present, e.g.
you supply it another way or override the command), set
`INIT_ENV_CONFIG=false`.

The config folder is bind-mounted from the repository:

- configuration: `./etc` → `/mangos/etc`

This path can be changed in `docker-compose.yml`. There is no separate data
volume — client data (`tiles`, `gomodels`, `dbc`) is placed under this same
mounted `etc` folder; see "Extract and add the client data" below. Inside
`mangosd.conf`, `DataDir` should point at wherever you place it under
`/mangos/etc`.

## 2. Initialise the databases

The MySQL data is stored in `../../dbdata`. The game databases must be created
and populated once before the servers will run — see the `mangostwo/database`
repository for the schema and migrations. The `mysqldb` service must be running
for this step; start just that service with:

```sh
docker compose up mysqldb
```

For the SQL import itself, follow the "Import the databases" section of the
official installation guide:

<https://www.getmangos.eu/wiki/documentation/installation-guides/guideslinux/installing-mangos-on-ubuntu-server-2204-r40014/>

Point the `mysql` client at the container instead of a local install, e.g.
`mysql -h 127.0.0.1 -P 3306 -u root -p`, using the `DB_*` / `MYSQL_*` values
from your `.env`.

## 3. Extract and add the client data

Run the extractor (`mangos-extractor`, built from `src/tools/extractor`) against
your client install to produce `tiles`, `gomodels` and `dbc`, then copy the
result into `./etc` (the folder bind-mounted to `/mangos/etc`) so the
container can see it. Set `DataDir` in `mangosd.conf` to match wherever you
place it under `/mangos/etc`.

## 4. Set the public address players connect to

The address the game **client** connects to is stored in the database, not in a
config file. After the databases are initialised, point the realm at your
public IP or DNS name:

```sql
UPDATE realmd.realmlist SET address = '203.0.113.10' WHERE id = 1;
```

`127.0.0.1` only works for a client on the same machine. `realmd`'s `BindIP`
stays `0.0.0.0` (listen on all interfaces) and does not need changing.

## Ports

- `8085` — world server (`mangosd`)
- `3724` — login server (`realmd`)
- `3306` — MySQL

## 6. Start

Registry images (default):

```sh
docker compose pull
docker compose up -d # Detach version
# or
docker compose up
```

Build locally instead:

```sh
docker compose -f docker-compose.yml -f docker-compose.build.yml up --build
```


## Attaching to the mangosd console

`mangosd` runs as the container's foreground process and reads commands from
stdin, so you can attach to it for interactive console access.

Find the container ID (or name) with:

```sh
docker compose ps
```

or, from anywhere, `docker ps` and look for the `mangosd` image/service. Then
attach to it:

```sh
docker attach <containerID>
```

**Detach with `Ctrl+P` then `Ctrl+Q`, not `Ctrl+C`.** `Ctrl+C` sends `SIGINT` to
`mangosd` inside the container and shuts the server down; the detach sequence
leaves the process running and just returns you to your shell.

## Kubernetes / other orchestrators

The entrypoint is baked into the image and behaves well outside compose:

- Mount your own `mangosd.conf` / `realmd.conf` and the entrypoint leaves it
alone (it only seeds when absent).
- Override the command entirely and it is `exec`'d verbatim, e.g.
`command: ["/usr/local/bin/docker-entrypoint.sh", "mangosd"]` with your own
`args`.
20 changes: 0 additions & 20 deletions extra/docker/Readme.txt

This file was deleted.

16 changes: 16 additions & 0 deletions extra/docker/docker-compose.build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Builds the server images locally from the Dockerfiles in this folder.
# docker compose -f docker-compose.yml -f docker-compose.build.yml up --build
# Configure the location of the configuration file and the data folder.
# The connection to mysql should match the name of the service, here "mysqldb".
services:
mangosd:
build:
# Context is the repository root: the Dockerfile compiles the full source
# tree (COPY . /mangoserver) and copies extra/docker/docker-entrypoint.sh.
context: ../..
dockerfile: extra/docker/mangosd.Dockerfile

realmd:
build:
context: ../..
dockerfile: extra/docker/realmd.Dockerfile
Loading
Loading