6
0
mirror of https://github.com/ChristianLight/tutor.git synced 2024-12-13 06:37:46 +00:00

Easily launch multiple platforms on a single server

By using a web proxy on the host, it's now extremely easy to launch
multiple platforms on a single server.
This commit is contained in:
Régis Behmo 2019-03-21 19:06:08 +01:00
parent f45a24caea
commit a70d48c6bb
5 changed files with 57 additions and 23 deletions

View File

@ -2,6 +2,7 @@
## Latest ## Latest
- [Feature] Multiple platforms on a single server \o/
- [Feature] Easily configure web proxy on the host - [Feature] Easily configure web proxy on the host
- [Bugfix] Fix `images pull all` command which failed on "all" image - [Bugfix] Fix `images pull all` command which failed on "all" image
- [Improvement] Add configurable mongodb, SMTP and rabbitmq authentication - [Improvement] Add configurable mongodb, SMTP and rabbitmq authentication

View File

@ -148,6 +148,36 @@ If you have configured your platform to use SSL/TLS certificates for HTTPS acces
tutor local https create tutor local https create
tutor local https renew tutor local https renew
Running multiple Open edX platforms on a single server
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
With Tutor, it is easy to run multiple Open edX instances on a single server. To do so, the following configuration parameters must be different for all platforms:
- ``TUTOR_ROOT``: so that configuration, environment and data are not mixed up between platforms.
- ``LOCAL_PROJECT_NAME``: the various docker-compose projects cannot share the same name.
- ``NGINX_HTTP_PORT``, ``NGINX_HTTPS_PORT``: ports cannot be shared by two different containers.
- ``LMS_HOST``, ``CMS_HOST``: the different platforms must be accessible from different domain (or subdomain) names.
In addition, a web proxy must be setup on the host, as described :ref:`above <web_proxy>`.
As an example, here is how to launch two different platforms, with nginx running as a web proxy:
# platform 1
export TUTOR_ROOT=~/openedx/site1
tutor config save --set WEB_PROXY=true --set LOCAL_PROJECT_NAME=tutor_site1 --set NGINX_HTTP_PORT=81 --set NGINX_HTTPS_PORT=481
tutor local quickstart
sudo ln -s $(tutor config printroot)/env/local/proxy/nginx/openedx.conf /etc/nginx/sites-enabled/site1.conf
# platform 2
export TUTOR_ROOT=~/openedx/site2
tutor config save --set WEB_PROXY=true --set LOCAL_PROJECT_NAME=tutor_site2 --set NGINX_HTTP_PORT=82 --set NGINX_HTTPS_PORT=482
tutor local quickstart
sudo ln -s $(tutor config printroot)/env/local/proxy/nginx/openedx.conf /etc/nginx/sites-enabled/site2.conf
You should then have two different platforms, completely isolated from one another, running on the same server.
Loading different production settings for ``edx-platform`` Loading different production settings for ``edx-platform``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -34,7 +34,7 @@ If you'd rather use a graphical user interface for viewing logs, you are encoura
"Cannot start service nginx: driver failed programming external connectivity" "Cannot start service nginx: driver failed programming external connectivity"
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
The containerized Nginx needs to listen to ports 80 and 443 on the host. If there is already a webserver, such as Apache or Nginx, running on the host, the nginx container will not be able to start. To solve this issue, check :ref:`web_proxy`. The containerized Nginx needs to listen to ports 80 and 443 on the host. If there is already a webserver, such as Apache or Nginx, running on the host, the nginx container will not be able to start. To solve this issue, check :ref:`out to setup a web proxy <web_proxy>`.
Help! The Docker containers are eating all my RAM/CPU/CHEESE Help! The Docker containers are eating all my RAM/CPU/CHEESE
------------------------------------------------------------ ------------------------------------------------------------

View File

@ -22,9 +22,7 @@ from . import ops
def local(): def local():
pass pass
@click.command( @click.command(help="Configure and run Open edX from scratch")
help="Configure and run Open edX from scratch"
)
@click.option("-p", "--pullimages", "pullimages_", is_flag=True, help="Update docker images") @click.option("-p", "--pullimages", "pullimages_", is_flag=True, help="Update docker images")
@opts.root @opts.root
def quickstart(pullimages_, root): def quickstart(pullimages_, root):
@ -42,16 +40,13 @@ def quickstart(pullimages_, root):
click.echo(fmt.title("Starting the platform in detached mode")) click.echo(fmt.title("Starting the platform in detached mode"))
start.callback(root, True) start.callback(root, True)
@click.command( @click.command(help="Update docker images")
help="Update docker images",
)
@opts.root @opts.root
def pullimages(root): def pullimages(root):
docker_compose(root, "pull") config = tutor_config.load(root)
docker_compose(root, config, "pull")
@click.command( @click.command(help="Run all configured Open edX services")
help="Run all configured Open edX services",
)
@opts.root @opts.root
@click.option("-d", "--detach", is_flag=True, help="Start in daemon mode") @click.option("-d", "--detach", is_flag=True, help="Start in daemon mode")
def start(root, detach): def start(root, detach):
@ -59,11 +54,11 @@ def start(root, detach):
if detach: if detach:
command.append("-d") command.append("-d")
docker_compose(root, *command) config = tutor_config.load(root)
docker_compose(root, config, *command)
if detach: if detach:
click.echo(fmt.info("The Open edX platform is now running in detached mode")) click.echo(fmt.info("The Open edX platform is now running in detached mode"))
config = tutor_config.load(root)
http = "https" if config["ACTIVATE_HTTPS"] else "http" http = "https" if config["ACTIVATE_HTTPS"] else "http"
urls = [] urls = []
if not config["ACTIVATE_HTTPS"] and not config["WEB_PROXY"]: if not config["ACTIVATE_HTTPS"] and not config["WEB_PROXY"]:
@ -81,7 +76,8 @@ def start(root, detach):
@click.command(help="Stop a running platform",) @click.command(help="Stop a running platform",)
@opts.root @opts.root
def stop(root): def stop(root):
docker_compose(root, "rm", "--stop", "--force") config = tutor_config.load(root)
docker_compose(root, config, "rm", "--stop", "--force")
@click.command( @click.command(
help="""Restart some components from a running platform. help="""Restart some components from a running platform.
@ -96,7 +92,8 @@ def restart(root, service):
command += ["lms", "cms", "lms_worker", "cms_worker"] command += ["lms", "cms", "lms_worker", "cms_worker"]
elif service != "all": elif service != "all":
command += [service] command += [service]
docker_compose(root, *command) config = tutor_config.load(root)
docker_compose(root, config, *command)
@click.command( @click.command(
help="Run a command in one of the containers", help="Run a command in one of the containers",
@ -116,7 +113,8 @@ def run(root, service, command, args):
run_command.append(command) run_command.append(command)
if args: if args:
run_command += args run_command += args
docker_compose(root, *run_command) config = tutor_config.load(root)
docker_compose(root, config, *run_command)
@click.command( @click.command(
help="Create databases and run database migrations", help="Create databases and run database migrations",
@ -134,16 +132,18 @@ def init_mysql(root):
if os.path.exists(mysql_data_path): if os.path.exists(mysql_data_path):
return return
click.echo(fmt.info("Initializing MySQL database...")) click.echo(fmt.info("Initializing MySQL database..."))
docker_compose(root, "up", "-d", "mysql") docker_compose(root, config, "up", "-d", "mysql")
while True: while True:
click.echo(fmt.info(" waiting for mysql initialization")) click.echo(fmt.info(" waiting for mysql initialization"))
# TODO this is duplicate code with the docker_compose function. We
# should rely on a dedicated function in utils module.
logs = subprocess.check_output([ logs = subprocess.check_output([
"docker-compose", "-f", tutor_env.pathjoin(root, "local", "docker-compose.yml"), "docker-compose", "-f", tutor_env.pathjoin(root, "local", "docker-compose.yml"),
"--project-name", "tutor_local", "logs", "mysql", "--project-name", config["LOCAL_PROJECT_NAME"], "logs", "mysql",
]) ])
if b"MySQL init process done. Ready for start up." in logs: if b"MySQL init process done. Ready for start up." in logs:
click.echo(fmt.info("MySQL database initialized")) click.echo(fmt.info("MySQL database initialized"))
docker_compose(root, "stop", "mysql") docker_compose(root, config, "stop", "mysql")
return return
sleep(4) sleep(4)
@ -219,7 +219,8 @@ def logs(root, follow, tail, service):
if tail is not None: if tail is not None:
command += ["--tail", str(tail)] command += ["--tail", str(tail)]
command += service command += service
docker_compose(root, *command) config = tutor_config.load(root)
docker_compose(root, config, *command)
@click.command(help="Create an Open edX user and interactively set their password") @click.command(help="Create an Open edX user and interactively set their password")
@opts.root @opts.root
@ -261,12 +262,13 @@ def portainer(root, port):
utils.docker_run(*docker_run) utils.docker_run(*docker_run)
def run_bash(root, service, command): def run_bash(root, service, command):
docker_compose(root, "run", "--rm", service, "bash", "-e", "-c", command) config = tutor_config.load(root)
docker_compose(root, config, "run", "--rm", service, "bash", "-e", "-c", command)
def docker_compose(root, *command): def docker_compose(root, config, *command):
return utils.docker_compose( return utils.docker_compose(
"-f", tutor_env.pathjoin(root, "local", "docker-compose.yml"), "-f", tutor_env.pathjoin(root, "local", "docker-compose.yml"),
"--project-name", "tutor_local", "--project-name", config["LOCAL_PROJECT_NAME"],
*command *command
) )

View File

@ -21,6 +21,7 @@ DOCKER_IMAGE_NGINX: "nginx:1.13"
DOCKER_IMAGE_RABBITMQ: "rabbitmq:3.6.10" DOCKER_IMAGE_RABBITMQ: "rabbitmq:3.6.10"
DOCKER_IMAGE_SMTP: "namshi/smtp:latest" DOCKER_IMAGE_SMTP: "namshi/smtp:latest"
DOCKER_REGISTRY: "" DOCKER_REGISTRY: ""
LOCAL_PROJECT_NAME: "tutor_local"
ELASTICSEARCH_HOST: "elasticsearch" ELASTICSEARCH_HOST: "elasticsearch"
ELASTICSEARCH_PORT: 9200 ELASTICSEARCH_PORT: 9200
MEMCACHED_HOST: "memcached" MEMCACHED_HOST: "memcached"