Como orquestrar os serviços do seu servidor de MU Online com Docker Compose
Containerize e orquestre ConnectServer, JoinServer, GameServer, banco de dados e web com Docker Compose, com exemplos de docker-compose.yml, redes internas, volumes persistentes e boas práticas de produção.
Servidores de MU Online tradicionalmente rodam como uma coleção de processos soltos em uma máquina Windows: ConnectServer, JoinServer, GameServer, banco de dados e, às vezes, um painel web separado. Isso funciona, mas dificulta backups consistentes, atualizações sem downtime e replicação do ambiente
Servidores de MU Online tradicionalmente rodam como uma coleção de processos soltos em uma máquina Windows: ConnectServer, JoinServer, GameServer, banco de dados e, às vezes, um painel web separado. Isso funciona, mas dificulta backups consistentes, atualizações sem downtime e replicação do ambiente em outra máquina. Docker Compose resolve esse problema orquestrando todos esses serviços como containers definidos em um único arquivo declarativo, com redes internas isoladas e volumes persistentes. Este tutorial mostra como estruturar essa orquestração na prática, com exemplos de configuração e cuidados específicos para a stack de um servidor de MU.
Por que containerizar um servidor de MU Online
Containerizar traz três ganhos concretos: (1) reprodutibilidade — o ambiente inteiro (versões de banco, dependências) fica descrito em arquivo, não na memória de quem configurou a máquina originalmente; (2) isolamento — um problema no banco de dados não derruba o GameServer, e vice-versa; (3) portabilidade — mover o servidor inteiro para outra máquina ou provedor se resume a copiar os arquivos de configuração e os volumes de dados.
Visão geral da arquitetura de serviços
| Serviço | Função | Depende de |
|---|---|---|
db | Banco de dados (MSSQL/MySQL) com contas e personagens | — |
connectserver | Ponto de entrada do cliente, lista de servidores | db |
joinserver | Autenticação e roteamento para o GameServer | db, connectserver |
gameserver | Lógica principal do jogo | db, joinserver |
web | Painel/site (cadastro, ranking, loja) | db |
Estrutura de diretórios recomendada
mu-infra/
├── docker-compose.yml
├── .env
├── db/
│ └── init/ # scripts de inicialização do schema
├── connectserver/
│ └── Data/
├── gameserver/
│ └── Data/
└── web/
└── (código do painel)
Manter cada serviço em sua própria pasta com um volume dedicado facilita tanto o backup individual quanto a substituição isolada de um componente.
Exemplo de docker-compose.yml
version: "3.9"
services:
db:
image: mysql:8.0
container_name: mu_db
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
MYSQL_DATABASE: mu_online
volumes:
- db_data:/var/lib/mysql
- ./db/init:/docker-entrypoint-initdb.d
networks:
- mu_internal
connectserver:
build: ./connectserver
container_name: mu_connectserver
restart: unless-stopped
depends_on:
- db
ports:
- "44405:44405"
networks:
- mu_internal
gameserver:
build: ./gameserver
container_name: mu_gameserver
restart: unless-stopped
depends_on:
- db
- connectserver
ports:
- "55901:55901"
volumes:
- ./gameserver/Data:/app/Data
networks:
- mu_internal
web:
build: ./web
container_name: mu_web
restart: unless-stopped
depends_on:
- db
ports:
- "8080:80"
networks:
- mu_internal
networks:
mu_internal:
driver: bridge
volumes:
db_data:
Variáveis de ambiente e o arquivo .env
Nunca deixe senhas de banco ou tokens hardcoded no docker-compose.yml. Centralize em um arquivo .env na raiz do projeto:
DB_ROOT_PASSWORD=troque-esta-senha
DB_USER=mu_app
DB_PASSWORD=outra-senha-forte
GAMESERVER_PORT=55901
O Compose lê automaticamente o .env na mesma pasta e substitui as variáveis ${...} referenciadas no YAML.
Redes internas e exposição de portas
Todos os serviços compartilham a rede mu_internal, o que permite que se comuniquem entre si pelo nome do serviço (por exemplo, o GameServer acessa o banco via host db, não localhost). Apenas as portas realmente necessárias ao cliente do jogo e ao painel web devem ser mapeadas para o host com ports: — o banco de dados não deve ter porta exposta externamente em produção, apenas acessível pela rede interna do Compose.
Persistência de dados com volumes
O volume nomeado db_data garante que o conteúdo do banco sobreviva a recriações do container (docker compose down seguido de up). Já os volumes de bind mount (como ./gameserver/Data:/app/Data) permitem editar arquivos de configuração do GameServer diretamente do host, sem precisar entrar no container — essencial para ajustes rápidos de drop rate, experiência e eventos.
Rotina de backup do banco de dados
Adicione um serviço auxiliar de backup agendado, ou rode externamente via cron um comando como:
docker exec mu_db mysqldump -u root -p"$DB_ROOT_PASSWORD" mu_online > backups/mu_online_$(date +%Y%m%d_%H%M).sql
Automatize isso com um cron no host (ou um container dedicado com cron + o mesmo comando) e mantenha uma política de retenção — por exemplo, backups diários dos últimos 14 dias e semanais dos últimos 3 meses.
Atualizando serviços sem downtime total
Para atualizar apenas o painel web, por exemplo, sem afetar o GameServer:
docker compose build web
docker compose up -d --no-deps web
Isso rebuilda e reinicia apenas o container web, mantendo gameserver, connectserver e db rodando normalmente. Mudanças de schema do banco, porém, exigem coordenação cuidadosa — teste sempre em um ambiente de staging com uma cópia do banco antes de aplicar em produção.
Monitoramento básico dos containers
Comandos essenciais para operação do dia a dia:
| Comando | Função |
|---|---|
docker compose ps | Ver status de todos os serviços |
docker compose logs -f gameserver | Acompanhar logs do GameServer em tempo real |
docker stats | Ver consumo de CPU/memória por container |
docker compose restart connectserver | Reiniciar um serviço específico |
docker compose down && docker compose up -d | Recriar a stack inteira (dados persistem via volume) |
Erros comuns e soluções
| Sintoma | Causa provável | Solução |
|---|---|---|
| GameServer não conecta ao banco | Nome de host errado (usando localhost em vez do nome do serviço) | Use o nome do serviço (db) como host dentro da rede Compose |
| Dados somem após recriar containers | Volume não declarado ou removido com -v | Declare volumes nomeados e evite docker compose down -v sem necessidade |
| Porta do banco acessível externamente | Mapeamento de porta desnecessário em produção | Remova ports: do serviço db em ambiente de produção |
| Senha exposta no repositório | Credenciais hardcoded no docker-compose.yml | Mova tudo para .env e adicione .env ao .gitignore |
| Atualização de um serviço derruba os outros | Uso de docker compose down completo para trocar um serviço | Use up -d --build <serviço> para atualizar isoladamente |
Checklist de orquestração com Docker Compose
- Arquitetura de serviços mapeada (db, connectserver, joinserver, gameserver, web).
- docker-compose.yml com redes internas e apenas portas necessárias expostas.
- Variáveis sensíveis centralizadas em
.enve fora do controle de versão. - Volumes nomeados para dados persistentes do banco.
- Rotina de backup automatizada e testada (restore validado ao menos uma vez).
- Processo de atualização isolada por serviço documentado.
- Monitoramento básico de logs e uso de recursos configurado.
Com a stack orquestrada e reprodutível, o próximo passo natural é aplicar esse mesmo rigor de infraestrutura ao restante do projeto — veja o tutorial de como criar um servidor de MU Online para revisar a configuração completa dos serviços que agora estão containerizados.
Perguntas frequentes
Preciso rodar o MU Server inteiro em Docker mesmo sendo baseado em Windows?
É possível usar containers Windows (Windows Server Core) para emuladores compilados para Windows, ou rodar via Wine em containers Linux para alguns componentes. A abordagem mais estável costuma ser containerizar o banco de dados e serviços web em Linux, e avaliar caso a caso o binário do emulador.
Docker Compose substitui um orquestrador como Kubernetes para esse caso?
Para um servidor de MU de porte pequeno a médio, Docker Compose é suficiente e muito mais simples de manter. Kubernetes só se justifica em cenários de múltiplas instâncias, alta disponibilidade real ou escala que exija scheduling automático entre vários hosts.
Como faço backup do banco de dados rodando em container?
Use o volume nomeado do banco (ex.: mssql_data ou mysql_data) e rode dumps periódicos com um serviço adicional no compose ou um cron externo que executa docker exec do comando de backup, salvando fora do container.
É seguro expor as portas do GameServer diretamente do container?
Sim, desde que você mapeie apenas as portas necessárias no host e mantenha um firewall configurado. Evite expor portas de banco de dados e de administração para fora da rede interna do Docker Compose.
Como atualizar um serviço sem derrubar o servidor inteiro?
Com Docker Compose, você pode rebuildar e reiniciar um serviço específico (ex.: docker compose up -d --build web) sem afetar os demais containers, desde que eles não dependam de uma mudança de schema do banco compartilhado.