Feat(Docker/bash): docker-compose system rework (#4488)

## ⚠️ATTENTION! ⚠️ Upgrading procedure:

**Database:** After this PR will be merged you need to backup your DB first (you can use the db-assembler or any mysql client to generate the dump) and restore it after.  The reason is that we use now docker named volumes instead of binded ones to improve performance.

**Conf & client data**: if you use the default configuration, both the etc and the data folder are now available inside the **/env/docker**. 

Finally, you can cleanup the /docker folder previously used by our system.

## Changes Proposed:

This PR will implement the [devcontainer ](https://code.visualstudio.com/docs/remote/containers) feature for VSCode. Allowing us to develop and debug directly within the container in the same way on all OSes.

* Implemented support for vscode dev-container feature by remote-extension suite
* Docker performance optimizations for MacOS and non-linux hosts
* Bash system improvements
* Implemented first command using Deno runtime environment (typescript) and [commander.js]
* Implemented wait mechanism for db_assembler
* Implemented db migration command
* possibility to run the authserver and worldserver with GDB using the integrated simple-restarter
* Implemented docker multi-stage mechanism to use one single Dockerfile for all the services
* client-data downloader now creates a placeholder to avoid downloading the same version of data files multiple times
* deployment of pre-compiled docker images on [docker hub](https://hub.docker.com/u/acore), you can test them [here](https://github.com/azerothcore/acore-docker)
This commit is contained in:
Yehonal
2021-04-22 09:57:05 +02:00
committed by GitHub
parent 4a8faafaff
commit 380f406248
100 changed files with 2747 additions and 777 deletions

128
apps/docker/Dockerfile Normal file
View File

@@ -0,0 +1,128 @@
#================================================================
#
# DEV: Stage used for the development environment
# and the locally built services
#
#=================================================================
FROM ubuntu:20.04 as dev
ARG USER_ID=1000
ARG GROUP_ID=1000
LABEL description="AC Worldserver Debug Container for use with Visual Studio"
# List of timezones: http://en.wikipedia.org/wiki/List_of_tz_database_time_zones
ENV DOCKER=1
# set timezone environment variable
ENV TZ=Etc/UTC
# set noninteractive mode so tzdata doesn't ask to set timezone on install
ENV DEBIAN_FRONTEND=noninteractive
# install essentials
RUN apt-get update && apt-get install -y gdb gdbserver git dos2unix lsb-core sudo curl unzip
# copy everything so we can work directly within the container
# using tools such as vscode dev-container
COPY . /azerothcore
# install the required dependencies to run the worldserver
RUN /azerothcore/acore.sh install-deps
# change timezone in container
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone && dpkg-reconfigure --frontend noninteractive tzdata
# Create a non-root user
RUN addgroup --gid $GROUP_ID acore && \
adduser --disabled-password --gecos '' --uid $USER_ID --gid $GROUP_ID acore && \
passwd -d acore && \
echo 'acore ALL=(ALL:ALL) NOPASSWD: ALL' >> /etc/sudoers
RUN mkdir -p /azerothcore
# Correct permissions for non-root operations
RUN chown -R acore:acore \
/run \
/home/acore \
/opt/ \
/azerothcore
USER acore
WORKDIR /azerothcore
#================================================================
#
# BUILD STAGE: to prepare binaries for the production services
#
#=================================================================
FROM dev as build
RUN bash acore.sh compiler build
#================================================================
#
# SERVICE BASE: prepare the OS for the production-ready services
#
#=================================================================
FROM ubuntu:20.04 as servicebase
# List of timezones: http://en.wikipedia.org/wiki/List_of_tz_database_time_zones
# set timezone environment variable
ENV TZ=Etc/UTC
# set noninteractive mode so tzdata doesn't ask to set timezone on install
ENV DEBIAN_FRONTEND=noninteractive
COPY --from=build /azerothcore/env /azerothcore/env
# copy the sources from the host machine
COPY apps /azerothcore/apps
COPY bin /azerothcore/bin
COPY conf /azerothcore/conf
COPY data /azerothcore/data
COPY deps /azerothcore/deps
COPY acore.json /azerothcore/acore.json
COPY acore.sh /azerothcore/acore.sh
# install the required dependencies to run the authserver
RUN apt-get update && apt-get install -y gdb gdbserver net-tools tzdata libmysqlclient-dev libace-dev mysql-client curl unzip;
# change timezone in container
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone && dpkg-reconfigure --frontend noninteractive tzdata
WORKDIR /azerothcore/
RUN cp -n "/azerothcore/env/docker/etc/worldserver.conf.dockerdist" "/azerothcore/env/dist/etc/worldserver.conf"
RUN cp -n "/azerothcore/env/docker/etc/authserver.conf.dockerdist" "/azerothcore/env/dist/etc/authserver.conf"
#================================================================
#
# AUTH SERVICE: create a ready-to-use authserver image
#
#=================================================================
FROM servicebase as authserver
CMD ./acore.sh run-authserver
#================================================================
#
# WORLD SERVICE: create a ready-to-use worldserver image
#
#=================================================================
FROM servicebase as worldserver
ENV DATAPATH=/azerothcore/env/dist/data
RUN /azerothcore/acore.sh client-data
CMD ./acore.sh run-worldserver

27
apps/docker/README.md Normal file
View File

@@ -0,0 +1,27 @@
# Run AzerothCore with Docker
*This readme it's a summary of the AzerothCore docker features.*
Docker. is a software that performs operating-system-level virtualization, allowing to wrap and launch applications inside containers.
Thanks to Docker, you can quickly setup and run AzerothCore in any operating system.
The **only** requirement is having [Docker](https://docs.docker.com/install/) installed into your system. Forget about installing mysql, visual studio, cmake, etc...
### Installation instructions
Check the [Install with Docker](https://www.azerothcore.org/wiki/Install-with-Docker) guide.
### Memory usage
The total amount of RAM when running all AzerothCore docker containers is **less than 2 GB**.
![AzerothCore containers memory](https://user-images.githubusercontent.com/75517/51078287-10e65b80-16b3-11e9-807f-f59a5844dae5.png)
### Docker containers vs Virtual machines
Using Docker will have the same benefits as using virtual machines, but with much less overhead:
![Docker containers vs Virtual machines](https://user-images.githubusercontent.com/75517/51078179-d4fec680-16b1-11e9-8ce6-87b5053f55dd.png)

View File

@@ -0,0 +1,6 @@
CUR_PATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
# allow the user to override configs
if [ -f "$AC_PATH_CONF/config.sh" ]; then
source "$AC_PATH_CONF/config.sh" # should overwrite previous
fi

174
apps/docker/docker-cmd.ts Normal file
View File

@@ -0,0 +1,174 @@
import { Command } from "https://cdn.depjs.com/cmd/mod.ts";
import * as ink from "https://deno.land/x/ink/mod.ts";
import {
Input,
Select,
} from "https://deno.land/x/cliffy@v0.18.2/prompt/mod.ts";
const program = new Command();
program.name("acore.sh docker")
.description("Shell scripts for docker")
.version("1.0.0");
shellCommandFactory(
"start:app",
"Startup the authserver and worldserver apps",
"docker-compose --profile app up",
);
shellCommandFactory(
"start:app:d",
"Startup the authserver and worldserver apps in detached mode",
"docker-compose --profile app up -d",
);
shellCommandFactory(
"start:dev",
"Startup the dev server",
"docker-compose --profile dev up",
);
shellCommandFactory(
"build",
"Build the authserver and worldserver",
`docker-compose run --rm ac-dev-server bash bin/acore-docker-build`,
);
shellCommandFactory(
"build:clean",
"Clean build data",
`docker-compose run --rm ac-dev-server bash rm -rf var/build`,
);
shellCommandFactory(
"client-data",
"Download client data inside the ac-data volume",
"docker-compose run --rm ac-dev-server bash acore.sh client-data",
);
shellCommandFactory(
"db-import",
"Create and upgrade the database with latest updates",
"docker-compose run --rm ac-dev-server bash acore.sh db-assembler import-all",
);
shellCommandFactory(
"dashboard [args...]",
"Execute acore dashboard within a running ac-dev-server",
"docker-compose exec ac-dev-server bash acore.sh",
);
program.command("attach [service]")
.description("attach to a service")
.action(async (service: string | undefined) => {
const { run } = Deno;
let command = `docker-compose ps`;
if (service) {
command = `${command} ${service}`;
}
console.log(ink.colorize(`<green>>>>>> Running: ${command}</green>`));
let cmd = command.split(" ");
const res = Deno.run({
cmd,
cwd: process.cwd(),
stdout: "piped",
stderr: "piped",
});
const output = await res.output(); // "piped" must be set
let services = new TextDecoder().decode(output).split("\n");
services.pop();
services = services.slice(2);
res.close(); // Don't forget to close it
let selService: string;
if (services.length > 1) {
selService = await Select.prompt({
message: `Select a service`,
options: services,
});
} else {
selService = services[0];
}
command = `docker attach ${selService.split(" ")[0]}`;
console.log(ink.colorize(`<green>>>>>> Running: ${command}</green>`));
console.log(
ink.colorize(
"<yellow>NOTE: you can detach from a container and leave it running using the CTRL-p CTRL-q key sequence.</yellow>",
),
);
cmd = command.split(" ");
const shellCmd = run({
cmd,
cwd: process.cwd(),
});
await shellCmd.status();
shellCmd.close();
});
program.command("quit").description("Close docker command").action(()=> {
process.exit(0)
})
// Handle it however you like
// e.g. display usage
while (true) {
if (Deno.args.length === 0) {
program.outputHelp();
const command = await Input.prompt({
message: "Enter the command:",
});
await program.parseAsync(command.split(" "));
} else {
await program.parseAsync(Deno.args);
process.exit(0)
}
}
function shellCommandFactory(
name: string,
description: string,
command: string,
): Command {
return program.command(name)
.description(
`${description}. Command: \n"${ink.colorize(`<green>${command}</green>`)}"\n`,
)
.action(async (args: any[] | undefined) => {
const { run } = Deno;
console.log(ink.colorize(`<green>>>>>> Running: ${command}</green>`));
const cmd = command.split(" ");
if (Array.isArray(args)) {
cmd.push(...args);
}
const shellCmd = run({
cmd,
cwd: process.cwd(),
});
await shellCmd.status();
shellCmd.close();
});
}