mirror of
https://github.com/ChristianLight/tutor.git
synced 2025-02-12 06:08:26 +00:00
Towards a stable Kubernetes integration
Missing features: - https certificates - xqueue - lms/cms workers Moreover, we scalability issues due to the uploaded file storage in the lms/cms. To address this issue we need to develop the MinIO plugin so that it becomes compatible with Open edX. Close #126 #179 #187
This commit is contained in:
parent
3b108d21de
commit
334f3e720e
108
docs/k8s.rst
108
docs/k8s.rst
@ -5,49 +5,78 @@ Kubernetes deployment
|
||||
|
||||
With the same docker images we created for :ref:`single server deployment <local>` and :ref:`local development <development>`, we can launch an Open edX platform on Kubernetes. Always in 1 click, of course :)
|
||||
|
||||
::
|
||||
|
||||
_ _ __ _
|
||||
__ _| |_ __ | |__ __ _ / _| ___ __ _| |_ _ _ _ __ ___
|
||||
/ _` | | '_ \| '_ \ / _` | | |_ / _ \/ _` | __| | | | '__/ _ \
|
||||
| (_| | | |_) | | | | (_| | | _| __/ (_| | |_| |_| | | | __/
|
||||
\__,_|_| .__/|_| |_|\__,_| |_| \___|\__,_|\__|\__,_|_| \___|
|
||||
|_|
|
||||
|
||||
Kubernetes deployment is currently an alpha feature, and we are hard at work to make it 100% reliable 🛠️ If you are interested in deploying Open edX to Kubernetes, please get in touch! Your input will be much appreciated.
|
||||
A word of warning: managing a Kubernetes platform is a fairly advanced endeavour. In this documentation, we assume familiarity with Kubernetes. Running an Open edX platform with Tutor on a single server or in a Kubernetes cluster are two very different things. The local Open edX install was designed such that users with no prior experience with system administration could still launch an Open edX platform. It is *not* the case for the installation method outlined here. You have been warned :)
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
In the following, we assume you have a working Kubernetes platform. For a start, you can run Kubernetes locally inside a VM with Minikube. Just follow the `official documentation <https://kubernetes.io/docs/setup/minikube/>`_.
|
||||
Memory
|
||||
~~~~~~
|
||||
|
||||
Start Minikube::
|
||||
|
||||
minikube start
|
||||
|
||||
When minikube starts, it spawns a virtual machine (VM) which you can configure in your VM manager: on most platforms, this is Virtualbox. You should configure your VM to have at least 4Gb RAM; otherwise, database migrations will crash halfway, and that's a nasty issue...
|
||||
In the following, we assume you have access to a working Kubernetes cluster. `kubectl` should use your cluster configuration by default. To launch a cluster locally, you may try out Minikube. Just follow the `official installation instructions <https://kubernetes.io/docs/setup/minikube/>`_.
|
||||
|
||||
The Kubernetes cluster should have at least 4Gb of RAM on each node. When running Minikube, the virtual machine should have that much allocated memory. See below for an example with VirtualBox::
|
||||
|
||||
.. image:: img/virtualbox-minikube-system.png
|
||||
:alt: Virtualbox memory settings for Minikube
|
||||
|
||||
Ingress addon must be installed::
|
||||
Ingress controller
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
In order to access your platform, you will have to setup an Ingress controller. Instructions vary for each cloud provider. To deploy an Nginx Ingress controller, it might be as simple as running::
|
||||
|
||||
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.24.1/deploy/mandatory.yaml
|
||||
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.24.1/deploy/provider/cloud-generic.yaml
|
||||
|
||||
See the `official instructions <https://kubernetes.github.io/ingress-nginx/deploy/>`_ for more details.
|
||||
|
||||
On Minikube, run::
|
||||
|
||||
minikube addons enable ingress
|
||||
|
||||
At any point, access a UI to view the state of the platform with::
|
||||
|
||||
minikube dashboard
|
||||
|
||||
With Kubernetes, your Open edX platform will not be available at localhost or studio.localhost. Instead, you will have to access your platform with the domain names you specified for the LMS and the CMS. To do so on a local computer, you will need to add the following line to /etc/hosts::
|
||||
With Kubernetes, your Open edX platform will *not* be available at localhost or studio.localhost. Instead, you will have to access your platform with the domain names you specified for the LMS and the CMS. To do so on a local computer, you will need to add the following line to /etc/hosts::
|
||||
|
||||
MINIKUBEIP yourdomain.com studio.yourdomain.com preview.yourdomain.com notes.yourdomain.com
|
||||
|
||||
where ``MINIKUBEIP`` should be replaced by the result of the command ``minikube ip``.
|
||||
|
||||
`ReadWriteMany` storage provider access mode
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Some of the data volumes are shared between pods and thus require the `ReadWriteMany` access mode. We assume that a persistent volume provisioner with such capability is already installed on the cluster. For instance, on AWS the `AWS EBS <https://kubernetes.io/docs/concepts/storage/storage-classes/#aws-ebs>`_ provisioner is available. On DigitalOcean, there is `no such provider <https://www.digitalocean.com/docs/kubernetes/how-to/add-volumes/>`_ out of the box and you have to install one yourself.
|
||||
|
||||
On Minikube, the standard storage class uses the `k8s.io/minikube-hostpath <https://kubernetes.io/docs/concepts/storage/volumes/#hostpath>`_ provider, which supports `ReadWriteMany` access mode out of the box, so there is no need to install an extra provider.
|
||||
|
||||
Kubernetes dashboard
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This is not a requirement per se, but it's very convenient to have a visual interface of the Kubernetes cluster. We suggest the official `Kubernetes dashboard <https://github.com/kubernetes/dashboard/>`_. Depending on your Kubernetes provider, you may need to install a dashboard yourself. There are generic instructions on the `project's README <https://github.com/kubernetes/dashboard/blob/master/README.md>`_. AWS provides `specific instructions <https://docs.aws.amazon.com/eks/latest/userguide/dashboard-tutorial.html>`_.
|
||||
|
||||
On Minikube, the dashboard is already installed. To access the dashboard, run::
|
||||
|
||||
minikube dashboard
|
||||
|
||||
Technical details
|
||||
-----------------
|
||||
|
||||
Under the hood, Tutor wraps ``kubectl`` commands to interact with the cluster. The various commands called by Tutor are printed in the console, so that you can reproduce and modify them yourself.
|
||||
|
||||
Basically, the whole platform is described in manifest files stored in ``$(tutor config printroot)/env/k8s``. There is also a ``kustomization.yml`` file at the project root for `declarative application management <https://kubectl.docs.kubernetes.io/pages/app_management/apply.html>`_. This allows us to start and update resources with commands similar to ``kubectl apply -k $(tutor config printroot) --selector=...`` (see the ``kubectl apply`` `official documentation <https://kubectl.docs.kubernetes.io/pages/app_management/apply.html>`_).
|
||||
|
||||
The other benefit of ``kubectl apply`` is that it allows you to customise the Kubernetes resources as much as you want. For instance, the default Tutor configuration can be extended by a ``kustomization.yml`` file stored in ``$(tutor config printroot)/env-custom/`` and which would start with::
|
||||
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
bases:
|
||||
- ../env/
|
||||
...
|
||||
|
||||
To learn more about "kustomizations", refer to the `official documentation <https://kubectl.docs.kubernetes.io/pages/app_customization/introduction.html>`_.
|
||||
|
||||
Quickstart
|
||||
----------
|
||||
|
||||
Launch the platform on k8s in 1 click::
|
||||
Launch the platform on Kubernetes in one command::
|
||||
|
||||
tutor k8s quickstart
|
||||
|
||||
@ -56,34 +85,14 @@ All Kubernetes resources are associated to the "openedx" namespace. If you don't
|
||||
.. image:: img/k8s-dashboard.png
|
||||
:alt: Kubernetes dashboard ("openedx" namespace)
|
||||
|
||||
Upgrading
|
||||
---------
|
||||
The same ``tutor k8s quickstart`` command can be used to upgrade the cluster to the latest version.
|
||||
|
||||
After pulling updates from the Tutor repository, you can apply changes with::
|
||||
Other commands
|
||||
--------------
|
||||
|
||||
tutor k8s stop
|
||||
tutor k8s start
|
||||
|
||||
Accessing the Kubernetes dashboard
|
||||
----------------------------------
|
||||
|
||||
Depending on your Kubernetes provider, you may need to create a dashboard yourself. To do so, run::
|
||||
|
||||
kubectl create -f https://raw.githubusercontent.com/kubernetes/dashboard/master/aio/deploy/recommended/kubernetes-dashboard.yaml
|
||||
|
||||
Then, you will have to create an admin user::
|
||||
|
||||
tutor k8s adminuser
|
||||
|
||||
Print the admin token required for authentication, and copy its value::
|
||||
|
||||
tutor k8s admintoken
|
||||
|
||||
Create a proxy to the Kubernetes API server::
|
||||
|
||||
kubectl proxy
|
||||
|
||||
Use the token to log in the dashboard at the following url: http://localhost:8001/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy/
|
||||
As with the :ref:`local installation <local>`, there are multiple commands to run operations on your Open edX platform. To view those commands, run::
|
||||
|
||||
tutor k8s -h
|
||||
|
||||
Missing features
|
||||
----------------
|
||||
@ -92,6 +101,5 @@ For now, the following features from the local deployment are not supported:
|
||||
|
||||
- HTTPS certificates
|
||||
- Xqueue
|
||||
- Student notes
|
||||
|
||||
Kubernetes deployment is under intense development, and these features should be implemented pretty soon. Stay tuned 🤓
|
||||
|
22
plugins/minio/tutorminio/patches/k8s-jobs.patch
Normal file
22
plugins/minio/tutorminio/patches/k8s-jobs.patch
Normal file
@ -0,0 +1,22 @@
|
||||
---
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: minio-client/init
|
||||
labels:
|
||||
app.kubernetes.io/component: script
|
||||
app.kubernetes.io/name: minio-client/init
|
||||
spec:
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: minio-client/init
|
||||
spec:
|
||||
restartPolicy: Never
|
||||
containers:
|
||||
- name: minio-client
|
||||
image: {{ MINIO_DOCKER_REGISTRY }}{{ MINIO_DOCKER_IMAGE_CLIENT }}
|
||||
command: ["/bin/sh", "-e", "-c"]
|
||||
args:
|
||||
- |
|
||||
{{ include_plugin_script("minio", "minio-client", "init")|indent(12) }}
|
@ -2,5 +2,6 @@ appdirs
|
||||
click>=7.0
|
||||
click_repl
|
||||
jinja2
|
||||
# TODO get rid of kubernetes?
|
||||
kubernetes
|
||||
pyyaml>=4.2b1
|
||||
|
@ -32,7 +32,7 @@ class ConfigTests(unittest.TestCase):
|
||||
self.assertEqual("abcd", config["MYSQL_ROOT_PASSWORD"])
|
||||
|
||||
@unittest.mock.patch.object(tutor_config.fmt, "echo")
|
||||
def test_save_twice(self, mock_echo):
|
||||
def test_save_twice(self, _):
|
||||
with tempfile.TemporaryDirectory() as root:
|
||||
tutor_config.save(root, silent=True)
|
||||
config1 = tutor_config.load_user(root)
|
||||
@ -43,20 +43,20 @@ class ConfigTests(unittest.TestCase):
|
||||
self.assertEqual(config1, config2)
|
||||
|
||||
@unittest.mock.patch.object(tutor_config.fmt, "echo")
|
||||
def test_removed_entry_is_added_on_save(self, mock_echo):
|
||||
def test_removed_entry_is_added_on_save(self, _):
|
||||
with tempfile.TemporaryDirectory() as root:
|
||||
with unittest.mock.patch.object(
|
||||
tutor_config.utils, "random_string"
|
||||
) as mock_random_string:
|
||||
mock_random_string.return_value = "abcd"
|
||||
config1, defaults = tutor_config.load_all(root)
|
||||
config1, _ = tutor_config.load_all(root)
|
||||
password1 = config1["MYSQL_ROOT_PASSWORD"]
|
||||
|
||||
config1.pop("MYSQL_ROOT_PASSWORD")
|
||||
tutor_config.save_config(root, config1)
|
||||
|
||||
mock_random_string.return_value = "efgh"
|
||||
config2, defaults = tutor_config.load_all(root)
|
||||
config2, _ = tutor_config.load_all(root)
|
||||
password2 = config2["MYSQL_ROOT_PASSWORD"]
|
||||
|
||||
self.assertEqual("abcd", password1)
|
||||
|
@ -2,7 +2,8 @@ import click
|
||||
|
||||
from . import config as tutor_config
|
||||
from .. import env as tutor_env
|
||||
from .. import exceptions
|
||||
|
||||
# from .. import exceptions
|
||||
from .. import fmt
|
||||
from .. import opts
|
||||
from .. import scripts
|
||||
@ -16,89 +17,80 @@ def k8s():
|
||||
|
||||
@click.command(help="Configure and run Open edX from scratch")
|
||||
@opts.root
|
||||
def quickstart(root):
|
||||
@click.option("-y", "--yes", "silent", is_flag=True, help="Run non-interactively")
|
||||
def quickstart(root, silent):
|
||||
click.echo(fmt.title("Interactive platform configuration"))
|
||||
tutor_config.save(root)
|
||||
click.echo(fmt.title("Stopping any existing platform"))
|
||||
stop.callback()
|
||||
tutor_config.save(root, silent=silent)
|
||||
click.echo(fmt.title("Starting the platform"))
|
||||
start.callback(root)
|
||||
click.echo(
|
||||
fmt.title(
|
||||
"Running migrations. NOTE: this might fail. If it does, please retry 'tutor k8s databases' later"
|
||||
)
|
||||
)
|
||||
click.echo(fmt.title("Database creation and migrations"))
|
||||
databases.callback(root)
|
||||
# TODO https certificates
|
||||
|
||||
|
||||
@click.command(help="Run all configured Open edX services")
|
||||
@opts.root
|
||||
def start(root):
|
||||
config = tutor_config.load(root)
|
||||
kubectl_no_fail("create", "-f", tutor_env.pathjoin(root, "k8s", "namespace.yml"))
|
||||
|
||||
kubectl(
|
||||
"create",
|
||||
"configmap",
|
||||
"nginx-config",
|
||||
"--from-file",
|
||||
tutor_env.pathjoin(root, "apps", "nginx"),
|
||||
# Create namespace
|
||||
utils.kubectl(
|
||||
"apply",
|
||||
"--kustomize",
|
||||
tutor_env.pathjoin(root),
|
||||
"--wait",
|
||||
"--selector",
|
||||
"app.kubernetes.io/component=namespace",
|
||||
)
|
||||
if config["ACTIVATE_MYSQL"]:
|
||||
kubectl(
|
||||
"create",
|
||||
"configmap",
|
||||
"mysql-config",
|
||||
"--from-env-file",
|
||||
tutor_env.pathjoin(root, "apps", "mysql", "auth.env"),
|
||||
)
|
||||
kubectl(
|
||||
"create",
|
||||
"configmap",
|
||||
"openedx-settings-lms",
|
||||
"--from-file",
|
||||
tutor_env.pathjoin(root, "apps", "openedx", "settings", "lms"),
|
||||
# Create volumes
|
||||
utils.kubectl(
|
||||
"apply",
|
||||
"--kustomize",
|
||||
tutor_env.pathjoin(root),
|
||||
"--wait",
|
||||
"--selector",
|
||||
"app.kubernetes.io/component=volume",
|
||||
)
|
||||
kubectl(
|
||||
"create",
|
||||
"configmap",
|
||||
"openedx-settings-cms",
|
||||
"--from-file",
|
||||
tutor_env.pathjoin(root, "apps", "openedx", "settings", "cms"),
|
||||
# Create everything else (except Job objects)
|
||||
utils.kubectl(
|
||||
"apply",
|
||||
"--selector",
|
||||
"app.kubernetes.io/component!=script",
|
||||
"--kustomize",
|
||||
tutor_env.pathjoin(root),
|
||||
)
|
||||
kubectl(
|
||||
"create",
|
||||
"configmap",
|
||||
"openedx-config",
|
||||
"--from-file",
|
||||
tutor_env.pathjoin(root, "apps", "openedx", "config"),
|
||||
)
|
||||
|
||||
kubectl("create", "-f", tutor_env.pathjoin(root, "k8s", "volumes.yml"))
|
||||
kubectl("create", "-f", tutor_env.pathjoin(root, "k8s", "ingress.yml"))
|
||||
kubectl("create", "-f", tutor_env.pathjoin(root, "k8s", "services.yml"))
|
||||
kubectl("create", "-f", tutor_env.pathjoin(root, "k8s", "deployments.yml"))
|
||||
|
||||
|
||||
@click.command(help="Stop a running platform")
|
||||
def stop():
|
||||
kubectl("delete", "deployments,services,ingress,configmaps", "--all")
|
||||
@opts.root
|
||||
def stop(root):
|
||||
config = tutor_config.load(root)
|
||||
utils.kubectl(
|
||||
"delete",
|
||||
"--namespace",
|
||||
config["K8S_NAMESPACE"],
|
||||
"--selector=app.kubernetes.io/instance=openedx-" + config["ID"],
|
||||
"deployments,services,ingress,configmaps,jobs",
|
||||
)
|
||||
|
||||
|
||||
@click.command(help="Completely delete an existing platform")
|
||||
@opts.root
|
||||
@click.option("-y", "--yes", is_flag=True, help="Do not ask for confirmation")
|
||||
def delete(yes):
|
||||
def delete(root, yes):
|
||||
if not yes:
|
||||
click.confirm(
|
||||
"Are you sure you want to delete the platform? All data will be removed.",
|
||||
abort=True,
|
||||
)
|
||||
kubectl("delete", "namespace", K8s.NAMESPACE)
|
||||
config = tutor_config.load(root)
|
||||
utils.kubectl(
|
||||
"delete", "-k", tutor_env.pathjoin(root), "--ignore-not-found=true", "--wait"
|
||||
)
|
||||
|
||||
|
||||
@click.command(help="Create databases and run database migrations")
|
||||
@opts.root
|
||||
def databases(root):
|
||||
# TODO this requires a running mysql/mongodb/elasticsearch. Maybe we should wait until they are up?
|
||||
config = tutor_config.load(root)
|
||||
runner = K8sScriptRunner(root, config)
|
||||
scripts.migrate(runner)
|
||||
@ -113,6 +105,7 @@ def databases(root):
|
||||
def createuser(root, superuser, staff, name, email):
|
||||
config = tutor_config.load(root)
|
||||
runner = K8sScriptRunner(root, config)
|
||||
# TODO this is not going to work
|
||||
scripts.create_user(runner, superuser, staff, name, email)
|
||||
|
||||
|
||||
@ -130,107 +123,70 @@ def importdemocourse(root):
|
||||
@click.command(help="Re-index courses for better searching")
|
||||
@opts.root
|
||||
def indexcourses(root):
|
||||
# Note: this is currently broken with "pymongo.errors.ConnectionFailure: [Errno 111] Connection refused"
|
||||
# I'm not quite sure the settings are correctly picked up. Which is weird because migrations work very well.
|
||||
config = tutor_config.load(root)
|
||||
runner = K8sScriptRunner(root, config)
|
||||
# TODO this is not going to work
|
||||
scripts.index_courses(runner)
|
||||
|
||||
|
||||
@click.command(help="Launch a shell in LMS or CMS")
|
||||
@click.argument("service", type=click.Choice(["lms", "cms"]))
|
||||
def shell(service):
|
||||
K8s().execute(service, "bash")
|
||||
# @click.command(help="Launch a shell in LMS or CMS")
|
||||
# @click.argument("service", type=click.Choice(["lms", "cms"]))
|
||||
# def shell(service):
|
||||
# K8s().execute(service, "bash")
|
||||
|
||||
|
||||
@click.command(help="Create a Kubernetesadmin user")
|
||||
@click.command(help="View output from containers")
|
||||
@opts.root
|
||||
def adminuser(root):
|
||||
utils.kubectl("create", "-f", tutor_env.pathjoin(root, "k8s", "adminuser.yml"))
|
||||
@click.option("-f", "--follow", is_flag=True, help="Follow log output")
|
||||
@click.option("--tail", type=int, help="Number of lines to show from each container")
|
||||
@click.argument("service")
|
||||
def logs(root, follow, tail, service):
|
||||
config = tutor_config.load(root)
|
||||
|
||||
command = ["logs"]
|
||||
command += ["--namespace", config["K8S_NAMESPACE"]]
|
||||
|
||||
@click.command(help="Print the Kubernetes admin user token")
|
||||
def admintoken():
|
||||
click.echo(K8s().admin_token())
|
||||
if follow:
|
||||
command += ["--follow"]
|
||||
if tail is not None:
|
||||
command += ["--tail", str(tail)]
|
||||
|
||||
selector = "--selector=app.kubernetes.io/instance=openedx-" + config["ID"]
|
||||
if service:
|
||||
selector += ",app.kubernetes.io/name=" + service
|
||||
command.append(selector)
|
||||
|
||||
def kubectl(*command):
|
||||
"""
|
||||
Run kubectl commands in the right namespace. Also, errors are completely
|
||||
ignored, to avoid stopping on "AlreadyExists" errors.
|
||||
"""
|
||||
args = list(command)
|
||||
args += ["--namespace", K8s.NAMESPACE]
|
||||
kubectl_no_fail(*args)
|
||||
|
||||
|
||||
def kubectl_no_fail(*command):
|
||||
"""
|
||||
Run kubectl commands and ignore exceptions, to avoid stopping on
|
||||
"AlreadyExists" errors.
|
||||
"""
|
||||
try:
|
||||
utils.kubectl(*command)
|
||||
except exceptions.TutorError:
|
||||
pass
|
||||
|
||||
|
||||
class K8s:
|
||||
CLIENT = None
|
||||
NAMESPACE = "openedx"
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@property
|
||||
def client(self):
|
||||
if self.CLIENT is None:
|
||||
# Import moved here for performance reasons
|
||||
import kubernetes
|
||||
|
||||
kubernetes.config.load_kube_config()
|
||||
self.CLIENT = kubernetes.client.CoreV1Api()
|
||||
return self.CLIENT
|
||||
|
||||
def pod_name(self, app):
|
||||
selector = "app=" + app
|
||||
try:
|
||||
return (
|
||||
self.client.list_namespaced_pod("openedx", label_selector=selector)
|
||||
.items[0]
|
||||
.metadata.name
|
||||
)
|
||||
except IndexError:
|
||||
raise exceptions.TutorError(
|
||||
"Pod with app {} does not exist. Make sure that the pod is running."
|
||||
)
|
||||
|
||||
def admin_token(self):
|
||||
# Note: this is a HORRIBLE way of looking for a secret
|
||||
try:
|
||||
secret = [
|
||||
s
|
||||
for s in self.client.list_namespaced_secret("kube-system").items
|
||||
if s.metadata.name.startswith("admin-user-token")
|
||||
][0]
|
||||
except IndexError:
|
||||
raise exceptions.TutorError(
|
||||
"Secret 'admin-user-token'. Make sure that admin user was created."
|
||||
)
|
||||
return self.client.read_namespaced_secret(
|
||||
secret.metadata.name, "kube-system"
|
||||
).data["token"]
|
||||
|
||||
def execute(self, app, *command):
|
||||
podname = self.pod_name(app)
|
||||
kubectl_no_fail(
|
||||
"exec", "--namespace", self.NAMESPACE, "-it", podname, "--", *command
|
||||
)
|
||||
utils.kubectl(*command)
|
||||
|
||||
|
||||
class K8sScriptRunner(scripts.BaseRunner):
|
||||
def exec(self, service, command):
|
||||
K8s().execute(service, "sh", "-e", "-c", command)
|
||||
def run(self, service, script, config=None):
|
||||
job_name = "{}/{}".format(service, script)
|
||||
selector = (
|
||||
"--selector=app.kubernetes.io/component=script,app.kubernetes.io/name="
|
||||
+ job_name
|
||||
)
|
||||
kustomization = tutor_env.pathjoin(self.root)
|
||||
# Delete any previously run jobs (completed job objects still exist)
|
||||
utils.kubectl("delete", "-k", kustomization, "--wait", selector)
|
||||
# Run job
|
||||
utils.kubectl("apply", "-k", kustomization, selector)
|
||||
# Wait until complete
|
||||
fmt.echo_info(
|
||||
"Waiting for job to complete. To view logs, run: \n\n kubectl logs -n {} -l app.kubernetes.io/name={} --follow\n".format(
|
||||
self.config["K8S_NAMESPACE"], job_name
|
||||
)
|
||||
)
|
||||
utils.kubectl(
|
||||
"wait",
|
||||
"--namespace",
|
||||
self.config["K8S_NAMESPACE"],
|
||||
"--for=condition=complete",
|
||||
"--timeout=-1s",
|
||||
selector,
|
||||
"job",
|
||||
)
|
||||
# TODO check failure?
|
||||
|
||||
|
||||
k8s.add_command(quickstart)
|
||||
@ -241,6 +197,5 @@ k8s.add_command(databases)
|
||||
k8s.add_command(createuser)
|
||||
k8s.add_command(importdemocourse)
|
||||
k8s.add_command(indexcourses)
|
||||
k8s.add_command(shell)
|
||||
k8s.add_command(adminuser)
|
||||
k8s.add_command(admintoken)
|
||||
# k8s.add_command(shell)
|
||||
k8s.add_command(logs)
|
||||
|
@ -28,6 +28,7 @@ class Renderer:
|
||||
environment.filters["random_string"] = utils.random_string
|
||||
environment.filters["common_domain"] = utils.common_domain
|
||||
environment.filters["reverse_host"] = utils.reverse_host
|
||||
environment.filters["walk_templates"] = walk_templates
|
||||
environment.globals["TUTOR_VERSION"] = __version__
|
||||
cls.ENVIRONMENT = environment
|
||||
|
||||
@ -97,6 +98,7 @@ def render_full(root, config):
|
||||
save_subdir(subdir, root, config)
|
||||
copy_subdir("build", root)
|
||||
save_file(VERSION_FILENAME, root, config)
|
||||
save_file("kustomization.yml", root, config)
|
||||
|
||||
|
||||
def save_subdir(subdir, root, config):
|
||||
|
@ -50,6 +50,7 @@ LOCAL_PROJECT_NAME: "tutor_local"
|
||||
ELASTICSEARCH_HOST: "elasticsearch"
|
||||
ELASTICSEARCH_PORT: 9200
|
||||
FORUM_HOST: "forum"
|
||||
K8S_NAMESPACE: "openedx"
|
||||
LANGUAGE_CODE: "en"
|
||||
MEMCACHED_HOST: "memcached"
|
||||
MEMCACHED_PORT: 11211
|
||||
|
@ -1,20 +0,0 @@
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: admin-user
|
||||
namespace: kube-system
|
||||
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: admin-user
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: cluster-admin
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: admin-user
|
||||
namespace: kube-system
|
@ -3,15 +3,16 @@ apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: cms
|
||||
labels:
|
||||
app.kubernetes.io/name: cms
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: cms
|
||||
app.kubernetes.io/name: cms
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: cms
|
||||
app.kubernetes.io/name: cms
|
||||
spec:
|
||||
containers:
|
||||
- name: cms
|
||||
@ -30,7 +31,6 @@ spec:
|
||||
name: config
|
||||
- mountPath: /openedx/data
|
||||
name: data
|
||||
#imagePullPolicy: Always
|
||||
volumes:
|
||||
- name: settings-lms
|
||||
configMap:
|
||||
@ -50,22 +50,22 @@ apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: forum
|
||||
labels:
|
||||
app.kubernetes.io/name: forum
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: forum
|
||||
app.kubernetes.io/name: forum
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: forum
|
||||
app.kubernetes.io/name: forum
|
||||
spec:
|
||||
containers:
|
||||
- name: forum
|
||||
image: {{ DOCKER_REGISTRY }}{{ DOCKER_IMAGE_FORUM }}
|
||||
ports:
|
||||
- containerPort: 4567
|
||||
imagePullPolicy: Always
|
||||
env:
|
||||
- name: SEARCH_SERVER
|
||||
value: "http://{{ ELASTICSEARCH_HOST }}:{{ ELASTICSEARCH_PORT }}"
|
||||
@ -81,15 +81,16 @@ apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: lms
|
||||
labels:
|
||||
app.kubernetes.io/name: lms
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: lms
|
||||
app.kubernetes.io/name: lms
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: lms
|
||||
app.kubernetes.io/name: lms
|
||||
spec:
|
||||
containers:
|
||||
- name: lms
|
||||
@ -105,7 +106,6 @@ spec:
|
||||
name: config
|
||||
- mountPath: /openedx/data
|
||||
name: data
|
||||
imagePullPolicy: Always
|
||||
volumes:
|
||||
- name: settings-lms
|
||||
configMap:
|
||||
@ -125,15 +125,16 @@ apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: elasticsearch
|
||||
labels:
|
||||
app.kubernetes.io/name: elasticearch
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: elasticsearch
|
||||
app.kubernetes.io/name: elasticsearch
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: elasticsearch
|
||||
app.kubernetes.io/name: elasticsearch
|
||||
spec:
|
||||
containers:
|
||||
- name: elasticsearch
|
||||
@ -161,15 +162,16 @@ apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: memcached
|
||||
labels:
|
||||
app.kubernetes.io/name: memcached
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: memcached
|
||||
app.kubernetes.io/name: memcached
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: memcached
|
||||
app.kubernetes.io/name: memcached
|
||||
spec:
|
||||
containers:
|
||||
- name: memcached
|
||||
@ -183,20 +185,21 @@ apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: mongodb
|
||||
labels:
|
||||
app.kubernetes.io/name: mongodb
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: mongodb
|
||||
app.kubernetes.io/name: mongodb
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: mongodb
|
||||
app.kubernetes.io/name: mongodb
|
||||
spec:
|
||||
containers:
|
||||
- name: mongodb
|
||||
image: {{ DOCKER_REGISTRY }}{{ DOCKER_IMAGE_MONGODB }}
|
||||
command: ["mongod", "--smallfiles", "--nojournal", "--storageEngine", "wiredTiger"]
|
||||
args: ["mongod", "--smallfiles", "--nojournal", "--storageEngine", "wiredTiger"]
|
||||
ports:
|
||||
- containerPort: 27017
|
||||
volumeMounts:
|
||||
@ -204,6 +207,7 @@ spec:
|
||||
name: data
|
||||
volumes:
|
||||
- name: data
|
||||
# TODO this should be a pvc, otherwise the volume data will be lost when the pod is deleted
|
||||
emptyDir: {}
|
||||
{% endif %}
|
||||
{% if ACTIVATE_MYSQL %}
|
||||
@ -212,19 +216,21 @@ apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: mysql
|
||||
labels:
|
||||
app.kubernetes.io/name: mysql
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: mysql
|
||||
app.kubernetes.io/name: mysql
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: mysql
|
||||
app.kubernetes.io/name: mysql
|
||||
spec:
|
||||
containers:
|
||||
- name: mysql
|
||||
image: {{ DOCKER_REGISTRY }}{{ DOCKER_IMAGE_MYSQL }}
|
||||
args: ["mysqld", "--character-set-server=utf8", "--collation-server=utf8_general_ci"]
|
||||
env:
|
||||
- name: MYSQL_ROOT_PASSWORD
|
||||
valueFrom:
|
||||
@ -241,21 +247,60 @@ spec:
|
||||
persistentVolumeClaim:
|
||||
claimName: mysql
|
||||
{% endif %}
|
||||
{% if ACTIVATE_NOTES %}
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: notes
|
||||
labels:
|
||||
app.kubernetes.io/name: notes
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: notes
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: notes
|
||||
spec:
|
||||
containers:
|
||||
- name: notes
|
||||
image: {{ DOCKER_REGISTRY }}{{ DOCKER_IMAGE_NOTES }}
|
||||
ports:
|
||||
- containerPort: 8000
|
||||
env:
|
||||
- name: DJANGO_SETTINGS_MODULE
|
||||
value: notesserver.settings.tutor
|
||||
volumeMounts:
|
||||
- mountPath: /openedx/edx-notes-api/notesserver/settings/tutor.py
|
||||
name: settings
|
||||
- mountPath: /openedx/data
|
||||
name: data
|
||||
volumes:
|
||||
- name: data
|
||||
persistentVolumeClaim:
|
||||
claimName: notes-data
|
||||
- name: settings
|
||||
configMap:
|
||||
name: notes-settings
|
||||
{% endif %}
|
||||
{% if ACTIVATE_SMTP %}
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: smtp
|
||||
labels:
|
||||
app.kubernetes.io/name: smtp
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: smtp
|
||||
app.kubernetes.io/name: smtp
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: smtp
|
||||
app.kubernetes.io/name: smtp
|
||||
spec:
|
||||
containers:
|
||||
- name: smtp
|
||||
@ -268,31 +313,30 @@ apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: nginx
|
||||
labels:
|
||||
app.kubernetes.io/name: nginx
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: nginx
|
||||
app.kubernetes.io/name: nginx
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: nginx
|
||||
app.kubernetes.io/name: nginx
|
||||
spec:
|
||||
initContainers:
|
||||
- name: clean-openedx-staticfiles
|
||||
image: {{ DOCKER_REGISTRY }}{{ DOCKER_IMAGE_OPENEDX }}
|
||||
command: ['rm', '-rf', '/var/www/openedx/staticfiles']
|
||||
args: ['rm', '-rf', '/var/www/openedx/staticfiles']
|
||||
volumeMounts:
|
||||
- mountPath: /var/www/openedx/
|
||||
name: openedx-staticfiles
|
||||
imagePullPolicy: Always
|
||||
- name: init-openedx-staticfiles
|
||||
image: {{ DOCKER_REGISTRY }}{{ DOCKER_IMAGE_OPENEDX }}
|
||||
command: ['cp', '-r', '/openedx/staticfiles', '/var/www/openedx/']
|
||||
args: ['cp', '-r', '/openedx/staticfiles', '/var/www/openedx/']
|
||||
volumeMounts:
|
||||
- mountPath: /var/www/openedx/
|
||||
name: openedx-staticfiles
|
||||
imagePullPolicy: Always
|
||||
containers:
|
||||
- name: nginx
|
||||
image: {{ DOCKER_REGISTRY }}{{ DOCKER_IMAGE_NGINX }}
|
||||
@ -301,38 +345,46 @@ spec:
|
||||
name: config
|
||||
- mountPath: /var/www/openedx/
|
||||
name: openedx-staticfiles
|
||||
readOnly: true
|
||||
- mountPath: /openedx/data/cms
|
||||
name: data-cms
|
||||
readOnly: true
|
||||
- mountPath: /openedx/data/lms
|
||||
name: data
|
||||
name: data-lms
|
||||
readOnly: true
|
||||
ports:
|
||||
- containerPort: 80
|
||||
name: http-port
|
||||
- containerPort: 443
|
||||
name: https-port
|
||||
volumes:
|
||||
- name: config
|
||||
configMap:
|
||||
name: nginx-config
|
||||
- name: openedx-staticfiles
|
||||
emptyDir: {}
|
||||
- name: data-cms
|
||||
persistentVolumeClaim:
|
||||
claimName: openedx-staticfiles
|
||||
- name: data
|
||||
claimName: cms-data
|
||||
readOnly: true
|
||||
- name: data-lms
|
||||
persistentVolumeClaim:
|
||||
claimName: lms-data
|
||||
readOnly: true
|
||||
{% if ACTIVATE_RABBITMQ %}
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: rabbitmq
|
||||
labels:
|
||||
app.kubernetes.io/name: rabbitmq
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: rabbitmq
|
||||
app.kubernetes.io/name: rabbitmq
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: rabbitmq
|
||||
app.kubernetes.io/name: rabbitmq
|
||||
spec:
|
||||
containers:
|
||||
- name: rabbitmq
|
||||
|
@ -5,9 +5,7 @@ metadata:
|
||||
name: web
|
||||
spec:
|
||||
rules:
|
||||
{% set hosts = [LMS_HOST, "preview." + LMS_HOST, CMS_HOST] %}
|
||||
{% if ACTIVATE_NOTES %}{% set hosts = hosts + [NOTES_HOST] %}{% endif %}
|
||||
{% for host in hosts %}
|
||||
{% set hosts = [LMS_HOST, "preview." + LMS_HOST, CMS_HOST] %}{% if ACTIVATE_NOTES %}{% set hosts = hosts + [NOTES_HOST] %}{% endif %}{% for host in hosts %}
|
||||
- host: {{ host }}
|
||||
http:
|
||||
paths:
|
||||
|
237
tutor/templates/k8s/jobs.yml
Normal file
237
tutor/templates/k8s/jobs.yml
Normal file
@ -0,0 +1,237 @@
|
||||
{% macro include_script(script) %}{% include "scripts/" + script %}{% endmacro %}---
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: mysql-client/init
|
||||
labels:
|
||||
app.kubernetes.io/component: script
|
||||
app.kubernetes.io/name: mysql-client/init
|
||||
spec:
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: mysql-client/init
|
||||
spec:
|
||||
restartPolicy: Never
|
||||
containers:
|
||||
- name: mysql-client
|
||||
image: {{ DOCKER_REGISTRY }}{{ DOCKER_IMAGE_MYSQL }}
|
||||
command: ["/bin/sh", "-e", "-c"]
|
||||
args:
|
||||
- |
|
||||
{{ include_script("mysql-client/createdatabases")|indent(12) }}
|
||||
---
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: cms/init
|
||||
labels:
|
||||
app.kubernetes.io/component: script
|
||||
app.kubernetes.io/name: cms/init
|
||||
spec:
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: cms/init
|
||||
spec:
|
||||
restartPolicy: Never
|
||||
containers:
|
||||
- name: cms
|
||||
image: {{ DOCKER_REGISTRY }}{{ DOCKER_IMAGE_OPENEDX }}
|
||||
command: ["/bin/sh", "-e", "-c"]
|
||||
args:
|
||||
- |
|
||||
{{ include_script("cms/init")|indent(12) }}
|
||||
volumeMounts:
|
||||
- mountPath: /openedx/edx-platform/lms/envs/tutor/
|
||||
name: settings-lms
|
||||
- mountPath: /openedx/edx-platform/cms/envs/tutor/
|
||||
name: settings-cms
|
||||
- mountPath: /openedx/config
|
||||
name: config
|
||||
volumes:
|
||||
- name: settings-lms
|
||||
configMap:
|
||||
name: openedx-settings-lms
|
||||
- name: settings-cms
|
||||
configMap:
|
||||
name: openedx-settings-cms
|
||||
- name: config
|
||||
configMap:
|
||||
name: openedx-config
|
||||
---
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: lms/init
|
||||
labels:
|
||||
app.kubernetes.io/component: script
|
||||
app.kubernetes.io/name: lms/init
|
||||
spec:
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: lms/init
|
||||
spec:
|
||||
restartPolicy: Never
|
||||
containers:
|
||||
- name: lms
|
||||
image: {{ DOCKER_REGISTRY }}{{ DOCKER_IMAGE_OPENEDX }}
|
||||
command: ["/bin/sh", "-e", "-c"]
|
||||
args:
|
||||
- |
|
||||
{{ include_script("lms/init")|indent(12) }}
|
||||
volumeMounts:
|
||||
- mountPath: /openedx/edx-platform/lms/envs/tutor/
|
||||
name: settings-lms
|
||||
- mountPath: /openedx/edx-platform/cms/envs/tutor/
|
||||
name: settings-cms
|
||||
- mountPath: /openedx/config
|
||||
name: config
|
||||
volumes:
|
||||
- name: settings-lms
|
||||
configMap:
|
||||
name: openedx-settings-lms
|
||||
- name: settings-cms
|
||||
configMap:
|
||||
name: openedx-settings-cms
|
||||
- name: config
|
||||
configMap:
|
||||
name: openedx-config
|
||||
---
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: cms/importdemocourse
|
||||
labels:
|
||||
app.kubernetes.io/component: script
|
||||
app.kubernetes.io/name: cms/importdemocourse
|
||||
spec:
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: cms/importdemocourse
|
||||
spec:
|
||||
restartPolicy: Never
|
||||
containers:
|
||||
- name: lms
|
||||
image: {{ DOCKER_REGISTRY }}{{ DOCKER_IMAGE_OPENEDX }}
|
||||
command: ["/bin/sh", "-e", "-c"]
|
||||
args:
|
||||
- |
|
||||
{{ include_script("cms/importdemocourse")|indent(12) }}
|
||||
volumeMounts:
|
||||
- mountPath: /openedx/edx-platform/lms/envs/tutor/
|
||||
name: settings-lms
|
||||
- mountPath: /openedx/edx-platform/cms/envs/tutor/
|
||||
name: settings-cms
|
||||
- mountPath: /openedx/config
|
||||
name: config
|
||||
- mountPath: /openedx/data
|
||||
name: data
|
||||
volumes:
|
||||
- name: settings-lms
|
||||
configMap:
|
||||
name: openedx-settings-lms
|
||||
- name: settings-cms
|
||||
configMap:
|
||||
name: openedx-settings-cms
|
||||
- name: config
|
||||
configMap:
|
||||
name: openedx-config
|
||||
- name: data
|
||||
persistentVolumeClaim:
|
||||
claimName: lms-data
|
||||
{% if ACTIVATE_FORUM %}
|
||||
---
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: forum/init
|
||||
labels:
|
||||
app.kubernetes.io/component: script
|
||||
app.kubernetes.io/name: forum/init
|
||||
spec:
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: forum/init
|
||||
spec:
|
||||
restartPolicy: Never
|
||||
containers:
|
||||
- name: forum
|
||||
image: {{ DOCKER_REGISTRY }}{{ DOCKER_IMAGE_FORUM }}
|
||||
command: ["/bin/sh", "-e", "-c"]
|
||||
args:
|
||||
- |
|
||||
{{ include_script("forum/init")|indent(12) }}
|
||||
env:
|
||||
- name: SEARCH_SERVER
|
||||
value: "http://{{ ELASTICSEARCH_HOST }}:{{ ELASTICSEARCH_PORT }}"
|
||||
- name: MONGOHQ_URL
|
||||
value: "mongodb://{% if MONGODB_USERNAME and MONGODB_PASSWORD %}{{ MONGODB_USERNAME}}:{{ MONGODB_PASSWORD }}@{% endif %}{{ MONGODB_HOST }}:{{ MONGODB_PORT }}/cs_comments_service"
|
||||
{% endif %}
|
||||
{% if ACTIVATE_NOTES %}
|
||||
---
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: notes/init
|
||||
labels:
|
||||
app.kubernetes.io/component: script
|
||||
app.kubernetes.io/name: notes/init
|
||||
spec:
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: notes/init
|
||||
spec:
|
||||
restartPolicy: Never
|
||||
containers:
|
||||
- name: notes
|
||||
image: {{ DOCKER_REGISTRY }}{{ DOCKER_IMAGE_NOTES }}
|
||||
command: ["/bin/sh", "-e", "-c"]
|
||||
args:
|
||||
- |
|
||||
{{ include_script("notes/init")|indent(12) }}
|
||||
volumeMounts:
|
||||
- mountPath: /openedx/edx-notes-api/notesserver/settings/tutor.py
|
||||
name: settings
|
||||
volumes:
|
||||
- name: settings
|
||||
configMap:
|
||||
name: notes-settings
|
||||
{% endif %}
|
||||
{% if ACTIVATE_XQUEUE %}
|
||||
---
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: xqueue/init
|
||||
labels:
|
||||
app.kubernetes.io/component: script
|
||||
app.kubernetes.io/name: xqueue/init
|
||||
spec:
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: xqueue/init
|
||||
spec:
|
||||
restartPolicy: Never
|
||||
containers:
|
||||
- name: xqueue
|
||||
image: {{ DOCKER_REGISTRY }}{{ DOCKER_IMAGE_NOTES }}
|
||||
command: ["/bin/sh", "-e", "-c"]
|
||||
args:
|
||||
- |
|
||||
{{ include_script("xqueue/init")|indent(12) }}
|
||||
volumeMounts:
|
||||
- mountPath: /openedx/xqueue/xqueue/tutor.py
|
||||
name: settings
|
||||
volumes:
|
||||
- name: settings
|
||||
configMap:
|
||||
name: notes-settings
|
||||
{% endif %}
|
||||
|
||||
{{ patch("k8s-jobs") }}
|
@ -2,4 +2,6 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: openedx
|
||||
name: {{ K8S_NAMESPACE }}
|
||||
labels:
|
||||
app.kubernetes.io/component: namespace
|
@ -9,7 +9,7 @@ spec:
|
||||
- port: 8000
|
||||
protocol: TCP
|
||||
selector:
|
||||
app: cms
|
||||
app.kubernetes.io/name: cms
|
||||
{% if ACTIVATE_FORUM %}
|
||||
---
|
||||
apiVersion: v1
|
||||
@ -22,7 +22,7 @@ spec:
|
||||
- port: 4567
|
||||
protocol: TCP
|
||||
selector:
|
||||
app: forum
|
||||
app.kubernetes.io/name: forum
|
||||
{% endif %}
|
||||
---
|
||||
apiVersion: v1
|
||||
@ -35,7 +35,7 @@ spec:
|
||||
- port: 8000
|
||||
protocol: TCP
|
||||
selector:
|
||||
app: lms
|
||||
app.kubernetes.io/name: lms
|
||||
{% if ACTIVATE_ELASTICSEARCH %}
|
||||
---
|
||||
apiVersion: v1
|
||||
@ -48,7 +48,7 @@ spec:
|
||||
- port: 9200
|
||||
protocol: TCP
|
||||
selector:
|
||||
app: elasticsearch
|
||||
app.kubernetes.io/name: elasticsearch
|
||||
{% endif %}
|
||||
{% if ACTIVATE_MEMCACHED %}
|
||||
---
|
||||
@ -62,7 +62,7 @@ spec:
|
||||
- port: 11211
|
||||
protocol: TCP
|
||||
selector:
|
||||
app: memcached
|
||||
app.kubernetes.io/name: memcached
|
||||
{% endif %}
|
||||
{% if ACTIVATE_MONGODB %}
|
||||
---
|
||||
@ -76,7 +76,7 @@ spec:
|
||||
- port: 27017
|
||||
protocol: TCP
|
||||
selector:
|
||||
app: mongodb
|
||||
app.kubernetes.io/name: mongodb
|
||||
{% endif %}
|
||||
{% if ACTIVATE_MYSQL %}
|
||||
---
|
||||
@ -90,7 +90,7 @@ spec:
|
||||
- port: 3306
|
||||
protocol: TCP
|
||||
selector:
|
||||
app: mysql
|
||||
app.kubernetes.io/name: mysql
|
||||
{% endif %}
|
||||
---
|
||||
apiVersion: v1
|
||||
@ -101,15 +101,25 @@ spec:
|
||||
type: NodePort
|
||||
ports:
|
||||
- port: 80
|
||||
protocol: TCP
|
||||
name: http
|
||||
targetPort: http-port
|
||||
- port: 443
|
||||
protocol: TCP
|
||||
name: https
|
||||
targetPort: https-port
|
||||
selector:
|
||||
app: nginx
|
||||
app.kubernetes.io/name: nginx
|
||||
{% if ACTIVATE_FORUM %}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: notes
|
||||
spec:
|
||||
type: NodePort
|
||||
ports:
|
||||
- port: 8000
|
||||
protocol: TCP
|
||||
selector:
|
||||
app.kubernetes.io/name: notes
|
||||
{% endif %}
|
||||
{% if ACTIVATE_RABBITMQ %}
|
||||
---
|
||||
apiVersion: v1
|
||||
@ -122,7 +132,7 @@ spec:
|
||||
- port: 5672
|
||||
protocol: TCP
|
||||
selector:
|
||||
app: rabbitmq
|
||||
app.kubernetes.io/name: rabbitmq
|
||||
{% endif %}
|
||||
{% if ACTIVATE_SMTP %}
|
||||
---
|
||||
@ -136,5 +146,5 @@ spec:
|
||||
- port: 25
|
||||
protocol: TCP
|
||||
selector:
|
||||
app: smtp
|
||||
app.kubernetes.io/name: smtp
|
||||
{% endif %}
|
||||
|
@ -3,21 +3,26 @@ apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: cms-data
|
||||
labels:
|
||||
app.kubernetes.io/component: volume
|
||||
app.kubernetes.io/name: cms-data
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
- ReadWriteMany
|
||||
resources:
|
||||
requests:
|
||||
storage: 2Gi
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: lms-data
|
||||
labels:
|
||||
app.kubernetes.io/component: volume
|
||||
app.kubernetes.io/name: lms-data
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
- ReadWriteMany
|
||||
resources:
|
||||
requests:
|
||||
storage: 2Gi
|
||||
@ -27,6 +32,9 @@ apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: elasticsearch
|
||||
labels:
|
||||
app.kubernetes.io/component: volume
|
||||
app.kubernetes.io/name: elasticearch
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
@ -40,6 +48,9 @@ apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: mysql
|
||||
labels:
|
||||
app.kubernetes.io/component: volume
|
||||
app.kubernetes.io/name: mysql
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
@ -47,23 +58,31 @@ spec:
|
||||
requests:
|
||||
storage: 5Gi
|
||||
{% endif %}
|
||||
{% if ACTIVATE_NOTES %}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: openedx-staticfiles
|
||||
name: notes-data
|
||||
labels:
|
||||
app.kubernetes.io/component: volume
|
||||
app.kubernetes.io/name: notes-data
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 1Gi
|
||||
{% endif %}
|
||||
{% if ACTIVATE_RABBITMQ %}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: rabbitmq
|
||||
labels:
|
||||
app.kubernetes.io/component: volume
|
||||
app.kubernetes.io/name: rabbitmq
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
|
40
tutor/templates/kustomization.yml
Normal file
40
tutor/templates/kustomization.yml
Normal file
@ -0,0 +1,40 @@
|
||||
---
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- k8s/namespace.yml
|
||||
- k8s/deployments.yml
|
||||
- k8s/ingress.yml
|
||||
- k8s/jobs.yml
|
||||
- k8s/services.yml
|
||||
- k8s/volumes.yml
|
||||
|
||||
# namespace to deploy all Resources to
|
||||
namespace: {{ K8S_NAMESPACE }}
|
||||
|
||||
# labels added to all Resources
|
||||
# https://kubernetes.io/docs/concepts/overview/working-with-objects/common-labels/
|
||||
commonLabels:
|
||||
app.kubernetes.io/instance: openedx-{{ ID }}
|
||||
app.kubernetes.io/version: {{ TUTOR_VERSION }}
|
||||
app.kubernetes.io/part-of: openedx
|
||||
app.kubernetes.io/managed-by: tutor
|
||||
|
||||
configMapGenerator:
|
||||
- name: openedx-settings-lms
|
||||
files:{% for file in "apps/openedx/settings/lms"|walk_templates %}
|
||||
- {{ file }}{% endfor %}
|
||||
- name: openedx-settings-cms
|
||||
files:{% for file in "apps/openedx/settings/cms"|walk_templates %}
|
||||
- {{ file }}{% endfor %}
|
||||
- name: openedx-config
|
||||
files:{% for file in "apps/openedx/config"|walk_templates %}
|
||||
- {{ file }}{% endfor %}
|
||||
- name: nginx-config
|
||||
files:{% for file in "apps/nginx"|walk_templates %}
|
||||
- {{ file }}{% endfor %}
|
||||
{% if ACTIVATE_MYSQL %}- name: mysql-config
|
||||
env: apps/mysql/auth.env{% endif %}
|
||||
{% if ACTIVATE_NOTES %}- name: notes-settings
|
||||
files:
|
||||
- apps/notes/settings/tutor.py{% endif %}
|
1
tutor/templates/scripts/migrate_xqueue.sh
Normal file
1
tutor/templates/scripts/migrate_xqueue.sh
Normal file
@ -0,0 +1 @@
|
||||
./manage.py migrate
|
@ -51,6 +51,15 @@ def reverse_host(domain):
|
||||
return ".".join(domain.split(".")[::-1])
|
||||
|
||||
|
||||
def walk_files(path):
|
||||
"""
|
||||
Iterate on file paths located in directory.
|
||||
"""
|
||||
for dirpath, _, filenames in os.walk(path):
|
||||
for filename in filenames:
|
||||
yield os.path.join(dirpath, filename)
|
||||
|
||||
|
||||
def docker_run(*command):
|
||||
return docker("run", "--rm", "-it", *command)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user